Update
This commit is contained in:
commit
2f06de5acb
1
.cursorignore
Normal file
1
.cursorignore
Normal file
@ -0,0 +1 @@
|
||||
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
|
26
.gitattributes
vendored
Normal file
26
.gitattributes
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# 二进制文件统一配置
|
||||
*.png filter=lfs diff=lfs merge=lfs binary
|
||||
*.mb filter=lfs diff=lfs merge=lfs binary
|
||||
*.ma filter=lfs diff=lfs merge=lfs binary
|
||||
*.fbx filter=lfs diff=lfs merge=lfs binary
|
||||
*.dna filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# 指定目录配置(如果需要特殊处理)
|
||||
assets/** filter=lfs diff=lfs merge=lfs
|
||||
assets/maya/** filter=lfs diff=lfs merge=lfs
|
||||
assets/MH.2/** filter=lfs diff=lfs merge=lfs
|
||||
assets/MH.4/** filter=lfs diff=lfs merge=lfs
|
||||
|
||||
# 文本文件配置
|
||||
*.py text eol=lf
|
||||
*.json text eol=lf
|
||||
*.xml text eol=lf
|
||||
*.txt text eol=lf
|
||||
|
||||
# 确保脚本文件使用正确的行尾
|
||||
*.sh text eol=lf
|
||||
*.bat text eol=crlf
|
||||
|
||||
# 其他常用配置
|
||||
.gitattributes text eol=lf
|
||||
.gitignore text eol=lf
|
41
.gitignore
vendored
Normal file
41
.gitignore
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.dylib
|
||||
|
||||
# Fortran module files
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Local build
|
||||
/build*
|
||||
|
||||
# Work Environment Artifacts
|
||||
/.vs
|
||||
/.vscode
|
||||
|
||||
*.pyc
|
||||
|
||||
/.idea
|
||||
/output
|
||||
|
||||
/Reference
|
5
CleanPycache.bat
Normal file
5
CleanPycache.bat
Normal file
@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
REM Delete all __pycache__ folders
|
||||
for /d /r %%d in (__pycache__) do @if exist "%%d" rd /s /q "%%d"
|
||||
|
||||
echo Cleaned up!
|
18
Install.mel
Normal file
18
Install.mel
Normal file
@ -0,0 +1,18 @@
|
||||
global proc install()
|
||||
{
|
||||
string $scriptPath = `whatIs install`;
|
||||
string $dirPath = `substring $scriptPath 25 (size($scriptPath))`;
|
||||
$dirPath = `dirname $dirPath`;
|
||||
string $pythonPath = $dirPath + "/Install.py";
|
||||
$pythonPath = substituteAllString($pythonPath, "\\", "/");
|
||||
|
||||
string $pythonCmd = "import os, sys\n";
|
||||
$pythonCmd += "INSTALL_PATH = r'" + $pythonPath + "'\n";
|
||||
$pythonCmd += "sys.path.append(os.path.dirname(INSTALL_PATH))\n";
|
||||
$pythonCmd += "import Install\n";
|
||||
$pythonCmd += "Install.main()\n";
|
||||
|
||||
python($pythonCmd);
|
||||
}
|
||||
|
||||
install();
|
511
Install.py
Normal file
511
Install.py
Normal file
@ -0,0 +1,511 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#===================================== 1. Module Imports =====================================
|
||||
import maya.OpenMayaUI as omui
|
||||
import maya.cmds as cmds
|
||||
import maya.mel as mel
|
||||
import webbrowser
|
||||
import sys
|
||||
import os
|
||||
|
||||
from scripts import config
|
||||
|
||||
QtCore, QtGui, QtWidgets, wrapInstance = config.Qt()
|
||||
|
||||
if QtCore is None or QtGui is None or QtWidgets is None or wrapInstance is None:
|
||||
|
||||
print(f"Qt加载失败: {QtCore}, {QtGui}, {QtWidgets}, {wrapInstance}")
|
||||
|
||||
TOOL_NAME = config.TOOL_NAME
|
||||
TOOL_ICON = config.TOOL_ICON
|
||||
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
|
||||
TOOL_VERSION = config.TOOL_VERSION
|
||||
TOOL_AUTHOR = config.TOOL_AUTHOR
|
||||
TOOL_LANG = config.TOOL_LANG
|
||||
TOOL_WSCL_NAME = config.TOOL_WSCL_NAME
|
||||
TOOL_YEAR = config.TOOL_YEAR
|
||||
TOOL_MOD_FILENAME = config.TOOL_MOD_FILENAME
|
||||
SYSTEM_OS = config.SYSTEM_OS
|
||||
TOOL_PATH = config.TOOL_PATH
|
||||
ROOT_DIR = config.TOOL_PATH
|
||||
ICONS_PATH = config.ICONS_PATH
|
||||
SCRIPTS_PATH = config.SCRIPTS_PATH
|
||||
TOOL_STYLE_FILE = config.TOOL_STYLE_FILE
|
||||
MAYA_VERSION = config.MAYA_VERSION
|
||||
PYTHON_VERSION = config.PYTHON_VERSION
|
||||
PYTHON_VERSION_DIR = config.PYTHON_VERSION_DIR
|
||||
TOOL_HELP_URL = config.TOOL_HELP_URL
|
||||
PLUGIN_PATH = config.PLUGIN_PATH
|
||||
PYDNA_PATH = config.PYDNA_PATH
|
||||
TOOL_MAIN_SCRIPT = config.TOOL_MAIN_SCRIPT
|
||||
|
||||
|
||||
print(f"TOOL_NAME: {TOOL_NAME}")
|
||||
print(f"TOOL_VERSION: {TOOL_VERSION}")
|
||||
print(f"TOOL_AUTHOR: {TOOL_AUTHOR}")
|
||||
print(f"TOOL_LANG: {TOOL_LANG}")
|
||||
print(f"TOOL_WSCL_NAME: {TOOL_WSCL_NAME}")
|
||||
print(f"TOOL_YEAR: {TOOL_YEAR}")
|
||||
print(f"TOOL_MOD_FILENAME: {TOOL_MOD_FILENAME}")
|
||||
print(f"TOOL_HELP_URL: {TOOL_HELP_URL}")
|
||||
|
||||
print(f"SYSTEM_OS: {SYSTEM_OS}")
|
||||
print(f"MAYA_VERSION: {MAYA_VERSION}")
|
||||
print(f"PYTHON: {PYTHON_VERSION_DIR}")
|
||||
print(f"PYTHON VERSION: {PYTHON_VERSION}")
|
||||
print(f"TOOL_PATH: {TOOL_PATH}")
|
||||
|
||||
print(f"ROOT_DIR: {ROOT_DIR}")
|
||||
print(f"SCRIPTS_PATH: {SCRIPTS_PATH}")
|
||||
print(f"TOOL_STYLE_FILE: {TOOL_STYLE_FILE}")
|
||||
print(f"PLUGIN_PATH: {PLUGIN_PATH}")
|
||||
print(f"PYDNA_PATH: {PYDNA_PATH}")
|
||||
|
||||
|
||||
#===================================== 3. Utility Functions =====================================
|
||||
def maya_main_window():
|
||||
"""获取Maya主窗口"""
|
||||
main_window_ptr = omui.MQtUtil.mainWindow()
|
||||
if main_window_ptr:
|
||||
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
|
||||
return None
|
||||
|
||||
def ensure_directory(directory_path):
|
||||
"""确保目录存在"""
|
||||
if directory_path and isinstance(directory_path, str):
|
||||
if not os.path.exists(directory_path):
|
||||
os.makedirs(directory_path)
|
||||
print(f"Created directory: {directory_path}")
|
||||
return directory_path
|
||||
|
||||
def get_maya_modules_dir():
|
||||
"""获取Maya模块目录"""
|
||||
maya_app_dir = cmds.internalVar(userAppDir=True)
|
||||
if maya_app_dir and isinstance(maya_app_dir, str):
|
||||
return ensure_directory(os.path.join(maya_app_dir, "modules"))
|
||||
return None
|
||||
|
||||
#===================================== 4. UI Component Classes =====================================
|
||||
class SetButton(QtWidgets.QPushButton):
|
||||
"""Custom styled button for installation interface"""
|
||||
def __init__(self, text):
|
||||
super(SetButton, self).__init__(text)
|
||||
|
||||
#===================================== 5. Main Window Class =====================================
|
||||
class InstallDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=maya_main_window()):
|
||||
super(InstallDialog, self).__init__(parent)
|
||||
self.load_stylesheet()
|
||||
self.setup_ui()
|
||||
|
||||
def load_stylesheet(self):
|
||||
with open(TOOL_STYLE_FILE, 'r', encoding='utf-8') as f:
|
||||
style = f.read()
|
||||
self.setStyleSheet(style)
|
||||
|
||||
def setup_ui(self):
|
||||
"""Initialize and setup UI components"""
|
||||
self.setWindowTitle(f"{TOOL_NAME} Installation")
|
||||
self.setFixedSize(220, 120)
|
||||
self.setup_window_icon()
|
||||
self.create_widgets()
|
||||
self.create_layouts()
|
||||
self.create_connections()
|
||||
|
||||
def setup_window_icon(self):
|
||||
"""Setup window icon if available"""
|
||||
if os.path.exists(TOOL_ICON):
|
||||
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
|
||||
else:
|
||||
print(f"Warning: Icon file not found: {TOOL_ICON}")
|
||||
|
||||
#----------------- 5.1 UI Methods -----------------
|
||||
def create_widgets(self):
|
||||
self.new_shelf_toggle = QtWidgets.QCheckBox(f"{TOOL_NAME} Installation")
|
||||
self.install_button = SetButton("Install " + TOOL_NAME)
|
||||
self.uninstall_button = SetButton("Uninstall " + TOOL_NAME)
|
||||
|
||||
def create_layouts(self):
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(10, 2, 10, 5)
|
||||
main_layout.setSpacing(5)
|
||||
|
||||
header_layout = QtWidgets.QHBoxLayout()
|
||||
header_layout.setSpacing(5)
|
||||
|
||||
welcome_label = QtWidgets.QLabel("Welcome to " + TOOL_NAME + "!")
|
||||
welcome_label.setStyleSheet("font-size: 11px; padding: 0px; margin: 0px;")
|
||||
header_layout.addWidget(welcome_label)
|
||||
header_layout.addStretch()
|
||||
|
||||
main_layout.addLayout(header_layout)
|
||||
main_layout.addWidget(self.install_button)
|
||||
main_layout.addWidget(self.uninstall_button)
|
||||
|
||||
self.install_button.setFixedHeight(30)
|
||||
self.uninstall_button.setFixedHeight(30)
|
||||
|
||||
def create_connections(self):
|
||||
self.install_button.clicked.connect(self.install)
|
||||
self.uninstall_button.clicked.connect(self.uninstall)
|
||||
|
||||
def create_styled_message_box(self, title, text):
|
||||
msg_box = QtWidgets.QMessageBox(self)
|
||||
msg_box.setWindowTitle(title)
|
||||
msg_box.setText(text)
|
||||
msg_box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
|
||||
msg_box.setStyleSheet(self.styleSheet())
|
||||
return msg_box
|
||||
|
||||
#----------------- 5.2 Event Handler Methods -----------------
|
||||
def event(self, event):
|
||||
if event.type() == QtCore.QEvent.EnterWhatsThisMode:
|
||||
QtWidgets.QWhatsThis.leaveWhatsThisMode()
|
||||
self.open_help_url()
|
||||
return True
|
||||
return QtWidgets.QDialog.event(self, event)
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Handle window close event"""
|
||||
try:
|
||||
super(InstallDialog, self).closeEvent(event)
|
||||
except Exception as e:
|
||||
print(f"Error closing window: {e}")
|
||||
event.accept()
|
||||
|
||||
def helpEvent(self, event):
|
||||
self.open_help_url()
|
||||
event.accept()
|
||||
|
||||
#----------------- 5.3 Utility Methods -----------------
|
||||
def open_help_url(self):
|
||||
webbrowser.open(TOOL_HELP_URL)
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
|
||||
def get_script_path():
|
||||
maya_script = mel.eval('getenv("MAYA_SCRIPT_NAME")')
|
||||
if maya_script and os.path.exists(maya_script):
|
||||
return os.path.dirname(maya_script)
|
||||
|
||||
for sys_path in sys.path:
|
||||
install_path = os.path.join(sys_path, "install.py")
|
||||
if os.path.exists(install_path):
|
||||
return os.path.dirname(install_path)
|
||||
|
||||
return os.getcwd()
|
||||
|
||||
#----------------- 5.4 Installation Methods -----------------
|
||||
def install(self):
|
||||
"""Handle install request with error handling"""
|
||||
if not self._validate_paths():
|
||||
return
|
||||
|
||||
msg_box = self.create_styled_message_box(
|
||||
"Confirm Installation",
|
||||
f"Are you sure you want to install {TOOL_NAME}?"
|
||||
)
|
||||
if msg_box.exec_() == QtWidgets.QMessageBox.Yes:
|
||||
try:
|
||||
self.install_tool()
|
||||
self.close()
|
||||
except Exception as e:
|
||||
error_msg = f"Error during installation: {e}"
|
||||
print(error_msg)
|
||||
QtWidgets.QMessageBox.critical(self, "Error", error_msg)
|
||||
|
||||
def uninstall(self, *args):
|
||||
"""Handle uninstall request"""
|
||||
msg_box = self.create_styled_message_box(
|
||||
"Confirm Uninstallation",
|
||||
f"Are you sure you want to uninstall {TOOL_NAME}?"
|
||||
)
|
||||
|
||||
if msg_box.exec_() == QtWidgets.QMessageBox.Yes:
|
||||
try:
|
||||
self.uninstall_tool()
|
||||
self.close()
|
||||
except Exception as e:
|
||||
error_msg = f"Error during uninstallation: {e}"
|
||||
print(error_msg)
|
||||
QtWidgets.QMessageBox.critical(self, "Error", error_msg)
|
||||
else:
|
||||
print("Uninstallation cancelled")
|
||||
|
||||
def create_mod_file(self):
|
||||
"""创建或更新Maya的.mod文件"""
|
||||
modules_dir = get_maya_modules_dir()
|
||||
|
||||
# 获取所有Maya版本和对应的Python版本
|
||||
version_map = {
|
||||
"2022": "python3",
|
||||
"2023": "python397",
|
||||
"2024": "python3108",
|
||||
"2025": "python311"
|
||||
}
|
||||
|
||||
# 系统映射
|
||||
os_paths = {
|
||||
"win64": "Windows",
|
||||
"linux": "Linux"
|
||||
}
|
||||
|
||||
# 创建mod文件内容
|
||||
mod_content = f"""+ {TOOL_NAME} {TOOL_VERSION} {TOOL_PATH}
|
||||
"""
|
||||
|
||||
# 添加每个Maya版本的配置
|
||||
for maya_version, python_version in version_map.items():
|
||||
# 添加每个操作系统的配置
|
||||
for os_name, os_path in os_paths.items():
|
||||
mod_content += f"""
|
||||
if MAYA_VERSION == {maya_version} && PLATFORM == {os_name}
|
||||
scripts: {SCRIPTS_PATH}
|
||||
plug-ins: {os.path.join(PLUGIN_PATH, os_path)}
|
||||
XBMLANGPATH+:={ICONS_PATH}
|
||||
PATH+:={os.path.join(PLUGIN_PATH, os_path)}
|
||||
PATH+:={os.path.join(PLUGIN_PATH, os_path, "pydna", python_version)}
|
||||
PYTHONPATH+:={SCRIPTS_PATH}
|
||||
PYTHONPATH+:={os.path.join(PLUGIN_PATH, os_path, "pydna", python_version)}
|
||||
endif
|
||||
"""
|
||||
|
||||
# 写入mod文件
|
||||
mod_file_path = os.path.join(modules_dir, TOOL_MOD_FILENAME)
|
||||
try:
|
||||
with open(mod_file_path, "w", encoding="utf-8") as f:
|
||||
f.write(mod_content)
|
||||
print(f"Created mod file: {mod_file_path}")
|
||||
except Exception as e:
|
||||
print(f"Error creating mod file {mod_file_path}: {e}")
|
||||
|
||||
def uninstall_mod_file(self):
|
||||
modules_dir = get_maya_modules_dir()
|
||||
mod_file_path = os.path.join(modules_dir, TOOL_MOD_FILENAME)
|
||||
if os.path.exists(mod_file_path):
|
||||
try:
|
||||
os.remove(mod_file_path)
|
||||
print(f"{TOOL_NAME}.mod file deleted")
|
||||
except Exception as e:
|
||||
print(f"Error deleting {TOOL_NAME}.mod file: {e}")
|
||||
|
||||
def clean_existing_buttons(self):
|
||||
if cmds.shelfLayout(TOOL_NAME, exists=True):
|
||||
buttons = cmds.shelfLayout(TOOL_NAME, query=True, childArray=True) or []
|
||||
for btn in buttons:
|
||||
if cmds.shelfButton(btn, query=True, exists=True):
|
||||
label = cmds.shelfButton(btn, query=True, label=True)
|
||||
if label == TOOL_NAME:
|
||||
cmds.deleteUI(btn)
|
||||
print(f"Deleted existing {TOOL_NAME} button: {btn}")
|
||||
|
||||
def install_tool(self):
|
||||
"""Install the tool to Maya"""
|
||||
if not os.path.exists(SCRIPTS_PATH):
|
||||
print(f"Error: Scripts path does not exist: {SCRIPTS_PATH}")
|
||||
return
|
||||
|
||||
if not os.path.exists(TOOL_MAIN_SCRIPT):
|
||||
print(f"Error: Main script file not found: {TOOL_MAIN_SCRIPT}")
|
||||
return
|
||||
|
||||
# Add scripts path to Python path
|
||||
if SCRIPTS_PATH not in sys.path:
|
||||
sys.path.insert(0, SCRIPTS_PATH)
|
||||
|
||||
# Create shelf and button
|
||||
self._create_shelf_button()
|
||||
self.create_mod_file()
|
||||
|
||||
# Switch to the newly created shelf
|
||||
try:
|
||||
cmds.shelfTabLayout("ShelfLayout", edit=True, selectTab=TOOL_NAME)
|
||||
print(f"Switched to {TOOL_NAME} shelf")
|
||||
except Exception as e:
|
||||
print(f"Error switching to {TOOL_NAME} shelf: {e}")
|
||||
|
||||
self._show_install_success_message()
|
||||
|
||||
def _create_shelf_button(self):
|
||||
"""Create shelf button for the tool"""
|
||||
shelf_layout = mel.eval('$tmpVar=$gShelfTopLevel')
|
||||
|
||||
# Create shelf if not exists
|
||||
if not cmds.shelfLayout(TOOL_NAME, exists=True):
|
||||
cmds.shelfLayout(TOOL_NAME, parent=shelf_layout)
|
||||
|
||||
# Clean existing buttons
|
||||
self.clean_existing_buttons()
|
||||
|
||||
# Create new button
|
||||
icon_path = TOOL_ICON if os.path.exists(TOOL_ICON) else TOOL_COMMAND_ICON
|
||||
|
||||
command = self._get_shelf_button_command()
|
||||
|
||||
cmds.shelfButton(
|
||||
parent=TOOL_NAME,
|
||||
image1=icon_path,
|
||||
label=TOOL_NAME,
|
||||
command=command,
|
||||
sourceType="python",
|
||||
annotation=f"{TOOL_NAME} {TOOL_VERSION}",
|
||||
noDefaultPopup=True,
|
||||
style="iconOnly"
|
||||
)
|
||||
|
||||
def _get_shelf_button_command(self):
|
||||
"""Get the command string for shelf button"""
|
||||
return f"""
|
||||
import sys
|
||||
import os
|
||||
TOOL_PATH = r'{TOOL_PATH}'
|
||||
if TOOL_PATH not in sys.path:
|
||||
sys.path.insert(0, TOOL_PATH)
|
||||
SCRIPTS_PATH = r'{SCRIPTS_PATH}'
|
||||
if SCRIPTS_PATH not in sys.path:
|
||||
sys.path.insert(0, SCRIPTS_PATH)
|
||||
os.chdir(SCRIPTS_PATH)
|
||||
try:
|
||||
import MetaFusion
|
||||
MetaFusion.show()
|
||||
except ImportError as e:
|
||||
print("Error importing MetaFusion:", str(e))
|
||||
print(f"Scripts path: {SCRIPTS_PATH}")
|
||||
print("sys.path:", sys.path)
|
||||
print(f"Contents of Scripts folder: {os.listdir(SCRIPTS_PATH)}")
|
||||
"""
|
||||
|
||||
def uninstall_tool(self):
|
||||
"""Uninstall the tool from Maya"""
|
||||
window_name = f"{TOOL_NAME}Window"
|
||||
dock_name = f"{TOOL_NAME}WindowDock"
|
||||
shelf_file = f"shelf_{TOOL_NAME}.mel"
|
||||
|
||||
if cmds.window(window_name, exists=True):
|
||||
try:
|
||||
cmds.deleteUI(window_name)
|
||||
except Exception as e:
|
||||
print(f"Error closing {TOOL_NAME} window: {e}")
|
||||
|
||||
if cmds.dockControl(dock_name, exists=True):
|
||||
try:
|
||||
cmds.deleteUI(dock_name)
|
||||
except Exception as e:
|
||||
print(f"Error closing docked {TOOL_NAME} window: {e}")
|
||||
|
||||
self.uninstall_mod_file()
|
||||
|
||||
# Get the current shelf before removing it
|
||||
current_shelf = cmds.shelfTabLayout("ShelfLayout", query=True, selectTab=True)
|
||||
|
||||
# Delete Shelves and Buttons
|
||||
if cmds.shelfLayout(TOOL_NAME, exists=True):
|
||||
try:
|
||||
cmds.deleteUI(TOOL_NAME, layout=True)
|
||||
except Exception as e:
|
||||
print(f"Error deleting {TOOL_NAME} shelf: {e}")
|
||||
|
||||
self._clean_all_shelf_buttons()
|
||||
|
||||
# Remove from Python path
|
||||
if SCRIPTS_PATH in sys.path:
|
||||
sys.path.remove(SCRIPTS_PATH)
|
||||
|
||||
# Deleting Shelf Files
|
||||
shelf_path = os.path.join(
|
||||
cmds.internalVar(userAppDir=True),
|
||||
cmds.about(version=True),
|
||||
"prefs",
|
||||
"shelves",
|
||||
f"shelf_{TOOL_NAME}.mel"
|
||||
)
|
||||
|
||||
if os.path.exists(shelf_path):
|
||||
try:
|
||||
os.remove(shelf_path)
|
||||
except Exception as e:
|
||||
print(f"Error deleting shelf file: {e}")
|
||||
|
||||
# If the current tool shelf is a deleted tool shelf, switch to another tool shelf
|
||||
if current_shelf == TOOL_NAME:
|
||||
shelves = cmds.shelfTabLayout("ShelfLayout", query=True, childArray=True)
|
||||
if shelves and len(shelves) > 0:
|
||||
cmds.shelfTabLayout("ShelfLayout", edit=True, selectTab=shelves[0])
|
||||
|
||||
self._show_uninstall_success_message()
|
||||
|
||||
def _clean_all_shelf_buttons(self):
|
||||
"""Clean up all shelf buttons related to the tool"""
|
||||
all_shelves = cmds.shelfTabLayout("ShelfLayout", query=True, childArray=True) or []
|
||||
for shelf in all_shelves:
|
||||
shelf_buttons = cmds.shelfLayout(shelf, query=True, childArray=True) or []
|
||||
for btn in shelf_buttons:
|
||||
if cmds.shelfButton(btn, query=True, exists=True):
|
||||
if cmds.shelfButton(btn, query=True, label=True) == TOOL_NAME:
|
||||
cmds.deleteUI(btn)
|
||||
|
||||
def _show_uninstall_success_message(self):
|
||||
"""Show uninstallation success message"""
|
||||
msg_box = QtWidgets.QMessageBox(self)
|
||||
msg_box.setWindowTitle("Uninstallation Successful")
|
||||
msg_box.setText(f"{TOOL_NAME} has been successfully uninstalled!")
|
||||
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
||||
msg_box.setWindowIcon(QtGui.QIcon(TOOL_ICON))
|
||||
msg_box.setStyleSheet(self.styleSheet())
|
||||
msg_box.exec_()
|
||||
|
||||
def _show_install_success_message(self):
|
||||
msg_box = QtWidgets.QMessageBox(self)
|
||||
msg_box.setWindowTitle("Installation Successful")
|
||||
msg_box.setText(f"{TOOL_NAME} has been successfully installed!")
|
||||
msg_box.setStandardButtons(QtWidgets.QMessageBox.Ok)
|
||||
msg_box.setWindowIcon(QtGui.QIcon(TOOL_ICON))
|
||||
msg_box.setStyleSheet(self.styleSheet())
|
||||
msg_box.exec_()
|
||||
|
||||
def _validate_paths(self):
|
||||
"""Validate all required paths exist"""
|
||||
paths = {
|
||||
"Root": TOOL_PATH,
|
||||
"Scripts": SCRIPTS_PATH,
|
||||
"Icons": ICONS_PATH
|
||||
}
|
||||
|
||||
for name, path in paths.items():
|
||||
if not os.path.exists(path):
|
||||
error_msg = f"Error: {name} path does not exist: {path}"
|
||||
print(error_msg)
|
||||
QtWidgets.QMessageBox.critical(self, "Error", error_msg)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _log(self, message, error=False):
|
||||
"""Log messages with timestamp"""
|
||||
from datetime import datetime
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
log_message = f"[{timestamp}] {message}"
|
||||
print(log_message)
|
||||
if error:
|
||||
QtWidgets.QMessageBox.critical(self, "Error", message)
|
||||
|
||||
def _load_mel_shelf(self):
|
||||
"""Load mel shelf file with error handling"""
|
||||
try:
|
||||
mel.eval(f'loadNewShelf "shelf_{TOOL_NAME}.mel"')
|
||||
except Exception as e:
|
||||
self._log(f"Error loading shelf file: {e}", error=True)
|
||||
|
||||
#===================================== 6. Main Function =====================================
|
||||
def main():
|
||||
"""Main entry point for the installer"""
|
||||
try:
|
||||
dialog = InstallDialog()
|
||||
dialog.show()
|
||||
except Exception as e:
|
||||
print(f"Error launching installer: {e}")
|
||||
return -1
|
||||
return dialog
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
410
Readme.md
Normal file
410
Readme.md
Normal file
@ -0,0 +1,410 @@
|
||||
Always respond in 中文,
|
||||
|
||||
先阅读知识库,并按照 Readme.md 来查看文件路径以及参考品文档和参考代码来协助用户完成项目
|
||||
|
||||
# MetaFusion 开发文档
|
||||
|
||||
## 一 本地知识库导航
|
||||
|
||||
### 1 文档
|
||||
|
||||
Reference\docs\Metahuman解析.pdf
|
||||
Reference\docs\SuperRiggingEditor使用文档.pdf
|
||||
Reference\DNA_Calibration\docs\dna_api.md
|
||||
Reference\DNA_Calibration\docs\dna_viewer_api_build_meshes.md
|
||||
Reference\DNA_Calibration\docs\dna_viewer_api_build_rig.md
|
||||
Reference\DNA_Calibration\docs\dna_viewer_API.md
|
||||
Reference\DNA_Calibration\docs\dna_viewer_maya.md
|
||||
Reference\DNA_Calibration\docs\dna_viewer.md
|
||||
Reference\DNA_Calibration\docs\dna.md
|
||||
Reference\DNA_Calibration\docs\dnacalib_api.md
|
||||
Reference\DNA_Calibration\docs\dnacalib.md
|
||||
Reference\DNA_Calibration\docs\faq.md
|
||||
Reference\DNA_Calibration\docs\repository_organization.md
|
||||
DNA_Calibration在线文档: https://epicgames.github.io/MetaHuman-DNA-Calibration
|
||||
|
||||
### 2 代码参考
|
||||
|
||||
Reference\DNA_Calibration
|
||||
Reference\MSLiveLink
|
||||
Reference\SuperRiggingEditor
|
||||
Reference\Utils
|
||||
|
||||
### 3 UI参考图片
|
||||
|
||||
Reference\UI
|
||||
|
||||
## 二 项目描述
|
||||
|
||||
### 1 目标
|
||||
|
||||
做一个Maya的Metahuman自定义的插件,语言:基于Python,Maya版本:2022, 2023, 2024, 2025
|
||||
|
||||
### 项目描述
|
||||
|
||||
- 本项目是一个Maya插件,主要功能是提供与MetaHuman相同拓扑的模型或者自定义的3d模型以来完成自定义绑定,编辑DNA,校准骨骼位置,保存DNA,载入DNA,导出fbx,保存DNA文件, 编辑BlendShape,等功能。
|
||||
|
||||
### 2 主要功能
|
||||
|
||||
- 提供与MetaHuman相同拓扑的模型或者自定义的3d模型以来完成自定义绑定,编辑DNA,校准骨骼位置,保存DNA,载入DNA,导出fbx,保存DNA文件, 编辑BlendShape,等功能。
|
||||
|
||||
### 3 注意Reference路径不参与参见功能实现,只作为参考。Reference只作为参考,可以从中拷贝必要的文件到当前项目中
|
||||
|
||||
### 4 代码规范
|
||||
|
||||
- 所有代码必须使用UTF-8编码
|
||||
- 所有模块开头必须添加 :
|
||||
|
||||
```.
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
```
|
||||
|
||||
- 代码必须考虑兼容 Maya2022, Maya2023, Maya2024, Maya2025
|
||||
- 代码必须考虑兼容 Python3.10, Python3.11, Python3.12
|
||||
- 所有模型引用关系自动更新修正
|
||||
- UI样式必须统一的一个样式文件来实现
|
||||
- 所有UI必须使用Qt来实现
|
||||
- 所有Pyside代码必须使用 widget, layout, connection 的结构来实现
|
||||
- 文件夹结构尽量以目前的代码结构来触发实现,各个模块各功能给要条理清晰
|
||||
- 使用config.py文件来统一实现配置文件
|
||||
- 使用style.qss文件来实现UI样式
|
||||
- 功能函数放在utils文件夹中
|
||||
|
||||
### 5 文件基本结构 (参考), 以"\"结尾的行为文件夹
|
||||
|
||||
- 参考[MetaFusion 文件基本结构](#metafusion-文件基本结构)
|
||||
|
||||
#### MetaFusion 文件基本结构
|
||||
|
||||
```.
|
||||
├── assets\
|
||||
│ ├── dna\ DNA文件路径
|
||||
│ ├── img\ DNA图标路径
|
||||
│ ├── maya\ Maya资源文件路径
|
||||
│ ├── MH.2\ MetaHuman 2.0文件路径
|
||||
│ ├── MH.4\ MetaHuman 4.0文件路径
|
||||
├── icons\ 插件图标路径
|
||||
├── plugins\
|
||||
│ └── Linux\
|
||||
│ │ ├── 2022\
|
||||
│ │ ├── 2023\
|
||||
│ │ ├── 2024\
|
||||
│ │ ├── 2025\
|
||||
│ │ ├── pydna\
|
||||
│ │ │ ├── python3\
|
||||
│ │ │ ├── python311\
|
||||
│ │ │ ├── python397\
|
||||
│ │ │ ├── python3108\
|
||||
│ └── Windows\
|
||||
│ │ ├── 2022\
|
||||
│ │ ├── 2023\
|
||||
│ │ ├── 2024\
|
||||
│ │ ├── 2025\
|
||||
│ │ ├── pydna\
|
||||
│ │ │ ├── python3\
|
||||
│ │ │ ├── python311\
|
||||
│ │ │ ├── python397\
|
||||
│ │ │ ├── python3108\
|
||||
├── Reference\ 参考模块(不引用,仅供参考)
|
||||
│ ├── DNA_Calibration 参考模块:DNA_Calibration
|
||||
│ ├── MSLiveLink 参考模块:MSLiveLink
|
||||
│ ├── SuperRiggingEditor 参考模块:SuperRiggingEditor
|
||||
├── scripts\
|
||||
│ ├── builder\
|
||||
│ │ ├── maya\
|
||||
│ │ │ ├── __init__.py
|
||||
│ │ │ ├── mesh.py
|
||||
│ │ │ ├── skin_weights.py
|
||||
│ │ │ ├── util.py
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── builder.py
|
||||
│ │ ├── config.py
|
||||
│ │ ├── joint.py
|
||||
│ │ ├── mesh.py
|
||||
│ │ ├── rig_builder.py
|
||||
│ ├── dnacalib\
|
||||
│ │ ├── CMakeModulesExtra\
|
||||
│ │ ├── DNACalib\
|
||||
│ │ ├── PyDNA\
|
||||
│ │ ├── PyDNACalib\
|
||||
│ │ ├── SPyUS\
|
||||
│ │ ├── CMakeLists.txt
|
||||
│ ├── dnalib\
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── behavior.py
|
||||
│ │ ├── definition.py
|
||||
│ │ ├── descriptor.py
|
||||
│ │ ├── dnalib.py
|
||||
│ │ ├── geometry.py
|
||||
│ │ ├── layer.py
|
||||
│ ├── ui\
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── style.qss UI样式文件
|
||||
│ │ ├── menu.py UI菜单UI文件
|
||||
│ │ ├── toolshelf.py UI工具架UI文件
|
||||
│ │ ├── meshes.py UI模型UI文件
|
||||
│ │ ├── rigging.py UI绑定UI文件
|
||||
│ │ ├── behaviour.py UI行为UI文件
|
||||
│ │ ├── definition.py UI定义UI文件
|
||||
│ ├── utils\ 功能模块路径
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── ...
|
||||
│ ├── MetaFusion.py 插件主文件
|
||||
│ ├── config.py 配置文件
|
||||
├── Install.mel 拖入maya安装文件
|
||||
├── Install.py 安装执行文件
|
||||
├── CleanPycache.bat 清除pycache文件(不修改)
|
||||
├── README.md 开发文档
|
||||
```
|
||||
|
||||
### 6 UI界面风格
|
||||
|
||||
- 扁平化设计风格,
|
||||
- 要有高级感和科幻未来感
|
||||
- 圆角设计
|
||||
- 中文要清晰大气
|
||||
- 英文要简洁明了
|
||||
- 颜色要统一
|
||||
- 字体要统一
|
||||
- 字体大小要统一
|
||||
- 按钮要统一
|
||||
- 输入框要统一
|
||||
- 标签要统一
|
||||
|
||||
### 7 UI界面
|
||||
|
||||
UI参考图片:
|
||||
Reference\UI\01_Menu_File.jpg
|
||||
Reference\UI\02_Menu_Edit.jpg
|
||||
Reference\UI\03_Menu_Tools.jpg
|
||||
Reference\UI\04_Language.jpg
|
||||
Reference\UI\05_Menu_Help.jpg
|
||||
Reference\UI\06_Tool_Shelf.jpg
|
||||
Reference\UI\07_Meshes_LOD0.jpg
|
||||
Reference\UI\08_Meshes_LOD1.jpg
|
||||
Reference\UI\09_Meshes_LOD2.jpg
|
||||
Reference\UI\10_Meshes_LOD3.jpg
|
||||
Reference\UI\11_Meshes_LOD4.jpg
|
||||
Reference\UI\12_Meshes_LOD5.jpg
|
||||
Reference\UI\13_Meshes_LOD6.jpg
|
||||
Reference\UI\14_Meshes_LOD7.jpg
|
||||
Reference\UI\15_Rigging.jpg
|
||||
Reference\UI\16_Behaviour.jpg
|
||||
Reference\UI\17_Definitions.jpg
|
||||
|
||||
#### MetaFusion UI 结构
|
||||
|
||||
##### 一、菜单栏
|
||||
|
||||
###### 1. 文件菜单 (File)
|
||||
|
||||
- 打开 DNA | icons\open.png
|
||||
- 保存 DNA | icons\save.png
|
||||
- 加载当前项目 DNA | icons\open.png
|
||||
- 修改混合目标名称 | icons\rename.png
|
||||
- 重置混合目标名称 | icons\resetname.png
|
||||
- 导出 FBX | icons\export.png
|
||||
- 退出 | icons\exit.png
|
||||
|
||||
###### 2. 编辑菜单 (Edit)
|
||||
|
||||
- 创建 RL4 节点 | icons\connect.png
|
||||
- 删除 RL4 节点 | icons\disconnect.png
|
||||
- 镜像左至右 | icons\mirrorL.png
|
||||
- 镜像右至左 | icons\mirrorR.png
|
||||
- 姿势由 A 型转 T 型 | icons\pose_A_To_T.png
|
||||
- 姿势由 T 型转 A 型 | icons\pose_T_To_A.png
|
||||
- 传输 LOD 贴图 | icons\locator.png
|
||||
- 设置关节颜色 | icons\color.png
|
||||
- 取消全部标记 | icons\unmark_all.png
|
||||
- 重建所有目标 | icons\rebuildTargets.png
|
||||
- 为所有表情设置关键帧 | icons\bakeAnimation.png
|
||||
- 烘焙所有表情的关键帧 | icons\centerCurrentTime.png
|
||||
|
||||
###### 3. 工具菜单 (Tools)
|
||||
|
||||
- 导出蒙皮 | icons\export_skin.png
|
||||
- 导入蒙皮 | icons\import_skin.png
|
||||
- 拷贝装皮 | icons\copy_skin.png
|
||||
- RBF变形器 | icons\blendShape.png
|
||||
- 快速绑定服装 | icons\clothing_weight.png
|
||||
- 克隆混合变形 | icons\blendShape.png
|
||||
- UV传递点序 | icons\repair_vertex_order.png
|
||||
- 面部生成控制器 | icons\controller.png
|
||||
- 提取52BS | icons\ARKit52.png
|
||||
- 关节轴向修复 | icons\joint.png
|
||||
- 生成身体控制器 | icons\create_body_ctrl.png
|
||||
- 导入面部动画 | icons\import_face_anim.png
|
||||
- 导入身体动画 | icons\import_body_anim.png
|
||||
|
||||
###### 4. 语言菜单 (Language)
|
||||
|
||||
- 中文 | icons\chinese.png
|
||||
- English | icons\english.png
|
||||
|
||||
###### 5. 帮助菜单 (Help)
|
||||
|
||||
- 检查更新 | icons\update.png
|
||||
- 帮助文档 | icons\help.png
|
||||
- 关于 | icons\about.png
|
||||
|
||||
##### 二、工具架 横向排列
|
||||
|
||||
- 保存 DNA | icons\save.png
|
||||
- 加载当前项目 DNA | icons\open.png
|
||||
- 分隔符 separator
|
||||
- 创建RL4节点 | icons\connect.png
|
||||
- 删除RL4节点 | icons\disconnect.png
|
||||
- 分隔符 separator
|
||||
- 导出 蒙皮 | icons\export_skin.png
|
||||
- 导入 蒙皮 | icons\import_skin.png
|
||||
- 复制 蒙皮 | icons\copy_skin.png
|
||||
- 分隔符 separator
|
||||
- 帮助文档 | icons\help.png
|
||||
- 关于 | icons\about.png
|
||||
|
||||
##### 三、主界面功能区
|
||||
|
||||
###### 1. 模型视图 (Meshes)
|
||||
|
||||
####### LOD选项卡 (LOD0-LOD7)
|
||||
|
||||
每个LOD包含以下模型项:
|
||||
|
||||
- LOD0: ["*头部", "*牙齿", "*牙龈", "*左眼", "*右眼", "*虹膜", "*睫毛", "*眼睑", "*软骨", "*身体"]
|
||||
- LOD1: ["头部", "牙齿", "牙龈", "左眼", "右眼", "虹膜", "睫毛", "眼睑", "软骨", "身体"]
|
||||
- LOD2: ["头部", "牙齿", "牙龈", "左眼", "右眼", "虹膜", "睫毛", "眼睑", "身体"]
|
||||
- LOD3: ["头部", "牙齿", "左眼", "右眼", "虹膜", "睫毛", "眼睑", "身体"]
|
||||
- LOD4: ["头部", "牙齿", "左眼", "右眼", "虹膜"]
|
||||
- LOD5: ["头部", "牙齿", "左眼", "右眼"]
|
||||
- LOD6: ["头部", "牙齿", "左眼", "右眼"]
|
||||
- LOD7: ["头部", "牙齿", "左眼", "右眼"]
|
||||
|
||||
####### 功能按钮 (是在LOD0-LOD7中的底部)
|
||||
|
||||
自动加载模型(icons\load_meshes.png);标准化命名(icons\standardize_name.png);自动分组(icons\auto_group.png);
|
||||
|
||||
####### 工具栏功能
|
||||
|
||||
第一行:拓扑结构(下拉框,默认:MetaHuman);选择LOD(下拉框,默认:LOD0,LOD1~LOD7);创建LOD(icons\create_lod.png);
|
||||
|
||||
第二行:模型分离(icons\separate.png);生成面部配件(icons\face_accessory.png);
|
||||
|
||||
第三行:修复法线(icons\fix_normal.png);修复点序(icons\fix_vertex_order.png);
|
||||
|
||||
第四行:修复接缝(icons\fix_seam.png);
|
||||
|
||||
###### 2. 绑定视图 (Rigging)
|
||||
|
||||
####### 预设
|
||||
|
||||
- DNA浏览器
|
||||
- 图标缩放滑条; - 导入/导出设置按钮
|
||||
|
||||
####### 资产
|
||||
- 项目路径: 输入框; 加载按钮
|
||||
- 预设文件: 输入框; 加载按钮
|
||||
- 数据分层: 下拉框(默认:行为(包括基础定义)); - 勾选框(勾选):覆盖表情
|
||||
|
||||
####### 描述
|
||||
- 名称:输入框(默认:Archetype); - 变换单位:下拉框(默认:厘米)
|
||||
- 原型:下拉框(默认:亚洲人); - 旋转单位:下拉框(默认:角度)
|
||||
- 性别:下拉框(默认:女性); - 向上轴标:下拉框(默认:Z轴向上)
|
||||
- 年龄:数值调节(默认:24); - LOD计数:数值调节(默认:8)
|
||||
|
||||
####### 功能按钮
|
||||
|
||||
- 清空选项(icons\delete.png); - 导入骨架(icons\HIKCharacterToolSkeleton.png); - 创建骨架(icons\HIKcreateControlRig.png);
|
||||
|
||||
###### 3. 行为视图 (Behaviour)
|
||||
|
||||
####### Raw Control [000/000] (在行为视图的左侧)
|
||||
|
||||
- 搜索过滤
|
||||
- BlendShape列表
|
||||
- 恢复表情按钮(icons\restore.png);- 混合筛选按钮(icons\blendRaw.png)
|
||||
- 全部按钮,2按钮,3按钮,4按钮,5按钮,6按钮
|
||||
- 范围控制(0.010),滑块,勾选框(未勾选), 文字"全部"
|
||||
- 范围+按钮,范围-按钮
|
||||
|
||||
####### Related Blend Shapes [000/000] (在行为视图的右侧)
|
||||
|
||||
- 关联BlendShape列表
|
||||
- 范围控制(0.000),滑块,勾选框(未勾选), 文字"全部"
|
||||
- 翻转目标(icons\flip.png) - 镜像目标(icons\mirror.png) - 查找翻转目标(icons\mirrorR.png)
|
||||
- 添加混合目标(:locator.png) - 删除混合目标(icons\delete.png) - 批量混合目标(icons\batch.png)
|
||||
- 重建混合目标(:locator.png) - 重建所有混合目标(icons\rebuildAll.png)
|
||||
- 范围控制(0.010),滑块,勾选框(未勾选), 文字"全部"
|
||||
- 范围+按钮,范围-按钮
|
||||
|
||||
####### 功能按钮(在行为视图的底部)
|
||||
|
||||
- 第一行 :PSD - BSE - KEY - MIR - ARK - CTR
|
||||
- 第二行 :范围控制(0.000),滑块,"+"按钮, 勾选框(未勾选), 文字"全部"
|
||||
- 第三行 按钮:还原默认表情(icons\rest.png);查找选择表情(icons\expressions_current.png);写入当前表情(icons\expression.png)
|
||||
- 第四行 按钮:控制面板查找(icons\controller.png);选择关联关节(icons\kinjoint.png);写入镜像表情(icons\ctrl_hide.png)
|
||||
|
||||
###### 4. 定义视图 (Definition)
|
||||
|
||||
####### LODs列表
|
||||
|
||||
- LOD 0-7
|
||||
- Define Joint For LOD
|
||||
|
||||
####### Meshes [010/54]
|
||||
|
||||
- head_lod0_mesh (000)
|
||||
- teeth_lod0_mesh (001)
|
||||
- saliva_lod0_mesh (002)
|
||||
- eyeLeft_lod0_mesh (003)
|
||||
- eyeRight_lod0_mesh (004)
|
||||
- eyeshell_lod0_mesh (005)
|
||||
- eyelashes_lod0_mesh (006)
|
||||
- eyeEdge_lod0_mesh (007)
|
||||
- Create Geometry 按钮
|
||||
|
||||
####### Joints [840/870]
|
||||
|
||||
- FACIAL_C_NeckB Group: 001
|
||||
- FACIAL_L_NeckB1 Group: 002
|
||||
- FACIAL_R_NeckB1 Group: 003
|
||||
|
||||
- FACIAL_L_NeckB2 Group: 002
|
||||
- FACIAL_R_NeckB2 Group: 003
|
||||
- FACIAL_C12PV_NeckB1 Group: 001
|
||||
|
||||
####### Blend Shapes [782/782]
|
||||
|
||||
- brow_down_L 000
|
||||
- brow_down_R 001
|
||||
- brow_lateral_L 002
|
||||
|
||||
- brow_lateral_R 003
|
||||
- brow_raiseIn_L 004
|
||||
- brow_raiseIn_R 005
|
||||
|
||||
####### AnimatedMap [082/82]
|
||||
|
||||
- head_cm2_color.head_wm2.browsDown 000
|
||||
- head_cm2_color.head_wm2.browsDown 001
|
||||
- head_cm2_color.head_wm2.browsLate 002
|
||||
|
||||
- head_cm2_color.head_wm2.browsLate 003
|
||||
- head_cm1_color.head_wm1.browsRais 004
|
||||
- head_cm1_color.head_wm1.browsRais 005
|
||||
|
||||
####### 操作区域
|
||||
|
||||
- Write:
|
||||
- Write Neutral Pose Joint Position
|
||||
- Write Geometry
|
||||
- Write Skin Weights
|
||||
- Write Blend Shapes Targets
|
||||
- Create:
|
||||
- Create Blend Shapes For Mesh
|
||||
- Bind Skin For Mesh
|
||||
- Unbind Skin For Mesh
|
||||
- Tools:
|
||||
- New Neutral Joint Transform
|
||||
- Quickly Create Presets
|
BIN
assets/MH.2/Linux/body_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Linux/body_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Linux/dh_lights.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Linux/dh_lights.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Linux/head_ac.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Linux/head_ac.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Linux/head_gui.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Linux/head_gui.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Linux/head_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Linux/head_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Windows/body_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Windows/body_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Windows/dh_lights.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Windows/dh_lights.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Windows/head_ac.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Windows/head_ac.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Windows/head_gui.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Windows/head_gui.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/Windows/head_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/Windows/head_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/additional_assemble_script.py
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/additional_assemble_script.py
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.2/flipflops/filplop_mtl_v001.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.2/flipflops/filplop_mtl_v001.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Linux/body_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Linux/body_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Linux/dh_lights.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Linux/dh_lights.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Linux/head_ac.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Linux/head_ac.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Linux/head_gui.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Linux/head_gui.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Linux/head_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Linux/head_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Windows/body_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Windows/body_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Windows/dh_lights.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Windows/dh_lights.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Windows/head_ac.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Windows/head_ac.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Windows/head_gui.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Windows/head_gui.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/Windows/head_shader.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/Windows/head_shader.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/additional_assemble_script.py
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/additional_assemble_script.py
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/MH.4/flipflops/filplop_mtl_v001.ma
(Stored with Git LFS)
Normal file
BIN
assets/MH.4/flipflops/filplop_mtl_v001.ma
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Ada.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Ada.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Amelia.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Amelia.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Aoi.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Aoi.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Bernice.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Bernice.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Bes.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Bes.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Chandra.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Chandra.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Cooper.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Cooper.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Danielle.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Danielle.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Dax.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Dax.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Dhruv.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Dhruv.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Emanuel.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Emanuel.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Emory.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Emory.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Erno.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Erno.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Ettore.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Ettore.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Farrukh.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Farrukh.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Fei.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Fei.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Gavin.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Gavin.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Glenda.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Glenda.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Hadley.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Hadley.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Hana.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Hana.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Hudson.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Hudson.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Irene.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Irene.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Jesse.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Jesse.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Kai.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Kai.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/dna/Keiji.dna
(Stored with Git LFS)
Normal file
BIN
assets/dna/Keiji.dna
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Ada.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Ada.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Amelia.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Amelia.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Aoi.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Aoi.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Bernice.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Bernice.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Bes.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Bes.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Chandra.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Chandra.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Cooper.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Cooper.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Danielle.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Danielle.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Dax.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Dax.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Default.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Default.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Dhruv.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Dhruv.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Emanuel.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Emanuel.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Emory.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Emory.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Erno.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Erno.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Ettore.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Ettore.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Farrukh.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Farrukh.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Fei.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Fei.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Gavin.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Gavin.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Glenda.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Glenda.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Hadley.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Hadley.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Hana.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Hana.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Hudson.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Hudson.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Irene.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Irene.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Jesse.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Jesse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Kai.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Kai.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Keiji.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Keiji.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Kellan.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Kellan.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Kendra.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Kendra.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Kioko.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Kioko.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Koda.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Koda.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Kristofer.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Kristofer.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Kwame.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Kwame.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Lena.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Lena.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Lexi.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Lexi.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Lucian.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Lucian.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Malika.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Malika.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Maria.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Maria.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Myles.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Myles.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Nasim.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Nasim.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Natalia.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Natalia.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Neema.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Neema.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Omar.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Omar.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Orla.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Orla.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/img/Oskar.png
(Stored with Git LFS)
Normal file
BIN
assets/img/Oskar.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user