Three.js로 제작한 3D Asset viewer를 위한 Arnold 쉐이더 속성 Excel파일로 추출하기 – v0.1



Three.js로 제작한 3D Asset viewer를 위한 Arnold 쉐이더 속성 Excel파일로 추출하기 – v0.1

초보자를 대상으로 한 이번 포스팅에서는 Three.js로 제작한 3D Asset viewer에서 사용되는 Arnold 쉐이더의 속성을 Excel 파일로 추출하는 방법을 알아보겠습니다.

 

필요한 패키지 설치하기

먼저 이 작업을 수행하기 위해 필요한 패키지를 설치해야 합니다. 아래 명령어를 터미널에 입력하여 필요한 패키지를 설치하세요.

pip install openpyxl

 

쉐이더 속성 추출하기

주어진 코드를 사용하여 쉐이더의 속성을 추출할 수 있습니다. 이 코드는 해당 쉐이더의 baseColor, metalness, specular, specularRoughness, specularColor 등의 속성을 가져옵니다.

 

쉐이더 속성을 Excel 파일로 저장하기

추출한 쉐이더 속성을 엑셀 파일로 저장할 수 있습니다. 엑셀 파일에는 각 쉐이더의 속성이 시트로 구분되어 저장됩니다.

 

전체 코드

아래는 전체 코드입니다. 주어진 코드를 사용하여 쉐이더 속성을 추출하고 엑셀 파일로 저장할 수 있습니다.

# 필요한 Maya 모듈 및 외부 라이브러리를 가져옵니다.
import maya.cmds as cmds
import os
from openpyxl import Workbook
from maya.OpenMaya import MGlobal

# 해당 속성이 연결되어 있는지 확인하는 함수
def is_connected(attr):
    """
    해당 속성이 연결되어 있는지 여부를 확인합니다.
    
    :param attr: 연결을 확인할 속성의 이름
    :return: 연결되어 있으면 True, 아니면 False
    """
    return cmds.connectionInfo(attr, isDestination=True) and cmds.listConnections(attr)

# 해당 속성에 연결된 노드를 가져오는 함수
def get_connected_node(attr):
    """
    해당 속성에 연결된 노드를 가져옵니다.
    
    :param attr: 연결된 노드를 가져올 속성의 이름
    :return: 연결된 노드의 이름, 없으면 None
    """
    connections = cmds.listConnections(attr, source=True, destination=False)
    if connections:
        return connections[0]
    else:
        return None

# RGB 값을 16진수로 변환하는 함수
def rgb_to_hex(rgb):
    """
    RGB 값을 16진수로 변환합니다.
    
    :param rgb: RGB 값의 튜플
    :return: 16진수 색상 코드
    """
    return '0x{:02x}{:02x}{:02x}'.format(int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255))

# 반사율을 계산하는 함수
def calculate_reflectivity(metalness_weight, specular_weight, specular_color):
    """
    반사율을 계산합니다.
    
    :param metalness_weight: 금속성 가중치
    :param specular_weight: 반사 가중치
    :param specular_color: 반사 색상
    :return: 계산된 반사율 값
    """
    # 반사 색상이 튜플의 리스트인 경우 첫 번째 값만 사용합니다.
    if isinstance(specular_color, list) and len(specular_color) == 1 and isinstance(specular_color[0], tuple):
        specular_color = specular_color[0]
    specular_brightness = sum(specular_color) / 3.0
    if metalness_weight == 1:
        return 0.8 + (specular_weight * 0.2)
    else:
        return specular_weight * specular_brightness

# 쉐이더의 속성을 가져오는 함수
def get_shader_attributes(shader):
    """
    쉐이더의 속성을 가져옵니다.
    
    :param shader: 쉐이더의 이름
    :return: 쉐이더의 속성 딕셔너리
    """
    attributes = {}
    # 쉐이더 속성 및 해당하는 메이어 노드 속성 매핑
    shader_props = {
        "baseColor": "baseColor",
        "metalness": "metalness",
        "specular": "specularIntensity",
        "specularRoughness": "roughness",
        "specularColor": "specularColor",
        "specularIOR": "ior",
        "transmission": "transmission",
        "transmissionColor": "transmissionColor",
        "coat": "clearcoat",
        "coatColor": "clearcoatColor",
        "coatRoughness": "clearcoatRoughness",
        "sheen": "sheen",
        "sheenColor": "sheenColor",
        "sheenRoughness": "sheenRoughness",
        "emission": "emissive"
    }
    
    for prop, attr_name in shader_props.items():
        prop_attr = f"{shader}.{prop}"
        # 연결된 텍스처 또는 노드인 경우 값을 가져오지 않고 건너뜁니다.
        if not is_connected(prop_attr):
            if prop in ["baseColor", "specularColor", "transmissionColor", "coatColor", "sheenColor"]:
                color_value = cmds.getAttr(prop_attr)[0]
                attributes[attr_name] = rgb_to_hex(color_value)
            else:
                value = cmds.getAttr(prop_attr)
                attributes[attr_name] = value
        else:
            print(f"{prop_attr} is connected to a texture or node, skipping.")

    # 반사율을 별도로 계산하고 'reflectivity'에 할당합니다.
    if "specularColor" in attributes:
        metalness_weight = attributes.get("metalness", 0)
        specular_weight = attributes.get("specularIntensity", 0)
        specular_color = cmds.getAttr(f"{shader}.specularColor")[0] if "specularColor" in shader_props and not is_connected(f"{shader}.specularColor") else (1, 1, 1)
        reflectivity_value = calculate_reflectivity(metalness_weight, specular_weight, specular_color)
        attributes["reflectivity"] = reflectivity_value

    return attributes

# 쉐이더 속성을 엑셀 파일로 내보내는 함수
def get_shader_properties_xlsx():
    """
    쉐이더 속성을 엑셀 파일로 내보냅니다.
    """
    # 건너뛸 쉐이더 목록
    skip_shaders = ['lambert1', 'particleCloud1', 'shaderGlow1', 'standardSurface1']
    current_file = cmds.file(query=True, sceneName=True)
    file_path = os.path.dirname(current_file)
    output_file_path = os.path.join(file_path, "props.xlsx")

    # 파일이 이미 존재하면 삭제합니다.
    if os.path.exists(output_file_path):
        os.remove(output_file_path)

    # 엑셀 워크북 생성
    wb = Workbook()
    first_sheet = wb.active
    first_sheet.title = "Arnold Shaders"
    
    # 모든 쉐이더에 대해 반복하면서 속성을 가져옵니다.
    shaders = sorted(cmds.ls(materials=True))
    for shader in shaders:
        if shader not in skip_shaders and cmds.nodeType(shader) == "aiStandardSurface":
            attr_data = get_shader_attributes(shader)
            if attr_data:
                ws = wb.create_sheet(title=shader)
                for attribute, value in attr_data.items():
                    ws.append([attribute, value])

    # 'Arnold Shaders' 시트 삭제
    if 'Arnold Shaders' in wb.sheetnames:
        wb.remove(wb['Arnold Shaders'])

    # 엑셀 파일 저장
    wb.save(output_file_path)
    MGlobal.displayInfo("props.xlsx 파일 생성이 완료되었습니다!!!")

# 함수 호출
get_shader_properties_xlsx()

# 완료 다이얼로그 표시
cmds.confirmDialog(title='완료', message='프로세스가 성공적으로 완료되었습니다!', button='확인')