2054 lines
108 KiB
Python
2054 lines
108 KiB
Python
#!/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() |