들어가며
Three.js 뷰어에 적용할 3D Asset의 V-Ray 쉐이더 속성을 Excel 파일로 저장하는 과정을 초보자를 위해 단계별로 설명합니다.
필요한 준비물
이 프로젝트를 시작하기 전에 Python과 필요한 패키지들을 설치해야 합니다. 다음 명령어들을 터미널에서 실행하여 필요한 패키지를 설치하세요:
pip install openpyxl
openpyxl을 설치한 후 마야가 해당 패키지를 인식하기 위해
‘C:\Users\사용자이름\AppData\Local\Programs\Python\파이썬 버전\Lib\site-packages’ 경로의
아래 4개 폴더를 복사 후 문서 폴더의 ‘maya\마야 버전\scripts\site-packages\’ 에 복사한 후 마야를 실행하거나 재실행 합니다.(패키지의 버전은 변경될 수 있습니다.)
et_xmlfile,
et_xmlfile-1.1.0.dist-info,
openpyxl,
openpyxl-3.1.2.dist-info
1단계: 필요한 모듈 임포트
먼저 필요한 Python 모듈들을 임포트합니다. 이 모듈들은 파일 작업, 색상 변환 및 Excel 파일 작업을 위해 필요합니다.
# 필요한 모듈 임포트
import maya.cmds as cmds # Maya 명령어를 위한 모듈
import os # 파일 시스템 경로와 상호작용을 위한 모듈
import colorsys # 색상 변환을 위한 모듈
from openpyxl import load_workbook, Workbook # Excel 파일 작업을 위한 모듈
from maya.OpenMaya import MGlobal # Maya 전역 메시지 출력을 위한 모듈
2단계: 색상 변환 및 연결 확인 함수 정의
HSV 색상을 RGB로 변환하고, 어트리뷰트가 다른 어트리뷰트에 연결되어 있는지 확인하는 함수를 정의합니다.
# HSV 색상을 RGB로 변환하는 함수
def hsv_to_rgb(h, s, v):
return colorsys.hsv_to_rgb(h, s, v)
# 어트리뷰트가 다른 어트리뷰트에 연결되어 있는지 확인하는 함수
def is_connected(attr):
return cmds.connectionInfo(attr, isDestination=True) and cmds.listConnections(attr)
3단계: RGB 색상을 16진수로 변환하는 함수 정의
RGB 색상을 16진수 형식으로 변환하는 함수를 정의합니다. 이 함수는 쉐이더 속성에서 RGB 값을 16진수로 변환하는 데 사용됩니다.
# RGB 색상을 16진수 형식으로 변환하는 함수
def rgb_to_hex(rgb):
return '0x{:02x}{:02x}{:02x}'.format(int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255))
4단계: 쉐이더 속성 추출 및 Excel 파일로 저장
V-Ray 쉐이더의 속성을 추출하고 이를 Excel 파일로 저장하는 메인 함수를 정의합니다. 이 함수는 Maya의 쉐이더 목록을 순회하면서 각 쉐이더의 속성을 Excel 파일에 기록합니다.
# 쉐이더 속성을 Excel 파일로 추출하는 함수
def get_shader_properties_xlsx():
# 건너뛸 쉐이더 리스트
skip_shaders = ['lambert1', 'particleCloud1', 'shaderGlow1', 'standardSurface1']
current_file = cmds.file(query=True, sceneName=True) # 현재 열려 있는 Maya 파일의 경로
file_path = os.path.dirname(current_file) # 파일의 디렉토리 경로
output_file_path = os.path.join(file_path, "props.xlsx") # 출력할 Excel 파일의 경로
# 기존 파일이 존재하면 삭제
if os.path.exists(output_file_path):
os.remove(output_file_path)
wb = Workbook() # 새 Excel 워크북 생성
shaders = sorted(cmds.ls(materials=True)) # 쉐이더 목록 불러오기
for shader in shaders:
if shader not in skip_shaders:
try:
# 쉐이더 이름으로 워크시트 생성
ws = wb[shader] if shader in wb.sheetnames else wb.create_sheet(title=shader)
attr_data = get_shader_attributes(shader) # 쉐이더 속성 추출
if attr_data:
for attribute, value in attr_data.items():
ws.append([attribute, value]) # 워크시트에 속성 추가
except ValueError as ve:
MGlobal.displayError(f"Error processing shader {shader}: {ve}") # 에러 메시지 출력
# 기본 생성된 Sheet 제거
if 'Sheet' in wb.sheetnames:
wb.remove(wb['Sheet'])
wb.save(output_file_path) # 워크북 저장
MGlobal.displayInfo("props.xlsx creation is completed!!!") # 완료 메시지 출력
5단계: 특정 쉐이더의 속성 추출 함수 정의
특정 쉐이더의 속성을 추출하는 get_shader_attributes 함수를 정의합니다. 이 함수는 특정 쉐이더의 VRayMtl 속성을 추출하고, 이를 해석하여 저장합니다.
# 특정 쉐이더의 속성을 추출하는 함수
def get_shader_attributes(shader):
shader_type = cmds.nodeType(shader) # 쉐이더 타입 확인
attributes = {}
# VRayMtl 속성 이름 매핑
vray_attr_name_mapping = {
"reflectionColorAmount": "reflectivity",
"reflectionGlossiness": "roughness",
"metalness": "metalness",
"refractionIOR": "ior",
"sheenColorAmount": "sheen",
"sheenGlossiness": "sheenRoughness",
"refractionColor": "transmission",
"color": "baseColor",
"sheenColor": "sheenColor"
}
# Lambert 속성 이름 매핑 (예시)
lambert_attr_name_mapping = {
"color": "baseColor",
"translucence": "transmission",
"refractiveIndex": "ior"
# 여기에 추가적인 Lambert 쉐이더 속성 매핑을 추가하세요.
}
if shader_type == "VRayMtl":
for internal_attr, display_attr in vray_attr_name_mapping.items():
full_attr = f"{shader}.{internal_attr}"
if not is_connected(full_attr):
attr_value = cmds.getAttr(full_attr)
if internal_attr == "refractionColor": # refractionColor 속성 처리
# RGB를 HSV로 변환
hsv_value = colorsys.rgb_to_hsv(attr_value[0][0], attr_value[0][1], attr_value[0][2])
# V(밝기) 값을 추출하여 속성에 할당
attributes[display_attr] = hsv_value[2]
elif isinstance(attr_value, list) and isinstance(attr_value[0], tuple): # RGB 색상값 처리
hex_value = rgb_to_hex(attr_value[0])
attributes[display_attr] = hex_value
elif isinstance(attr_value, float): # 단일 float 값인 경우
attributes[display_attr] = round(attr_value, 3)
else: # 다른 타입의 경우 (예: 리스트)
attributes[display_attr] = str(attr_value) # 문자열로 변환
# 추가 속성 처리
attributes['specularIntensity'] = 1.0
elif shader_type == "lambert":
for internal_attr, display_attr in lambert_attr_name_mapping.items():
full_attr = f"{shader}.{internal_attr}"
if not is_connected(full_attr):
attr_value = cmds.getAttr(full_attr)
if isinstance(attr_value, list) and isinstance(attr_value[0], tuple): # RGB 색상값이 리스트 안의 튜플로 들어있는 경우
hex_value = rgb_to_hex(attr_value[0])
attributes[display_attr] = hex_value
elif isinstance(attr_value, float): # 단일 float 값인 경우
attributes[display_attr] = round(attr_value, 3)
else: # 다른 타입의 경우 (예: 리스트)
attributes[display_attr] = str(attr_value) # 문자열로 변환
return attributes # 추출된 속성 반환
get_shader_properties_xlsx() # 쉐이더 속성 추출 함수 실행
6단계: 완료 다이얼로그 표시
모든 과정이 끝나면 사용자에게 작업 완료를 알리는 다이얼로그를 표시합니다.
# 완료 다이얼로그 표시
cmds.confirmDialog(title='완료 다이얼로그', message='프로세스가 성공적으로 완료되었습니다!', button='확인')
7단계: 최종 코드
# 필요한 모듈 임포트
import maya.cmds as cmds # Maya 명령어를 위한 모듈
import os # 파일 시스템 경로와 상호작용을 위한 모듈
import colorsys # 색상 변환을 위한 모듈
from openpyxl import load_workbook, Workbook # Excel 파일 작업을 위한 모듈
from maya.OpenMaya import MGlobal # Maya 전역 메시지 출력을 위한 모듈
# HSV 색상을 RGB로 변환하는 함수
def hsv_to_rgb(h, s, v):
return colorsys.hsv_to_rgb(h, s, v)
# 어트리뷰트가 다른 어트리뷰트에 연결되어 있는지 확인하는 함수
def is_connected(attr):
return cmds.connectionInfo(attr, isDestination=True) and cmds.listConnections(attr)
# RGB 색상을 16진수 형식으로 변환하는 함수
def rgb_to_hex(rgb):
return '0x{:02x}{:02x}{:02x}'.format(int(rgb[0]*255), int(rgb[1]*255), int(rgb[2]*255))
# 쉐이더 속성을 Excel 파일로 추출하는 함수
def get_shader_properties_xlsx():
# 건너뛸 쉐이더 리스트
skip_shaders = ['lambert1', 'particleCloud1', 'shaderGlow1', 'standardSurface1']
current_file = cmds.file(query=True, sceneName=True) # 현재 열려 있는 Maya 파일의 경로
file_path = os.path.dirname(current_file) # 파일의 디렉토리 경로
output_file_path = os.path.join(file_path, "props.xlsx") # 출력할 Excel 파일의 경로
# 기존 파일이 존재하면 삭제
if os.path.exists(output_file_path):
os.remove(output_file_path)
wb = Workbook() # 새 Excel 워크북 생성
shaders = sorted(cmds.ls(materials=True)) # 쉐이더 목록 불러오기
for shader in shaders:
if shader not in skip_shaders:
try:
# 쉐이더 이름으로 워크시트 생성
ws = wb[shader] if shader in wb.sheetnames else wb.create_sheet(title=shader)
attr_data = get_shader_attributes(shader) # 쉐이더 속성 추출
if attr_data:
for attribute, value in attr_data.items():
ws.append([attribute, value]) # 워크시트에 속성 추가
except ValueError as ve:
MGlobal.displayError(f"Error processing shader {shader}: {ve}") # 에러 메시지 출력
# 기본 생성된 Sheet 제거
if 'Sheet' in wb.sheetnames:
wb.remove(wb['Sheet'])
wb.save(output_file_path) # 워크북 저장
MGlobal.displayInfo("props.xlsx creation is completed!!!") # 완료 메시지 출력
# 특정 쉐이더의 속성을 추출하는 함수
def get_shader_attributes(shader):
shader_type = cmds.nodeType(shader) # 쉐이더 타입 확인
attributes = {}
# VRayMtl 속성 이름 매핑
vray_attr_name_mapping = {
"reflectionColorAmount": "reflectivity",
"reflectionGlossiness": "roughness",
"metalness": "metalness",
"refractionIOR": "ior",
"sheenColorAmount": "sheen",
"sheenGlossiness": "sheenRoughness",
"refractionColor": "transmission",
"color": "baseColor",
"sheenColor": "sheenColor"
}
# Lambert 속성 이름 매핑 (예시)
lambert_attr_name_mapping = {
"color": "baseColor",
"translucence": "transmission",
"refractiveIndex": "ior"
# 여기에 추가적인 Lambert 쉐이더 속성 매핑을 추가하세요.
}
if shader_type == "VRayMtl":
for internal_attr, display_attr in vray_attr_name_mapping.items():
full_attr = f"{shader}.{internal_attr}"
if not is_connected(full_attr):
attr_value = cmds.getAttr(full_attr)
if internal_attr == "refractionColor": # refractionColor 속성 처리
# RGB를 HSV로 변환
hsv_value = colorsys.rgb_to_hsv(attr_value[0][0], attr_value[0][1], attr_value[0][2])
# V(밝기) 값을 추출하여 속성에 할당
attributes[display_attr] = hsv_value[2]
elif isinstance(attr_value, list) and isinstance(attr_value[0], tuple): # RGB 색상값 처리
hex_value = rgb_to_hex(attr_value[0])
attributes[display_attr] = hex_value
elif isinstance(attr_value, float): # 단일 float 값인 경우
attributes[display_attr] = round(attr_value, 3)
else: # 다른 타입의 경우 (예: 리스트)
attributes[display_attr] = str(attr_value) # 문자열로 변환
# 추가 속성 처리
attributes['specularIntensity'] = 1.0
elif shader_type == "lambert":
for internal_attr, display_attr in lambert_attr_name_mapping.items():
full_attr = f"{shader}.{internal_attr}"
if not is_connected(full_attr):
attr_value = cmds.getAttr(full_attr)
if isinstance(attr_value, list) and isinstance(attr_value[0], tuple): # RGB 색상값이 리스트 안의 튜플로 들어있는 경우
hex_value = rgb_to_hex(attr_value[0])
attributes[display_attr] = hex_value
elif isinstance(attr_value, float): # 단일 float 값인 경우
attributes[display_attr] = round(attr_value, 3)
else: # 다른 타입의 경우 (예: 리스트)
attributes[display_attr] = str(attr_value) # 문자열로 변환
return attributes # 추출된 속성 반환
get_shader_properties_xlsx() # 쉐이더 속성 추출 함수 실행
# 완료 다이얼로그 표시
cmds.confirmDialog(title='완료 다이얼로그', message='프로세스가 성공적으로 완료되었습니다!', button='확인')
8단계: 실행