이번에는 Maya에서 작성된 standardSurface 쉐이더의 속성을 Excel 파일로 내보내고, 이를 Three.js와 같은 다른 플랫폼에서 사용할 수 있도록 하는 과정을 알아보겠습니다.
단계 1: 필요한 모듈 가져오기
먼저 필요한 모듈을 가져옵니다. 이 모듈들은 Excel 파일 생성 및 속성 정보 가져오기에 사용됩니다.
import maya.cmds as cmds
import os
from openpyxl import Workbook
from openpyxl.styles import Alignment
from maya.OpenMaya import MGlobal
단계 2: 속성 연결 확인 함수 작성하기
쉐이더의 속성이 다른 노드에 연결되어 있는지 확인하는 함수를 작성합니다.
def is_connected(attr):
"""속성이 다른 노드에 연결되어 있는지 확인합니다."""
return cmds.connectionInfo(attr, isDestination=True) and cmds.listConnections(attr)
단계 3: 속성에 연결된 노드 가져오기 함수 작성하기
쉐이더의 속성에 연결된 노드를 가져오는 함수를 작성합니다.
def get_connected_node(attr):
"""속성에 연결된 노드를 가져옵니다."""
connections = cmds.listConnections(attr, source=True, destination=False)
if connections:
return connections[0]
else:
return None
단계 4: RGB 값을 16진수 색상 코드로 변환하는 함수 작성하기
RGB 값을 16진수 색상 코드로 변환하는 함수를 작성합니다.
def rgb_to_hex(rgb):
"""RGB 값을 16진수 색상 코드로 변환합니다."""
return '0x{:02x}{:02x}{:02x}'.format(int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255))
단계 5: 반사율 계산 함수 작성하기
반사율을 계산하는 함수를 작성합니다.
def calculate_reflectivity(metalness_weight, specular_weight, specular_color):
"""반사율을 계산합니다."""
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
단계 6: 쉐이더 속성 가져오기 함수 작성하기
쉐이더의 속성을 가져오는 함수를 작성합니다.
def get_shader_attributes(shader):
"""
쉐이더의 속성을 가져옵니다. 특정 속성이 0이면 관련 속성들을 제외합니다.
: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"
}
# 속성 값을 먼저 검사합니다.
excluded_props = []
if cmds.getAttr(f"{shader}.transmission") == 0:
excluded_props.extend(["transmission", "transmissionColor"])
if cmds.getAttr(f"{shader}.coat") == 0:
excluded_props.extend(["coat", "coatColor", "coatRoughness"])
if cmds.getAttr(f"{shader}.sheen") == 0:
excluded_props.extend(["sheen", "sheenColor", "sheenRoughness"])
if cmds.getAttr(f"{shader}.emission") == 0:
excluded_props.append("emission")
for prop, attr_name in shader_props.items():
if prop in excluded_props:
continue # 제외할 속성이면 건너뜁니다.
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.")
if "specularColor" in attributes and "metalness" in attributes and "specularIntensity" in attributes:
# 반사율 계산은 모든 필요한 속성이 있는 경우에만 수행합니다.
metalness_weight = attributes["metalness"]
specular_weight = attributes["specularIntensity"]
specular_color = cmds.getAttr(f"{shader}.specularColor")[0] if 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
단계 7: 쉐이더 속성을 Excel 파일로 내보내는 함수 작성하기
쉐이더의 속성을 Excel 파일로 내보내는 함수를 작성합니다.
def get_shader_properties_xlsx():
"""쉐이더 속성을 엑셀 파일로 내보냅니다. 특정 속성이 0이면 관련 속성들을 제외하고, 열 너비와 정렬을 설정합니다."""
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 = "StandardSurface Shaders"
shaders = sorted(cmds.ls(materials=True))
for shader in shaders:
if shader not in skip_shaders and cmds.nodeType(shader) == "standardSurface":
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])
# A열 너비 설정, A열 왼쪽 정렬
ws.column_dimensions['A'].width = 20
for cell in ws['A']:
cell.alignment = Alignment(horizontal='left')
# B열 너비 설정, B열 오른쪽 정렬
ws.column_dimensions['B'].width = 10
for cell in ws['B']:
cell.alignment = Alignment(horizontal='right')
# 'Arnold Shaders' 시트가 비어있으면 삭제합니다.
if 'StandardSurface Shaders' in wb.sheetnames and not list(first_sheet.rows):
wb.remove(first_sheet)
# 엑셀 파일 저장
wb.save(output_file_path)
MGlobal.displayInfo("props.xlsx 파일 생성이 완료되었습니다!!!")
단계 8: 함수 호출 및 완료 다이얼로그 표시
작성한 함수를 호출하고, 프로세스 완료를 알리는 다이얼로그를 표시합니다.
get_shader_properties_xlsx()
cmds.confirmDialog(title='완료', message='프로세스가 성공적으로 완료되었습니다!', button='확인')
단계 9: 최종 코드
import maya.cmds as cmds
import os
from openpyxl import Workbook
from openpyxl.styles import Alignment
from maya.OpenMaya import MGlobal
def is_connected(attr):
"""속성이 다른 노드에 연결되어 있는지 확인합니다."""
return cmds.connectionInfo(attr, isDestination=True) and cmds.listConnections(attr)
def get_connected_node(attr):
"""속성에 연결된 노드를 가져옵니다."""
connections = cmds.listConnections(attr, source=True, destination=False)
if connections:
return connections[0]
else:
return None
def rgb_to_hex(rgb):
"""RGB 값을 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):
"""반사율을 계산합니다."""
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):
"""
쉐이더의 속성을 가져옵니다. 특정 속성이 0이면 관련 속성들을 제외합니다.
: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"
}
# 속성 값을 먼저 검사합니다.
excluded_props = []
if cmds.getAttr(f"{shader}.transmission") == 0:
excluded_props.extend(["transmission", "transmissionColor"])
if cmds.getAttr(f"{shader}.coat") == 0:
excluded_props.extend(["coat", "coatColor", "coatRoughness"])
if cmds.getAttr(f"{shader}.sheen") == 0:
excluded_props.extend(["sheen", "sheenColor", "sheenRoughness"])
if cmds.getAttr(f"{shader}.emission") == 0:
excluded_props.append("emission")
for prop, attr_name in shader_props.items():
if prop in excluded_props:
continue # 제외할 속성이면 건너뜁니다.
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.")
if "specularColor" in attributes and "metalness" in attributes and "specularIntensity" in attributes:
# 반사율 계산은 모든 필요한 속성이 있는 경우에만 수행합니다.
metalness_weight = attributes["metalness"]
specular_weight = attributes["specularIntensity"]
specular_color = cmds.getAttr(f"{shader}.specularColor")[0] if 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():
"""쉐이더 속성을 엑셀 파일로 내보냅니다. 특정 속성이 0이면 관련 속성들을 제외하고, 열 너비와 정렬을 설정합니다."""
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 = "StandardSurface Shaders"
shaders = sorted(cmds.ls(materials=True))
for shader in shaders:
if shader not in skip_shaders and cmds.nodeType(shader) == "standardSurface":
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])
# A열 너비 설정, A열 왼쪽 정렬
ws.column_dimensions['A'].width = 20
for cell in ws['A']:
cell.alignment = Alignment(horizontal='left')
# B열 너비 설정, B열 오른쪽 정렬
ws.column_dimensions['B'].width = 10
for cell in ws['B']:
cell.alignment = Alignment(horizontal='right')
# 'Arnold Shaders' 시트가 비어있으면 삭제합니다.
if 'StandardSurface Shaders' in wb.sheetnames and not list(first_sheet.rows):
wb.remove(first_sheet)
# 엑셀 파일 저장
wb.save(output_file_path)
MGlobal.displayInfo("props.xlsx 파일 생성이 완료되었습니다!!!")
get_shader_properties_xlsx()
cmds.confirmDialog(title='완료', message='프로세스가 성공적으로 완료되었습니다!', button='확인')
이렇게 하면 Maya의 standardSurface 쉐이더 속성을 Excel 파일로 저장하는 스크립트를 만들었습니다. 이제 Three.js나 다른 플랫폼에서 이 속성을 쉽게 사용할 수 있습니다.
제 글이 마음에 드셨다면 광고 한 번씩 클릭 부탁드립니다.
제작에 큰 힘이 됩니다. 감사합니다.