MetaFusion/scripts/MetaFusion.py
2025-01-13 23:36:50 +08:00

440 lines
16 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#===================================== IMPORTS =====================================
# Standard library imports
import os
import sys
import webbrowser
import locale
# Qt imports
from PySide2 import QtWidgets, QtCore, QtGui
from shiboken2 import wrapInstance
# Maya imports
from maya import OpenMayaUI as omui
import maya.cmds as cmds
import maya.mel as mel
#===================================== IMPORT MODULES =====================================
import BodyPrep
import BatchImport
import DNA_Viewer
<<<<<<< Updated upstream
=======
>>>>>>> Stashed changes
#===================================== CONSTANTS =====================================
# Tool info
TOOL_NAME = "MetaFusion"
TOOL_VERSION = "Beta v1.0.0"
TOOL_AUTHOR = "CGNICO"
TOOL_LANG = 'en_US'
# UI Constants
TOOL_WSCL_NAME = "MetaFusionWorkSpaceControl"
<<<<<<< Updated upstream
TOOL_HELP_URL = f"http://10.72.61.59:3000/ArtGroup/{TOOL_NAME}/wiki"
=======
TOOL_HELP_URL = f"https://gitea.cgnico.com/CGNICO/MetaFusion/wiki"
>>>>>>> Stashed changes
DEFAULT_WINDOW_SIZE = (500, 800)
# Paths
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))).replace("\\", "/")
SCRIPTS_PATH = os.path.join(TOOL_PATH, "scripts").replace("\\", "/")
ICONS_PATH = os.path.join(TOOL_PATH, "icons").replace("\\", "/")
TOOL_ICON = os.path.join(ICONS_PATH, "logo.png").replace("\\", "/")
# Metahuman paths
DATA_PATH = os.path.join(TOOL_PATH, "data").replace("\\", "/")
DNA_PATH = os.path.join(DATA_PATH, "dna").replace("\\", "/")
BODY_PATH = os.path.join(DATA_PATH, "body").replace("\\", "/")
IMG_PATH = os.path.join(DATA_PATH, "img").replace("\\", "/")
MAP_PATH = os.path.join(DATA_PATH, "map").replace("\\", "/")
MASKS_PATH = os.path.join(DATA_PATH, "masks").replace("\\", "/")
SHADERS_PATH = os.path.join(DATA_PATH, "shaders").replace("\\", "/")
MH4_PATH = os.path.join(DATA_PATH, "mh4").replace("\\", "/")
MH4_DNA_PATH = os.path.join(MH4_PATH, "dna").replace("\\", "/")
OUT_PATH = os.path.join(DATA_PATH, "out").replace("\\", "/")
SAVE_PATH = os.path.join(DATA_PATH, "save").replace("\\", "/")
MAYA_VERSION = cmds.about(version=True)
PLUGIN_PATH = os.path.join(TOOL_PATH, "plugins", f"{MAYA_VERSION}").replace("\\", "/")
if not os.path.exists(PLUGIN_PATH):
cmds.warning(f"Plugin path not found: {PLUGIN_PATH}")
print(f"TOOL_PATH: {TOOL_PATH}")
print(f"SCRIPTS_PATH: {SCRIPTS_PATH}")
print(f"ICONS_PATH: {ICONS_PATH}")
print(f"TOOL_ICON: {TOOL_ICON}")
print(f"DATA_PATH: {DATA_PATH}")
print(f"DNA_PATH: {DNA_PATH}")
print(f"BODY_PATH: {BODY_PATH}")
print(f"IMG_PATH: {IMG_PATH}")
print(f"MAP_PATH: {MAP_PATH}")
print(f"MASKS_PATH: {MASKS_PATH}")
print(f"SHADERS_PATH: {SHADERS_PATH}")
#===================================== LANGUAGE SETTINGS =====================================
TOOL_LANG = 'en_US'
SUPPORTED_LANGUAGES = ['en_US', 'zh_CN']
LANG = {
"en_US": {
"MetaFusion": "MetaFusion",
"Prepare": "Prepare",
"Body Prepare": "Body Prepare",
"DNA Edit": "DNA Edit",
"Open DNA Viewer": "Open DNA Viewer",
"Import": "Import",
"Batch Import": "Batch Import",
"Help": "Help",
"Switch Language": "Switch Language",
"Language switched": "Language switched",
"EN": "EN",
"ZH": "ZH",
"English": "English",
"Chinese": "Chinese"
},
"zh_CN": {
"MetaFusion": "MetaFusion",
"Prepare": "准备",
"Body Prepare": "身体准备",
"DNA Edit": "DNA 编辑",
"Open DNA Viewer": "打开 DNA 查看器",
"Import": "导入",
"Batch Import": "批量导入",
"Help": "帮助",
"Switch Language": "切换语言",
"Language switched": "语言已切换",
"EN": "英文",
"ZH": "中文",
"English": "英语",
"Chinese": "中文"
}
}
#===================================== UTILITY FUNCTIONS =====================================
def get_system_encoding():
encoding = sys.getdefaultencoding()
if encoding.lower() == 'ascii':
encoding = locale.getpreferredencoding()
return encoding
def maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
#===================================== UI COMPONENTS =====================================
class MainButton(QtWidgets.QPushButton):
DEFAULT_COLORS = {"normal": "#D0D0D0", "hover": "#E0E0E0", "pressed": "#C0C0C0"}
def __init__(self, text="", icon=None, color=None, hover_color=None, pressed_color=None):
super().__init__(text)
if icon:
self.setIcon(icon)
self.setIconSize(QtCore.QSize(24, 24))
self.setMinimumHeight(30)
colors = {
"normal": color or self.DEFAULT_COLORS["normal"],
"hover": hover_color or self.DEFAULT_COLORS["hover"],
"pressed": pressed_color or self.DEFAULT_COLORS["pressed"]
}
self.setStyleSheet(self._generate_style_sheet(**colors))
@staticmethod
def _generate_style_sheet(normal, hover, pressed):
return f"""
QPushButton {{
background-color: {normal};
color: #303030;
border-radius: 10px;
padding: 5px;
font-weight: bold;
text-align: center;
}}
QPushButton:hover {{
background-color: {hover};
}}
QPushButton:pressed {{
background-color: {pressed};
}}
"""
class BottomButton(QtWidgets.QPushButton):
def __init__(self, text="", icon=None):
super().__init__(text)
self.setMinimumHeight(20)
self.setStyleSheet(self._generate_style_sheet())
self.setFont(QtGui.QFont("Microsoft YaHei", 10))
@staticmethod
def _generate_style_sheet():
return """
QPushButton {
background-color: transparent;
border: none;
color: gray;
font-weight: bold;
}
QPushButton:hover {
color: black;
}
"""
#===================================== MAIN WINDOW =====================================
class MainWindow(QtWidgets.QWidget):
instance = None
def __init__(self, parent=maya_main_window()):
self.load_required_plugins()
super(MainWindow, self).__init__(parent)
self.setWindowTitle(f"{TOOL_NAME} - {TOOL_VERSION}")
self.setObjectName(TOOL_PATH)
self.setWindowFlags(QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
self.setMinimumSize(300, 800)
self.create_widgets()
self.create_layouts()
self.create_connections()
if os.path.exists(TOOL_ICON):
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
else:
print(f"WARNING: Icon file not found: {TOOL_ICON}")
def load_required_plugins(self):
try:
if PLUGIN_PATH not in os.environ.get('MAYA_PLUG_IN_PATH', ''):
if 'MAYA_PLUG_IN_PATH' in os.environ:
os.environ['MAYA_PLUG_IN_PATH'] = f"{PLUGIN_PATH};{os.environ['MAYA_PLUG_IN_PATH']}"
else:
os.environ['MAYA_PLUG_IN_PATH'] = PLUGIN_PATH
required_plugins = ['embeddedRL4.mll']
for plugin in required_plugins:
plugin_path = os.path.join(PLUGIN_PATH, plugin)
if os.path.exists(plugin_path):
try:
if not cmds.pluginInfo(plugin, query=True, loaded=True):
cmds.loadPlugin(plugin_path)
print(f"Successfully loaded plugin: {plugin}")
except Exception as e:
cmds.warning(f"Failed to load plugin {plugin}: {str(e)}")
else:
cmds.warning(f"Plugin not found: {plugin_path}")
except Exception as e:
cmds.warning(f"Error loading plugins: {str(e)}")
@classmethod
def show_window(cls):
try:
if cmds.workspaceControl(TOOL_WSCL_NAME, exists=True):
cmds.deleteUI(TOOL_WSCL_NAME, control=True)
if cls.instance is not None:
try:
cls.instance.close()
cls.instance.deleteLater()
except Exception:
pass
cls.instance = cls()
cls.instance.dock_to_maya()
return cls.instance
except Exception as e:
print(f"Error showing {TOOL_NAME} window: {e}")
return None
def dock_to_maya(self):
if cmds.workspaceControl(TOOL_WSCL_NAME, exists=True):
cmds.deleteUI(TOOL_WSCL_NAME)
try:
workspace_control = cmds.workspaceControl(
TOOL_WSCL_NAME,
label=TOOL_NAME,
floating=True,
retain=True,
resizeWidth=True,
initialWidth=500,
minimumWidth=500
)
cmds.workspaceControl(TOOL_WSCL_NAME, e=True, resizeWidth=True)
cmds.control(self.objectName(), e=True, p=workspace_control)
cmds.evalDeferred(lambda: cmds.workspaceControl(TOOL_WSCL_NAME, e=True, resizeWidth=True))
except Exception as e:
print(f"Error creating workspace control: {e}")
#===================================== UI COMPONENTS =====================================
def create_widgets(self):
<<<<<<< Updated upstream
# DNA Edit group
self.dna_edit_btn = MainButton(LANG[TOOL_LANG]["DNA Edit"])
self.dna_viewer_btn = MainButton(LANG[TOOL_LANG]["Open DNA Viewer"], color="#B8E6B3", hover_color="#C4F2BF", pressed_color="#A3D99E")
=======
>>>>>>> Stashed changes
# Prepare group
self.prepare_btn = MainButton(LANG[TOOL_LANG]["Prepare"])
self.body_prepare_btn = MainButton(LANG[TOOL_LANG]["Body Prepare"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A")
<<<<<<< Updated upstream
=======
# DNA Edit group
self.dna_edit_btn = MainButton(LANG[TOOL_LANG]["DNA Edit"])
self.dna_viewer_btn = MainButton(LANG[TOOL_LANG]["Open DNA Viewer"], color="#B8E6B3", hover_color="#C4F2BF", pressed_color="#A3D99E")
# Import group
self.import_btn = MainButton(LANG[TOOL_LANG]["Import"])
self.batch_import_btn = MainButton(LANG[TOOL_LANG]["Batch Import"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
>>>>>>> Stashed changes
# Bottom buttons (existing code)
self.help_btn = BottomButton(LANG[TOOL_LANG]["Help"])
self.help_btn.setToolTip(LANG[TOOL_LANG]["Help"])
self.help_btn.setFixedSize(100, 20)
self.lang_btn = BottomButton(LANG[TOOL_LANG]["ZH" if TOOL_LANG == 'en_US' else "EN"])
self.lang_btn.setToolTip(LANG[TOOL_LANG]["Switch Language"])
self.lang_btn.setFixedSize(30, 20)
for button in [self.help_btn, self.lang_btn]:
button.setFont(QtGui.QFont("Microsoft YaHei", 10))
def create_layouts(self):
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(2, 2, 2, 2)
content_layout = QtWidgets.QVBoxLayout()
content_layout.setContentsMargins(5, 5, 5, 5)
bottom_layout = QtWidgets.QHBoxLayout()
bottom_layout.setContentsMargins(5, 0, 5, 5)
prepare_group = QtWidgets.QGroupBox("Prepare")
prepare_layout = QtWidgets.QVBoxLayout(prepare_group)
prepare_layout.addWidget(self.body_prepare_btn)
content_layout.addWidget(prepare_group)
import_group = QtWidgets.QGroupBox("Import")
import_layout = QtWidgets.QVBoxLayout(import_group)
import_layout.addWidget(self.batch_import_btn)
content_layout.addWidget(import_group)
<<<<<<< Updated upstream
main_layout.addLayout(content_layout)
main_layout.addStretch()
# Bottom layout (existing code)
bottom_layout = QtWidgets.QHBoxLayout()
bottom_layout.setContentsMargins(5, 0, 5, 5)
=======
dna_edit_group = QtWidgets.QGroupBox("DNA Edit")
dna_edit_layout = QtWidgets.QVBoxLayout(dna_edit_group)
dna_edit_layout.addWidget(self.dna_viewer_btn)
content_layout.addWidget(dna_edit_group)
>>>>>>> Stashed changes
icon_label = QtWidgets.QLabel()
if os.path.exists(TOOL_ICON):
icon = QtGui.QPixmap(TOOL_ICON).scaled(24, 24, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
icon_label.setPixmap(icon)
version_label = QtWidgets.QLabel(f"{TOOL_VERSION}")
version_label.setStyleSheet("color: gray; font-size: 12px;")
bottom_layout.addWidget(icon_label)
bottom_layout.addWidget(version_label)
bottom_layout.addWidget(self.help_btn)
bottom_layout.addWidget(self.lang_btn)
main_layout.addLayout(content_layout)
main_layout.addLayout(bottom_layout)
main_layout.addStretch()
def create_connections(self):
self.body_prepare_btn.clicked.connect(self.run_body_prepare)
self.dna_viewer_btn.clicked.connect(self.run_dna_viewer)
<<<<<<< Updated upstream
# Existing connections
=======
self.batch_import_btn.clicked.connect(self.run_batch_import)
>>>>>>> Stashed changes
self.help_btn.clicked.connect(self.help)
self.lang_btn.clicked.connect(self.switch_language)
#===================================== FUNCTIONS =====================================
#===================================== MAIN FUNCTIONS =====================================
def run_body_prepare(self):
BodyPrep.run()
def run_batch_import(self):
BatchImport.run()
def run_dna_viewer(self):
<<<<<<< Updated upstream
import DNA_Viewer
DNA_Viewer.show()
=======
DNA_Viewer.show()
>>>>>>> Stashed changes
#===================================== BOTTOM LAYOUT =====================================
def help(self):
webbrowser.open(TOOL_HELP_URL)
def switch_language(self):
global TOOL_LANG
TOOL_LANG = 'en_US' if TOOL_LANG == 'zh_CN' else 'zh_CN'
self.lang_btn.setText("ZH" if TOOL_LANG == 'en_US' else "EN")
self.retranslate_ui()
QtWidgets.QToolTip.showText(
self.lang_btn.mapToGlobal(QtCore.QPoint(0, -30)),
"Language switched" if TOOL_LANG == 'en_US' else "语言已切换",
self.lang_btn
)
def retranslate_ui(self):
<<<<<<< Updated upstream
# Update function button translations
=======
>>>>>>> Stashed changes
self.load_dna_btn.setText(LANG[TOOL_LANG]["Load DNA"])
self.body_prepare_btn.setText(LANG[TOOL_LANG]["Body Prepare"])
self.dna_viewer_btn.setText(LANG[TOOL_LANG]["Open DNA Viewer"])
self.batch_import_btn.setText(LANG[TOOL_LANG]["Batch Import"])
self.help_btn.setText(LANG[TOOL_LANG]["Help"])
self.lang_btn.setText("ZH" if TOOL_LANG == 'en_US' else "EN")
for button in [self.body_prepare_btn, self.dna_viewer_btn, self.batch_import_btn]:
button.setFont(QtGui.QFont("Microsoft YaHei", 10))
for button in [self.help_btn, self.lang_btn]:
button.setFont(QtGui.QFont("Microsoft YaHei", 10))
self.dna_file_label.setText(LANG[TOOL_LANG]["DNA File:"])
def on_dna_selected(self, dna_path):
"""当DNA被选中时"""
global DNA_File
DNA_File = dna_path
self.dna_file_input.setText(DNA_File)
print(f"Selected DNA file: {DNA_File}")
def on_dna_file_changed(self):
"""当DNA文件输入框内容改变时"""
global DNA_File
DNA_File = self.dna_file_input.text()
print(f"DNA file path updated: {DNA_File}")
#===================================== LAUNCH FUNCTIONS =====================================
def show():
return MainWindow.show_window()