Files
MetaBox/Scripts/MetaBox.py
2025-04-17 04:52:48 +08:00

2054 lines
108 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#===================================== 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 importlib
import traceback
import webbrowser
import locale
import sys
import os, subprocess
from TaskReporter import task_reporter_decorator
#===================================== IMPORT FUNCTIONS ===================================
from Modeling.Manage import Rename
from Modeling.Edit import SpeedCut, EvenEdgeLoop, SpeedBend, PolyFold, ArcDeformer, InstantDrag
from Modeling.Edit import UnBevel, RoundInset, EdgeSensei, AlignEdge, AutoSnap, XgenController
# from Modeling.Edit import gs_curvetools
from Modeling.Select import EdgeLoopSmartSelect, SamePositionSelector, IntervalSelectEdge
from Modeling.UV import UVSetEditor
from Metahuman.Custom import BodyPrep
from Animation.Blendshape import MorphShape
from Animation import UniversalRigAdapter
from Dev import mayaiconview
# #importlib.reload(CreasePlus)
# #importlib.reload(gs_curvetools)
#===================================== VARIABLES =====================================
debug_mode = False
TOOL_PATH = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/")
sys.path.append(TOOL_PATH)
TOOL_NAME = "MetaBox"
TOOL_VERSION = "Beta v1.0.0"
TOOL_AUTHOR = "CGNICO"
TOOL_LANG = 'en_US'
SCRIPTS_PATH = os.path.join(TOOL_PATH, "Scripts").replace("\\", "/")
ICONS_PATH = os.path.join(os.path.dirname(TOOL_PATH), "icons").replace("\\", "/")
TOOL_ICON = os.path.join(ICONS_PATH, "mtblogo.png").replace("\\", "/")
DEFAULT_ICON = "commandButton.png"
TOOL_HELP_URL = "http://10.72.61.59:3000/ArtGroup/{TOOL_NAME}/wiki".format(TOOL_NAME=TOOL_NAME)
TOOL_WSCL_NAME = "ToolBoxWorkSpaceControl"
MOD_FILE_NAME = "{TOOL_NAME}.mod".format(TOOL_NAME=TOOL_NAME)
MAIN_SCRIPT_NAME = "{TOOL_NAME}.py".format(TOOL_NAME=TOOL_NAME)
LDMT_PATH = os.path.join(TOOL_PATH, "Modeling", "Edit", "LDMT").replace("\\", "/")
#===================================== UI BUTTONS COMPONENTS =====================================
class RoundedButton(QtWidgets.QPushButton):
def __init__(self, text="", icon=None, color="#D0D0D0", hover_color="#E0E0E0", pressed_color="#C0C0C0"):
super(RoundedButton, self).__init__(text)
if icon:
self.setIcon(icon)
self.setIconSize(QtCore.QSize(24, 24))
self.setMinimumHeight(30)
self.setStyleSheet(
"""
QPushButton {{
background-color: {color};
color: #303030;
border-radius: 10px;
padding: 5px;
font-weight: bold;
text-align: center;
}}
QPushButton:hover {{
background-color: {hover_color};
}}
QPushButton:pressed {{
background-color: {pressed_color};
}}
""".format(color=color, hover_color=hover_color, pressed_color=pressed_color)
)
#===================================== GLOBAL FUNCTIONS ===================================
def get_system_encoding():
encoding = sys.getdefaultencoding()
if encoding.lower() == 'ascii':
encoding = locale.getpreferredencoding()
return encoding
def maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
LANG = {
'en_US': {
"DOCUMENT": "DOCUMENT",
"Help": "Help",
"EN": "EN",
"ZH": "ZH",
"zh_CN": "zh_CN",
"Switch Language": "Switch Language",
"Modeling": "Modeling",
"Metahuman": "Metahuman",
"Rigging": "Rigging",
"Animation": "Animation",
"Display": "Display",
"Xray": "Xray",
"Joint Xray": "Joint Xray",
"Manage": "Manage",
"Rename": "Rename",
"Batch Import": "Batch Import",
"Select": "Select",
"Interval Select Edge": "Interval Select Edge",
"Same Position Selector": "Same Position Selector",
"Edge Loop Smart Select": "Edge Loop Smart Select",
"Even Edge Loop": "Even Edge Loop",
"Tools": "Tools",
"Crease Plus": "Crease Plus",
"Speed Cut": "Speed Cut",
"ModIt": "ModIt",
"PlugIt": "PlugIt",
"Zirail": "Zirail",
"Groomer`s Tool": "Groomer`s Tool",
"Edge Sensei": "Edge Sensei",
"Round Inset": "Round Inset",
"Arc Deformer": "Arc Deformer",
"Instant Drag": "Instant Drag",
"Un Bevel": "Un Bevel",
"Align Edge": "Align Edge",
"Extra Curve": "Extra Curve",
"Auto Snap": "Auto Snap",
"Xgen Controller": "Xgen Controller",
"Speed Bend": "Speed Bend",
"Hair Tools": "Hair Tools",
"GS Curve Tools": "GS Curve Tools",
"GS Curve Tools Reset": "GS Curve Tools Reset",
"GS Curve Tools Close": "GS Curve Tools Close",
"Export XGen to Groom": "Export XGen to Groom",
"Export XGen Description": "Export XGen Description",
"UV": "UV",
"UVDeluxe": "UVDeluxe",
"RizomUV Bridge": "RizomUV Bridge",
"UV Set Editor": "UV Set Editor",
"Preparation": "Preparation",
"Body Prepare": "Body Prepare",
"Setup": "Setup",
"Advanced Skeleton": "Advanced Skeleton",
"Weight Export": "Weight Export",
"Weight Import": "Weight Import",
"Unbind Skin": "Unbind Skin",
"Select": "Select",
"Anim School Picker": "Anim School Picker",
"DWPicker": "DWPicker",
"Tools": "Tools",
"bhGhost": "bhGhost",
"IK/FK Switch": "IK/FK Switch",
"aTools": "aTools",
"Keyframe Pro": "Keyframe Pro",
"Studio Library": "Studio Library",
"Pose Tools": "Pose Tools",
"Epic Pose Wrangler": "Epic Pose Wrangler",
"Morph Shape": "Morph Shape",
"Universal Rig Adapter": "Universal Rig Adapter",
"Dev": "Dev",
"Dev Tool": "Dev Tool",
"Icon Viewer": "Icon Viewer",
"Import": "Import",
"IK/FK Mocap": "IK/FK Mocap Tool",
"MotionCapHelper": "MotionCap Helper",
"SpringMagic": "Spring Magic",
"Ahoge": "Ahoge",
"QuadRemesher": "Quad Remesher",
"LDMT": "LDMT",
"Simplify": "Simplify",
'Deformer': 'Deformer',
'Instant Meshes': 'Instant Meshes',
'Topo Blendshape': 'Topo Blendshape',
'Face Transfer': 'Face Transfer',
'Cloth Transfer': 'Cloth Transfer',
'Marvelous Tool': 'Marvelous Tool',
"Morph to UV": "Morph to UV",
"Quick Export": "Quick Export",
"Check UV Bleed":"Check UV Bleed",
"Overlap UV Out":"Overlap UV Out",
"Overlap UV In":"Overlap UV In",
"Switch UV Set":"Switch UV Set",
"Debug Tools": "Debug Tools",
"Scene": "Scene",
"CleanM": "CleanM",
"Normal": "Normal",
"KeepHS": "KeepHS",
"Rename": "Rename",
"DelName": "DelName",
"Ungroup": "Ungroup",
"Reverse": "Reverse",
"XgenVis": "XgenVis",
"Task Path Builder": "TaskPathBuilder"
},
'zh_CN': {
"DOCUMENT": "说明文档",
"Help": "帮助",
"EN": "EN",
"ZH": "ZH",
"zh_CN": "zh_CN",
"Switch Language": "切换语言",
"Modeling": "建模",
"Metahuman": "Metahuman",
"Rigging": "绑定",
"Animation": "动画",
"Display": "显示",
"Xray": "X光显示",
"Joint Xray": "关节X光显示",
"Manage": "管理",
"Rename": "重命名",
"Batch Import": "批量导入",
"Select": "选择",
"Interval Select Edge": "间隔选择边",
"Same Position Selector": "相同位置物体选择器",
"Edge Loop Smart Select": "边缘循环智能选择",
"Even Edge Loop": "等边循环",
"Tools": "工具",
"Crease Plus": "Crease ++",
"Speed Cut": "快速切割",
"ModIt": "ModIt",
"PlugIt": "PlugIt",
"Zirail": "Zirail 拓扑工具",
"Groomer`s Tool": "Groomer 工具",
"Edge Sensei": "边线大师",
"Round Inset": "圆角插入",
"Arc Deformer": "弧形变形器",
"Instant Drag": "吸附放置",
"Un Bevel": "去除倒角",
"Align Edge": "对齐到边",
"Extra Curve": "提取曲线",
"Auto Snap": "自动吸附",
"Xgen Controller": "Xgen 控制器",
"Speed Bend": "快速弯曲",
"Hair Tools": "毛发工具",
"GS Curve Tools": "GS曲线工具",
"GS Curve Tools Reset": "重置",
"GS Curve Tools Close": "关闭",
"Export XGen to Groom": "导出 XGen 到 Groom",
"Export XGen Description": "导出 XGen Description",
"UV": "UV",
"UVDeluxe": "UVDeluxe",
"RizomUV Bridge": "RizomUV Bridge",
"UV Set Editor": "UV 编辑器",
"Preparation": "准备",
"Body Prepare": "身体准备",
"Setup": "设置",
"Advanced Skeleton": "高级骨骼",
"Weight Export": "权重导出",
"Weight Import": "权重导入",
"Unbind Skin": "取消蒙皮",
"Select": "选择",
"Anim School Picker": "Anim School 拾取器",
"DWPicker": "DW 拾取器",
"Tools": "工具",
"bhGhost": "洋葱皮",
"IK/FK Switch": "IK/FK 切换",
"aTools": "aTools",
"Keyframe Pro": "关键帧大师",
"Studio Library": "工作室库",
"Pose Tools": "姿势工具",
"Epic Pose Wrangler": "Epic 姿势变形器",
"Morph Shape": "变形工具",
"Universal Rig Adapter": "通用绑定适配器",
"Dev": "开发",
"Dev Tool": "开发工具",
"Icon Viewer": "图标查看器",
"Import": "导入",
"IK/FK Mocap": "IK/FK 动捕工具",
"MotionCapHelper": "动捕助手",
"SpringMagic": "飘带插件",
"Ahoge": "Ahoge工具",
"QuadRemesher": "重拓扑工具",
"LDMT": "LDMT",
"Simplify": "减面工具",
'Deformer': '变形器',
'Instant Meshes': '快速重拓扑',
'Topo Blendshape': '拓扑变形器',
'Face Transfer': '面部传递',
'Cloth Transfer': '服装传递',
'Marvelous Tool': 'MD工具集',
"Morph to UV": "模型 to UV",
"Quick Export": "快速导出",
"Check UV Bleed":"检查 UV 溢出",
"Overlap UV Out":"重叠 UV 修复",
"Overlap UV In":"重叠 UV 合并",
"Switch UV Set":"切换 UV Set",
"Debug Tools": "Debug 工具",
"Scene": "场景优化",
"CleanM": "清理模型",
"Normal": "面法线",
"KeepHS": "保留平滑组",
"Rename": "重命名",
"DelName": "删除命名空间",
"Ungroup": "取消打组",
"Reverse": "翻转",
"XgenVis": "Xgen 显示",
"Task Path Builder": "任务路径构建"
}
}
#===================================== UI MAIN WINDOW COMPONENTS ===================================
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent=maya_main_window()):
super(MainWindow, self).__init__(parent)
self.setWindowTitle(TOOL_NAME)
self.setObjectName(TOOL_PATH)
self.setWindowFlags(QtCore.Qt.Window)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred)
self.setMinimumSize(300, 800)
self.create_widgets()
self.create_layouts()
self.create_connections()
if os.path.exists(TOOL_ICON):
self.setWindowIcon(QtGui.QIcon(TOOL_ICON))
else:
print("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.help_btn = QtWidgets.QPushButton(LANG[TOOL_LANG]["DOCUMENT"])
self.help_btn.setToolTip(LANG[TOOL_LANG]["Help"])
self.help_btn.setFixedSize(100, 20)
self.help_btn.setStyleSheet("""
QPushButton {
background-color: transparent;
border: none;
color: gray;
font-weight: bold;
}
QPushButton:hover {
color: black;
}
""")
self.lang_btn = QtWidgets.QPushButton("EN" if TOOL_LANG == 'zh_CN' else "ZH")
self.lang_btn.setToolTip(LANG[TOOL_LANG]["Switch Language"])
self.lang_btn.setFixedSize(30, 20)
self.lang_btn.setStyleSheet("""
QPushButton {
background-color: transparent;
border: none;
color: gray;
font-weight: bold;
}
QPushButton:hover {
color: black;
}
""")
# Create tabs
self.modeling_tab_btn = RoundedButton(LANG[TOOL_LANG]["Modeling"])
self.metahuman_tab_btn = RoundedButton(LANG[TOOL_LANG]["Metahuman"])
self.rigging_tab_btn = RoundedButton(LANG[TOOL_LANG]["Rigging"])
self.animation_tab_btn = RoundedButton(LANG[TOOL_LANG]["Animation"])
self.dev_tab_btn = RoundedButton(LANG[TOOL_LANG]["Dev"])
# Modeling group widgets
self.modeling_display_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Display"] )
self.modeling_xray_btn = RoundedButton(LANG[TOOL_LANG]["Xray"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF6F61")
self.modeling_joint_xray_btn = RoundedButton(LANG[TOOL_LANG]["Joint Xray"], color="#FFDAA5", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.modeling_manage_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Manage"])
self.modeling_rename_btn = RoundedButton(LANG[TOOL_LANG]["Rename"], color="#A4D7E1", hover_color="#A0D8D0", pressed_color="#8CC8C5")
self.modeling_batch_import_btn = RoundedButton(LANG[TOOL_LANG]["Batch Import"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
self.modeling_quick_export_btn = RoundedButton(LANG[TOOL_LANG]["Quick Export"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
self.modeling_task_path_builder_btn = RoundedButton(LANG[TOOL_LANG]["Task Path Builder"], color="#A4D7E1", hover_color="#A0D8D0", pressed_color="#8CC8C5")
self.modeling_select_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Select"])
self.modeling_interval_select_edge_btn = RoundedButton(LANG[TOOL_LANG]["Interval Select Edge"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A")
self.modeling_same_position_selector_btn = RoundedButton(LANG[TOOL_LANG]["Same Position Selector"], color="#FFABAB", hover_color="#FFC3C3", pressed_color="#FF8C8C")
self.modeling_edge_loop_smart_select_btn = RoundedButton(LANG[TOOL_LANG]["Edge Loop Smart Select"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
self.modeling_even_edge_loop_btn = RoundedButton(LANG[TOOL_LANG]["Even Edge Loop"], color="#FF8C94", hover_color="#FFB3B8", pressed_color="#FF6F7D")
self.modeling_tools_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Tools"])
self.modeling_crease_plus_btn = RoundedButton(LANG[TOOL_LANG]["Crease Plus"], color="#FFB74D", hover_color="#FFD54F", pressed_color="#FFA726")
self.modeling_speed_cut_btn = RoundedButton(LANG[TOOL_LANG]["Speed Cut"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A")
self.modeling_modit_btn = RoundedButton(LANG[TOOL_LANG]["ModIt"], color="#A4D7E1", hover_color="#A0D8D0", pressed_color="#8CC8C5")
self.modeling_plugit_btn = RoundedButton(LANG[TOOL_LANG]["PlugIt"], color="#B39DDB", hover_color="#D1C4E9", pressed_color="#9575CD")
self.modeling_zirail_btn = RoundedButton(LANG[TOOL_LANG]["Zirail"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
self.modeling_xgtools_btn = RoundedButton(LANG[TOOL_LANG]["Groomer`s Tool"], color="#FFAB40", hover_color="#FFB74D", pressed_color="#FF8F00")
self.modeling_edge_sensei_btn = RoundedButton(LANG[TOOL_LANG]["Edge Sensei"], color="#B2E0B2", hover_color="#C6E6C6", pressed_color="#99D699")
self.modeling_round_inset_btn = RoundedButton(LANG[TOOL_LANG]["Round Inset"], color="#FF8C94", hover_color="#FFB3B8", pressed_color="#FF6F7D")
self.modeling_arc_deformer_btn = RoundedButton(LANG[TOOL_LANG]["Arc Deformer"], color="#E1BEE7", hover_color="#EAB8E4", pressed_color="#D81B60")
self.modeling_speed_bend_btn = RoundedButton(LANG[TOOL_LANG]["Speed Bend"], color="#FFABAB", hover_color="#FF8C8C", pressed_color="#FF6F61")
self.modeling_instant_drag_btn = RoundedButton(LANG[TOOL_LANG]["Instant Drag"], color="#BBDEFB", hover_color="#90CAF9", pressed_color="#64B5F6")
self.modeling_unbevel_btn = RoundedButton(LANG[TOOL_LANG]["Un Bevel"], color="#C8E6C9", hover_color="#A5D6A7", pressed_color="#81C784")
self.modeling_align_edge_btn = RoundedButton(LANG[TOOL_LANG]["Align Edge"], color="#FFCCBC", hover_color="#FFAB91", pressed_color="#FF8A65")
self.modeling_extra_curve_btn = RoundedButton(LANG[TOOL_LANG]["Extra Curve"], color="#E1BEE7", hover_color="#D1C4E9", pressed_color="#BA68C8")
self.modeling_auto_snap_btn = RoundedButton(LANG[TOOL_LANG]["Auto Snap"], color="#FFABAB", hover_color="#FF8C8C", pressed_color="#FF6F61")
self.modeling_quad_remesher_btn = RoundedButton(LANG[TOOL_LANG]["QuadRemesher"], color="#BAE1FF", hover_color="#A2D1FF", pressed_color="#8AC4FF")
self.modeling_ldmt_btn = RoundedButton(LANG[TOOL_LANG]["LDMT"], color="#BAE1FF", hover_color="#A2D1FF", pressed_color="#8AC4FF")
self.modeling_simplify_btn = RoundedButton(LANG[TOOL_LANG]["Simplify"], color="#BAE1FF", hover_color="#A2D1FF", pressed_color="#8AC4FF")
self.modeling_morph_to_uv_btn = RoundedButton(LANG[TOOL_LANG]["Morph to UV"], color="#BAE1FF", hover_color="#A2D1FF", pressed_color="#8AC4FF")
self.modeling_gs_curve_tools_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Hair Tools"])
self.modeling_gs_curve_tools_btn = RoundedButton(LANG[TOOL_LANG]["GS Curve Tools"], color="#C8E6C9", hover_color="#A5D6A7", pressed_color="#81C784")
self.modeling_reset_gs_curve_tools_btn = RoundedButton(LANG[TOOL_LANG]["GS Curve Tools Reset"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A")
self.modeling_close_gs_curve_tools_btn = RoundedButton(LANG[TOOL_LANG]["GS Curve Tools Close"], color="#FFCCBC", hover_color="#FFAB91", pressed_color="#FF8A65")
self.modeling_xgen_controller_btn = RoundedButton(LANG[TOOL_LANG]["Xgen Controller"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A")
self.modeling_export_xgen_to_groom_btn = RoundedButton(LANG[TOOL_LANG]["Export XGen to Groom"], color="#A5D6A7", hover_color="#FFF5B3", pressed_color="#FF8A65")
self.modeling_export_xgen_description_btn = RoundedButton(LANG[TOOL_LANG]["Export XGen Description"], color="#A5D6A7", hover_color="#FFF5B3", pressed_color="#FF8A65")
self.modeling_ahoge_btn = RoundedButton(LANG[TOOL_LANG]["Ahoge"], color="#BAE1FF", hover_color="#A2D1FF", pressed_color="#8AC4FF")
self.modeling_uv_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["UV"])
self.modeling_uvdeluxe_btn = RoundedButton(LANG[TOOL_LANG]["UVDeluxe"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
self.modeling_rizom_uv_bridge_btn = RoundedButton(LANG[TOOL_LANG]["RizomUV Bridge"], color="#FFABAB", hover_color="#FFC3C3", pressed_color="#FF8C8C")
self.modeling_uv_set_editor_btn = RoundedButton(LANG[TOOL_LANG]["UV Set Editor"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A")
self.modeling_check_uv_bleed_btn = RoundedButton(LANG[TOOL_LANG]["Check UV Bleed"], color="#FFABAB", hover_color="#FFC3C3", pressed_color="#FF8C8C")
self.modeling_overlap_uv_out_btn = RoundedButton(LANG[TOOL_LANG]["Overlap UV Out"], color='#A7C6ED', hover_color='#B2D3F0', pressed_color='#8BB8E0')
self.modeling_overlap_uv_in_btn = RoundedButton(LANG[TOOL_LANG]["Overlap UV In"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A")
self.modeling_switch_uv_set_btn = RoundedButton(LANG[TOOL_LANG]["Switch UV Set"], color='#BAE1FF', hover_color='#A2D1FF', pressed_color='#8AC4FF')
self.modeling_deformer_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]['Deformer'])
self.modeling_instant_mesh_btn = RoundedButton(LANG[TOOL_LANG]['Instant Meshes'], color='#A7C6ED', hover_color='#B2D3F0', pressed_color='#8BB8E0')
self.modeling_topo_blendshape_btn = RoundedButton(LANG[TOOL_LANG]['Topo Blendshape'], color='#A7C6ED', hover_color='#B2D3F0', pressed_color='#8BB8E0')
self.modeling_face_transfer_btn = RoundedButton(LANG[TOOL_LANG]['Face Transfer'], color='#FFABAB', hover_color='#FFC3C3', pressed_color='#FF8C8C')
self.modeling_cloth_transfer_btn = RoundedButton(LANG[TOOL_LANG]['Cloth Transfer'], color='#FFEBA1', hover_color='#FFF5B3', pressed_color='#FFE68A')
self.modeling_marvelous_tool_btn = RoundedButton(LANG[TOOL_LANG]['Marvelous Tool'], color='#BAE1FF', hover_color='#A2D1FF', pressed_color='#8AC4FF')
# Metahuman group widgets
self.metahuman_preparation_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Preparation"])
self.metahuman_body_prepare_btn = RoundedButton(LANG[TOOL_LANG]["Body Prepare"], color="#FFABAB", hover_color="#FF6F6F", pressed_color="#FF8C8C")
self.metahuman_import_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Import"])
self.metahuman_batch_import_btn = RoundedButton(LANG[TOOL_LANG]["Batch Import"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
# Rigging group widgets
self.rigging_setup_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Setup"])
self.rigging_advanced_skeleton_btn = RoundedButton(LANG[TOOL_LANG]["Advanced Skeleton"], color="#FFDAA5", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.rigging_weight_export_btn = RoundedButton(LANG[TOOL_LANG]["Weight Export"], color="#A7C6ED", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.rigging_weight_import_btn = RoundedButton(LANG[TOOL_LANG]["Weight Import"], color="#A7C6ED", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.rigging_unbind_skin_btn = RoundedButton(LANG[TOOL_LANG]["Unbind Skin"], color="#FFABAB", hover_color="#FFC3C3", pressed_color="#FF8C8C")
# Animation group widgets
self.animation_select_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Select"])
self.animation_animschool_picker_btn = RoundedButton(LANG[TOOL_LANG]["Anim School Picker"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF8C94")
self.animation_dwpicker_btn = RoundedButton(LANG[TOOL_LANG]["DWPicker"], color="#A0D8D0", hover_color="#8CC8C5", pressed_color="#7FBFBF")
self.animation_tools_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Tools"])
self.animation_bhghost_btn = RoundedButton(LANG[TOOL_LANG]["bhGhost"], color="#FFDAA5", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.animation_ikfk_switch_btn = RoundedButton(LANG[TOOL_LANG]["IK/FK Switch"], color="#B2E1D4", hover_color="#A0D8D0", pressed_color="#8CC8C5")
self.animation_atools_btn = RoundedButton(LANG[TOOL_LANG]["aTools"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF8C94")
self.animation_keyframepro_btn = RoundedButton(LANG[TOOL_LANG]["Keyframe Pro"], color="#FFDAA5", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.animation_studiolibrary_btn = RoundedButton(LANG[TOOL_LANG]["Studio Library"], color="#A0D8D0", hover_color="#8CC8C5", pressed_color="#7FBFBF")
# self.animation_ikfk_mocap_btn = RoundedButton(LANG[TOOL_LANG]["IK/FK Mocap"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF8C94")
self.animation_motioncap_helper_btn = RoundedButton(LANG[TOOL_LANG]["MotionCapHelper"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF8C94")
self.animation_spring_magic_btn = RoundedButton(LANG[TOOL_LANG]["SpringMagic"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF8C94")
self.animation_pose_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Pose Tools"])
self.animation_epic_pose_wrangler_btn = RoundedButton(LANG[TOOL_LANG]["Epic Pose Wrangler"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF8C94")
self.animation_morph_shape_btn = RoundedButton(LANG[TOOL_LANG]["Morph Shape"], color="#FFDAA5", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.animation_universal_rig_adapter_btn = RoundedButton(LANG[TOOL_LANG]["Universal Rig Adapter"], color="#A0D8D0", hover_color="#8CC8C5", pressed_color="#7FBFBF")
# Dev group widgets
self.dev_tools_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Dev Tool"])
self.dev_icon_viewer_btn = RoundedButton(LANG[TOOL_LANG]["Icon Viewer"], color="#FFDAA5", hover_color="#FFC78C", pressed_color="#FFC0A1")
# Debug group widgets
self.debug_tools_group = QtWidgets.QGroupBox(LANG[TOOL_LANG]["Debug Tools"])
self.debug_scene_btn = RoundedButton(LANG[TOOL_LANG]["Scene"], color="#A0D8D0", hover_color="#8CC8C5", pressed_color="#7FBFBF")
self.debug_cleanm_btn = RoundedButton(LANG[TOOL_LANG]["CleanM"], color="#FFDAA5", hover_color="#FFC78C", pressed_color="#FFC0A1")
self.debug_normal_btn = RoundedButton(LANG[TOOL_LANG]["Normal"], color="#FFB3BA", hover_color="#FF9DAF", pressed_color="#FF8C94")
self.debug_keephs_btn = RoundedButton(LANG[TOOL_LANG]["KeepHS"], color='#BAE1FF', hover_color='#A2D1FF', pressed_color='#8AC4FF')
self.debug_xgen_btn = RoundedButton(LANG[TOOL_LANG]["XgenVis"], color="#A7C6ED", hover_color="#B2D3F0", pressed_color="#8BB8E0")
self.debug_rename_btn = RoundedButton(LANG[TOOL_LANG]["Rename"], color='#A7C6ED', hover_color='#B2D3F0', pressed_color='#8BB8E0')
self.debug_delname_btn = RoundedButton(LANG[TOOL_LANG]["DelName"], color='#FFDAA5', hover_color='#FFC78C', pressed_color='#FFC0A1')
self.debug_ungroup_btn = RoundedButton(LANG[TOOL_LANG]["Ungroup"], color='#A0D8D0', hover_color='#8CC8C5', pressed_color='#7FBFBF')
self.debug_reverse_btn = RoundedButton(LANG[TOOL_LANG]["Reverse"], color='#FFB3BA', hover_color='#FF9DAF', pressed_color='#FF8C94')
def create_layouts(self):
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setContentsMargins(2, 2, 2, 2)
# Resizable by dragging
main_layout.setStretch(0, 1)
# Tabs Layout
tabs_layout = QtWidgets.QTabWidget(self)
main_layout.addWidget(tabs_layout)
#===================================MODELING TAB===================================
modeling_tab = QtWidgets.QWidget()
modeling_layout = QtWidgets.QHBoxLayout(modeling_tab)
# Scroll area
modeling_scroll_area = QtWidgets.QScrollArea()
modeling_scroll_area.setWidgetResizable(True)
modeling_scroll_area_content = QtWidgets.QWidget()
modeling_scroll_area_layout = QtWidgets.QVBoxLayout(modeling_scroll_area_content)
modeling_scroll_area.setWidget(modeling_scroll_area_content)
# Display
modeling_scroll_area_layout.addWidget(self.modeling_display_group)
modeling_display_layout = QtWidgets.QGridLayout(self.modeling_display_group)
modeling_display_layout.addWidget(self.modeling_xray_btn, 0, 0)
modeling_display_layout.addWidget(self.modeling_joint_xray_btn, 0, 1)
# Manage
modeling_scroll_area_layout.addWidget(self.modeling_manage_group)
modeling_manage_layout = QtWidgets.QGridLayout(self.modeling_manage_group)
modeling_manage_layout.addWidget(self.modeling_rename_btn, 1, 0)
modeling_manage_layout.addWidget(self.modeling_batch_import_btn, 0, 0)
modeling_manage_layout.addWidget(self.modeling_quick_export_btn, 0, 1)
modeling_manage_layout.addWidget(self.modeling_task_path_builder_btn, 1, 1)
# Select
modeling_scroll_area_layout.addWidget(self.modeling_select_group)
modeling_select_layout = QtWidgets.QVBoxLayout(self.modeling_select_group)
modeling_select_layout.addWidget(self.modeling_interval_select_edge_btn)
modeling_select_layout.addWidget(self.modeling_same_position_selector_btn)
modeling_select_layout.addWidget(self.modeling_edge_loop_smart_select_btn)
modeling_select_layout.addWidget(self.modeling_even_edge_loop_btn)
# Tools
modeling_scroll_area_layout.addWidget(self.modeling_tools_group)
modeling_tools_layout = QtWidgets.QGridLayout(self.modeling_tools_group)
modeling_tools_layout.addWidget(self.modeling_crease_plus_btn, 0, 0)
modeling_tools_layout.addWidget(self.modeling_speed_cut_btn, 0, 1)
modeling_tools_layout.addWidget(self.modeling_modit_btn, 1, 0)
modeling_tools_layout.addWidget(self.modeling_plugit_btn, 1, 1)
modeling_tools_layout.addWidget(self.modeling_zirail_btn, 2, 0)
modeling_tools_layout.addWidget(self.modeling_edge_sensei_btn, 2, 1)
modeling_tools_layout.addWidget(self.modeling_round_inset_btn, 3, 0)
modeling_tools_layout.addWidget(self.modeling_arc_deformer_btn, 3, 1)
modeling_tools_layout.addWidget(self.modeling_speed_bend_btn, 4, 0)
modeling_tools_layout.addWidget(self.modeling_instant_drag_btn, 4, 1)
modeling_tools_layout.addWidget(self.modeling_unbevel_btn, 5, 0)
modeling_tools_layout.addWidget(self.modeling_align_edge_btn, 5, 1)
modeling_tools_layout.addWidget(self.modeling_extra_curve_btn, 6, 0)
modeling_tools_layout.addWidget(self.modeling_auto_snap_btn, 6, 1)
modeling_tools_layout.addWidget(self.modeling_quad_remesher_btn, 7, 0)
modeling_tools_layout.addWidget(self.modeling_morph_to_uv_btn, 7, 1)
# modeling_tools_layout.addWidget(self.modeling_simplify_btn, 8, 1)
# modeling_tools_layout.addWidget(self.modeling_ldmt_btn, 9, 0)
# GS Curve Tools
modeling_scroll_area_layout.addWidget(self.modeling_gs_curve_tools_group)
modeling_gs_curve_tools_layout = QtWidgets.QVBoxLayout(self.modeling_gs_curve_tools_group)
modeling_gs_curve_tools_layout.addWidget(self.modeling_gs_curve_tools_btn)
modeling_gs_curve_tools_layout.addWidget(self.modeling_reset_gs_curve_tools_btn)
modeling_gs_curve_tools_layout.addWidget(self.modeling_close_gs_curve_tools_btn)
modeling_gs_curve_tools_layout.addWidget(self.modeling_xgtools_btn)
modeling_gs_curve_tools_layout.addWidget(self.modeling_xgen_controller_btn)
modeling_gs_curve_tools_layout.addWidget(self.modeling_export_xgen_to_groom_btn)
modeling_gs_curve_tools_layout.addWidget(self.modeling_export_xgen_description_btn)
modeling_gs_curve_tools_layout.addWidget(self.modeling_ahoge_btn)
# UV
modeling_scroll_area_layout.addWidget(self.modeling_uv_group)
modeling_uv_layout = QtWidgets.QGridLayout(self.modeling_uv_group)
modeling_uv_layout.addWidget(self.modeling_uv_set_editor_btn, 0, 0)
modeling_uv_layout.addWidget(self.modeling_uvdeluxe_btn, 0, 1)
modeling_uv_layout.addWidget(self.modeling_rizom_uv_bridge_btn, 1, 0)
modeling_uv_layout.addWidget(self.modeling_check_uv_bleed_btn, 1, 1)
modeling_uv_layout.addWidget(self.modeling_overlap_uv_out_btn, 2, 0)
modeling_uv_layout.addWidget(self.modeling_overlap_uv_in_btn, 2, 1)
modeling_uv_layout.addWidget(self.modeling_switch_uv_set_btn, 3, 0)
modeling_scroll_area_layout.addWidget(self.modeling_deformer_group)
modeling_deformer_layout = QtWidgets.QGridLayout(self.modeling_deformer_group)
modeling_deformer_layout.addWidget(self.modeling_instant_mesh_btn, 0, 0)
# modeling_deformer_layout.addWidget(self.modeling_topo_blendshape_btn, 0, 1)
modeling_deformer_layout.addWidget(self.modeling_face_transfer_btn, 1, 0)
modeling_deformer_layout.addWidget(self.modeling_cloth_transfer_btn, 1, 1)
modeling_deformer_layout.addWidget(self.modeling_marvelous_tool_btn, 0, 1)
# Add the scroll area to the main layout
modeling_layout.addWidget(modeling_scroll_area)
tabs_layout.addTab(modeling_tab, "Modeling")
#===================================METAHUMAN TAB===================================
metahuman_tab = QtWidgets.QWidget()
metahuman_layout = QtWidgets.QVBoxLayout(metahuman_tab)
# Scroll area
metahuman_scroll_area = QtWidgets.QScrollArea()
metahuman_scroll_area.setWidgetResizable(True)
metahuman_scroll_area_content = QtWidgets.QWidget()
metahuman_scroll_area_layout = QtWidgets.QVBoxLayout(metahuman_scroll_area_content)
metahuman_scroll_area.setWidget(metahuman_scroll_area_content)
# Add all buttons and groups to the scroll area
metahuman_scroll_area_layout.addWidget(self.metahuman_preparation_group)
metahuman_preparation_layout = QtWidgets.QVBoxLayout(self.metahuman_preparation_group)
metahuman_preparation_layout.addWidget(self.metahuman_body_prepare_btn)
# Add Import group layout
metahuman_scroll_area_layout.addWidget(self.metahuman_import_group)
metahuman_import_layout = QtWidgets.QVBoxLayout(self.metahuman_import_group)
metahuman_import_layout.addWidget(self.metahuman_batch_import_btn)
# Add the scroll area to the main layout
metahuman_layout.addWidget(metahuman_scroll_area)
tabs_layout.addTab(metahuman_tab, "Metahuman")
#===================================RIGGING TAB===================================
rigging_tab = QtWidgets.QWidget()
rigging_layout = QtWidgets.QVBoxLayout(rigging_tab)
# Scroll area
rigging_scroll_area = QtWidgets.QScrollArea()
rigging_scroll_area.setWidgetResizable(True)
rigging_scroll_area_content = QtWidgets.QWidget()
rigging_scroll_area_layout = QtWidgets.QVBoxLayout(rigging_scroll_area_content)
rigging_scroll_area.setWidget(rigging_scroll_area_content)
# Add all buttons and groups to the scroll area
rigging_scroll_area_layout.addWidget(self.rigging_setup_group)
rigging_setup_layout = QtWidgets.QVBoxLayout(self.rigging_setup_group)
rigging_setup_layout.addWidget(self.rigging_advanced_skeleton_btn)
rigging_weight_layout = QtWidgets.QGridLayout()
rigging_weight_layout.addWidget(self.rigging_weight_export_btn, 0, 0)
rigging_weight_layout.addWidget(self.rigging_weight_import_btn, 0, 1)
rigging_weight_layout.addWidget(self.rigging_unbind_skin_btn, 1, 0)
rigging_setup_layout.addLayout(rigging_weight_layout)
# Add the scroll area to the main layout
rigging_layout.addWidget(rigging_scroll_area)
tabs_layout.addTab(rigging_tab, "Rigging")
#===================================ANIMATION TAB===================================
animation_tab = QtWidgets.QWidget()
animation_layout = QtWidgets.QVBoxLayout(animation_tab)
# Scroll area
animation_scroll_area = QtWidgets.QScrollArea()
animation_scroll_area.setWidgetResizable(True)
animation_scroll_area_content = QtWidgets.QWidget()
animation_scroll_area_layout = QtWidgets.QVBoxLayout(animation_scroll_area_content)
animation_scroll_area.setWidget(animation_scroll_area_content)
# Add all buttons and groups to the scroll area
animation_scroll_area_layout.addWidget(self.animation_select_group)
animation_select_layout = QtWidgets.QVBoxLayout(self.animation_select_group)
animation_select_layout.addWidget(self.animation_animschool_picker_btn)
animation_select_layout.addWidget(self.animation_dwpicker_btn)
animation_scroll_area_layout.addWidget(self.animation_tools_group)
animation_tools_layout = QtWidgets.QGridLayout(self.animation_tools_group)
animation_tools_layout.addWidget(self.animation_bhghost_btn, 0, 0)
animation_tools_layout.addWidget(self.animation_ikfk_switch_btn, 0, 1)
animation_tools_layout.addWidget(self.animation_atools_btn, 1, 0)
animation_tools_layout.addWidget(self.animation_keyframepro_btn, 1, 1)
animation_tools_layout.addWidget(self.animation_studiolibrary_btn, 2, 0)
# animation_tools_layout.addWidget(self.animation_ikfk_mocap_btn, 2, 1)
animation_tools_layout.addWidget(self.animation_motioncap_helper_btn, 2, 1)
animation_tools_layout.addWidget(self.animation_spring_magic_btn, 3, 0)
animation_scroll_area_layout.addWidget(self.animation_pose_group)
animation_pose_layout = QtWidgets.QVBoxLayout(self.animation_pose_group)
animation_pose_layout.addWidget(self.animation_epic_pose_wrangler_btn)
animation_pose_layout.addWidget(self.animation_morph_shape_btn)
animation_pose_layout.addWidget(self.animation_universal_rig_adapter_btn)
# Add the scroll area to the main layout
animation_layout.addWidget(animation_scroll_area)
tabs_layout.addTab(animation_tab, "Animation")
#===================================DEV TAB===================================
dev_tab = QtWidgets.QWidget()
dev_layout = QtWidgets.QVBoxLayout(dev_tab)
# Scroll area
dev_scroll_area = QtWidgets.QScrollArea()
dev_scroll_area.setWidgetResizable(True)
dev_scroll_area_content = QtWidgets.QWidget()
dev_scroll_area_layout = QtWidgets.QVBoxLayout(dev_scroll_area_content)
dev_scroll_area.setWidget(dev_scroll_area_content)
# Add all buttons and groups to the scroll area
dev_scroll_area_layout.addWidget(self.dev_tools_group)
dev_tools_layout = QtWidgets.QVBoxLayout(self.dev_tools_group)
dev_tools_layout.addWidget(self.dev_icon_viewer_btn)
# Debug
dev_scroll_area_layout.addWidget(self.debug_tools_group)
debug_tools_layout = QtWidgets.QGridLayout(self.debug_tools_group)
debug_tools_layout.addWidget(self.debug_scene_btn, 0, 0)
debug_tools_layout.addWidget(self.debug_cleanm_btn, 0, 1)
debug_tools_layout.addWidget(self.debug_normal_btn, 0, 2)
debug_tools_layout.addWidget(self.debug_xgen_btn, 0, 3)
# debug_tools_layout.addWidget(self.debug_keephs_btn, 0, 3)
debug_tools_layout.addWidget(self.debug_rename_btn, 1, 0)
debug_tools_layout.addWidget(self.debug_delname_btn, 1, 1)
debug_tools_layout.addWidget(self.debug_ungroup_btn, 1, 2)
debug_tools_layout.addWidget(self.debug_reverse_btn, 1, 3)
# Add the scroll area to the main layout
dev_layout.addWidget(dev_scroll_area)
tabs_layout.addTab(dev_tab, "Dev")
# change bottom layout
bottom_layout = QtWidgets.QHBoxLayout()
# create icon label
icon_label = QtWidgets.QLabel()
if os.path.exists(TOOL_ICON):
icon = QtGui.QPixmap(TOOL_ICON).scaled(24, 24, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
icon_label.setPixmap(icon)
else:
print("Warning: Icon file '{}' does not exist.".format(TOOL_ICON))
# add icon label to bottom layout
bottom_layout.addWidget(icon_label)
# add version information label
version_label = QtWidgets.QLabel("{}".format(TOOL_VERSION))
version_label.setStyleSheet("color: gray; font-size: 12px;")
bottom_layout.addWidget(version_label)
# add a stretchable space to push the help and language buttons to the right
bottom_layout.addStretch()
# add help and language buttons
bottom_layout.addWidget(self.help_btn)
bottom_layout.addWidget(self.lang_btn)
# add bottom layout to main layout
main_layout.addLayout(bottom_layout)
def create_connections(self):
# Modeling tab connections
self.modeling_xray_btn.clicked.connect(self.run_xray)
self.modeling_joint_xray_btn.clicked.connect(self.run_joint_xray)
self.modeling_rename_btn.clicked.connect(self.run_rename)
self.modeling_batch_import_btn.clicked.connect(self.run_batch_import)
self.modeling_quick_export_btn.clicked.connect(self.run_quick_export)
self.modeling_task_path_builder_btn.clicked.connect(self.run_task_path_builder)
self.modeling_interval_select_edge_btn.clicked.connect(self.run_select_edge)
self.modeling_same_position_selector_btn.clicked.connect(self.run_same_position_selector)
self.modeling_edge_loop_smart_select_btn.clicked.connect(self.run_edge_loop_smart_select)
self.modeling_even_edge_loop_btn.clicked.connect(self.run_even_edge_loop)
self.modeling_crease_plus_btn.clicked.connect(self.run_crease_plus)
self.modeling_speed_cut_btn.clicked.connect(self.run_speed_cut)
self.modeling_modit_btn.clicked.connect(self.run_modit)
self.modeling_plugit_btn.clicked.connect(self.run_plugit)
self.modeling_zirail_btn.clicked.connect(self.run_zirail)
self.modeling_xgtools_btn.clicked.connect(self.run_xgtools)
self.modeling_edge_sensei_btn.clicked.connect(self.run_edge_sensei)
self.modeling_round_inset_btn.clicked.connect(self.run_round_inset)
self.modeling_arc_deformer_btn.clicked.connect(self.run_arc_deformer)
self.modeling_instant_drag_btn.clicked.connect(self.run_instant_drag)
self.modeling_unbevel_btn.clicked.connect(self.run_unbevel)
self.modeling_speed_bend_btn.clicked.connect(self.run_speed_bend)
self.modeling_align_edge_btn.clicked.connect(self.run_align_edge)
self.modeling_extra_curve_btn.clicked.connect(self.run_extra_curve)
self.modeling_auto_snap_btn.clicked.connect(self.run_auto_snap)
self.modeling_xgen_controller_btn.clicked.connect(self.run_xgen_controller)
self.modeling_quad_remesher_btn.clicked.connect(self.run_quad_remesher)
self.modeling_morph_to_uv_btn.clicked.connect(self.run_morph_to_uv)
self.modeling_ldmt_btn.clicked.connect(self.run_ldmt)
self.modeling_simplify_btn.clicked.connect(self.run_simplify)
self.modeling_gs_curve_tools_btn.clicked.connect(self.run_gs_curve_tools)
self.modeling_reset_gs_curve_tools_btn.clicked.connect(self.reset_gs_curve_tools)
self.modeling_close_gs_curve_tools_btn.clicked.connect(self.stop_gs_curve_tools)
self.modeling_ahoge_btn.clicked.connect(self.run_ahoge)
self.modeling_export_xgen_to_groom_btn.clicked.connect(self.run_export_xgen_to_groom)
self.modeling_export_xgen_description_btn.clicked.connect(self.run_export_xgen_description)
self.modeling_uv_set_editor_btn.clicked.connect(self.run_uv_set_editor)
self.modeling_uvdeluxe_btn.clicked.connect(self.run_uvdeluxe)
self.modeling_rizom_uv_bridge_btn.clicked.connect(self.run_rizom_uv_bridge)
self.modeling_check_uv_bleed_btn.clicked.connect(self.run_check_uv_bleed)
self.modeling_overlap_uv_out_btn.clicked.connect(self.run_overlap_uv_out)
self.modeling_overlap_uv_in_btn.clicked.connect(self.run_overlap_uv_in)
self.modeling_switch_uv_set_btn.clicked.connect(self.run_switch_uv_set)
self.modeling_instant_mesh_btn.clicked.connect(self.run_instant_mesh)
self.modeling_topo_blendshape_btn.clicked.connect(self.run_topo_blendshape)
self.modeling_face_transfer_btn.clicked.connect(self.run_face_transfer)
self.modeling_cloth_transfer_btn.clicked.connect(self.run_cloth_transfer)
self.modeling_marvelous_tool_btn.clicked.connect(self.run_marvelous_tool)
# Metahuman tab connections
self.metahuman_body_prepare_btn.clicked.connect(self.run_body_prepare)
self.metahuman_batch_import_btn.clicked.connect(self.run_batch_import)
# Rigging tab connections
self.rigging_advanced_skeleton_btn.clicked.connect(self.run_advanced_skeleton)
self.rigging_weight_export_btn.clicked.connect(self.run_weight_export)
self.rigging_weight_import_btn.clicked.connect(self.run_weight_import)
self.rigging_unbind_skin_btn.clicked.connect(self.run_unbind_skin)
# Animation tab connections
self.animation_animschool_picker_btn.clicked.connect(self.run_anim_school_picker)
self.animation_dwpicker_btn.clicked.connect(self.run_dwpicker)
self.animation_bhghost_btn.clicked.connect(self.run_bhghost)
self.animation_ikfk_switch_btn.clicked.connect(self.run_ik_fk_switch)
self.animation_atools_btn.clicked.connect(self.open_aTools)
self.animation_keyframepro_btn.clicked.connect(self.open_keyframe_pro)
self.animation_studiolibrary_btn.clicked.connect(self.open_studio_library)
# self.animation_ikfk_mocap_btn.clicked.connect(self.run_ikfk_mocap)
self.animation_motioncap_helper_btn.clicked.connect(self.run_motioncap_helper)
self.animation_spring_magic_btn.clicked.connect(self.run_spring_magic)
self.animation_epic_pose_wrangler_btn.clicked.connect(self.open_epic_pose_wrangler)
self.animation_morph_shape_btn.clicked.connect(self.run_morph_shape)
self.animation_universal_rig_adapter_btn.clicked.connect(self.run_universal_rig_adapter)
# Dev tab connections
self.dev_icon_viewer_btn.clicked.connect(self.run_icon_viewer)
self.debug_scene_btn.clicked.connect(self.run_debug_scene)
self.debug_cleanm_btn.clicked.connect(self.run_debug_cleanm)
self.debug_normal_btn.clicked.connect(self.run_debug_normal)
self.debug_keephs_btn.clicked.connect(self.run_debug_keephs)
self.debug_xgen_btn.clicked.connect(self.run_debug_xgen)
self.debug_rename_btn.clicked.connect(self.run_debug_rename)
self.debug_delname_btn.clicked.connect(self.run_debug_delname)
self.debug_ungroup_btn.clicked.connect(self.run_debug_ungroup)
self.debug_reverse_btn.clicked.connect(self.run_debug_reverse)
# connect help button
self.help_btn.clicked.connect(self.show_help)
# connect language switch button
self.lang_btn.clicked.connect(self.toggle_language)
#========================================================================== FUNCTIONS ==========================================================================
def show_error(self, task, e):
ERROR_MESSAGE = "Error occurred while running {}: {}".format(task, e)
cmds.warning(ERROR_MESSAGE)
cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK')
return False
def not_run_in_2025(self, task,version=2025):
maya_version = cmds.about(version=True)
if int(maya_version) >= version:
cmds.confirmDialog(title='Warning', message="{} is not supported in Maya {} now.".format(task, version), button=['OK'], defaultButton='OK')
return True
else:
return False
def not_run_in_py2(self, task):
maya_version = cmds.about(version=True)
if int(maya_version) <= 2020:
cmds.confirmDialog(title='Warning', message="{} is not supported in Maya 2020 and below.".format(task), button=['OK'], defaultButton='OK')
return True
else:
return False
def has_pymel(self):
try:
import pymel.core as pm
return True
except:
cmds.confirmDialog(title='Error', message='No pymel found, please install pymel first', button=['OK'])
return False
# Modeling Functions
# ****************************************************************************************************************
# Display
@task_reporter_decorator(tool_name='MetaBox', task_name='Xray', debug=debug_mode, time_saved=1)
def run_xray(self, *args):
try:
result = cmds.modelEditor('modelPanel4', q=True, xr=True)
cmds.modelEditor('modelPanel4', e=True, xr=not result)
except Exception as e:
return self.show_error('Xray', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='XrayJoint', debug=debug_mode, time_saved=3)
def run_joint_xray(self, *args):
try:
result = cmds.modelEditor('modelPanel4', q=True, jx=True)
cmds.modelEditor('modelPanel4', e=True, jx=not result)
except Exception as e:
return self.show_error('XrayJoint', e)
# Manage
@task_reporter_decorator(tool_name='MetaBox', task_name='Rename', debug=debug_mode, time_saved=30)
def run_rename(self, *args):
try:
Rename_Path = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Manage', 'Rename.py')).replace('\\', '/')
sys.path.append(Rename_Path)
Rename.UI()
except Exception as e:
return self.show_error('Rename', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='BatchImport', debug=debug_mode, time_saved=5)
def run_batch_import(self, *args):
try:
BatchImport_Path = os.path.normpath(os.path.join(TOOL_PATH, 'Metahuman', 'Custom', 'BatchImport.py')).replace('\\', '/')
if BatchImport_Path not in sys.path:
sys.path.append(BatchImport_Path)
from Metahuman.Custom import BatchImport
BatchImport.run()
except Exception as e:
return self.show_error('BatchImport', e)
# Edit
@task_reporter_decorator(tool_name='MetaBox', task_name='CreasePlus', debug=debug_mode, time_saved=60)
def run_crease_plus(self, *args):
try:
if self.not_run_in_2025('CreasePlus'): return False
crease_plus_dir = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'CreasePlus')).replace('\\', '/')
print("CreasePlus directory: {}".format(crease_plus_dir))
if crease_plus_dir not in sys.path:
sys.path.append(crease_plus_dir)
from Modeling.Edit.CreasePlus import CreasePlusMain
CreasePlusMain.start()
print("CreasePlus loaded successfully")
return True
except Exception as e:
return self.show_error('CreasePlus', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='SpeedCut', debug=debug_mode, time_saved=10)
def run_speed_cut(self, *args):
try:
SpeedCut.run()
except Exception as e:
return self.show_error('SpeedCut', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='GS Curve Tools', debug=debug_mode, time_saved=100)
def run_gs_curve_tools(self, *args):
try:
if self.not_run_in_2025('GS Curve Tools'): return False
gs_curvetools_path = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'gs_curvetools')).replace('\\', '/')
if gs_curvetools_path not in sys.path:
sys.path.insert(0, gs_curvetools_path)
gs_curvetools_sub_path = [
os.path.join(gs_curvetools_path, 'fonts').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'icons').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'plugins').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'utils').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'constants').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'core').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'main').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'ui').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'uv_editor').replace('\\', '/')
]
for path in gs_curvetools_sub_path:
if path not in sys.path:
sys.path.insert(0, path)
from Modeling.Edit.gs_curvetools import main as ct_main
# Run the main function
ct_main.main()
except Exception as e:
return self.show_error('GS Curve Tools', e)
def stop_gs_curve_tools(self, *args):
try:
gs_curvetools_path = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'gs_curvetools')).replace('\\', '/')
if gs_curvetools_path not in sys.path:
sys.path.insert(0, gs_curvetools_path)
from Modeling.Edit.gs_curvetools.utils import utils as ct_ut
ct_ut.stopUI()
except Exception as e:
return self.show_error('GS Curve Tools', e)
def reset_gs_curve_tools(self, *args):
try:
gs_curvetools_path = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'gs_curvetools')).replace('\\', '/')
if gs_curvetools_path not in sys.path:
sys.path.insert(0, gs_curvetools_path)
from Modeling.Edit.gs_curvetools.utils import utils as ct_ut
ct_ut.resetOptionVars()
def __getMayaOS():
"""Get Maya version and parent OS"""
maya = str(cmds.about(api=1))[:4]
os = str(cmds.about(os=1))
return [int(maya), os]
logger = ct_ut.Logger()
MAYA_VER = __getMayaOS()[0]
LOGGER = logger.logger
if MAYA_VER >= 2018:
ct_ut.stopUI(True)
# Reload all files
gs_curvetools_subpaths = [
os.path.join(gs_curvetools_path, 'constants').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'core').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'main').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'ui').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'uv_editor').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'utils').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'utils', 'gs_math').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'utils', 'style').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'utils', 'tooltips').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'utils', 'utils').replace('\\', '/'),
os.path.join(gs_curvetools_path, 'utils', 'wrap').replace('\\', '/')
]
for subpath in gs_curvetools_subpaths:
if subpath not in sys.path:
sys.path.insert(0, subpath)
from Modeling.Edit.gs_curvetools import main as ct_main
ct_main.main()
except Exception as e:
return self.show_error('GS Curve Tools', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Export XGen to Groom', debug=debug_mode, time_saved=20)
def run_export_xgen_to_groom(self, *args):
try:
import Modeling.Edit.XGenUEGroomExporter as ExportXGenToGroom
ExportXGenToGroom.run()
except Exception as e:
return self.show_error('Export XGen to Groom', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Export XGen Description', debug=debug_mode, time_saved=20)
def run_export_xgen_description(self, *args):
try:
import Modeling.Edit.XGenDescriptionUEGroomExporter as ExportXGenDescription
ExportXGenDescription.run()
except Exception as e:
return self.show_error('Export XGen Description', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='ModIt', debug=debug_mode, time_saved=30)
def run_modit(self, *args):
try:
modit_path = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'ModIt')).replace('\\', '/')
if modit_path not in sys.path:
sys.path.append(modit_path)
modlit_sub_paths = [
modit_path,
os.path.join(modit_path, 'Classes'),
os.path.join(modit_path, 'Icons'),
os.path.join(modit_path, 'Mesh'),
os.path.join(modit_path, 'Preferences'),
os.path.join(modit_path, 'Shaders'),
os.path.join(modit_path, 'Tools')
]
for path in modlit_sub_paths:
if path not in sys.path:
sys.path.append(path)
os.environ['MAYA_PLUG_IN_PATH'] = os.pathsep.join(modlit_sub_paths)
modit_ui_path = os.path.join(modit_path, 'ModIt_UI.py').replace('\\', '/')
if modit_ui_path not in sys.path:
sys.path.append(os.path.dirname(modit_ui_path))
from Modeling.Edit.ModIt import ModIt_UI
# #importlib.reload(ModIt_UI)
ModIt_UI.run()
except Exception as e:
return self.show_error('ModIt', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='PlugIt', debug=debug_mode, time_saved=50)
def run_plugit(self, *args):
try:
if self.not_run_in_2025('PlugIt'): return False
if self.not_run_in_py2('PlugIt'): return False
PlugIt_Path = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'PlugIt')).replace('\\', '/')
plugIt_sub_paths = [
os.path.join(PlugIt_Path, 'Icons'),
os.path.join(PlugIt_Path, 'LIBRARY'),
os.path.join(PlugIt_Path, 'PlugIt_Creation'),
os.path.join(PlugIt_Path, 'Preferences'),
os.path.join(PlugIt_Path, 'Tools'),
]
for path in plugIt_sub_paths:
if path not in sys.path:
sys.path.append(path)
os.environ['MAYA_PLUG_IN_PATH'] = os.pathsep.join(plugIt_sub_paths)
plugIt_ui_path = os.path.join(PlugIt_Path, 'PlugIt_UI.py').replace('\\', '/')
if plugIt_ui_path not in sys.path:
sys.path.append(os.path.dirname(plugIt_ui_path))
from Modeling.Edit.PlugIt import PlugIt_UI
# #importlib.reload(PlugIt_UI)
PlugIt_UI.showUI()
except Exception as e:
return self.show_error('PlugIt', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Groomers Tools', debug=debug_mode, time_saved=10)
def run_xgtools(self, *args):
try:
if self.not_run_in_2025('Groomers Tools'): return False
if self.not_run_in_py2('Groomers Tools'): return False
import maya.cmds as cmds
# print("Successfully imported maya.cmds")
import sys
import os
import traceback
XGTC_PARENT_PATH = os.path.join(TOOL_PATH, 'Modeling', 'Edit')
if XGTC_PARENT_PATH not in sys.path:
sys.path.insert(0, XGTC_PARENT_PATH)
xgtc_path = os.path.join(XGTC_PARENT_PATH, 'xgtc').replace('\\', '/')
if xgtc_path not in sys.path:
sys.path.insert(0, xgtc_path)
xgtc_scripts_path = os.path.join(xgtc_path, 'scripts').replace('\\', '/')
if xgtc_scripts_path not in sys.path:
sys.path.insert(0, xgtc_scripts_path)
xgtc_icons_path = os.path.join(xgtc_path, 'icons').replace('\\', '/')
if xgtc_icons_path not in sys.path:
sys.path.insert(0, xgtc_icons_path)
from Modeling.Edit.xgtc.scripts import xgToolsUI_user_sub
print("Successfully imported XGTools modules")
xgToolsUI_user_sub.xgToolsUI()
except ImportError as e:
return self.show_error('XGTools', e)
except Exception as e:
return self.show_error('XGTools', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='ziRail', debug=debug_mode, time_saved=80)
def run_zirail(self, *args):
try:
if self.not_run_in_2025('ziRail'): return False
# Get Maya version
MAYA_VERSION = cmds.about(version=True).split()[0]
if MAYA_VERSION == '2018' or MAYA_VERSION == '2019' or MAYA_VERSION == '2020':
ZIRAIL_PATH = os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'ziRail', '2018_2020').replace('\\', '/')
ZIRAIL_PLUGIN_PATH = os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'ziRail', '2018_2020', 'plug-ins').replace('\\', '/')
for plugin in ['ziRail_{}.mll'.format(MAYA_VERSION), 'ziWireframeViewport_{}.mll'.format(MAYA_VERSION)]:
plugin_path = os.path.join(ZIRAIL_PLUGIN_PATH, plugin)
if os.path.exists(plugin_path):
if not cmds.pluginInfo(plugin_path, query=True, loaded=True):
cmds.loadPlugin(plugin_path)
else:
print("Warning: Plugin file does not exist: {}".format(plugin_path))
elif MAYA_VERSION == '2022' or MAYA_VERSION == '2023':
ZIRAIL_PATH = os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'ziRail', '2022_2023').replace('\\', '/')
ZIRAIL_PLUGIN_PATH = os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'ziRail', '2022_2023', 'plug-ins').replace('\\', '/')
for plugin in ['ziRail_{}.mll'.format(MAYA_VERSION), 'ziWireframeViewport_{}.mll'.format(MAYA_VERSION)]:
plugin_path = os.path.join(ZIRAIL_PLUGIN_PATH, plugin)
if os.path.exists(plugin_path):
if not cmds.pluginInfo(plugin_path, query=True, loaded=True):
cmds.loadPlugin(plugin_path)
else:
print("Warning: Plugin file does not exist: {}".format(plugin_path))
if os.path.exists(ZIRAIL_PLUGIN_PATH):
os.environ['MAYA_PLUG_IN_PATH'] = os.pathsep.join([os.environ.get('MAYA_PLUG_IN_PATH', ''), ZIRAIL_PLUGIN_PATH])
else:
ERROR_MESSAGE = "Error occurred while running ziRail: Maya version {} is not supported".format(MAYA_VERSION)
cmds.warning(ERROR_MESSAGE)
cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK')
return False
# Check if ZIRAIL_PATH exists before adding to sys.path
if os.path.exists(ZIRAIL_PATH) and ZIRAIL_PATH not in sys.path:
sys.path.insert(0, ZIRAIL_PATH)
# Import and run the appropriate ziRail module
if MAYA_VERSION in ['2018', '2019', '2020']:
zi_rail = importlib.import_module('Modeling.Edit.ziRail.2018_2020.zi_rail')
elif MAYA_VERSION in ['2022', '2023']:
zi_rail = importlib.import_module('Modeling.Edit.ziRail.2022_2023.zi_rail')
else:
ERROR_MESSAGE = "Error occurred while running ziRail: Maya version {} is not supported".format(MAYA_VERSION)
cmds.warning(ERROR_MESSAGE)
cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK')
return
# #importlib.reload(zi_rail)
zi_rail.main()
except Exception as e:
return self.show_error('ziRail', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Edge Sensei', debug=debug_mode, time_saved=80)
def run_edge_sensei(self, *args):
try:
EdgeSensei.run()
except Exception as e:
return self.show_error('EdgeSensei', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Even Edge Loop', debug=debug_mode, time_saved=10)
def run_even_edge_loop(self, *args):
try:
EvenEdgeLoop.run()
except Exception as e:
return self.show_error('EvenEdgeLoop', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Speed Bend', debug=debug_mode, time_saved=50)
def run_speed_bend(self, *args):
try:
SpeedBend.run()
except Exception as e:
return self.show_error('SpeedBend', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Poly Fold', debug=debug_mode, time_saved=10)
def run_poly_fold(self, *args):
try:
PolyFold.run()
except Exception as e:
return self.show_error('PolyFold', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Round Inset', debug=debug_mode, time_saved=10)
def run_round_inset(self, *args):
try:
RoundInset.run()
except Exception as e:
return self.show_error('RoundInset', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Arc Deformer', debug=debug_mode, time_saved=30)
def run_arc_deformer(self, *args):
try:
ArcDeformer.run()
except Exception as e:
return self.show_error('ArcDeformer', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Instant Drag', debug=debug_mode, time_saved=10)
def run_instant_drag(self, *args):
try:
InstantDrag.run()
except Exception as e:
return self.show_error('InstantDrag', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='UnBevel', debug=debug_mode, time_saved=5)
def run_unbevel(self, *args):
try:
UnBevel.run()
except Exception as e:
return self.show_error('UnBevel', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='ExtractCurve', debug=debug_mode, time_saved=20)
def run_extra_curve(self, *args):
try:
sel = cmds.ls(sl=True, flatten=True)
sel_edge = [o for o in sel if ".e[" in o]
if len(sel_edge) == 0:
cmds.warning('Please select at least one edge')
return False
mel.eval('polyToCurve -form 2 -degree 3 -conformToSmoothMeshPreview 1')
except Exception as e:
return self.show_error('ExtractCurve', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Auto Snap', debug=debug_mode, time_saved=30)
def run_auto_snap(self, *args):
try:
AutoSnap.cmd()
except Exception as e:
return self.show_error('AutoSnap', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Xgen Controller', debug=debug_mode, time_saved=30)
def run_xgen_controller(self, *args):
try:
XgenController.create_window()
except Exception as e:
return self.show_error('XgenController', e)
# Select
@task_reporter_decorator(tool_name='MetaBox', task_name='Edge Loop Smart Select', debug=debug_mode, time_saved=10)
def run_edge_loop_smart_select(self, *args):
try:
EdgeLoopSmartSelect.run()
except Exception as e:
return self.show_error('EdgeLoopSmartSelect', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Interval Select Edge', debug=debug_mode, time_saved=5)
def run_select_edge(self, *args):
try:
IntervalSelectEdge.show()
except Exception as e:
return self.show_error('IntervalSelectEdge', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Same Position Selector', debug=debug_mode, time_saved=20)
def run_same_position_selector(self, *args):
try:
SamePositionSelector.show()
except Exception as e:
return self.show_error('SamePositionSelector', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Align Edge', debug=debug_mode, time_saved=5)
def run_align_edge(self, *args):
try:
AlignEdge.run()
except Exception as e:
return self.show_error('AlignEdge', e)
# UV
@task_reporter_decorator(tool_name='MetaBox', task_name='UV Set Editor', debug=debug_mode, time_saved=10)
def run_uv_set_editor(self, *args):
try:
UVSetEditor.show()
except Exception as e:
return self.show_error('UVSetEditor', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='UVDeluxe', debug=debug_mode, time_saved=10)
def run_uvdeluxe(self, *args):
try:
if not self.has_pymel(): return False
from Modeling.UV.UVDeluxe import uvdeluxe
uvdeluxe.createUI()
except Exception as e:
return self.show_error('UVDeluxe', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='RizomUV Bridge', debug=debug_mode, time_saved=10)
def run_rizom_uv_bridge(self, *args):
try:
RIZOMUV_PATH = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'UV', 'RizomUVBridge')).replace('\\', '/')
if RIZOMUV_PATH not in sys.path:
sys.path.insert(0, RIZOMUV_PATH)
RIZOMUV_LUA_PATH = os.path.join(RIZOMUV_PATH, 'RizomUVBridge.lua').replace('\\', '/')
if RIZOMUV_LUA_PATH not in sys.path:
sys.path.insert(0, RIZOMUV_LUA_PATH)
from Modeling.UV.RizomBridge import RizomUVBridge
RizomUVBridge.run()
except Exception as e:
return self.show_error('RizomUVBridge', e)
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Rigging Functions
# ****************************************************************************************************************
@task_reporter_decorator(tool_name='MetaBox', task_name='Advanced Skeleton', debug=debug_mode, time_saved=5)
def run_advanced_skeleton(self, *args):
try:
adv_sub_path = [
os.path.join(TOOL_PATH, 'Animation', 'AdvancedSkeleton').replace('\\', '/'),
os.path.join(TOOL_PATH, 'Animation', 'AdvancedSkeleton', 'AdvancedSkeleton5Files').replace('\\', '/')
]
for path in adv_sub_path:
if path not in sys.path:
sys.path.insert(0, path)
# If advancedSkeleton5Files does not exist, run the adv_install.py and the launch.py, else run the adv_launch.py directly
if not os.path.exists(os.path.join(TOOL_PATH, 'Animation', 'AdvancedSkeleton', 'adv_install.py').replace('\\', '/')):
from Animation.AdvancedSkeleton import adv_install
adv_install.install()
from Animation.AdvancedSkeleton import adv_launch
adv_launch.launch()
except Exception as e:
return self.show_error('AdvancedSkeleton', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Weight Export', debug=debug_mode, time_saved=10)
def run_weight_export(self, *args):
try:
skin_api_path = os.path.normpath(os.path.join(TOOL_PATH, 'Animation')).replace('\\', '/')
if skin_api_path not in sys.path:
sys.path.insert(0, skin_api_path)
import Animation.skin_api.apiVtxAttribs as apiVA
msg = apiVA.ApiVtxAttribs().exportSkinWeights(selected=True)
print(msg)
except Exception as e:
return self.show_error('WeightExport', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Weight Import', debug=debug_mode, time_saved=10)
def run_weight_import(self, *args):
try:
skin_api_path = os.path.normpath(os.path.join(TOOL_PATH, 'Animation')).replace('\\', '/')
if skin_api_path not in sys.path:
sys.path.insert(0, skin_api_path)
import Animation.skin_api.apiVtxAttribs as apiVA
msg = apiVA.ApiVtxAttribs().importSkinWeights(selected=True)
print(msg)
except Exception as e:
return self.show_error('WeightImport', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Unbind Skin', debug=debug_mode, time_saved=10)
def run_unbind_skin(self, *args):
try:
mel.eval("doDetachSkin \"2\" { \"1\",\"1\" };")
print("已取消蒙皮!")
except Exception as e:
return self.show_error('UnbindSkin', e)
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Metahuman Functions
# ****************************************************************************************************************
# Preparation
@task_reporter_decorator(tool_name='MetaBox', task_name='Body Prepare', debug=debug_mode, time_saved=10)
def run_body_prepare(self, *args):
try:
BodyPrep.run()
except Exception as e:
return self.show_error('BodyPrepare', e)
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Animation Functions
# ****************************************************************************************************************
# Pose
@task_reporter_decorator(tool_name='MetaBox', task_name='aTools', debug=debug_mode, time_saved=30)
def open_aTools(self, *args):
try:
if self.not_run_in_py2('aTools'): return False
# Get aTools path
ATOOLS_PATH = os.path.normpath(os.path.join(TOOL_PATH, 'Animation', 'aTools')).replace('\\', '/')
if ATOOLS_PATH not in sys.path:
sys.path.insert(0, ATOOLS_PATH)
ATOOLS_PARENT_PATH = os.path.dirname(ATOOLS_PATH)
if ATOOLS_PARENT_PATH not in sys.path:
sys.path.insert(0, ATOOLS_PARENT_PATH)
atools = importlib.import_module('aTools')
#importlib.reload(atools)
animTools = importlib.import_module('aTools.animTools')
#importlib.reload(animTools)
animBar = importlib.import_module('aTools.animTools.animBar')
#importlib.reload(animBar)
animBarUI = importlib.import_module('aTools.animTools.animBar.animBarUI')
#importlib.reload(animBarUI)
animBarUI.show('refresh')
except Exception as e:
return self.show_error('aTools', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Keyframe Pro', debug=debug_mode, time_saved=10)
def open_keyframe_pro(self, *args):
try:
KEYFRAME_PRO_PATH = [
os.path.join(TOOL_PATH, 'Animation', 'keyframe_pro'),
os.path.join(TOOL_PATH, 'Animation', 'keyframe_pro', 'keyframe_pro'),
os.path.join(TOOL_PATH, 'Animation', 'keyframe_pro', 'keyframe_pro_maya')
]
for path in KEYFRAME_PRO_PATH:
if path not in sys.path:
sys.path.insert(0, path)
for path in sys.path:
print("Added the keyframe_Pro submoudle path: ", path)
from Animation.keyframe_pro.keyframe_pro_maya.maya_to_keyframe_pro import MayaToKeyframePro
MayaToKeyframePro.display()
except Exception as e:
return self.show_error('KeyframePro', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='DWPicker', debug=debug_mode, time_saved=10)
def run_dwpicker(self, *args):
try:
DWPICKER_PATH = os.path.normpath(os.path.join(TOOL_PATH, 'Animation', 'dwpicker')).replace('\\', '/')
if DWPICKER_PATH not in sys.path:
sys.path.insert(0, DWPICKER_PATH)
DWPICKER_SUB_PATHS = [
os.path.join(DWPICKER_PATH, 'scripts'),
os.path.join(DWPICKER_PATH, 'dwpicker')
]
for path in DWPICKER_SUB_PATHS:
if path not in sys.path:
sys.path.insert(0, path)
# for path in sys.path:
# print("Added the dwpicker submoudle path: ", path)
from Animation.dwpicker import dwpicker
dwpicker.show()
except Exception as e:
return self.show_error('dwpicker', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Studio Library', debug=debug_mode, time_saved=30)
def open_studio_library(self, *args):
try:
STUDIOLIBRARY_PATH = os.path.normpath(os.path.join(TOOL_PATH, 'Animation', 'studiolibrary')).replace('\\', '/')
STUDIOLIBRARY_SUB_PATHS = [
os.path.join(STUDIOLIBRARY_PATH, 'src'),
os.path.join(STUDIOLIBRARY_PATH, 'src', 'studiolibrary'),
os.path.join(STUDIOLIBRARY_PATH, 'src', 'studiolibrarymaya'),
os.path.join(STUDIOLIBRARY_PATH, 'src', 'studioqt'),
os.path.join(STUDIOLIBRARY_PATH, 'src', 'mutils'),
os.path.join(STUDIOLIBRARY_PATH, 'src', 'studiovendor')
]
# Added the main path to sys.path
if STUDIOLIBRARY_PATH not in sys.path:
sys.path.insert(0, STUDIOLIBRARY_PATH)
# Added the sub path to sys.path
for path in STUDIOLIBRARY_SUB_PATHS:
if path not in sys.path:
sys.path.insert(0, path.replace('\\', '/'))
for path in sys.path:
print("Added the studiolibrary submoudle path: ", path)
# Import studiolibrary from the STUDIOLIBRARY_PATH with importlib
studiolibrary = importlib.import_module('studiolibrary')
# #importlib.reload(studiolibrary)
# Run studiolibrary
studiolibrary.main()
except Exception as e:
return self.show_error('StudioLibrary', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Anim School Picker', debug=debug_mode, time_saved=20)
def run_anim_school_picker(self, *args):
try:
if self.not_run_in_2025('Anim School Picker'): return False
# Added the path to the AnimSchoolPicker.mel file
ANIMPICKER_PATH = os.path.normpath(os.path.join(TOOL_PATH, 'Animation', 'AnimSchoolPicker')).replace('\\', '/')
if ANIMPICKER_PATH not in sys.path:
sys.path.insert(0, ANIMPICKER_PATH)
# Get Maya Version
MAYA_VERSION = cmds.about(version=True).split()[0]
# Set plugin path
ANIMPICKER_PLUGIN_PATH = os.path.join(ANIMPICKER_PATH, MAYA_VERSION).replace('\\', '/')
# Added the plugin path to MAYA_PLUG_IN_PATH
os.environ['MAYA_PLUG_IN_PATH'] = ANIMPICKER_PLUGIN_PATH
# load the plugin
animpicker_mll = os.path.join(ANIMPICKER_PLUGIN_PATH, 'AnimSchoolPicker.mll').replace('\\', '/')
cmds.loadPlugin(animpicker_mll, quiet=True)
cmds.AnimSchoolPicker()
print("Anim School Picker loaded successfully from {}".format(animpicker_mll))
except Exception as e:
return self.show_error('AnimSchoolPicker', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='bhGhost', debug=debug_mode, time_saved=5)
def run_bhghost(self, *args):
try:
bhghost_path = os.path.normpath(os.path.join(TOOL_PATH, 'Animation', 'bhGhost')).replace('\\', '/')
print(bhghost_path)
if bhghost_path not in sys.path:
sys.path.insert(0, bhghost_path)
bhghost_mel = os.path.join(bhghost_path, 'bhGhost.mel').replace('\\', '/')
print(bhghost_mel)
mel.eval('source "{}";'.format(bhghost_mel))
print("bhGhost loaded successfully from {}".format(bhghost_mel))
except Exception as e:
return self.show_error('bhGhost', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='IK/FK Switch', debug=debug_mode, time_saved=10)
def run_ik_fk_switch(self, *args):
try:
if not self.has_pymel(): return False
from Animation import mog_ikFkSwitchFree
mog_ikFkSwitchFree.FkIk_UI()
except Exception as e:
return self.show_error('IK/FK Switch', e)
# Blendshape
@task_reporter_decorator(tool_name='MetaBox', task_name='Epic Pose Wrangler', debug=debug_mode, time_saved=20)
def open_epic_pose_wrangler(self, *args):
try:
if self.not_run_in_2025('Epic Pose Wrangler'): return False
epic_pose_wrangler_path = os.path.join(TOOL_PATH, 'Animation', 'epic_pose_wrangler').replace('\\', '/')
sys.path.append(epic_pose_wrangler_path)
print(epic_pose_wrangler_path)
print("Attempting to import Epic Pose Wrangler from: {}".format(epic_pose_wrangler_path))
MAYA_VERSION = cmds.about(version=True).split()[0]
plugin_dir = os.path.join(epic_pose_wrangler_path, 'plugins', 'Windows', MAYA_VERSION)
for plugin in ['embeddedRL4.mll', 'MayaUE4RBFPlugin{}.mll'.format(MAYA_VERSION), 'MayaUERBFPlugin.mll']:
plugin_path = os.path.join(plugin_dir, plugin)
if os.path.exists(plugin_path):
if not cmds.pluginInfo(plugin_path, query=True, loaded=True):
cmds.loadPlugin(plugin_path)
else:
print("Warning: Plugin file does not exist: {}".format(plugin_path))
sys.path.insert(0, os.path.dirname(epic_pose_wrangler_path))
from Animation.epic_pose_wrangler import main
pose_wrangler = main.PoseWrangler()
cmds.inViewMessage(amg='Epic Pose Wrangler loaded successfully', pos='midCenter', fade=True)
except Exception as e:
return self.show_error('EpicPoseWrangler', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Universal Rig Adapter', debug=debug_mode, time_saved=50)
def run_universal_rig_adapter(self, *args):
try:
UniversalRigAdapter.run()
except Exception as e:
return self.show_error('UniversalRigAdapter', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Morph Shape', debug=debug_mode, time_saved=30)
def run_morph_shape(self, *args):
try:
MorphShape.show()
except Exception as e:
return self.show_error('MorphShape', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Icon Viewer', debug=debug_mode, time_saved=10)
def run_icon_viewer(self, *args):
try:
from Dev.mayaiconview import create_icon_viewer
create_icon_viewer()
except Exception as e:
return self.show_error('IconViewer', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='MotionCap Helper', debug=debug_mode, time_saved=20)
def run_motioncap_helper(self, *args):
try:
if self.not_run_in_2025('MotionCap Helper'): return False
plugin_folder = os.path.join(TOOL_PATH, 'Animation', 'MotionCapHelper', 'bin').replace('\\', '/')
if plugin_folder not in sys.path:
sys.path.append(plugin_folder)
os.environ['MAYA_PLUG_IN_PATH'] = os.pathsep.join([os.environ.get('MAYA_PLUG_IN_PATH', ''), plugin_folder])
plugin_path = os.path.join(plugin_folder, "mocaphelper.py").replace('\\', '/')
if not cmds.pluginInfo(plugin_path, query=True, loaded=True):
cmds.loadPlugin(plugin_path, quiet=True)
mel.eval("moCapHelper_showUi -lan \"CN\"")
except Exception as e:
return self.show_error('MotionCapHelper', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Spring Magic', debug=debug_mode, time_saved=50)
def run_spring_magic(self, *args):
try:
if not self.has_pymel(): return False
from Animation.springmagic import main
main.main()
except Exception as e:
return self.show_error('SpringMagic', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Ahoge', debug=debug_mode, time_saved=30)
def run_ahoge(self, *args):
try:
ahoge_path = os.path.join(TOOL_PATH, 'Modeling', 'Edit','ahoge').replace('\\', '/')
maya_version = cmds.about(version=True).split()[0]
if maya_version not in ['2023', '2024', '2025']:
cmds.warning(u"Ahoge 目前只支持 Maya 2023, 2024, 2025 使用!")
return
plugin_dir = os.path.join(ahoge_path, 'plugins', maya_version)
paths = {
'MAYA_PLUG_IN_PATH': plugin_dir,
'MAYA_SCRIPT_PATH': os.path.join(ahoge_path, 'scripts'),
'XBMLANGPATH': os.path.join(ahoge_path, 'icons'),
'MTOA_EXTENSIONS_PATH': os.path.join(ahoge_path, 'mtoa')
}
for env_var, path in paths.items():
if os.path.exists(path):
current_path = os.environ.get(env_var, '')
if path not in current_path:
if current_path:
os.environ[env_var] = current_path + os.pathsep + path
else:
os.environ[env_var] = path
if env_var == 'MAYA_PLUG_IN_PATH':
mel.eval('putenv "MAYA_PLUG_IN_PATH" "' + os.environ['MAYA_PLUG_IN_PATH'] + '"')
plugin_path = os.path.join(plugin_dir, 'ahoge.mll').replace('\\', '/')
if not cmds.pluginInfo(plugin_path, query=True, loaded=True):
cmds.loadPlugin(plugin_path)
except Exception as e:
return self.show_error('Ahoge', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Quad Remesher', debug=debug_mode, time_saved=30)
def run_quad_remesher(self, *args):
try:
import Modeling.Edit.QuadRemesher.Contents.scripts.QuickInstall as qi
is_installed = qi.quick_install()
if is_installed == 1:
import QuadRemesher
QuadRemesher.QuadRemesher()
except Exception as e:
return self.show_error('QuadRemesher', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='LDMT', debug=debug_mode, time_saved=10)
def run_ldmt(self, *args):
try:
ldmt_path = os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'LDMT').replace('\\', '/')
ldmt_func_path = os.path.join(ldmt_path, 'ldmt_function').replace('\\', '/')
for path in [ldmt_path, ldmt_func_path]:
if path not in sys.path:
sys.path.insert(0, path)
import ldmt_ui
ldmt_ui.show()
except Exception as e:
return self.show_error('LDMT', e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Simplify', debug=debug_mode, time_saved=10)
def run_simplify(self, *args):
try:
maya_version = cmds.about(version=True).split()[0]
# 判断版本对不对
if maya_version != "2018":
cmds.warning(u"Simplify 目前只支持 Maya 2018 使用!")
return
# 判断插件是否存在
simplify_path = "C:/Program Files/Autodesk/Maya2018/bin/plug-ins/eatechmeshtools.mll"
if not os.path.exists(simplify_path):
# 如果插件不存在则运行bat文件
bat_path = os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'Simplify', 'LODTools_2018', 'set_EASimplify.bat').replace('\\', '/')
try:
subprocess.Popen([
'powershell.exe',
'Start-Process',
'"{}"'.format(bat_path),
'-Verb',
'RunAs'
])
cmds.confirmDialog(title='提示', message=u'Simplify 插件已安装成功,请重启 Maya', button=['OK'], defaultButton='OK')
except:
cmds.confirmDialog(title='提示', message=u'Simplify 安装失败!', button=['OK'], defaultButton='OK')
else:
if not cmds.pluginInfo(simplify_path, query=True, loaded=True):
cmds.loadPlugin(simplify_path)
mel.eval("EATechMeshTools_Simplify;")
except Exception as e:
return self.show_error("Simplify", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Instant Meshes', debug=debug_mode, time_saved=20)
def run_instant_mesh(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
# import Modeling.Edit.LDMT.ldmt_ui_frame as ldmt_instantMeshes
import ldmt_instantMeshes
# #importlib.reload(ldmt_instantMeshes)
ldmt_instantMeshes.ldmt_show()
except Exception as e:
return self.show_error("Instant Meshes", e)
def run_topo_blendshape(self, *args):
pass
@task_reporter_decorator(tool_name='MetaBox', task_name='Face Transfer', debug=debug_mode, time_saved=20)
def run_face_transfer(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import faceTransfer.ui as faceui
# #importlib.reload(faceui)
faceui.show()
except Exception as e:
return self.show_error("Face Transfer", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Cloth Transfer', debug=debug_mode, time_saved=20)
def run_cloth_transfer(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_clothTransfer
# #importlib.reload(ldmt_clothTransfer)
ldmt_clothTransfer.ldmt_show()
except Exception as e:
return self.show_error("Cloth Transfer", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Marvelous Tool', debug=debug_mode, time_saved=10)
def run_marvelous_tool(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_marvelousTool
# #importlib.reload(ldmt_marvelousTool)
ldmt_marvelousTool.ldmt_show()
except Exception as e:
return self.show_error("Marvelous Tool", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Morph to UV', debug=debug_mode, time_saved=20)
def run_morph_to_uv(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
from ldmt_function import ldmt_morphToUV
ldmt_morphToUV.runMorph2UV()
except Exception as e:
return self.show_error("Morph to UV", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Quick Export', debug=debug_mode, time_saved=10)
def run_quick_export(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_quickExport
# #importlib.reload(ldmt_quickExport)
ldmt_quickExport.ldmt_show()
except Exception as e:
return self.show_error("Quick Export", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Check UV Bleed', debug=debug_mode, time_saved=20)
def run_check_uv_bleed(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_checkUVBleed
# #importlib.reload(ldmt_checkUVBleed)
ldmt_checkUVBleed.ldmt_show()
except Exception as e:
return self.show_error("Check UV Bleed", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Overlap UV Out', debug=debug_mode, time_saved=5)
def run_overlap_uv_out(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_moveOverlapUVOut
# #importlib.reload(ldmt_moveOverlapUVOut)
ldmt_moveOverlapUVOut.LD_moveOverlapUVOut()
except Exception as e:
return self.show_error("Overlap UV Out", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Overlap UV In', debug=debug_mode, time_saved=5)
def run_overlap_uv_in(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_move2rdUVIn
# #importlib.reload(ldmt_move2rdUVIn)
ldmt_move2rdUVIn.LD_move2rdUVIn()
except Exception as e:
return self.show_error("Overlap UV In", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Switch UV Set', debug=debug_mode, time_saved=5)
def run_switch_uv_set(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
from ldmt_core import ldmt_cmds as ld
sel = ld.ls(0,'mesh')
ld.switchUVSet(sel)
except Exception as e:
return self.show_error("Switch UV Set", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Scene', debug=debug_mode, time_saved=5)
def run_debug_scene(self, *args):
try:
mel.eval("OptimizeSceneOptions")
except Exception as e:
return self.show_error("Debug Scene", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Cleanmesh', debug=debug_mode, time_saved=10)
def run_debug_cleanm(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_cleanMesh
# #importlib.reload(ldmt_cleanMesh)
ldmt_cleanMesh.ldmt_show()
except Exception as e:
return self.show_error("Debug Cleanmesh", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Normal', debug=debug_mode, time_saved=5)
def run_debug_normal(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_normalFacet
# #importlib.reload(ldmt_normalFacet)
ldmt_normalFacet.normalFacet()
except Exception as e:
return self.show_error("Debug Normal", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug KeepHS', debug=debug_mode, time_saved=10)
def run_debug_keephs(self, *args):
try:
pass
except Exception as e:
return self.show_error("Debug KeepHS", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Rename', debug=debug_mode, time_saved=10)
def run_debug_rename(self, *args):
try:
melPath = LDMT_PATH + '/patternRename.mel'
message = 'source "' + melPath +'"'
mel.eval(message)
mel.eval('patternRename')
except Exception as e:
return self.show_error("Debug Rename", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Delname', debug=debug_mode, time_saved=10)
def run_debug_delname(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_deleteNamespace
# #importlib.reload(ldmt_deleteNamespace)
ldmt_deleteNamespace.deleteNamespace()
except Exception as e:
return self.show_error("Debug Delname", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Ungroup', debug=debug_mode, time_saved=5)
def run_debug_ungroup(self, *args):
try:
sel = cmds.ls(sl=1)
for i in sel:
try:
cmds.ungroup(i)
except:
pass
except Exception as e:
return self.show_error("Debug Ungroup", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Reverse', debug=debug_mode, time_saved=5)
def run_debug_reverse(self, *args):
try:
if LDMT_PATH not in sys.path:
sys.path.append(LDMT_PATH)
import ldmt_fixReverse
# #importlib.reload(ldmt_fixReverse)
ldmt_fixReverse.fixReverse()
except Exception as e:
return self.show_error("Debug Reverse", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Debug Xgen', debug=debug_mode, time_saved=10)
def run_debug_xgen(self, *args):
try:
guide_nodes = cmds.ls(type='xgmMakeGuide')
if not guide_nodes:
cmds.warning("No XgenGuide nodes found")
return
for node in guide_nodes:
downstream_nodes = cmds.listConnections(node, destination=True)
if not downstream_nodes:
continue
downstream_node = downstream_nodes[0]
cmds.connectAttr(node + '.outputMesh', downstream_node + '.inputMesh', force=True)
print('Connected', node + '.outputMesh', 'to', downstream_node + '.inputMesh')
cmds.connectAttr(node + '.toGuide', downstream_node + '.toMakeGuide', force=True)
print('Connected', node + '.toGuide', 'to', downstream_node + '.toMakeGuide')
except Exception as e:
return self.show_error("Debug Xgen", e)
@task_reporter_decorator(tool_name='MetaBox', task_name='Task Path Builder', debug=debug_mode, time_saved=10)
def run_task_path_builder(self, *args):
try:
if not self.has_pymel(): return False
from Modeling.Manage.NewTask import window_class
window_class()
except Exception as e:
return self.show_error("Task Path Builder", e)
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Help and Language
# ****************************************************************************************************************
def show_help(self):
# Specify the URL of the website you want to open
webbrowser.open(TOOL_HELP_URL)
def toggle_language(self):
global TOOL_LANG
TOOL_LANG = 'en_US' if TOOL_LANG == 'zh_CN' else 'zh_CN'
self.lang_btn.setText("EN" if TOOL_LANG == 'zh_CN' else "CN")
self.retranslate_ui()
QtWidgets.QToolTip.showText(
self.lang_btn.mapToGlobal(QtCore.QPoint(0, -30)),
"Language switched" if TOOL_LANG == 'en_US' else "语言已切换",
self.lang_btn
)
def retranslate_ui(self):
# Update all UI elements
self.setWindowTitle("MetaBox")
self.modeling_tab_btn.setText(LANG[TOOL_LANG]["Modeling"])
self.metahuman_tab_btn.setText(LANG[TOOL_LANG]["Metahuman"])
self.rigging_tab_btn.setText(LANG[TOOL_LANG]["Rigging"])
self.animation_tab_btn.setText(LANG[TOOL_LANG]["Animation"])
self.modeling_display_group.setTitle(LANG[TOOL_LANG]["Display"] )
self.modeling_xray_btn.setText(LANG[TOOL_LANG]["Xray"])
self.modeling_joint_xray_btn.setText(LANG[TOOL_LANG]["Joint Xray"])
self.modeling_manage_group.setTitle(LANG[TOOL_LANG]["Manage"])
self.modeling_rename_btn.setText(LANG[TOOL_LANG]["Rename"])
self.modeling_batch_import_btn.setText(LANG[TOOL_LANG]["Batch Import"])
self.modeling_quick_export_btn.setText(LANG[TOOL_LANG]["Quick Export"])
self.modeling_select_group.setTitle(LANG[TOOL_LANG]["Select"])
self.modeling_interval_select_edge_btn.setText(LANG[TOOL_LANG]["Interval Select Edge"])
self.modeling_same_position_selector_btn.setText(LANG[TOOL_LANG]["Same Position Selector"])
self.modeling_edge_loop_smart_select_btn.setText(LANG[TOOL_LANG]["Edge Loop Smart Select"])
self.modeling_even_edge_loop_btn.setText(LANG[TOOL_LANG]["Even Edge Loop"])
self.modeling_tools_group.setTitle(LANG[TOOL_LANG]["Tools"])
self.modeling_crease_plus_btn.setText(LANG[TOOL_LANG]["Crease Plus"])
self.modeling_speed_cut_btn.setText(LANG[TOOL_LANG]["Speed Cut"])
self.modeling_modit_btn.setText(LANG[TOOL_LANG]["ModIt"])
self.modeling_plugit_btn.setText(LANG[TOOL_LANG]["PlugIt"])
self.modeling_zirail_btn.setText(LANG[TOOL_LANG]["Zirail"])
self.modeling_xgtools_btn.setText(LANG[TOOL_LANG]["Groomer`s Tool"])
self.modeling_edge_sensei_btn.setText(LANG[TOOL_LANG]["Edge Sensei"])
self.modeling_round_inset_btn.setText(LANG[TOOL_LANG]["Round Inset"])
self.modeling_arc_deformer_btn.setText(LANG[TOOL_LANG]["Arc Deformer"])
self.modeling_instant_drag_btn.setText(LANG[TOOL_LANG]["Instant Drag"])
self.modeling_unbevel_btn.setText(LANG[TOOL_LANG]["Un Bevel"])
self.modeling_align_edge_btn.setText(LANG[TOOL_LANG]["Align Edge"])
self.modeling_extra_curve_btn.setText(LANG[TOOL_LANG]["Extra Curve"])
self.modeling_auto_snap_btn.setText(LANG[TOOL_LANG]["Auto Snap"])
self.modeling_xgen_controller_btn.setText(LANG[TOOL_LANG]["Xgen Controller"])
self.modeling_speed_bend_btn.setText(LANG[TOOL_LANG]["Speed Bend"])
self.modeling_gs_curve_tools_group.setTitle(LANG[TOOL_LANG]["GS Curve Tools"])
self.modeling_gs_curve_tools_btn.setText(LANG[TOOL_LANG]["GS Curve Tools"])
self.modeling_reset_gs_curve_tools_btn.setText(LANG[TOOL_LANG]["GS Curve Tools Reset"])
self.modeling_close_gs_curve_tools_btn.setText(LANG[TOOL_LANG]["GS Curve Tools Close"])
self.modeling_export_xgen_to_groom_btn.setText(LANG[TOOL_LANG]["Export XGen to Groom"])
self.modeling_export_xgen_description_btn.setText(LANG[TOOL_LANG]["Export XGen Description"])
self.modeling_uv_group.setTitle(LANG[TOOL_LANG]["UV"])
self.modeling_uvdeluxe_btn.setText(LANG[TOOL_LANG]["UVDeluxe"])
self.modeling_rizom_uv_bridge_btn.setText(LANG[TOOL_LANG]["RizomUV Bridge"])
self.modeling_uv_set_editor_btn.setText(LANG[TOOL_LANG]["UV Set Editor"])
self.metahuman_preparation_group.setTitle(LANG[TOOL_LANG]["Preparation"])
self.metahuman_body_prepare_btn.setText(LANG[TOOL_LANG]["Body Prepare"])
self.metahuman_batch_import_btn.setText(LANG[TOOL_LANG]["Batch Import"])
self.rigging_setup_group.setTitle(LANG[TOOL_LANG]["Setup"])
self.rigging_advanced_skeleton_btn.setText(LANG[TOOL_LANG]["Advanced Skeleton"])
self.animation_select_group.setTitle(LANG[TOOL_LANG]["Select"])
self.animation_animschool_picker_btn.setText(LANG[TOOL_LANG]["Anim School Picker"])
self.animation_dwpicker_btn.setText(LANG[TOOL_LANG]["DWPicker"])
self.animation_tools_group.setTitle(LANG[TOOL_LANG]["Tools"])
self.animation_bhghost_btn.setText(LANG[TOOL_LANG]["bhGhost"])
self.animation_ikfk_switch_btn.setText(LANG[TOOL_LANG]["IK/FK Switch"])
self.animation_atools_btn.setText(LANG[TOOL_LANG]["aTools"])
self.animation_keyframepro_btn.setText(LANG[TOOL_LANG]["Keyframe Pro"])
self.animation_studiolibrary_btn.setText(LANG[TOOL_LANG]["Studio Library"])
self.animation_pose_group.setTitle(LANG[TOOL_LANG]["Pose Tools"])
self.animation_epic_pose_wrangler_btn.setText(LANG[TOOL_LANG]["Epic Pose Wrangler"])
self.animation_morph_shape_btn.setText(LANG[TOOL_LANG]["Morph Shape"])
self.animation_universal_rig_adapter_btn.setText(LANG[TOOL_LANG]["Universal Rig Adapter"])
self.dev_tools_group.setTitle(LANG[TOOL_LANG]["Dev Tool"])
self.dev_icon_viewer_btn.setText(LANG[TOOL_LANG]["Icon Viewer"])
self.metahuman_import_group.setTitle(LANG[TOOL_LANG]["Import"])
self.animation_motioncap_helper_btn.setText(LANG[TOOL_LANG]["MotionCapHelper"])
self.animation_spring_magic_btn.setText(LANG[TOOL_LANG]["SpringMagic"])
self.modeling_ahoge_btn.setText(LANG[TOOL_LANG]["Ahoge"])
self.modeling_quad_remesher_btn.setText(LANG[TOOL_LANG]["QuadRemesher"])
self.modeling_morph_to_uv_btn.setText(LANG[TOOL_LANG]["Morph to UV"])
self.modeling_ldmt_btn.setText(LANG[TOOL_LANG]["LDMT"])
self.modeling_simplify_btn.setText(LANG[TOOL_LANG]["Simplify"])
self.help_btn.setText(LANG[TOOL_LANG]["DOCUMENT"])
self.lang_btn.setText(LANG[TOOL_LANG]["CN" if TOOL_LANG == 'en_US' else "EN"])
self.lang_btn.setToolTip(LANG[TOOL_LANG]["Switch Language"])
for buttons_01 in [
self.help_btn,
self.lang_btn
]:
buttons_01.setFont(QtGui.QFont("Microsoft YaHei", 10))
for buttons_02 in [
# Modeling Group
self.modeling_tab_btn,
self.modeling_display_group,
self.modeling_select_group,
self.modeling_tools_group,
self.modeling_xray_btn,
self.modeling_joint_xray_btn,
self.modeling_rename_btn,
self.modeling_manage_group,
self.modeling_batch_import_btn,
self.modeling_quick_export_btn,
self.modeling_ahoge_btn,
self.modeling_quad_remesher_btn,
self.modeling_morph_to_uv_btn,
self.modeling_ldmt_btn,
self.modeling_simplify_btn,
# Metahuman Group
self.metahuman_tab_btn,
self.metahuman_preparation_group,
self.metahuman_import_group,
self.metahuman_body_prepare_btn,
self.metahuman_batch_import_btn,
# Rigging Group
self.rigging_tab_btn,
self.rigging_setup_group,
self.rigging_advanced_skeleton_btn,
# Animation Group
self.animation_tab_btn,
self.animation_select_group,
self.animation_tools_group,
self.animation_pose_group,
self.animation_animschool_picker_btn,
self.animation_dwpicker_btn,
self.animation_bhghost_btn,
self.animation_ikfk_switch_btn,
self.animation_atools_btn,
self.animation_keyframepro_btn,
self.animation_studiolibrary_btn,
self.animation_epic_pose_wrangler_btn,
self.animation_morph_shape_btn,
self.animation_universal_rig_adapter_btn,
self.animation_motioncap_helper_btn,
self.animation_spring_magic_btn,
# Dev Tools Group
self.dev_tools_group,
self.dev_icon_viewer_btn
]:
buttons_02.setFont(QtGui.QFont("Microsoft YaHei", 8))
# -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# Show Window
# ************************************************************************************************************************************************************************************************************
def show():
global main_window # Ensure this is the instance variable
current_width = 300
try:
if cmds.workspaceControl(TOOL_WSCL_NAME, exists=True):
current_width = cmds.workspaceControl(TOOL_WSCL_NAME, q=True, width=True)
cmds.deleteUI(TOOL_WSCL_NAME, control=True)
# Check if main_window is already defined and close it
if 'main_window' in globals() and main_window is not None:
main_window.close()
main_window.deleteLater()
except Exception as e:
print("Error during workspace control check: {}".format(str(e)))
def create_ui(retry_count=0, width=300):
global main_window
try:
main_window = MainWindow() # Create an instance of MainWindow
main_window.dock_to_maya()
cmds.evalDeferred(lambda: cmds.workspaceControl(TOOL_WSCL_NAME, e=True, width=width, resizeWidth=True))
except Exception as e:
if retry_count < 3:
print("MetaBox creation failed, retrying... (Attempt {})".format(retry_count + 1))
utils.executeDeferred(lambda: create_ui(retry_count + 1, width))
else:
print("Failed to create MetaBox after 3 attempts: {}".format(str(e)))
utils.executeDeferred(lambda: create_ui(width=current_width))
if __name__ == "__main__":
show()