This commit is contained in:
2025-05-02 00:14:28 +08:00
commit 6f27dc11e3
132 changed files with 28609 additions and 0 deletions

24
.gitattributes vendored Normal file
View File

@@ -0,0 +1,24 @@
# Unified configuration of binary files
*.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
# Specify directory configuration (if special processing is required)
assets/dna/** filter=lfs diff=lfs merge=lfs
assets/img/** filter=lfs diff=lfs merge=lfs
# Text file configuration
*.py text eol=lf
*.json text eol=lf
*.xml text eol=lf
*.txt text eol=lf
# Ensure script files use correct line endings
*.sh text eol=lf
*.bat text eol=crlf
# Other common configurations
.gitattributes text eol=lf
.gitignore text eol=lf

43
.gitignore vendored Normal file
View File

@@ -0,0 +1,43 @@
# 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
/assets/dna
/assets/img

100
.windsurfrules Normal file
View File

@@ -0,0 +1,100 @@
## Global rules:
- Comprehensive search: All questions must first retrieve all relevant documents in the project folder to obtain context.
- Web search: After retrieving local files, a web search must be conducted to obtain more information and the latest data.
- Use context7 as much as possible to reduce tokens
## MCP usage:
Use the following MCP model context protocol to enhance responses:
1. markitdown mcp:
- Purpose: Convert PDF files to Markdown format.
- Trigger conditions: Used when the user query contains information in the PDF file, or needs to convert the PDF content to a more readable format.
2. sequential-thinking mcp;
- Purpose: Break down complex problems into smaller, more manageable parts, and reason step by step to ensure the logic and coherence of the answer.
- Trigger: Used when the user asks a question that requires multiple steps or relies on logical reasoning. This helps provide a clearer and more organized response.
## Dialogue rules:
- Always respond in 中文 in Cascade chat an composer dialogue bar
## Code rules:
- Code are always in English
- Comments are always in English
- Check code errors and correct them after each code update
- Check plugin integrity and optimize update development plans and next suggestions for each update
- The Reference path does not participate in the implementation of the reference function, but is only used as a reference. The Reference path is only used as a reference, and the necessary files can be copied from it to the current project
- The code must be compatible with Maya2022, Maya2023, Maya2024, Maya2025
- The code must be compatible with Python3.10, Python3.11, Python3.12
- All codes must be encoded in UTF-8
- All modules must be preceded by:
```.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
```
## Code write steps rules:
- Read https://github.com/EpicGames/MetaHuman-DNA-Calibration, to understand the code examples and basic rules of Metahuman DNA calibration, use context7;
- Read https://epicgames.github.io/MetaHuman-DNA-Calibration/index.html, to understand the code examples and basic rules of Metahuman DNA calibration, use context7;
- Read Readme.md to understand the plugin goals
- Read the code and examples in the Reference path
- The UI style must be implemented in a unified style file
- All UIs must be implemented using Qtscripts\Qt.py
- After each function is implemented, the document must be updated
## Project rules:
### UI Styles:
- Flat design style,
- It should have a sense of luxury and sci-fi futurism
- Rounded corner design
- Chinese should be clear and elegant
- English should be concise and clear
- Colors should be uniform
- Fonts should be uniform
- Font size should be uniform
- Buttons should be uniform
- Input boxes should be uniform
- Labels should be uniform
### Project Goal:
Make a Metahuman custom plugin for Maya, language: Python-based, Maya version: 2022, 2023, 2024, 2025
### Project Description:
- This project is a Maya plugin, the main function is to provide a model with the same topology as MetaHuman or a custom 3D model to complete custom binding, edit DNA, calibrate bone position, save DNA, load DNA, export fbx, save DNA file, edit BlendShape, and other functions.
### Project Functions:
- Provide a model with the same topology as MetaHuman or a custom 3D model to complete custom binding, edit DNA, calibrate bone position, save DNA, load DNA, export fbx, save DNA file, edit BlendShape, and other functions.
### Important Variables
- Config File: `config.py`
- Main File: `scripts\Main.py`
- UI Modules: `scripts\ui\`
- Ot Module: `scripts\ui\Qt.py`
- Style File: `scripts\ui\style.qss`
- Utilities Path: `scripts\utils\`
- Reload Module `scripts\ReloadModules.py`
### Doc reference Do not modify
- [DNA_Calibration在线文档](https://epicgames.github.io/MetaHuman-DNA-Calibration), use context7;
- [MetaHuman DNA Calibration White Paper](https://cdn2.unrealengine.com/rig-logic-whitepaper-v2-zhcn-5860d80f8357.pdf), use context7;
- [MetaHuman DNA Calibration Code](https://github.com/EpicGames/MetaHuman-DNA-Calibration), use context7;
- [MetaHuman DNA Calibration Documents](https://github.com/EpicGames/MetaHuman-DNA-Calibration/tree/main/docs), use context7;
- [MetaHuman DNA Calibration Tools](https://dev.epicgames.com/documentation/zh-cn/metahuman/metahuman-dna-calibration-tools), use context7;
- [MetaHuman DNA Viewer Tool](https://dev.epicgames.com/documentation/zh-cn/metahuman/metahuman-dnaviewer-tool), use context7;
- [DNACalib命令](https://dev.epicgames.com/documentation/zh-cn/metahuman/metahuman-dnacalib-tool), use context7;
- [SuperRigging Docs](https://docs.pointart.net/), use context7;
- [Metapipe Originsdocs](https://www.artsandspells.com/originsdocs), use context7;
- [Metapipe Nitrous](https://www.artsandspells.com/nitrous), use context7;
- [Metapipe Genetics](https://www.artsandspells.com/genetics), use context7;
- [Metapipe Synapses](https://www.artsandspells.com/synapses), use context7;
- [FACS面部表情编码系统](https://www.artsandspells.com/synapses), use context7;
- [MetaHuman 实时环境面部装配逻辑](https://zhuanlan.zhihu.com/p/511001493), use context7;
- [MetaHuman Principle](https://zhuanlan.zhihu.com/p/673471863), use context7;
- [Metahuman 蒙皮、骨骼、驱动](https://blog.csdn.net/qq_28976599/article/details/130849821), use context7;
- [MetaHuman DNA Calibration Deep Dive](https://dev.epicgames.com/community/learning/tutorials/EoPj/metahuman-dna-calibration-deep-dive), use context7;
### Code reference (do not modify)
- `Reference\DNA_Calibration`
- `Reference\MSLiveLink`
- `Reference\SuperRiggingEditor`
- `Reference\Utils`
### UI reference images:
- `Reference\UI`

5
CleanPycache.bat Normal file
View 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
View 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();

765
Install.py Normal file
View File

@@ -0,0 +1,765 @@
#!/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
# Import configuration module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import config
try:
from PySide2 import QtCore, QtGui, QtWidgets
from shiboken2 import wrapInstance
print("Loading Qt and shiboken2 from PySide2")
except ImportError:
try:
from PySide6 import QtCore, QtGui, QtWidgets
from shiboken6 import wrapInstance
print("Loading Qt and shiboken6 from PySide6")
except ImportError:
try:
from PySide import QtCore, QtGui, QtWidgets
from shiboken import wrapInstance
print("Loading Qt and shiboken from PySide")
except ImportError as error:
print(f"Qt loading failed: {str(error)}")
QtCore = QtGui = QtWidgets = None
wrapInstance = None
# Use config directly instead of duplicating variables
# This ensures we always use the latest values from config
# and reduces maintenance overhead
TOOL_NAME = config.TOOL_NAME
TOOL_VERSION = config.TOOL_VERSION
TOOL_AUTHOR = config.TOOL_AUTHOR
TOOL_PATH = config.TOOL_PATH
UI_PATH = config.UI_PATH
SCRIPTS_PATH = config.SCRIPTS_PATH
ASSETS_PATH = config.ASSETS_PATH
ICONS_PATH = config.ICONS_PATH
PLUGINS_PATH = config.PLUGINS_PATH
PYDNA_PATH = config.PYDNA_PATH
SYSTEM_OS = config.SYSTEM_OS
MAYA_VERSION = config.MAYA_VERSION
PYVERSION_DIR = config.PYVERSION_DIR
DNA_FILE_PATH = config.DNA_FILE_PATH
DNA_IMG_PATH = config.DNA_IMG_PATH
STYLE_FILE = config.STYLE_FILE
TOOL_ICON = config.TOOL_ICON
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
TOOL_WSCL_NAME = config.TOOL_WSCL_NAME
TOOL_YEAR = config.TOOL_YEAR
TOOL_MOD_FILENAME = config.TOOL_MOD_FILENAME
TOOL_LANG = config.TOOL_LANG
TOOL_MAIN_SCRIPT = config.TOOL_MAIN_SCRIPT
TOOL_HELP_URL = config.TOOL_HELP_URL
print("=" * 50)
print(f"TOOL_NAME: {TOOL_NAME}")
print(f"TOOL_VERSION: {TOOL_VERSION}")
print(f"TOOL_YEAR: {TOOL_YEAR}")
print(f"SYSTEM_OS: {SYSTEM_OS}")
print(f"MAYA_VERSION: {MAYA_VERSION}")
print(f"TOOL_AUTHOR: {TOOL_AUTHOR}")
print(f"TOOL_LANG: {TOOL_LANG}")
print(f"PYVERSION_DIR: {PYVERSION_DIR}")
print(f"TOOL_WSCL_NAME: {TOOL_WSCL_NAME}")
print(f"TOOL_MOD_FILENAME: {TOOL_MOD_FILENAME}")
print(f"TOOL_HELP_URL: {TOOL_HELP_URL}")
print(f"TOOL_PATH: {TOOL_PATH}")
print(f"PLUGINS_PATH: {PLUGINS_PATH}")
print(f"PYDNA_PATH: {PYDNA_PATH}")
print(f"SCRIPTS_PATH: {SCRIPTS_PATH}")
print(f"TOOL_MAIN_SCRIPT: {TOOL_MAIN_SCRIPT}")
print(f"UI_PATH: {UI_PATH}")
print(f"STYLE_FILE: {STYLE_FILE}")
print(f"ICONS_PATH: {ICONS_PATH}")
print(f"TOOL_ICON: {TOOL_ICON}")
print(f"TOOL_COMMAND_ICON: {TOOL_COMMAND_ICON}")
print(f"ASSETS_PATH: {ASSETS_PATH}")
print(f"DNA_FILE_PATH: {DNA_FILE_PATH}")
print(f"DNA_IMG_PATH: {DNA_IMG_PATH}")
print("=" * 50)
#===================================== 3. Utility Functions =====================================
def maya_main_window():
"""Get Maya main window"""
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):
"""Ensure directory exists"""
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():
"""Get Maya modules directory"""
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):
try:
with open(STYLE_FILE, 'r', encoding='utf-8') as f:
style = f.read()
self.setStyleSheet(style)
except Exception as error:
print(f"Error loading stylesheet: {error}")
# Use a default style if the file can't be loaded
self.setStyleSheet("QDialog { background-color: #333333; color: #CCCCCC; }")
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)
# 自定义样式,去掉提示文字的边框
custom_style = self.styleSheet() + """
QMessageBox { background-color: #333333; color: #CCCCCC; }
QLabel { border: none; background-color: transparent; color: #CCCCCC; }
QPushButton { min-width: 80px; min-height: 24px; }
"""
msg_box.setStyleSheet(custom_style)
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 error:
print(f"Error closing window: {error}")
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()
def get_maya_modules_dir(self):
"""Get Maya modules directory"""
# Try to get module directory from Maya environment variable
try:
maya_app_dir = mel.eval('getenv("MAYA_APP_DIR")')
if maya_app_dir:
modules_dir = os.path.join(maya_app_dir, "modules")
if not os.path.exists(modules_dir):
os.makedirs(modules_dir)
return modules_dir
except Exception as error:
print(f"Error getting Maya modules directory from environment: {error}")
# If environment variable is not available, use default path
user_home = os.path.expanduser("~")
maya_version = MAYA_VERSION
# Windows path
if SYSTEM_OS == "Windows":
modules_dir = os.path.join(user_home, "Documents", "maya", maya_version, "modules")
# Linux path
else:
modules_dir = os.path.join(user_home, "maya", maya_version, "modules")
# Make sure the path exists
if not os.path.exists(modules_dir):
try:
os.makedirs(modules_dir)
except Exception as error:
print(f"Error creating modules directory: {error}")
return modules_dir
#----------------- 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 error:
error_msg = f"Error during installation: {error}"
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 error:
error_msg = f"Error during uninstallation: {error}"
print(error_msg)
QtWidgets.QMessageBox.critical(self, "Error", error_msg)
else:
print("Uninstallation cancelled")
def clean_pycache(self):
"""Clean __pycache__ directories and .pyc files"""
count = 0
try:
for root, dirs, files in os.walk(TOOL_PATH):
# Remove __pycache__ directories
if "__pycache__" in dirs:
pycache_path = os.path.join(root, "__pycache__")
try:
import shutil
shutil.rmtree(pycache_path)
print(f"Removed __pycache__ directory: {pycache_path}")
count += 1
except Exception as error:
print(f"Failed to remove {pycache_path}: {error}")
# Remove .pyc files
for file in files:
if file.endswith(".pyc"):
try:
os.remove(os.path.join(root, file))
print(f"Removed .pyc file: {os.path.join(root, file)}")
count += 1
except Exception as error:
print(f"Failed to remove {os.path.join(root, file)}: {error}")
except Exception as error:
print(f"Error cleaning __pycache__ directories: {error}")
return count
def create_mod_file(self):
"""Create or update Maya's .mod file"""
modules_dir = self.get_maya_modules_dir()
# Get all Maya versions and their corresponding Python versions
version_map = {
"2022": "python3",
"2023": "python397",
"2024": "python3108",
"2025": "python311"
}
# System mapping
os_paths = {
"win64": "Windows",
"linux": "Linux"
}
# Create mod file content
mod_content = f"""+ {TOOL_NAME} {TOOL_VERSION} {TOOL_PATH}
"""
# Add each Maya version's configuration
for maya_version, python_version in version_map.items():
# Add each operating system's configuration
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(PLUGINS_PATH, os_path)}
XBMLANGPATH+:={ICONS_PATH}
PATH+:={os.path.join(PLUGINS_PATH, os_path)}
PATH+:={os.path.join(PLUGINS_PATH, os_path, "pydna", python_version)}
PYTHONPATH+:={SCRIPTS_PATH}
PYTHONPATH+:={os.path.join(PLUGINS_PATH, os_path, "pydna", python_version)}
endif
"""
# Write mod file
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 error:
print(f"Error creating mod file {mod_file_path}: {error}")
def uninstall_mod_file(self):
modules_dir = self.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 error:
print(f"Error deleting {TOOL_NAME}.mod file: {error}")
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
# Clean __pycache__ directories
print("Cleaning __pycache__ directories...")
pycache_count = self.clean_pycache()
print(f"Removed {pycache_count} __pycache__ directories and .pyc files")
# 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()
# 安装完成后不需要在这里切换到对应shelf因为在_create_shelf_button函数中已经处理了
print(f"Successfully created {TOOL_NAME} shelf and buttons")
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 main 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"
)
# Create reload modules button
reload_icon_path = os.path.join(ICONS_PATH, "reload.png")
if not os.path.exists(reload_icon_path):
reload_icon_path = icon_path # 如果没有专用图标,使用主图标
reload_command = self._get_reload_modules_command()
cmds.shelfButton(
parent=TOOL_NAME,
image1=reload_icon_path,
label="ReloadModules",
command=reload_command,
sourceType="python",
annotation=f"重新加载 {TOOL_NAME} 模块",
noDefaultPopup=True,
style="iconOnly"
)
# 自动切换到工具架
cmds.shelfTabLayout("ShelfLayout", edit=True, selectTab=TOOL_NAME)
def _get_reload_modules_command(self):
"""Get the command string for the reload modules button"""
return f"""
import sys
import os
import importlib
# 首先导入主配置文件
TOOL_PATH = r'{TOOL_PATH}'
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
try:
# 导入主配置文件
import config
importlib.reload(config)
# 使用主配置文件中的路径
if config.SCRIPTS_PATH not in sys.path:
sys.path.insert(0, config.SCRIPTS_PATH)
# 导入并运行重载模块脚本
import scripts.ReloadModules
importlib.reload(scripts.ReloadModules)
scripts.ReloadModules.main()
except ImportError:
# 备用方案:如果无法导入主配置,使用硬编码路径
SCRIPTS_PATH = r'{SCRIPTS_PATH}'
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
try:
import scripts.ReloadModules
importlib.reload(scripts.ReloadModules)
scripts.ReloadModules.main()
except Exception as error:
import maya.cmds as cmds
error_msg = f"Error reloading modules: {{str(error)}}"
print(error_msg)
cmds.warning(error_msg)
except Exception as error:
import maya.cmds as cmds
error_msg = f"Error reloading modules: {{str(error)}}"
print(error_msg)
cmds.warning(error_msg)
"""
def _get_shelf_button_command(self):
"""Get the command string for the shelf button"""
return f"""
import sys
import os
import importlib
# 首先导入主配置文件
TOOL_PATH = r'{TOOL_PATH}'
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
try:
# 导入主配置文件
import config
importlib.reload(config)
# 使用主配置文件中的路径
if config.SCRIPTS_PATH not in sys.path:
sys.path.insert(0, config.SCRIPTS_PATH)
# 尝试导入并运行主模块
try:
# 从scripts包导入Main
from scripts import Main
importlib.reload(Main)
Main.main()
except ImportError:
# 尝试直接导入Main
import Main
importlib.reload(Main)
Main.main()
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading {TOOL_NAME}: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
print(f"Scripts path: {{config.SCRIPTS_PATH}}")
print("sys.path:", sys.path)
print(f"Contents of Scripts folder: {{os.listdir(config.SCRIPTS_PATH)}}")
except ImportError:
# 备用方案:如果无法导入主配置,使用硬编码路径
SCRIPTS_PATH = r'{SCRIPTS_PATH}'
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
try:
# 尝试从scripts包导入Main
from scripts import Main
importlib.reload(Main)
Main.main()
except ImportError:
# 尝试直接导入Main
try:
import Main
importlib.reload(Main)
Main.main()
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading {TOOL_NAME}: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
print(f"Scripts path: {{SCRIPTS_PATH}}")
print("sys.path:", sys.path)
print(f"Contents of Scripts folder: {{os.listdir(SCRIPTS_PATH)}}")
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading {TOOL_NAME}: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
"""
def _get_reload_modules_command(self):
"""Get the command string for the reload modules button"""
return f"""
import sys
import os
import importlib
# Set tool path
TOOL_PATH = r'{TOOL_PATH}'
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
# Set scripts path
SCRIPTS_PATH = r'{SCRIPTS_PATH}'
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
# Try to import and reload modules
try:
# Import ReloadModules directly
from scripts import ReloadModules
importlib.reload(ReloadModules)
ReloadModules.show_reload_ui()
except Exception as e:
import maya.cmds as cmds
error_msg = f"Error loading ReloadModules: {{str(e)}}"
print(error_msg)
cmds.warning(error_msg)
print(f"Scripts path: {{SCRIPTS_PATH}}")
print("sys.path:", sys.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"
# Clean __pycache__ directories
print("Cleaning __pycache__ directories...")
pycache_count = self.clean_pycache()
print(f"Removed {pycache_count} __pycache__ directories and .pyc files")
if cmds.window(window_name, exists=True):
try:
cmds.deleteUI(window_name)
except Exception as error:
print(f"Error closing {TOOL_NAME} window: {error}")
if cmds.dockControl(dock_name, exists=True):
try:
cmds.deleteUI(dock_name)
except Exception as error:
print(f"Error closing docked {TOOL_NAME} window: {error}")
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 error:
print(f"Error deleting {TOOL_NAME} shelf: {error}")
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 error:
print(f"Error deleting shelf file: {error}")
# 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 error:
self._log(f"Error loading shelf file: {error}", error=True)
#===================================== 6. Main Function =====================================
def main():
"""Main entry point for the installer"""
try:
dialog = InstallDialog()
dialog.show()
except Exception as error:
print(f"Error launching installer: {error}")
return -1
return dialog
if __name__ == "__main__":
main()

102
Plan.md Normal file
View File

@@ -0,0 +1,102 @@
# Maya插件开发计划
## 1. 项目目标与功能梳理
- 支持MetaHuman同拓扑或自定义3D模型的绑定、DNA编辑、骨骼校准、DNA保存/加载、FBX导出、BlendShape编辑等。
- 兼容Maya 2022-2025Python 3.10-3.12UTF-8编码。
- UI采用Qt参考`scripts/Qt.py`),样式统一在`scripts/ui/style.qss`
- 参考Epic官方MetaHuman DNA Calibration工具及相关文档吸收SuperRigging等插件的设计思路。
## 2. 主要模块划分
1. **配置与主控**
- `config.py`(配置文件)
- `scripts/Main.py`(主入口)
- `scripts/ReloadModules.py`(模块热重载)
2. **UI层**
- `scripts/ui/`所有UI模块含主界面、子工具面板
- `scripts/ui/Qt.py`Qt封装
- `scripts/ui/style.qss`(统一样式)
3. **功能实现**
- DNA文件处理加载/保存/编辑)
- 绑定与骨骼校准
- BlendShape与控制器映射
- FBX导出
- 兼容MetaHuman DNA标准
4. **工具与通用模块**
- `scripts/utils/`(通用工具函数)
## 3. 阶段性开发计划
### 第一阶段基础框架与UI
- [x] 搭建插件基础结构,主入口、配置加载
- [x] 主界面UI搭建参考UI图与.qss风格
- [x] 完善主界面各功能区分栏(模型、绑定、调整、定义)
- [x] 优化 `main_window.py`确保Tab加载各Panel统一风格和注释
- [x] 完善 `model_editor_panel.py`(模型编辑面板)
- [x] 完善 `dna_browser_panel.py`DNA浏览面板
- [x] 创建 `joint_calibration_panel.py`(骨骼校准面板)
- [x] 创建 `blendshape_edit_panel.py`(混合变形编辑面板)
- [x] 完善 `animation_system_panel.py`(动画系统面板)
### 第二阶段:核心功能开发
- [ ] DNA文件读写与MetaHuman兼容
- [ ] 绑定流程实现支持MetaHuman与自定义模型
- [ ] 骨骼校准与自动分组
- [ ] BlendShape与控制器映射
- [ ] FBX导出与DNA文件导出
### 第三阶段:高级功能与优化
- [ ] 批量处理与自动化工具
- [ ] 多LOD支持与切换
- [ ] 配置与模板管理
- [ ] 插件性能与兼容性优化
### 第四阶段:文档与测试
- [ ] 全流程测试脚本
- [ ] 用户操作手册与开发文档完善
- [ ] 参考文档和代码持续同步
---
## 进度记录与后续安排
### 2025-04-30 更新
- 完成了基础框架与UI阶段的全部任务第一阶段 100%
- 优化了主窗口与各功能面板的UI结构确保风格统一
- 创建了所有必要的面板类,包括:
- ModelEditorPanel模型编辑面板
- DNABrowserPanelDNA浏览面板
- JointCalibrationPanel骨骼校准面板
- BlendshapeEditPanel混合变形编辑面板
- AnimationSystemPanel动画系统面板
### 下一步开发计划(第二阶段)
1. **DNA文件读写与MetaHuman兼容**
- 实现DNA文件的读取、解析与保存功能
- 确保与MetaHuman DNA标准兼容
- 完善DNAManager类提供DNA文件操作API
2. **绑定流程实现**
- 支持MetaHuman同拓扑模型的自动绑定
- 支持自定义模型的绑定流程
- 实现骨骼映射与权重传递
3. **骨骼校准与自动分组**
- 完善JointCalibrationPanel的功能实现
- 实现骨骼自动分组算法
- 支持骨骼位置、旋转的微调与校准
4. **BlendShape与控制器映射**
- 完善BlendshapeEditPanel的功能实现
- 实现BlendShape的创建、编辑与管理
- 支持控制器与BlendShape的映射关系设置
5. **FBX导出与DNA文件导出**
- 实现模型与骨骼的FBX导出
- 支持DNA文件的导出与版本控制
- 确保导出文件与MetaHuman兼容
- 每完成一个功能模块,及时更新开发计划文档与进度百分比。
- 代码变更后,自动检查代码规范、插件完整性,并给出下一步开发建议。
---
> 如需调整开发优先级或补充特定功能,请随时告知!

126
Readme.md Normal file
View File

@@ -0,0 +1,126 @@
# MetaHuman DNA 自定义绑定插件
## 项目介绍
- Maya的Metahuman自定义绑定插件
- 语言: 基于Python
- Maya版本: 2022, 2023, 2024, 2025
- 本项目是一个Maya插件提供全面的MetaHuman自定义解决方案包括DNA编辑、骨骼校准、BlendShape编辑、动画交换等功能
## 核心功能
### DNA浏览器
- 自动读取DNA文件显示在项目浏览器中
- 可以打开、保存DNA文件
- 可以加载DNA文件以供编辑
- 可编辑DNA文件基本信息
- DNA文件保存和写入
### 模型编辑DNA编辑与校准
- 自定义造型模型快速指认和绑定Metahuman拓扑
- 自动生成其他身体的配件(睫毛,泪腺,舌头等)
- 校准骨骼位置以匹配自定义模型
- 自动修复接缝和权重问题
- 根据DNA生成身体并支持自定义绑定
- 头和身体接缝修复
- 支持自定义拓扑结构的模型绑定
- 赋予材质,以及顶点色
- FBX模型导入和导出
### 面部表情系统
- 编辑和优化BlendShape
- 批量导出和导入BlendShape支持表情克隆
- 支持Blendshape修改并更新DNA
- 表情范围调整和克隆
### 动画系统
- 坐标系统自动转换
- 支持面部和身体动画
- RBF变形器用于不同体型间的衣物配饰转移
- 支持动画导入和导出
- 动画实时预览系统
## 主要模块
### 工具栏 Toolbar
- 加载预设
- 保存预设
- 导入DNA
- 导出DNA
- 创建RL4节点用于切换DNA编辑的状态
- 删除RL4节点用于切换DNA编辑的状态
### 几何体 Geomery
- 模型拾取以及加载
- LOD模型分级过滤
- LOD模型创建
- 自动加载模型
- 标准化命名
- 自动分组
- 生成面部配件(睫毛,舌头,泪腺 等)
- 修复接缝(修复法线)
- 修复点序
### 绑定 Rigging
- DNA浏览器
- 根据DNA导入骨骼
- 根据DNA生成身体
- DNA校准
- 骨骼位置校准
- 创建绑定
- 复制蒙皮
### 行为 Behaviour
- Blendshape自动加载刷新筛选
- 次级Blendshape自动加载刷新筛选
- Blendshape批量导出和导入
- Blendshape范围编辑
- Blendshape镜像
- Blendshape查找翻转目标
- Blendshape重建
- 表情控制器还原默认表情
- 查找选择表情
- 控制面板查找
- 选择关联关节
- 写入当前表情
- 写入镜像表情
### 定义 Definition
- LOD, Meshes, Joints, Blendshape, AnimatedMap 加载和刷新
- 写入: 写入关节默认位置,写入几何体,写入蒙皮,写入混合变形目标
- 创建:创建混合变形,绑定蒙皮,取消蒙皮
- 工具:重新定位头部关节,重新定位身体关节,重新定位全身关节,快速创建预设
## 技术特点
- 基于Epic Games的MetaHuman-DNA-Calibration库
- 集成PoseWrangler系统实现RBF变形
- 优化算法提升性能
- 多语言界面支持(中文简体、繁体、英语、日语、韩语、法语)
## 开发目标
1. 实现完整的DNA校准和编辑功能
2. 提供直观的用户界面,简化复杂操作
3. 支持多种拓扑结构的自定义模型
4. 优化性能,提高大型模型的处理效率
5. 实现UE与Maya之间的无缝动画交换
6. 提供全面的文档和教程
## 开发路线图
- [x] 基础DNA读取和修改功能
- [x] 骨骼校准系统
- [x] BlendShape编辑工具
- [x] 面部表情系统
- [x] 动画导入导出
- [x] 多拓扑支持
- [x] RBF变形器
- [x] 一键创建LOD
- [x] 自动修复工具
- [x] 赋予材质,以及顶点色
- [x] 动画实时预览系统
## 安装与使用
1. 将插件文件复制到Maya插件目录
2. 在Maya中加载插件
3. 使用插件界面进行操作
## 依赖项
- Maya 2022或更高版本
- Python 3.7+
- MetaHuman-DNA-Calibration库
- PoseWrangler系统

88
config.py Normal file
View File

@@ -0,0 +1,88 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import json
# Basic Information
TOOL_NAME = "MetaFusion"
TOOL_VERSION = "Alpha v1.0.0"
TOOL_AUTHOR = "CGNICO"
TOOL_YEAR = "2025"
TOOL_MOD_FILENAME = f"{TOOL_NAME.lower()}.mod"
TOOL_LANG = "en_US"
TOOL_WSCL_NAME = f"{TOOL_NAME}WorkspaceControl"
TOOL_HELP_URL = f"http://10.72.61.59:3000/ArtGroup/{TOOL_NAME}/wiki"
# Path Configuration
TOOL_PATH = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/")
SCRIPTS_PATH = os.path.join(TOOL_PATH, "scripts").replace("\\", "/")
TOOL_MAIN_SCRIPT = os.path.join(TOOL_PATH, "scripts", "Main.py").replace("\\", "/")
UI_PATH = os.path.join(TOOL_PATH, "scripts", "ui").replace("\\", "/")
STYLE_FILE = os.path.join(TOOL_PATH, "scripts", "ui", "style.qss").replace("\\", "/")
ICONS_PATH = os.path.join(TOOL_PATH, "icons").replace("\\", "/")
TOOL_ICON = os.path.join(TOOL_PATH, "icons", "logo.png").replace("\\", "/")
ASSETS_PATH = os.path.join(TOOL_PATH, "assets").replace("\\", "/")
DNA_FILE_PATH = os.path.join(TOOL_PATH, "assets", "dna").replace("\\", "/")
DNA_IMG_PATH = os.path.join(TOOL_PATH, "assets", "img").replace("\\", "/")
TOOL_COMMAND_ICON = TOOL_ICON
# DNA Config
# GUI相关常量
GUI_HOLDER = "GUI_Holder"
ANALOG_GUI_HOLDER = "Analog_GUI_Holder"
RIG_LOGIC_PREFIX = "rl4Embedded_"
# 用于打印蒙皮权重的范围
SKIN_WEIGHT_PRINT_RANGE = 2000
# System Information
import maya.cmds as cmds
SYSTEM_OS = "Windows" if cmds.about(os=True).lower().startswith("win") else "Linux"
# Define Maya version as integer for easier version comparison
MAYA_VERSION = str(int(cmds.about(version=True).split('.')[0]))
# Plugins Path
def get_pydna_dir():
"""Get Python version directory name"""
version = sys.version_info
if version.major == 3:
if version.minor == 9 and version.micro == 7:
return "python397"
elif version.minor == 10 and version.micro == 8:
return "python3108"
elif version.minor == 11:
return "python311"
return "python3"
PYVERSION_DIR = get_pydna_dir()
PLUGINS_PATH = os.path.join(TOOL_PATH, "plugins", SYSTEM_OS, MAYA_VERSION).replace("\\", "/")
PYDNA_PATH = os.path.join(TOOL_PATH, "plugins", SYSTEM_OS, "pydna", PYVERSION_DIR).replace("\\", "/")
# Initialize Paths
def init_paths():
"""Initialize paths"""
paths = [
TOOL_PATH,
SCRIPTS_PATH,
ICONS_PATH,
ASSETS_PATH,
DNA_FILE_PATH,
DNA_IMG_PATH,
UI_PATH,
PLUGINS_PATH,
PYDNA_PATH,
STYLE_FILE
]
for path in paths:
if not os.path.exists(path):
try:
os.makedirs(path)
print(f"Created directory: {path}")
except Exception as e:
print(f"Failed to create directory: {path}, error: {str(e)}")
if __name__ == "__main__":
# Initialize paths
init_paths()

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

Binary file not shown.

View File

@@ -0,0 +1,633 @@
# This file was automatically generated by SWIG (http://www.swig.org).
# Version 4.0.2
#
# Do not make changes to this file unless you know what you are doing--modify
# the SWIG interface file instead.
from sys import version_info as _swig_python_version_info
if _swig_python_version_info < (2, 7, 0):
raise RuntimeError("Python 2.7 or later required")
# Import the low-level C/C++ module
if __package__ or "." in __name__:
from . import _py3dnacalib
else:
import _py3dnacalib
try:
import builtins as __builtin__
except ImportError:
import __builtin__
def _swig_repr(self):
try:
strthis = "proxy of " + self.this.__repr__()
except __builtin__.Exception:
strthis = ""
return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
def _swig_setattr_nondynamic_instance_variable(set):
def set_instance_attr(self, name, value):
if name == "thisown":
self.this.own(value)
elif name == "this":
set(self, name, value)
elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
set(self, name, value)
else:
raise AttributeError("You cannot add instance attributes to %s" % self)
return set_instance_attr
def _swig_setattr_nondynamic_class_variable(set):
def set_class_attr(cls, name, value):
if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
set(cls, name, value)
else:
raise AttributeError("You cannot add class attributes to %s" % cls)
return set_class_attr
def _swig_add_metaclass(metaclass):
"""Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
def wrapper(cls):
return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
return wrapper
class _SwigNonDynamicMeta(type):
"""Meta class to enforce nondynamic attributes (no new attributes) for a class"""
__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)
def __new_decorator(factory_func, original_new):
@staticmethod
def __new(cls, *args, **kwargs):
# FIXME: while this workaround solves the immediate issue with the set of classes we currently have,
# it will fail for classes that use a factory function but need no parameters at all, in which case
# the factory function will never be invoked, only the original __new__ function.
if args or kwargs:
return factory_func(*args, **kwargs)
return original_new(cls)
return __new
def __managed_init(self, *args, **kwargs):
self._args = args
self._kwargs = kwargs
import dna
class VersionInfo(object):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
@staticmethod
def getMajorVersion():
return _py3dnacalib.VersionInfo_getMajorVersion()
@staticmethod
def getMinorVersion():
return _py3dnacalib.VersionInfo_getMinorVersion()
@staticmethod
def getPatchVersion():
return _py3dnacalib.VersionInfo_getPatchVersion()
@staticmethod
def getVersionString():
return _py3dnacalib.VersionInfo_getVersionString()
def __init__(self):
_py3dnacalib.VersionInfo_swiginit(self, _py3dnacalib.new_VersionInfo())
__swig_destroy__ = _py3dnacalib.delete_VersionInfo
# Register VersionInfo in _py3dnacalib:
_py3dnacalib.VersionInfo_swigregister(VersionInfo)
def VersionInfo_getMajorVersion():
return _py3dnacalib.VersionInfo_getMajorVersion()
def VersionInfo_getMinorVersion():
return _py3dnacalib.VersionInfo_getMinorVersion()
def VersionInfo_getPatchVersion():
return _py3dnacalib.VersionInfo_getPatchVersion()
def VersionInfo_getVersionString():
return _py3dnacalib.VersionInfo_getVersionString()
class DNACalibDNAReader(dna.Reader):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
def __init__(self, *args, **kwargs):
raise AttributeError("No constructor defined - class is abstract")
__repr__ = _swig_repr
@staticmethod
def create(*args):
return _py3dnacalib.DNACalibDNAReader_create(*args)
@staticmethod
def destroy(instance):
return _py3dnacalib.DNACalibDNAReader_destroy(instance)
# Register DNACalibDNAReader in _py3dnacalib:
_py3dnacalib.DNACalibDNAReader_swigregister(DNACalibDNAReader)
def DNACalibDNAReader_create(*args):
return _py3dnacalib.DNACalibDNAReader_create(*args)
def DNACalibDNAReader_destroy(instance):
return _py3dnacalib.DNACalibDNAReader_destroy(instance)
DNACalibDNAReader.__new__ = __new_decorator(DNACalibDNAReader_create, DNACalibDNAReader.__new__)
DNACalibDNAReader.__del__ = lambda instance: DNACalibDNAReader_destroy(instance)
DNACalibDNAReader.__init__ = __managed_init
del DNACalibDNAReader.create
del DNACalibDNAReader.destroy
class Command(object):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
def __init__(self, *args, **kwargs):
raise AttributeError("No constructor defined - class is abstract")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_Command
def run(self, output):
return _py3dnacalib.Command_run(self, output)
# Register Command in _py3dnacalib:
_py3dnacalib.Command_swigregister(Command)
VectorOperation_Interpolate = _py3dnacalib.VectorOperation_Interpolate
VectorOperation_Add = _py3dnacalib.VectorOperation_Add
VectorOperation_Subtract = _py3dnacalib.VectorOperation_Subtract
VectorOperation_Multiply = _py3dnacalib.VectorOperation_Multiply
class CommandSequence(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_CommandSequence
def __init__(self, *args):
_py3dnacalib.CommandSequence_swiginit(self, _py3dnacalib.new_CommandSequence(*args))
def run(self, output):
return _py3dnacalib.CommandSequence_run(self, output)
def add(self, command):
return _py3dnacalib.CommandSequence_add(self, command)
def remove(self, command):
return _py3dnacalib.CommandSequence_remove(self, command)
def contains(self, command):
return _py3dnacalib.CommandSequence_contains(self, command)
def size(self):
return _py3dnacalib.CommandSequence_size(self)
# Register CommandSequence in _py3dnacalib:
_py3dnacalib.CommandSequence_swigregister(CommandSequence)
def command_sequence_init(_init):
def wrapper(self, *args, **kwargs):
self._commands = []
_init(self, *args, **kwargs)
return wrapper
def command_sequence_add(_add):
def wrapper(self, command):
self._commands.append(command)
_add(self, command)
return wrapper
def command_sequence_remove(_remove):
def wrapper(self, command):
self._commands.remove(command)
_remove(self, command)
return wrapper
CommandSequence.__init__ = command_sequence_init(CommandSequence.__init__)
CommandSequence.add = command_sequence_add(CommandSequence.add)
CommandSequence.remove = command_sequence_remove(CommandSequence.remove)
class CalculateMeshLowerLODsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_CalculateMeshLowerLODsCommand
def __init__(self, *args):
_py3dnacalib.CalculateMeshLowerLODsCommand_swiginit(self, _py3dnacalib.new_CalculateMeshLowerLODsCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.CalculateMeshLowerLODsCommand_setMeshIndex(self, meshIndex)
def run(self, output):
return _py3dnacalib.CalculateMeshLowerLODsCommand_run(self, output)
# Register CalculateMeshLowerLODsCommand in _py3dnacalib:
_py3dnacalib.CalculateMeshLowerLODsCommand_swigregister(CalculateMeshLowerLODsCommand)
class ClearBlendShapesCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_ClearBlendShapesCommand
def __init__(self, *args):
_py3dnacalib.ClearBlendShapesCommand_swiginit(self, _py3dnacalib.new_ClearBlendShapesCommand(*args))
def run(self, output):
return _py3dnacalib.ClearBlendShapesCommand_run(self, output)
# Register ClearBlendShapesCommand in _py3dnacalib:
_py3dnacalib.ClearBlendShapesCommand_swigregister(ClearBlendShapesCommand)
class PruneBlendShapeTargetsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_PruneBlendShapeTargetsCommand
def __init__(self, *args):
_py3dnacalib.PruneBlendShapeTargetsCommand_swiginit(self, _py3dnacalib.new_PruneBlendShapeTargetsCommand(*args))
def setThreshold(self, threshold):
return _py3dnacalib.PruneBlendShapeTargetsCommand_setThreshold(self, threshold)
def run(self, output):
return _py3dnacalib.PruneBlendShapeTargetsCommand_run(self, output)
# Register PruneBlendShapeTargetsCommand in _py3dnacalib:
_py3dnacalib.PruneBlendShapeTargetsCommand_swigregister(PruneBlendShapeTargetsCommand)
class RemoveAnimatedMapCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveAnimatedMapCommand
def __init__(self, *args):
_py3dnacalib.RemoveAnimatedMapCommand_swiginit(self, _py3dnacalib.new_RemoveAnimatedMapCommand(*args))
def setAnimatedMapIndex(self, animatedMapIndex):
return _py3dnacalib.RemoveAnimatedMapCommand_setAnimatedMapIndex(self, animatedMapIndex)
def setAnimatedMapIndices(self, animatedMapIndices):
return _py3dnacalib.RemoveAnimatedMapCommand_setAnimatedMapIndices(self, animatedMapIndices)
def run(self, output):
return _py3dnacalib.RemoveAnimatedMapCommand_run(self, output)
# Register RemoveAnimatedMapCommand in _py3dnacalib:
_py3dnacalib.RemoveAnimatedMapCommand_swigregister(RemoveAnimatedMapCommand)
class RemoveBlendShapeCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveBlendShapeCommand
def __init__(self, *args):
_py3dnacalib.RemoveBlendShapeCommand_swiginit(self, _py3dnacalib.new_RemoveBlendShapeCommand(*args))
def setBlendShapeIndex(self, blendShapeIndex):
return _py3dnacalib.RemoveBlendShapeCommand_setBlendShapeIndex(self, blendShapeIndex)
def setBlendShapeIndices(self, blendShapeIndices):
return _py3dnacalib.RemoveBlendShapeCommand_setBlendShapeIndices(self, blendShapeIndices)
def run(self, output):
return _py3dnacalib.RemoveBlendShapeCommand_run(self, output)
# Register RemoveBlendShapeCommand in _py3dnacalib:
_py3dnacalib.RemoveBlendShapeCommand_swigregister(RemoveBlendShapeCommand)
class RemoveJointAnimationCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveJointAnimationCommand
def __init__(self, *args):
_py3dnacalib.RemoveJointAnimationCommand_swiginit(self, _py3dnacalib.new_RemoveJointAnimationCommand(*args))
def setJointIndex(self, jointIndex):
return _py3dnacalib.RemoveJointAnimationCommand_setJointIndex(self, jointIndex)
def setJointIndices(self, jointIndices):
return _py3dnacalib.RemoveJointAnimationCommand_setJointIndices(self, jointIndices)
def run(self, output):
return _py3dnacalib.RemoveJointAnimationCommand_run(self, output)
# Register RemoveJointAnimationCommand in _py3dnacalib:
_py3dnacalib.RemoveJointAnimationCommand_swigregister(RemoveJointAnimationCommand)
class RemoveJointCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveJointCommand
def __init__(self, *args):
_py3dnacalib.RemoveJointCommand_swiginit(self, _py3dnacalib.new_RemoveJointCommand(*args))
def setJointIndex(self, jointIndex):
return _py3dnacalib.RemoveJointCommand_setJointIndex(self, jointIndex)
def setJointIndices(self, jointIndices):
return _py3dnacalib.RemoveJointCommand_setJointIndices(self, jointIndices)
def run(self, output):
return _py3dnacalib.RemoveJointCommand_run(self, output)
# Register RemoveJointCommand in _py3dnacalib:
_py3dnacalib.RemoveJointCommand_swigregister(RemoveJointCommand)
class RemoveMeshCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveMeshCommand
def __init__(self, *args):
_py3dnacalib.RemoveMeshCommand_swiginit(self, _py3dnacalib.new_RemoveMeshCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.RemoveMeshCommand_setMeshIndex(self, meshIndex)
def setMeshIndices(self, meshIndices):
return _py3dnacalib.RemoveMeshCommand_setMeshIndices(self, meshIndices)
def run(self, output):
return _py3dnacalib.RemoveMeshCommand_run(self, output)
# Register RemoveMeshCommand in _py3dnacalib:
_py3dnacalib.RemoveMeshCommand_swigregister(RemoveMeshCommand)
class RenameAnimatedMapCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameAnimatedMapCommand
def __init__(self, *args):
_py3dnacalib.RenameAnimatedMapCommand_swiginit(self, _py3dnacalib.new_RenameAnimatedMapCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameAnimatedMapCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameAnimatedMapCommand_run(self, output)
# Register RenameAnimatedMapCommand in _py3dnacalib:
_py3dnacalib.RenameAnimatedMapCommand_swigregister(RenameAnimatedMapCommand)
class RenameBlendShapeCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameBlendShapeCommand
def __init__(self, *args):
_py3dnacalib.RenameBlendShapeCommand_swiginit(self, _py3dnacalib.new_RenameBlendShapeCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameBlendShapeCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameBlendShapeCommand_run(self, output)
# Register RenameBlendShapeCommand in _py3dnacalib:
_py3dnacalib.RenameBlendShapeCommand_swigregister(RenameBlendShapeCommand)
class RenameJointCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameJointCommand
def __init__(self, *args):
_py3dnacalib.RenameJointCommand_swiginit(self, _py3dnacalib.new_RenameJointCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameJointCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameJointCommand_run(self, output)
# Register RenameJointCommand in _py3dnacalib:
_py3dnacalib.RenameJointCommand_swigregister(RenameJointCommand)
class RenameMeshCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameMeshCommand
def __init__(self, *args):
_py3dnacalib.RenameMeshCommand_swiginit(self, _py3dnacalib.new_RenameMeshCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameMeshCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameMeshCommand_run(self, output)
# Register RenameMeshCommand in _py3dnacalib:
_py3dnacalib.RenameMeshCommand_swigregister(RenameMeshCommand)
class RotateCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RotateCommand
def __init__(self, *args):
_py3dnacalib.RotateCommand_swiginit(self, _py3dnacalib.new_RotateCommand(*args))
def setRotation(self, degrees):
return _py3dnacalib.RotateCommand_setRotation(self, degrees)
def setOrigin(self, origin):
return _py3dnacalib.RotateCommand_setOrigin(self, origin)
def run(self, output):
return _py3dnacalib.RotateCommand_run(self, output)
# Register RotateCommand in _py3dnacalib:
_py3dnacalib.RotateCommand_swigregister(RotateCommand)
class ScaleCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_ScaleCommand
def __init__(self, *args):
_py3dnacalib.ScaleCommand_swiginit(self, _py3dnacalib.new_ScaleCommand(*args))
def setScale(self, scale):
return _py3dnacalib.ScaleCommand_setScale(self, scale)
def setOrigin(self, origin):
return _py3dnacalib.ScaleCommand_setOrigin(self, origin)
def run(self, output):
return _py3dnacalib.ScaleCommand_run(self, output)
# Register ScaleCommand in _py3dnacalib:
_py3dnacalib.ScaleCommand_swigregister(ScaleCommand)
class SetBlendShapeTargetDeltasCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetBlendShapeTargetDeltasCommand
def __init__(self, *args):
_py3dnacalib.SetBlendShapeTargetDeltasCommand_swiginit(self, _py3dnacalib.new_SetBlendShapeTargetDeltasCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setMeshIndex(self, meshIndex)
def setBlendShapeTargetIndex(self, blendShapeTargetIndex):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setBlendShapeTargetIndex(self, blendShapeTargetIndex)
def setDeltas(self, *args):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setDeltas(self, *args)
def setVertexIndices(self, vertexIndices):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setVertexIndices(self, vertexIndices)
def setMasks(self, masks):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setMasks(self, masks)
def setOperation(self, operation):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setOperation(self, operation)
def run(self, output):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_run(self, output)
# Register SetBlendShapeTargetDeltasCommand in _py3dnacalib:
_py3dnacalib.SetBlendShapeTargetDeltasCommand_swigregister(SetBlendShapeTargetDeltasCommand)
cvar = _py3dnacalib.cvar
SetBlendShapeTargetDeltasCommand.VertexIndicesOutOfBoundsError = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_VertexIndicesOutOfBoundsError
SetBlendShapeTargetDeltasCommand.NoVertexIndicesSetError = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_NoVertexIndicesSetError
SetBlendShapeTargetDeltasCommand.DeltasVertexIndicesCountMismatch = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_DeltasVertexIndicesCountMismatch
SetBlendShapeTargetDeltasCommand.DeltasMasksCountMismatch = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_DeltasMasksCountMismatch
class SetLODsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetLODsCommand
def __init__(self, *args):
_py3dnacalib.SetLODsCommand_swiginit(self, _py3dnacalib.new_SetLODsCommand(*args))
def setLODs(self, lods):
return _py3dnacalib.SetLODsCommand_setLODs(self, lods)
def run(self, output):
return _py3dnacalib.SetLODsCommand_run(self, output)
# Register SetLODsCommand in _py3dnacalib:
_py3dnacalib.SetLODsCommand_swigregister(SetLODsCommand)
class SetNeutralJointRotationsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetNeutralJointRotationsCommand
def __init__(self, *args):
_py3dnacalib.SetNeutralJointRotationsCommand_swiginit(self, _py3dnacalib.new_SetNeutralJointRotationsCommand(*args))
def setRotations(self, *args):
return _py3dnacalib.SetNeutralJointRotationsCommand_setRotations(self, *args)
def run(self, output):
return _py3dnacalib.SetNeutralJointRotationsCommand_run(self, output)
# Register SetNeutralJointRotationsCommand in _py3dnacalib:
_py3dnacalib.SetNeutralJointRotationsCommand_swigregister(SetNeutralJointRotationsCommand)
class SetNeutralJointTranslationsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetNeutralJointTranslationsCommand
def __init__(self, *args):
_py3dnacalib.SetNeutralJointTranslationsCommand_swiginit(self, _py3dnacalib.new_SetNeutralJointTranslationsCommand(*args))
def setTranslations(self, *args):
return _py3dnacalib.SetNeutralJointTranslationsCommand_setTranslations(self, *args)
def run(self, output):
return _py3dnacalib.SetNeutralJointTranslationsCommand_run(self, output)
# Register SetNeutralJointTranslationsCommand in _py3dnacalib:
_py3dnacalib.SetNeutralJointTranslationsCommand_swigregister(SetNeutralJointTranslationsCommand)
class SetSkinWeightsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetSkinWeightsCommand
def __init__(self, *args):
_py3dnacalib.SetSkinWeightsCommand_swiginit(self, _py3dnacalib.new_SetSkinWeightsCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.SetSkinWeightsCommand_setMeshIndex(self, meshIndex)
def setVertexIndex(self, vertexIndex):
return _py3dnacalib.SetSkinWeightsCommand_setVertexIndex(self, vertexIndex)
def setWeights(self, weights):
return _py3dnacalib.SetSkinWeightsCommand_setWeights(self, weights)
def setJointIndices(self, jointIndices):
return _py3dnacalib.SetSkinWeightsCommand_setJointIndices(self, jointIndices)
def run(self, output):
return _py3dnacalib.SetSkinWeightsCommand_run(self, output)
# Register SetSkinWeightsCommand in _py3dnacalib:
_py3dnacalib.SetSkinWeightsCommand_swigregister(SetSkinWeightsCommand)
class SetVertexPositionsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetVertexPositionsCommand
def __init__(self, *args):
_py3dnacalib.SetVertexPositionsCommand_swiginit(self, _py3dnacalib.new_SetVertexPositionsCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.SetVertexPositionsCommand_setMeshIndex(self, meshIndex)
def setPositions(self, *args):
return _py3dnacalib.SetVertexPositionsCommand_setPositions(self, *args)
def setMasks(self, masks):
return _py3dnacalib.SetVertexPositionsCommand_setMasks(self, masks)
def setOperation(self, operation):
return _py3dnacalib.SetVertexPositionsCommand_setOperation(self, operation)
def run(self, output):
return _py3dnacalib.SetVertexPositionsCommand_run(self, output)
# Register SetVertexPositionsCommand in _py3dnacalib:
_py3dnacalib.SetVertexPositionsCommand_swigregister(SetVertexPositionsCommand)
SetVertexPositionsCommand.PositionsMasksCountMismatch = _py3dnacalib.cvar.SetVertexPositionsCommand_PositionsMasksCountMismatch
class TranslateCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_TranslateCommand
def __init__(self, *args):
_py3dnacalib.TranslateCommand_swiginit(self, _py3dnacalib.new_TranslateCommand(*args))
def setTranslation(self, translation):
return _py3dnacalib.TranslateCommand_setTranslation(self, translation)
def run(self, output):
return _py3dnacalib.TranslateCommand_run(self, output)
# Register TranslateCommand in _py3dnacalib:
_py3dnacalib.TranslateCommand_swigregister(TranslateCommand)

View File

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,633 @@
# This file was automatically generated by SWIG (http://www.swig.org).
# Version 4.0.1
#
# Do not make changes to this file unless you know what you are doing--modify
# the SWIG interface file instead.
from sys import version_info as _swig_python_version_info
if _swig_python_version_info < (2, 7, 0):
raise RuntimeError("Python 2.7 or later required")
# Import the low-level C/C++ module
if __package__ or "." in __name__:
from . import _py3dnacalib
else:
import _py3dnacalib
try:
import builtins as __builtin__
except ImportError:
import __builtin__
def _swig_repr(self):
try:
strthis = "proxy of " + self.this.__repr__()
except __builtin__.Exception:
strthis = ""
return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
def _swig_setattr_nondynamic_instance_variable(set):
def set_instance_attr(self, name, value):
if name == "thisown":
self.this.own(value)
elif name == "this":
set(self, name, value)
elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
set(self, name, value)
else:
raise AttributeError("You cannot add instance attributes to %s" % self)
return set_instance_attr
def _swig_setattr_nondynamic_class_variable(set):
def set_class_attr(cls, name, value):
if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
set(cls, name, value)
else:
raise AttributeError("You cannot add class attributes to %s" % cls)
return set_class_attr
def _swig_add_metaclass(metaclass):
"""Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
def wrapper(cls):
return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
return wrapper
class _SwigNonDynamicMeta(type):
"""Meta class to enforce nondynamic attributes (no new attributes) for a class"""
__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)
def __new_decorator(factory_func, original_new):
@staticmethod
def __new(cls, *args, **kwargs):
# FIXME: while this workaround solves the immediate issue with the set of classes we currently have,
# it will fail for classes that use a factory function but need no parameters at all, in which case
# the factory function will never be invoked, only the original __new__ function.
if args or kwargs:
return factory_func(*args, **kwargs)
return original_new(cls)
return __new
def __managed_init(self, *args, **kwargs):
self._args = args
self._kwargs = kwargs
import dna
class VersionInfo(object):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
@staticmethod
def getMajorVersion():
return _py3dnacalib.VersionInfo_getMajorVersion()
@staticmethod
def getMinorVersion():
return _py3dnacalib.VersionInfo_getMinorVersion()
@staticmethod
def getPatchVersion():
return _py3dnacalib.VersionInfo_getPatchVersion()
@staticmethod
def getVersionString():
return _py3dnacalib.VersionInfo_getVersionString()
def __init__(self):
_py3dnacalib.VersionInfo_swiginit(self, _py3dnacalib.new_VersionInfo())
__swig_destroy__ = _py3dnacalib.delete_VersionInfo
# Register VersionInfo in _py3dnacalib:
_py3dnacalib.VersionInfo_swigregister(VersionInfo)
def VersionInfo_getMajorVersion():
return _py3dnacalib.VersionInfo_getMajorVersion()
def VersionInfo_getMinorVersion():
return _py3dnacalib.VersionInfo_getMinorVersion()
def VersionInfo_getPatchVersion():
return _py3dnacalib.VersionInfo_getPatchVersion()
def VersionInfo_getVersionString():
return _py3dnacalib.VersionInfo_getVersionString()
class DNACalibDNAReader(dna.Reader):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
def __init__(self, *args, **kwargs):
raise AttributeError("No constructor defined - class is abstract")
__repr__ = _swig_repr
@staticmethod
def create(*args):
return _py3dnacalib.DNACalibDNAReader_create(*args)
@staticmethod
def destroy(instance):
return _py3dnacalib.DNACalibDNAReader_destroy(instance)
# Register DNACalibDNAReader in _py3dnacalib:
_py3dnacalib.DNACalibDNAReader_swigregister(DNACalibDNAReader)
def DNACalibDNAReader_create(*args):
return _py3dnacalib.DNACalibDNAReader_create(*args)
def DNACalibDNAReader_destroy(instance):
return _py3dnacalib.DNACalibDNAReader_destroy(instance)
DNACalibDNAReader.__new__ = __new_decorator(DNACalibDNAReader_create, DNACalibDNAReader.__new__)
DNACalibDNAReader.__del__ = lambda instance: DNACalibDNAReader_destroy(instance)
DNACalibDNAReader.__init__ = __managed_init
del DNACalibDNAReader.create
del DNACalibDNAReader.destroy
class Command(object):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
def __init__(self, *args, **kwargs):
raise AttributeError("No constructor defined - class is abstract")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_Command
def run(self, output):
return _py3dnacalib.Command_run(self, output)
# Register Command in _py3dnacalib:
_py3dnacalib.Command_swigregister(Command)
VectorOperation_Interpolate = _py3dnacalib.VectorOperation_Interpolate
VectorOperation_Add = _py3dnacalib.VectorOperation_Add
VectorOperation_Subtract = _py3dnacalib.VectorOperation_Subtract
VectorOperation_Multiply = _py3dnacalib.VectorOperation_Multiply
class CommandSequence(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_CommandSequence
def __init__(self, *args):
_py3dnacalib.CommandSequence_swiginit(self, _py3dnacalib.new_CommandSequence(*args))
def run(self, output):
return _py3dnacalib.CommandSequence_run(self, output)
def add(self, command):
return _py3dnacalib.CommandSequence_add(self, command)
def remove(self, command):
return _py3dnacalib.CommandSequence_remove(self, command)
def contains(self, command):
return _py3dnacalib.CommandSequence_contains(self, command)
def size(self):
return _py3dnacalib.CommandSequence_size(self)
# Register CommandSequence in _py3dnacalib:
_py3dnacalib.CommandSequence_swigregister(CommandSequence)
def command_sequence_init(_init):
def wrapper(self, *args, **kwargs):
self._commands = []
_init(self, *args, **kwargs)
return wrapper
def command_sequence_add(_add):
def wrapper(self, command):
self._commands.append(command)
_add(self, command)
return wrapper
def command_sequence_remove(_remove):
def wrapper(self, command):
self._commands.remove(command)
_remove(self, command)
return wrapper
CommandSequence.__init__ = command_sequence_init(CommandSequence.__init__)
CommandSequence.add = command_sequence_add(CommandSequence.add)
CommandSequence.remove = command_sequence_remove(CommandSequence.remove)
class CalculateMeshLowerLODsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_CalculateMeshLowerLODsCommand
def __init__(self, *args):
_py3dnacalib.CalculateMeshLowerLODsCommand_swiginit(self, _py3dnacalib.new_CalculateMeshLowerLODsCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.CalculateMeshLowerLODsCommand_setMeshIndex(self, meshIndex)
def run(self, output):
return _py3dnacalib.CalculateMeshLowerLODsCommand_run(self, output)
# Register CalculateMeshLowerLODsCommand in _py3dnacalib:
_py3dnacalib.CalculateMeshLowerLODsCommand_swigregister(CalculateMeshLowerLODsCommand)
class ClearBlendShapesCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_ClearBlendShapesCommand
def __init__(self, *args):
_py3dnacalib.ClearBlendShapesCommand_swiginit(self, _py3dnacalib.new_ClearBlendShapesCommand(*args))
def run(self, output):
return _py3dnacalib.ClearBlendShapesCommand_run(self, output)
# Register ClearBlendShapesCommand in _py3dnacalib:
_py3dnacalib.ClearBlendShapesCommand_swigregister(ClearBlendShapesCommand)
class PruneBlendShapeTargetsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_PruneBlendShapeTargetsCommand
def __init__(self, *args):
_py3dnacalib.PruneBlendShapeTargetsCommand_swiginit(self, _py3dnacalib.new_PruneBlendShapeTargetsCommand(*args))
def setThreshold(self, threshold):
return _py3dnacalib.PruneBlendShapeTargetsCommand_setThreshold(self, threshold)
def run(self, output):
return _py3dnacalib.PruneBlendShapeTargetsCommand_run(self, output)
# Register PruneBlendShapeTargetsCommand in _py3dnacalib:
_py3dnacalib.PruneBlendShapeTargetsCommand_swigregister(PruneBlendShapeTargetsCommand)
class RemoveAnimatedMapCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveAnimatedMapCommand
def __init__(self, *args):
_py3dnacalib.RemoveAnimatedMapCommand_swiginit(self, _py3dnacalib.new_RemoveAnimatedMapCommand(*args))
def setAnimatedMapIndex(self, animatedMapIndex):
return _py3dnacalib.RemoveAnimatedMapCommand_setAnimatedMapIndex(self, animatedMapIndex)
def setAnimatedMapIndices(self, animatedMapIndices):
return _py3dnacalib.RemoveAnimatedMapCommand_setAnimatedMapIndices(self, animatedMapIndices)
def run(self, output):
return _py3dnacalib.RemoveAnimatedMapCommand_run(self, output)
# Register RemoveAnimatedMapCommand in _py3dnacalib:
_py3dnacalib.RemoveAnimatedMapCommand_swigregister(RemoveAnimatedMapCommand)
class RemoveBlendShapeCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveBlendShapeCommand
def __init__(self, *args):
_py3dnacalib.RemoveBlendShapeCommand_swiginit(self, _py3dnacalib.new_RemoveBlendShapeCommand(*args))
def setBlendShapeIndex(self, blendShapeIndex):
return _py3dnacalib.RemoveBlendShapeCommand_setBlendShapeIndex(self, blendShapeIndex)
def setBlendShapeIndices(self, blendShapeIndices):
return _py3dnacalib.RemoveBlendShapeCommand_setBlendShapeIndices(self, blendShapeIndices)
def run(self, output):
return _py3dnacalib.RemoveBlendShapeCommand_run(self, output)
# Register RemoveBlendShapeCommand in _py3dnacalib:
_py3dnacalib.RemoveBlendShapeCommand_swigregister(RemoveBlendShapeCommand)
class RemoveJointAnimationCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveJointAnimationCommand
def __init__(self, *args):
_py3dnacalib.RemoveJointAnimationCommand_swiginit(self, _py3dnacalib.new_RemoveJointAnimationCommand(*args))
def setJointIndex(self, jointIndex):
return _py3dnacalib.RemoveJointAnimationCommand_setJointIndex(self, jointIndex)
def setJointIndices(self, jointIndices):
return _py3dnacalib.RemoveJointAnimationCommand_setJointIndices(self, jointIndices)
def run(self, output):
return _py3dnacalib.RemoveJointAnimationCommand_run(self, output)
# Register RemoveJointAnimationCommand in _py3dnacalib:
_py3dnacalib.RemoveJointAnimationCommand_swigregister(RemoveJointAnimationCommand)
class RemoveJointCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveJointCommand
def __init__(self, *args):
_py3dnacalib.RemoveJointCommand_swiginit(self, _py3dnacalib.new_RemoveJointCommand(*args))
def setJointIndex(self, jointIndex):
return _py3dnacalib.RemoveJointCommand_setJointIndex(self, jointIndex)
def setJointIndices(self, jointIndices):
return _py3dnacalib.RemoveJointCommand_setJointIndices(self, jointIndices)
def run(self, output):
return _py3dnacalib.RemoveJointCommand_run(self, output)
# Register RemoveJointCommand in _py3dnacalib:
_py3dnacalib.RemoveJointCommand_swigregister(RemoveJointCommand)
class RemoveMeshCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RemoveMeshCommand
def __init__(self, *args):
_py3dnacalib.RemoveMeshCommand_swiginit(self, _py3dnacalib.new_RemoveMeshCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.RemoveMeshCommand_setMeshIndex(self, meshIndex)
def setMeshIndices(self, meshIndices):
return _py3dnacalib.RemoveMeshCommand_setMeshIndices(self, meshIndices)
def run(self, output):
return _py3dnacalib.RemoveMeshCommand_run(self, output)
# Register RemoveMeshCommand in _py3dnacalib:
_py3dnacalib.RemoveMeshCommand_swigregister(RemoveMeshCommand)
class RenameAnimatedMapCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameAnimatedMapCommand
def __init__(self, *args):
_py3dnacalib.RenameAnimatedMapCommand_swiginit(self, _py3dnacalib.new_RenameAnimatedMapCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameAnimatedMapCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameAnimatedMapCommand_run(self, output)
# Register RenameAnimatedMapCommand in _py3dnacalib:
_py3dnacalib.RenameAnimatedMapCommand_swigregister(RenameAnimatedMapCommand)
class RenameBlendShapeCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameBlendShapeCommand
def __init__(self, *args):
_py3dnacalib.RenameBlendShapeCommand_swiginit(self, _py3dnacalib.new_RenameBlendShapeCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameBlendShapeCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameBlendShapeCommand_run(self, output)
# Register RenameBlendShapeCommand in _py3dnacalib:
_py3dnacalib.RenameBlendShapeCommand_swigregister(RenameBlendShapeCommand)
class RenameJointCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameJointCommand
def __init__(self, *args):
_py3dnacalib.RenameJointCommand_swiginit(self, _py3dnacalib.new_RenameJointCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameJointCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameJointCommand_run(self, output)
# Register RenameJointCommand in _py3dnacalib:
_py3dnacalib.RenameJointCommand_swigregister(RenameJointCommand)
class RenameMeshCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RenameMeshCommand
def __init__(self, *args):
_py3dnacalib.RenameMeshCommand_swiginit(self, _py3dnacalib.new_RenameMeshCommand(*args))
def setName(self, *args):
return _py3dnacalib.RenameMeshCommand_setName(self, *args)
def run(self, output):
return _py3dnacalib.RenameMeshCommand_run(self, output)
# Register RenameMeshCommand in _py3dnacalib:
_py3dnacalib.RenameMeshCommand_swigregister(RenameMeshCommand)
class RotateCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_RotateCommand
def __init__(self, *args):
_py3dnacalib.RotateCommand_swiginit(self, _py3dnacalib.new_RotateCommand(*args))
def setRotation(self, degrees):
return _py3dnacalib.RotateCommand_setRotation(self, degrees)
def setOrigin(self, origin):
return _py3dnacalib.RotateCommand_setOrigin(self, origin)
def run(self, output):
return _py3dnacalib.RotateCommand_run(self, output)
# Register RotateCommand in _py3dnacalib:
_py3dnacalib.RotateCommand_swigregister(RotateCommand)
class ScaleCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_ScaleCommand
def __init__(self, *args):
_py3dnacalib.ScaleCommand_swiginit(self, _py3dnacalib.new_ScaleCommand(*args))
def setScale(self, scale):
return _py3dnacalib.ScaleCommand_setScale(self, scale)
def setOrigin(self, origin):
return _py3dnacalib.ScaleCommand_setOrigin(self, origin)
def run(self, output):
return _py3dnacalib.ScaleCommand_run(self, output)
# Register ScaleCommand in _py3dnacalib:
_py3dnacalib.ScaleCommand_swigregister(ScaleCommand)
class SetBlendShapeTargetDeltasCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetBlendShapeTargetDeltasCommand
def __init__(self, *args):
_py3dnacalib.SetBlendShapeTargetDeltasCommand_swiginit(self, _py3dnacalib.new_SetBlendShapeTargetDeltasCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setMeshIndex(self, meshIndex)
def setBlendShapeTargetIndex(self, blendShapeTargetIndex):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setBlendShapeTargetIndex(self, blendShapeTargetIndex)
def setDeltas(self, *args):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setDeltas(self, *args)
def setVertexIndices(self, vertexIndices):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setVertexIndices(self, vertexIndices)
def setMasks(self, masks):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setMasks(self, masks)
def setOperation(self, operation):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_setOperation(self, operation)
def run(self, output):
return _py3dnacalib.SetBlendShapeTargetDeltasCommand_run(self, output)
# Register SetBlendShapeTargetDeltasCommand in _py3dnacalib:
_py3dnacalib.SetBlendShapeTargetDeltasCommand_swigregister(SetBlendShapeTargetDeltasCommand)
cvar = _py3dnacalib.cvar
SetBlendShapeTargetDeltasCommand.VertexIndicesOutOfBoundsError = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_VertexIndicesOutOfBoundsError
SetBlendShapeTargetDeltasCommand.NoVertexIndicesSetError = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_NoVertexIndicesSetError
SetBlendShapeTargetDeltasCommand.DeltasVertexIndicesCountMismatch = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_DeltasVertexIndicesCountMismatch
SetBlendShapeTargetDeltasCommand.DeltasMasksCountMismatch = _py3dnacalib.cvar.SetBlendShapeTargetDeltasCommand_DeltasMasksCountMismatch
class SetLODsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetLODsCommand
def __init__(self, *args):
_py3dnacalib.SetLODsCommand_swiginit(self, _py3dnacalib.new_SetLODsCommand(*args))
def setLODs(self, lods):
return _py3dnacalib.SetLODsCommand_setLODs(self, lods)
def run(self, output):
return _py3dnacalib.SetLODsCommand_run(self, output)
# Register SetLODsCommand in _py3dnacalib:
_py3dnacalib.SetLODsCommand_swigregister(SetLODsCommand)
class SetNeutralJointRotationsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetNeutralJointRotationsCommand
def __init__(self, *args):
_py3dnacalib.SetNeutralJointRotationsCommand_swiginit(self, _py3dnacalib.new_SetNeutralJointRotationsCommand(*args))
def setRotations(self, *args):
return _py3dnacalib.SetNeutralJointRotationsCommand_setRotations(self, *args)
def run(self, output):
return _py3dnacalib.SetNeutralJointRotationsCommand_run(self, output)
# Register SetNeutralJointRotationsCommand in _py3dnacalib:
_py3dnacalib.SetNeutralJointRotationsCommand_swigregister(SetNeutralJointRotationsCommand)
class SetNeutralJointTranslationsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetNeutralJointTranslationsCommand
def __init__(self, *args):
_py3dnacalib.SetNeutralJointTranslationsCommand_swiginit(self, _py3dnacalib.new_SetNeutralJointTranslationsCommand(*args))
def setTranslations(self, *args):
return _py3dnacalib.SetNeutralJointTranslationsCommand_setTranslations(self, *args)
def run(self, output):
return _py3dnacalib.SetNeutralJointTranslationsCommand_run(self, output)
# Register SetNeutralJointTranslationsCommand in _py3dnacalib:
_py3dnacalib.SetNeutralJointTranslationsCommand_swigregister(SetNeutralJointTranslationsCommand)
class SetSkinWeightsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetSkinWeightsCommand
def __init__(self, *args):
_py3dnacalib.SetSkinWeightsCommand_swiginit(self, _py3dnacalib.new_SetSkinWeightsCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.SetSkinWeightsCommand_setMeshIndex(self, meshIndex)
def setVertexIndex(self, vertexIndex):
return _py3dnacalib.SetSkinWeightsCommand_setVertexIndex(self, vertexIndex)
def setWeights(self, weights):
return _py3dnacalib.SetSkinWeightsCommand_setWeights(self, weights)
def setJointIndices(self, jointIndices):
return _py3dnacalib.SetSkinWeightsCommand_setJointIndices(self, jointIndices)
def run(self, output):
return _py3dnacalib.SetSkinWeightsCommand_run(self, output)
# Register SetSkinWeightsCommand in _py3dnacalib:
_py3dnacalib.SetSkinWeightsCommand_swigregister(SetSkinWeightsCommand)
class SetVertexPositionsCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_SetVertexPositionsCommand
def __init__(self, *args):
_py3dnacalib.SetVertexPositionsCommand_swiginit(self, _py3dnacalib.new_SetVertexPositionsCommand(*args))
def setMeshIndex(self, meshIndex):
return _py3dnacalib.SetVertexPositionsCommand_setMeshIndex(self, meshIndex)
def setPositions(self, *args):
return _py3dnacalib.SetVertexPositionsCommand_setPositions(self, *args)
def setMasks(self, masks):
return _py3dnacalib.SetVertexPositionsCommand_setMasks(self, masks)
def setOperation(self, operation):
return _py3dnacalib.SetVertexPositionsCommand_setOperation(self, operation)
def run(self, output):
return _py3dnacalib.SetVertexPositionsCommand_run(self, output)
# Register SetVertexPositionsCommand in _py3dnacalib:
_py3dnacalib.SetVertexPositionsCommand_swigregister(SetVertexPositionsCommand)
SetVertexPositionsCommand.PositionsMasksCountMismatch = _py3dnacalib.cvar.SetVertexPositionsCommand_PositionsMasksCountMismatch
class TranslateCommand(Command):
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
__swig_destroy__ = _py3dnacalib.delete_TranslateCommand
def __init__(self, *args):
_py3dnacalib.TranslateCommand_swiginit(self, _py3dnacalib.new_TranslateCommand(*args))
def setTranslation(self, translation):
return _py3dnacalib.TranslateCommand_setTranslation(self, translation)
def run(self, output):
return _py3dnacalib.TranslateCommand_run(self, output)
# Register TranslateCommand in _py3dnacalib:
_py3dnacalib.TranslateCommand_swigregister(TranslateCommand)

Binary file not shown.

View File

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

284
scripts/Main.py Normal file
View File

@@ -0,0 +1,284 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Main module for Metahuman customize plugin
主模块 - 负责初始化UI和功能集成
功能: 从ui模块加载子模块显示
作者: Virtuos Games
版本: Alpha v1.0.0
"""
#===================================== IMPORT MODULES =====================================
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import maya.cmds as cmds
import maya.mel as mel
import maya.utils as utils
import webbrowser
import subprocess
import importlib
import traceback
import locale
import sys
import os
#===================================== IMPORT UI MODULES ===================================
from scripts.ui import toolbar
from scripts.ui import geometry
from scripts.ui import rigging
from scripts.ui import behaviour
from scripts.ui import definition
#========================================== CONFIG ========================================
import config
TOOL_NAME = config.TOOL_NAME
TOOL_VERSION = config.TOOL_VERSION
TOOL_AUTHOR = config.TOOL_AUTHOR
TOOL_YEAR = config.TOOL_VERSION
TOOL_MOD_FILENAME = config.TOOL_MOD_FILENAME
TOOL_LANG = config.TOOL_LANG
TOOL_WSCL_NAME = config.TOOL_WSCL_NAME
TOOL_HELP_URL = config.TOOL_HELP_URL
TOOL_PATH = config.TOOL_PATH
SCRIPTS_PATH = config.SCRIPTS_PATH
TOOL_MAIN_SCRIPT = config.TOOL_MAIN_SCRIPT
UI_PATH = config.UI_PATH
STYLE_FILE = config.STYLE_FILE
ICONS_PATH = config.ICONS_PATH
TOOL_ICON = config.TOOL_ICON
ASSETS_PATH = config.ASSETS_PATH
DNA_FILE_PATH = config.DNA_FILE_PATH
DNA_IMG_PATH = config.DNA_IMG_PATH
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
#====================================== LOCALIZATION ==================================
from scripts.ui import localization
LANG = localization.LANG
#========================================= INIT =======================================
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)
#===================================== MAIN FUNCTION ===================================
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent=maya_main_window()):
super(MainWindow, self).__init__(parent)
self.setWindowTitle(TOOL_NAME)
self.setObjectName(f"{TOOL_NAME}MainWindow")
self.setWindowFlags(QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
# 设置自适应大小策略
self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self.setMinimumSize(300, 600) # 减小最小高度,让窗口更灵活
self.create_widgets()
self.create_layouts()
self.create_connections()
if os.path.exists(TOOL_ICON):
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
else:
print("WARNING: Icon file not found: {}".format(TOOL_ICON))
def dock_to_maya(self):
if cmds.workspaceControl(TOOL_WSCL_NAME, exists=True):
cmds.deleteUI(TOOL_WSCL_NAME)
def create_control():
try:
workspace_control = cmds.workspaceControl(
TOOL_WSCL_NAME,
label=TOOL_NAME,
floating=True,
retain=True,
resizeWidth=True,
initialWidth=300,
minimumWidth=300
)
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("Error creating workspace control: {}".format(e))
cmds.evalDeferred(create_control)
#===================================== UI COMPONENTS =====================================
def create_widgets(self):
# 创建滚动区域
self.scroll_area = QtWidgets.QScrollArea()
self.scroll_area.setObjectName("main_scroll_area")
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) # 改回按需显示
self.scroll_area.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 创建滚动区域内容控件
self.scroll_content = QtWidgets.QWidget()
self.scroll_content.setObjectName("scroll_content")
self.scroll_content.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 创建主标签页
self.main_tab = QtWidgets.QTabWidget()
self.main_tab.setObjectName("main_tab")
self.main_tab.setTabPosition(QtWidgets.QTabWidget.North)
self.main_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.main_tab.setDocumentMode(True)
self.main_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self.main_tab.setMinimumHeight(400)
# 创建各功能模块标签页
self.geometry_tab = QtWidgets.QWidget()
self.geometry_tab.setObjectName("geometry_tab")
self.geometry_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self.rigging_tab = QtWidgets.QWidget()
self.rigging_tab.setObjectName("rigging_tab")
self.rigging_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self.behaviour_tab = QtWidgets.QWidget()
self.behaviour_tab.setObjectName("behaviour_tab")
self.behaviour_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self.definition_tab = QtWidgets.QWidget()
self.definition_tab.setObjectName("definition_tab")
self.definition_tab.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 创建工具栏
self.toolbar_frame = QtWidgets.QFrame()
self.toolbar_frame.setObjectName("toolbar_frame")
self.toolbar_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.toolbar_frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.toolbar_frame.setMaximumHeight(40)
self.toolbar_frame.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# 创建状态栏
self.status_bar = QtWidgets.QStatusBar()
self.status_bar.setObjectName("status_bar")
self.status_bar.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.status_bar.showMessage(f"{TOOL_NAME} {TOOL_VERSION}")
# 初始化各模块UI组件
toolbar.widgets()
geometry.widgets()
rigging.widgets()
behaviour.widgets()
definition.widgets()
def create_layouts(self):
# 主布局
self.main_layout = QtWidgets.QVBoxLayout(self)
self.main_layout.setContentsMargins(2, 2, 2, 2)
self.main_layout.setSpacing(2)
# 滚动区域内容布局
self.scroll_content_layout = QtWidgets.QVBoxLayout(self.scroll_content)
self.scroll_content_layout.setContentsMargins(2, 2, 2, 2)
self.scroll_content_layout.setSpacing(2)
# 添加工具栏
self.toolbar_layout = QtWidgets.QVBoxLayout(self.toolbar_frame)
self.toolbar_layout.setContentsMargins(0, 0, 0, 0)
toolbar.layouts(parent_frame=self.toolbar_frame)
# 设置各标签页布局
self.geometry_layout = QtWidgets.QVBoxLayout(self.geometry_tab)
self.geometry_layout.setContentsMargins(4, 4, 4, 4)
geometry.layouts(parent_tab=self.geometry_tab)
self.rigging_layout = QtWidgets.QVBoxLayout(self.rigging_tab)
self.rigging_layout.setContentsMargins(4, 4, 4, 4)
rigging.layouts(parent_tab=self.rigging_tab)
self.behaviour_layout = QtWidgets.QVBoxLayout(self.behaviour_tab)
self.behaviour_layout.setContentsMargins(4, 4, 4, 4)
behaviour.layouts(parent_tab=self.behaviour_tab)
self.definition_layout = QtWidgets.QVBoxLayout(self.definition_tab)
self.definition_layout.setContentsMargins(4, 4, 4, 4)
definition.layouts(parent_tab=self.definition_tab)
# 添加标签页到主标签控件
self.main_tab.addTab(self.geometry_tab, "几何模型")
self.main_tab.addTab(self.rigging_tab, "绑定系统")
self.main_tab.addTab(self.behaviour_tab, "行为系统")
self.main_tab.addTab(self.definition_tab, "定义系统")
# 将组件添加到滚动区域内容布局
self.scroll_content_layout.addWidget(self.toolbar_frame)
self.scroll_content_layout.addWidget(self.main_tab)
# 设置滚动区域的内容控件
self.scroll_area.setWidget(self.scroll_content)
# 将滚动区域和状态栏添加到主布局
self.main_layout.addWidget(self.scroll_area)
self.main_layout.addWidget(self.status_bar)
# 加载样式表
if os.path.exists(STYLE_FILE):
try:
with open(STYLE_FILE, "r", encoding="utf-8") as f:
style = f.read()
self.setStyleSheet(style)
except UnicodeDecodeError:
# 尝试使用系统默认编码
encoding = get_system_encoding()
try:
with open(STYLE_FILE, "r", encoding=encoding) as f:
style = f.read()
self.setStyleSheet(style)
except Exception as e:
print(f"警告: 无法加载样式表文件: {e}")
else:
print(f"警告: 样式表文件不存在: {STYLE_FILE}")
def create_connections(self):
# 连接各模块的信号和槽
toolbar.connections()
geometry.connections()
rigging.connections()
behaviour.connections()
definition.connections()
# 标签页切换信号
self.main_tab.currentChanged.connect(self.on_tab_changed)
def on_tab_changed(self, index):
tab_name = self.main_tab.tabText(index)
self.status_bar.showMessage(f"当前模块: {tab_name}")
print(f"切换到模块: {tab_name}")
def main():
"""
Main function to initialize and show the Plugin UI
"""
try:
# Initialize UI modules with placeholder functions
# Each module only contains UI framework without actual functionality
toolbar.toolbar_temp_function()
geometry.geometry_temp_function()
rigging.rigging_temp_function()
behaviour.behaviour_temp_function()
definition.definition_temp_function()
# Create and show main window
global tool_window
tool_window = MainWindow()
tool_window.dock_to_maya()
print(f"{TOOL_NAME} plugin initialized successfully!")
return tool_window
except Exception as e:
error_msg = f"Error initializing {TOOL_NAME} plugin: {str(e)}"
print(error_msg)
traceback.print_exc()
cmds.warning(error_msg)
return None
# Auto-run when imported
if __name__ == "__main__":
main()

741
scripts/ReloadModules.py Normal file
View File

@@ -0,0 +1,741 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Tool - Module Reload Tool
Provides module reloading functionality for the plugin, supporting hot updates
用法说明:
1. 在Maya中直接运行:
import scripts.ReloadModules
scripts.ReloadModules.main()
2. 从命令行重新加载所有模块:
import scripts.ReloadModules
scripts.ReloadModules.reload_all()
3. 重新加载特定模块:
import scripts.ReloadModules
scripts.ReloadModules.ModuleReloader.reload_module('module_name')
4. 在开发过程中使用:
- 当修改了代码后,运行此模块可以热更新所有更改
- 无需重启Maya即可测试新功能
- 支持UI和命令行两种方式
注意事项:
- 某些深度依赖的模块可能需要手动重启Maya
- 如果遇到导入错误,请检查模块路径是否正确
- 重新加载可能不会影响已经创建的对象实例
"""
import sys
import importlib
import os
import traceback
import shutil
from maya import cmds
# 设置工具路径
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
# 设置脚本路径
SCRIPTS_PATH = os.path.dirname(os.path.abspath(__file__))
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)
# 导入主配置 - 多级尝试导入策略
def import_main_config():
"""尝试多种方式导入主配置文件"""
global TOOL_NAME, TOOL_VERSION, TOOL_AUTHOR, TOOL_PATH, SCRIPTS_PATH
global UI_PATH, STYLE_FILE, ICONS_PATH, ASSETS_PATH, DNA_FILE_PATH, Config
# 尝试直接导入
try:
import config
importlib.reload(config) # 确保获取最新配置
# 从主配置文件导入路径和设置
TOOL_NAME = config.TOOL_NAME
TOOL_VERSION = config.TOOL_VERSION
TOOL_AUTHOR = config.TOOL_AUTHOR
TOOL_PATH = config.TOOL_PATH
SCRIPTS_PATH = config.SCRIPTS_PATH
UI_PATH = config.UI_PATH
STYLE_FILE = config.STYLE_FILE
ICONS_PATH = config.ICONS_PATH
ASSETS_PATH = config.ASSETS_PATH
DNA_FILE_PATH = config.DNA_FILE_PATH
print(f"成功从主配置文件导入配置")
return True
except ImportError as e:
print(f"直接导入主配置文件失败: {str(e)}")
# 尝试从上级目录导入
parent_dir = os.path.dirname(TOOL_PATH)
if parent_dir not in sys.path:
sys.path.insert(0, parent_dir)
try:
import config
importlib.reload(config) # 确保获取最新配置
# 从主配置文件导入路径和设置
TOOL_NAME = config.TOOL_NAME
TOOL_VERSION = config.TOOL_VERSION
TOOL_AUTHOR = config.TOOL_AUTHOR
TOOL_PATH = config.TOOL_PATH
SCRIPTS_PATH = config.SCRIPTS_PATH
UI_PATH = config.UI_PATH
STYLE_FILE = config.STYLE_FILE
ICONS_PATH = config.ICONS_PATH
ASSETS_PATH = config.ASSETS_PATH
DNA_FILE_PATH = config.DNA_FILE_PATH
print(f"成功从上级目录导入主配置文件")
return True
except ImportError as e:
print(f"从上级目录导入主配置文件失败: {str(e)}")
if parent_dir in sys.path:
sys.path.remove(parent_dir)
return False
# 尝试导入主配置
if not import_main_config():
print("警告: 无法导入主配置文件,使用默认配置")
# 使用默认路径
TOOL_NAME = "Delos"
TOOL_VERSION = "Alpha v1.0.0"
TOOL_AUTHOR = "Virtuos Games"
TOOL_PATH = TOOL_PATH
UI_PATH = os.path.join(SCRIPTS_PATH, 'ui')
STYLE_FILE = os.path.join(SCRIPTS_PATH, 'ui', 'style.qss')
ICONS_PATH = os.path.join(TOOL_PATH, 'icons')
ASSETS_PATH = os.path.join(TOOL_PATH, 'assets')
DNA_FILE_PATH = os.path.join(TOOL_PATH, 'assets', 'dna')
# 尝试导入Config模块
try:
from scripts.utils import Config
except ImportError:
try:
from utils import Config
except ImportError:
try:
import Config
except ImportError:
print("警告: 无法导入Config模块")
Config = None
# 创建默认Config对象
class DefaultConfig:
# 使用TOOL_PATH而不是ROOT_DIR
DNA_CONFIG = {
'DNA_PATH': os.path.join(TOOL_PATH, 'assets', 'dna'),
'DNA_FILE_PATH': os.path.join(TOOL_PATH, 'assets', 'dna', 'default.dna'),
'DNA_VERSION': 'DNAv4',
'LOD_LEVELS': [0, 1, 2, 3, 4],
'DEFAULT_MESH_INDICES': [0],
'GUI_PATH': os.path.join(TOOL_PATH, 'ui'),
'ASSEMBLE_SCRIPT': os.path.join(TOOL_PATH, 'scripts', 'assemble.py')
}
DNA_LIB_PATHS = [
os.path.join(TOOL_PATH, 'lib'),
os.path.join(TOOL_PATH, 'lib', 'windows' if sys.platform == 'win32' else 'linux')
]
Config = DefaultConfig()
# 尝试导入 Qt 模块
# 首先尝试使用项目中的 Qt.py 兼容层
try:
# 添加父目录到路径中以确保可以导入 Qt.py
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if parent_dir not in sys.path:
sys.path.append(parent_dir)
# 尝试导入 Qt.py
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
# 获取 Maya 主窗口
def getMayaMainWindow():
from maya import OpenMayaUI as omui
mainWindowPtr = omui.MQtUtil.mainWindow()
return wrapInstance(int(mainWindowPtr), QtWidgets.QWidget)
HAS_QT = True
print("Successfully imported Qt modules using Qt.py compatibility layer")
except ImportError:
# 如果无法导入 Qt.py尝试直接导入 PySide2/PySide6
try:
from PySide2 import QtWidgets, QtCore, QtGui
from shiboken2 import wrapInstance
from maya import OpenMayaUI as omui
def getMayaMainWindow():
mainWindowPtr = omui.MQtUtil.mainWindow()
return wrapInstance(int(mainWindowPtr), QtWidgets.QWidget)
HAS_QT = True
print("Successfully imported Qt modules using PySide2")
except ImportError:
try:
from PySide6 import QtWidgets, QtCore, QtGui
from shiboken6 import wrapInstance
from maya import OpenMayaUI as omui
def getMayaMainWindow():
mainWindowPtr = omui.MQtUtil.mainWindow()
return wrapInstance(int(mainWindowPtr), QtWidgets.QWidget)
HAS_QT = True
print("Successfully imported Qt modules using PySide6")
except ImportError:
# 如果所有导入尝试都失败,设置标志并显示警告
HAS_QT = False
cmds.warning("Failed to import Qt modules. UI functionality will be limited to command line only.")
def clean_pycache(root_dir):
"""Delete all __pycache__ directories and .pyc files under the given root directory
Args:
root_dir (str): Root directory to search for __pycache__ folders and .pyc files
Returns:
int: Number of __pycache__ directories and .pyc files removed
"""
count = 0
try:
# 首先确保目录存在
if not os.path.exists(root_dir) or not os.path.isdir(root_dir):
print(f"Warning: Directory does not exist or is not a directory: {root_dir}")
return count
print(f"Cleaning __pycache__ in directory: {root_dir}")
# 收集所有需要删除的路径,避免在遍历时修改目录结构
pycache_dirs = []
pyc_files = []
# 首先收集所有 __pycache__ 目录和 .pyc 文件
for root, dirs, files in os.walk(root_dir):
# 收集 __pycache__ 目录
if "__pycache__" in dirs:
pycache_path = os.path.join(root, "__pycache__")
pycache_dirs.append(pycache_path)
# 收集 .pyc 文件
for file in files:
if file.endswith(".pyc"):
file_path = os.path.join(root, file)
pyc_files.append(file_path)
# 优先使用批处理命令删除 __pycache__ 目录(更可靠)
if os.name == 'nt': # Windows
# 创建临时批处理文件
temp_bat = os.path.join(os.environ.get('TEMP', '.'), 'clean_pycache_temp.bat')
with open(temp_bat, 'w') as f:
f.write('@echo off\n')
# 添加删除 __pycache__ 目录的命令
for pycache_path in pycache_dirs:
f.write(f'if exist "{pycache_path}" rd /s /q "{pycache_path}"\n')
# 添加删除 .pyc 文件的命令
for file_path in pyc_files:
f.write(f'if exist "{file_path}" del /f /q "{file_path}"\n')
# 执行批处理文件
os.system(f'"{temp_bat}"')
# 删除临时批处理文件
try:
os.remove(temp_bat)
except:
pass
# 验证是否删除成功
remaining_pycache = 0
for pycache_path in pycache_dirs:
if not os.path.exists(pycache_path):
count += 1
else:
remaining_pycache += 1
remaining_pyc = 0
for file_path in pyc_files:
if not os.path.exists(file_path):
count += 1
else:
remaining_pyc += 1
if remaining_pycache > 0 or remaining_pyc > 0:
print(f"Warning: {remaining_pycache} __pycache__ directories and {remaining_pyc} .pyc files could not be removed")
else: # Unix/Linux
# 使用系统命令删除 __pycache__ 目录
for pycache_path in pycache_dirs:
if os.system(f'rm -rf "{pycache_path}"') == 0:
print(f"Removed __pycache__ directory: {pycache_path}")
count += 1
else:
print(f"Failed to remove {pycache_path}")
# 使用系统命令删除 .pyc 文件
for file_path in pyc_files:
if os.system(f'rm -f "{file_path}"') == 0:
print(f"Removed .pyc file: {file_path}")
count += 1
else:
print(f"Failed to remove {file_path}")
except Exception as error:
print(f"Error cleaning __pycache__ directories: {str(error)}")
print(f"Removed {count} files/directories: {len(pycache_dirs)} __pycache__ directories and {len(pyc_files)} .pyc files")
traceback.print_exc()
return count
class ModuleReloader(object):
"""Class for reloading modules in the Plugin"""
@staticmethod
def get_package_modules(package_name):
"""
Get all modules in a package
Args:
package_name (str): Name of the package
Returns:
list: List of module names
"""
package_modules = []
try:
# 尝试导入包
package = importlib.import_module(package_name)
package_path = os.path.dirname(package.__file__)
# 遍历包目录查找模块
for root, dirs, files in os.walk(package_path):
for file in files:
if file.endswith('.py') and file != '__init__.py':
# 计算相对路径
rel_path = os.path.relpath(os.path.join(root, file), package_path)
# 转换为模块路径格式
module_path = os.path.splitext(rel_path)[0].replace(os.sep, '.')
# 构建完整模块名
module_name = f"{package_name}.{module_path}"
package_modules.append(module_name)
# 添加子包
for dir_name in dirs:
init_file = os.path.join(root, dir_name, '__init__.py')
if os.path.exists(init_file):
rel_path = os.path.relpath(os.path.join(root, dir_name), package_path)
module_name = f"{package_name}.{rel_path.replace(os.sep, '.')}"
package_modules.append(module_name)
return package_modules
except Exception as e:
print(f"错误: 无法导入包 {package_name}: {str(e)}")
traceback.print_exc()
return []
@staticmethod
def reload_module(module_name):
"""Reload a specific module
Args:
module_name (str): Name of the module to reload
Returns:
bool: True if successful, False otherwise
"""
try:
# 尝试导入模块
try:
module = __import__(module_name, fromlist=["*"])
except ImportError:
# 如果失败,尝试将点替换为斜杠
module_path = module_name.replace('.', '/')
if os.path.exists(os.path.join(TOOL_PATH, module_path + '.py')):
sys_path_modified = False
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
sys_path_modified = True
module = __import__(module_name, fromlist=["*"])
if sys_path_modified:
sys.path.remove(TOOL_PATH)
else:
raise ImportError(f"Module {module_name} not found")
# 重新加载模块
importlib.reload(module)
print(f"成功重新加载模块: {module_name}")
return True
except Exception as e:
print(f"重新加载模块 {module_name} 时出错: {str(e)}")
traceback.print_exc()
return False
@classmethod
def reload_all_modules(cls):
"""
Reload all Plugin modules
Returns:
dict: Results of reloading each module
"""
# 首先声明全局变量
global TOOL_NAME, TOOL_VERSION, TOOL_AUTHOR, TOOL_PATH, SCRIPTS_PATH
global UI_PATH, STYLE_FILE, ICONS_PATH, ASSETS_PATH, DNA_FILE_PATH
results = {}
# 清理缓存文件
clean_pycache(TOOL_PATH)
# 首先尝试重新加载主配置文件
try:
# 尝试直接导入主配置
if 'config' in sys.modules:
config_module = sys.modules['config']
importlib.reload(config_module)
print("成功重新加载主配置文件")
results['config'] = True
TOOL_NAME = config_module.TOOL_NAME
TOOL_VERSION = config_module.TOOL_VERSION
TOOL_AUTHOR = config_module.TOOL_AUTHOR
TOOL_PATH = config_module.TOOL_PATH
SCRIPTS_PATH = config_module.SCRIPTS_PATH
UI_PATH = config_module.UI_PATH
STYLE_FILE = config_module.STYLE_FILE
ICONS_PATH = config_module.ICONS_PATH
ASSETS_PATH = config_module.ASSETS_PATH
DNA_FILE_PATH = config_module.DNA_FILE_PATH
else:
# 尝试重新导入
import_main_config()
results['config'] = True
except Exception as e:
print(f"重新加载主配置文件时出错: {str(e)}")
results['config'] = False
# 定义要重新加载的模块
modules_to_reload = [
"scripts.utils.Config", # 首先重新加载配置
"scripts.utils",
"scripts.ui",
"scripts.Main"
]
# 获取所有子模块
all_modules = []
for module in modules_to_reload:
all_modules.append(module)
try:
submodules = cls.get_package_modules(module)
if submodules:
all_modules.extend(submodules)
except Exception as e:
print(f"获取模块 {module} 的子模块时出错: {str(e)}")
# 去除重复项并排序
all_modules = sorted(list(set(all_modules)))
# 按照依赖关系对模块进行排序
# 确保配置模块先重新加载
priority_modules = []
normal_modules = []
for module in all_modules:
if "Config" in module or module.endswith(".config"):
priority_modules.append(module)
else:
normal_modules.append(module)
# 先重新加载优先级模块,然后是普通模块
for module in priority_modules + normal_modules:
results[module] = cls.reload_module(module)
return results
def reload_all():
"""Reload all Plugin modules and display results"""
print("\n" + "-"*50)
print("Reloading Plugin modules...")
print("-"*50)
# 获取插件根目录 - 使用config中定义的TOOL_PATH
try:
import config
TOOL_PATH = config.TOOL_PATH
except ImportError:
# 如果无法导入config则使用相对路径
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(f"Plugin root directory: {TOOL_PATH}")
# 清理 __pycache__ 目录
print("Cleaning __pycache__ directories...")
pycache_count = clean_pycache(TOOL_PATH)
print(f"Removed {pycache_count} __pycache__ directories and .pyc files")
# Reload modules
results = ModuleReloader.reload_all_modules()
success_count = sum(1 for success in results.values() if success)
total_count = len(results)
print("\nReload Summary:")
print(f"Successfully reloaded {success_count} of {total_count} modules")
if success_count < total_count:
print("\nFailed modules:")
for module, success in results.items():
if not success:
print(f" - {module}")
print("-"*50)
return results
def show_reload_ui():
"""Show a UI for reloading modules"""
# 检查是否有Qt模块可用
if not 'HAS_QT' in globals() or not HAS_QT:
cmds.warning("Qt modules not available. Falling back to command line reload.")
return reload_all()
try:
# 创建对话框
dialog = QtWidgets.QDialog(getMayaMainWindow())
dialog.setWindowTitle("Plugin Reload UI")
dialog.setMinimumWidth(450)
dialog.setWindowFlags(dialog.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
# 创建布局
layout = QtWidgets.QVBoxLayout(dialog)
# 创建信息标签
info_label = QtWidgets.QLabel("Reload Plugin modules, no need to restart Maya.")
layout.addWidget(info_label)
# 创建模块选择区域
module_group = QtWidgets.QGroupBox("Select Modules to Reload")
module_layout = QtWidgets.QVBoxLayout(module_group)
# 创建全选复选框
all_modules_cb = QtWidgets.QCheckBox("All Modules")
all_modules_cb.setChecked(True)
module_layout.addWidget(all_modules_cb)
# 创建模块类别复选框
module_cbs = {}
module_categories = [
("Core Modules", [
"scripts",
"scripts.Main",
"scripts.ReloadModules"
]
),
("UI Modules", [
"scripts.ui",
"scripts.ui.toolbar",
"scripts.ui.geometry",
"scripts.ui.rigging",
"scripts.ui.behaviour",
"scripts.ui.definition"
]
),
("Utility Modules", [
"scripts.utils",
"scripts.utils.utils_toolbar",
"scripts.utils.utils_geometry",
"scripts.utils.utils_rigging",
"scripts.utils.utils_behaviour",
"scripts.utils.utils_definition"
]
),
("Config", ["config"])
]
for category, modules in module_categories:
category_cb = QtWidgets.QCheckBox(category)
category_cb.setChecked(True)
category_cb.setEnabled(False)
module_layout.addWidget(category_cb)
module_cbs[category] = (category_cb, modules)
# 全选/取消全选逻辑
def toggle_all_modules():
checked = all_modules_cb.isChecked()
for category, (cb, _) in module_cbs.items():
cb.setChecked(checked)
cb.setEnabled(not checked)
all_modules_cb.toggled.connect(toggle_all_modules)
layout.addWidget(module_group)
# 创建操作按钮区域
button_layout = QtWidgets.QHBoxLayout()
# 创建重载按钮
reload_button = QtWidgets.QPushButton("Reload Selected Modules")
reload_button.setMinimumHeight(30)
button_layout.addWidget(reload_button)
# 创建清理缓存按钮
clean_button = QtWidgets.QPushButton("Clean Caches Only")
clean_button.setMinimumHeight(30)
button_layout.addWidget(clean_button)
layout.addLayout(button_layout)
# 创建结果文本区域
results_text = QtWidgets.QTextEdit()
results_text.setReadOnly(True)
results_text.setMinimumHeight(300)
layout.addWidget(results_text)
# 创建关闭按钮
close_button = QtWidgets.QPushButton("Close")
close_button.setMinimumHeight(30)
close_button.clicked.connect(dialog.close)
layout.addWidget(close_button)
# 重载并更新UI的函数
def reload_and_update_ui(text_widget):
text_widget.clear()
text_widget.append("Reloading modules...\n")
# 获取插件根目录 - 使用config中定义的TOOL_PATH
try:
import config
TOOL_PATH = config.TOOL_PATH
except ImportError:
# 如果无法导入config则使用相对路径
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
text_widget.append(f"Plugin root directory: {TOOL_PATH}")
# 清理 __pycache__ 目录
text_widget.append("Cleaning __pycache__ directories...")
pycache_count = clean_pycache(TOOL_PATH)
text_widget.append(f"Removed {pycache_count} __pycache__ directories and .pyc files\n")
# 确定要重载的模块
results = {}
if all_modules_cb.isChecked():
# 重载所有模块
results = ModuleReloader.reload_all_modules()
else:
# 重载选定的模块类别
selected_categories = []
for category, (cb, modules) in module_cbs.items():
if cb.isChecked():
selected_categories.extend(modules)
if not selected_categories:
text_widget.append("No module was selected, the operation was canceled.")
return
# 获取所有模块
all_modules = []
for package in selected_categories:
if package.startswith("scripts."):
all_modules.extend(ModuleReloader.get_package_modules(package))
else:
all_modules.append(package)
# 重载选定的模块
results = {}
for module in all_modules:
results[module] = ModuleReloader.reload_module(module)
# 更新UI显示结果
success_count = sum(1 for success in results.values() if success)
total_count = len(results)
text_widget.append(f"Successfully reloaded {success_count}/{total_count} modules\n")
# 显示成功重载的模块
text_widget.append("Successfully reloaded modules:")
for module, success in results.items():
if success:
text_widget.append(f" - {module}")
# 显示失败的模块(如果有)
if success_count < total_count:
text_widget.append("\nFailed to reload modules:")
for module, success in results.items():
if not success:
text_widget.append(f" - {module}")
# 提示用户重载完成
text_widget.append("\nReload operation completed!")
# 仅清理缓存的函数
def clean_cache_only(text_widget):
text_widget.clear()
text_widget.append("Cleaning caches only...\n")
# 获取插件根目录
try:
import config
TOOL_PATH = config.TOOL_PATH
except ImportError:
TOOL_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
text_widget.append(f"Plugin root directory: {TOOL_PATH}")
# 清理 __pycache__ 目录
pycache_count = clean_pycache(TOOL_PATH)
text_widget.append(f"Removed {pycache_count} __pycache__ directories and .pyc files")
text_widget.append("\nCache cleaning operation completed!")
# 连接按钮信号
reload_button.clicked.connect(lambda: reload_and_update_ui(results_text))
clean_button.clicked.connect(lambda: clean_cache_only(results_text))
# 显示对话框
dialog.show()
except Exception as e:
traceback.print_exc()
cmds.warning(f"Failed to show UI: {str(e)}. Falling back to command line reload.")
return reload_all()
# Main function to be called from Maya
def main():
"""Main function to be called from Maya"""
try:
if HAS_QT:
show_reload_ui()
else:
reload_all()
print("Modules reloaded successfully!")
return True
except Exception as e:
print(f"Error during module reload: {str(e)}")
traceback.print_exc()
return False
# Allow running this script directly
if __name__ == "__main__":
main()

32
scripts/__init__.py Normal file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
MetaHuman DNA工具包
这个包包含了用于处理MetaHuman DNA文件的工具和实用程序。
"""
import os
import sys
import config
# 将主配置中的变量导入到当前模块的命名空间
TOOL_NAME = config.TOOL_NAME
TOOL_VERSION = config.TOOL_VERSION
TOOL_AUTHOR = config.TOOL_AUTHOR
TOOL_PATH = config.TOOL_PATH
SCRIPTS_PATH = config.SCRIPTS_PATH
UI_PATH = config.UI_PATH
STYLE_FILE = config.STYLE_FILE
ICONS_PATH = config.ICONS_PATH
ASSETS_PATH = config.ASSETS_PATH
DNA_FILE_PATH = config.DNA_FILE_PATH
# 确保项目路径在sys.path中
if TOOL_PATH not in sys.path:
sys.path.insert(0, TOOL_PATH)
# 确保scripts路径在sys.path中
if SCRIPTS_PATH not in sys.path:
sys.path.insert(0, SCRIPTS_PATH)

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import *

Some files were not shown because too many files have changed in this diff Show More