From 024937e6272fecf00cb719ee4d5092166354a565 Mon Sep 17 00:00:00 2001 From: Jeffreytsai1004 Date: Tue, 14 Jan 2025 01:57:26 +0800 Subject: [PATCH] Update Update --- Scripts/MetaBox.py | 1645 ++++++++++++++++++++++++++++++++++++++ Scripts/ReloadModules.py | 91 +++ 2 files changed, 1736 insertions(+) create mode 100644 Scripts/MetaBox.py create mode 100644 Scripts/ReloadModules.py diff --git a/Scripts/MetaBox.py b/Scripts/MetaBox.py new file mode 100644 index 0000000..71f8389 --- /dev/null +++ b/Scripts/MetaBox.py @@ -0,0 +1,1645 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#===================================== IMPORT MODULES ===================================== +from PySide2 import QtWidgets, QtCore, QtGui +from shiboken2 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 + +#===================================== IMPORT FUNCTIONS =================================== +from Modeling.Manage import Rename +from Modeling.Edit import ( + SpeedCut, + EvenEdgeLoop, + SpeedBend, + PolyFold, + ArcDeformer, + InstantDrag, + UnBevel, + RoundInset, + CreasePlus, + 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 ===================================== + +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 = "Virtuos" +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, "logo.png").replace("\\", "/") +DEFAULT_ICON = "commandButton.png" +TOOL_HELP_URL = f"http://10.72.61.59:3000/ArtGroup/{TOOL_NAME}/wiki" +TOOL_WSCL_NAME = "ToolBoxWorkSpaceControl" +MOD_FILE_NAME = f"{TOOL_NAME}.mod" +MAIN_SCRIPT_NAME = f"{TOOL_NAME}.py" + +#===================================== 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( + f""" + 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}; + }} + """ + ) + +#===================================== 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", + "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", + "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" + }, + '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": "关闭", + "UV": "UV", + "UVDeluxe": "UVDeluxe", + "RizomUV Bridge": "RizomUV Bridge", + "UV Set Editor": "UV 编辑器", + "Preparation": "准备", + "Body Prepare": "身体准备", + "Setup": "设置", + "Advanced Skeleton": "高级骨骼", + "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": "减面工具" + } +} +#===================================== 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(f"WARNING: Icon file not found: {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(f"Error creating workspace control: {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_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_xgen_controller_btn = RoundedButton(LANG[TOOL_LANG]["Xgen Controller"], color="#FFEBA1", hover_color="#FFF5B3", pressed_color="#FFE68A") + 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_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_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") + + # 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") + + # 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") + + 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.QVBoxLayout(self.modeling_manage_group) + modeling_manage_layout.addWidget(self.modeling_rename_btn) + modeling_manage_layout.addWidget(self.modeling_batch_import_btn) + # 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_xgtools_btn, 2, 1) + modeling_tools_layout.addWidget(self.modeling_edge_sensei_btn, 3, 0) + modeling_tools_layout.addWidget(self.modeling_round_inset_btn, 3, 1) + modeling_tools_layout.addWidget(self.modeling_arc_deformer_btn, 4, 0) + modeling_tools_layout.addWidget(self.modeling_speed_bend_btn, 4, 1) + modeling_tools_layout.addWidget(self.modeling_instant_drag_btn, 5, 0) + modeling_tools_layout.addWidget(self.modeling_unbevel_btn, 5, 1) + modeling_tools_layout.addWidget(self.modeling_align_edge_btn, 6, 0) + modeling_tools_layout.addWidget(self.modeling_extra_curve_btn, 6, 1) + modeling_tools_layout.addWidget(self.modeling_auto_snap_btn, 7, 0) + modeling_tools_layout.addWidget(self.modeling_xgen_controller_btn, 7, 1) + modeling_tools_layout.addWidget(self.modeling_quad_remesher_btn, 8, 0) + # 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_ahoge_btn) + # UV + modeling_scroll_area_layout.addWidget(self.modeling_uv_group) + modeling_uv_layout = QtWidgets.QVBoxLayout(self.modeling_uv_group) + modeling_uv_layout.addWidget(self.modeling_uv_set_editor_btn) + modeling_uv_layout.addWidget(self.modeling_uvdeluxe_btn) + modeling_uv_layout.addWidget(self.modeling_rizom_uv_bridge_btn) + # 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) + # 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) + # 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(f"Warning: Icon file '{TOOL_ICON}' does not exist.") + # add icon label to bottom layout + bottom_layout.addWidget(icon_label) + # add version information label + version_label = QtWidgets.QLabel(f"{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_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_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_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) + # 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) + # 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) + # 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 = f"Error occurred while running {task}: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + # Modeling Functions + # **************************************************************************************************************** + # Display + 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: + ERROR_MESSAGE = f"Error occurred while running Xray: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + 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: + ERROR_MESSAGE = f"Error occurred while running XrayJoint: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + # Manage + 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: + ERROR_MESSAGE = f"Error occurred while running Rename: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + 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: + ERROR_MESSAGE = f"Error occurred while running Batch Import: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + # Edit + def run_crease_plus(self, *args): + try: + crease_plus_dir = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'CreasePlus')).replace('\\', '/') + print(f"CreasePlus directory: {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") + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Crease Plus: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + print(f"Detailed error: {traceback.format_exc()}") + + def run_speed_cut(self, *args): + try: + SpeedCut.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Speed Cut: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_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) + + 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: + ERROR_MESSAGE = f"Error occurred while running GS Curve Tools: {str(e)}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + print(f"Detailed error: {traceback.format_exc()}") + + 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: + ERROR_MESSAGE = f"Error occurred while running GS Curve Tools: {str(e)}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + print(f"Detailed error: {traceback.format_exc()}") + + 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: + ERROR_MESSAGE = f"Error occurred while running GS Curve Tools: {str(e)}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + print(f"Detailed error: {traceback.format_exc()}") + + + def run_modit(self, *args): + try: + modit_path = os.path.normpath(os.path.join(TOOL_PATH, 'Modeling', 'Edit', 'ModIt')).replace('\\', '/') + modlit_sub_paths = [ + 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 + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running ModIt: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_plugit(self, *args): + try: + 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: + ERROR_MESSAGE = f"Error occurred while running PlugIt: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_xgtools(self, *args): + try: + 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: + ERROR_MESSAGE = f"Error importing modules for XGTools: {str(e)}" + print(ERROR_MESSAGE) + cmds.warning(ERROR_MESSAGE) + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running XGTools: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_zirail(self, *args): + try: + # 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 [f'ziRail_{MAYA_VERSION}.mll', f'ziWireframeViewport_{MAYA_VERSION}.mll']: + 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(f"Warning: Plugin file does not exist: {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 [f'ziRail_{MAYA_VERSION}.mll', f'ziWireframeViewport_{MAYA_VERSION}.mll']: + 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(f"Warning: Plugin file does not exist: {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 = f"Error occurred while running ziRail: Maya version {MAYA_VERSION} is not supported" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + return + + # 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(f'Modeling.Edit.ziRail.2018_2020.zi_rail') + elif MAYA_VERSION in ['2022', '2023']: + zi_rail = importlib.import_module(f'Modeling.Edit.ziRail.2022_2023.zi_rail') + else: + ERROR_MESSAGE = f"Error occurred while running ziRail: Maya version {MAYA_VERSION} is not supported" + 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: + ERROR_MESSAGE = f"Error occurred while running ziRail: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + + def run_edge_sensei(self, *args): + try: + EdgeSensei.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Edge Sensei: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_even_edge_loop(self, *args): + try: + EvenEdgeLoop.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Even Edge Loop: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_speed_bend(self, *args): + try: + SpeedBend.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Speed Bend: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_poly_fold(self, *args): + try: + PolyFold.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Poly Fold: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_round_inset(self, *args): + try: + RoundInset.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Round Inset: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_arc_deformer(self, *args): + try: + ArcDeformer.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Arc Deformer: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_instant_drag(self, *args): + try: + InstantDrag.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Instant Drag: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_unbevel(self, *args): + try: + UnBevel.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running UnBevel: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_extra_curve(self, *args): + try: + mel.eval('polyToCurve -form 2 -degree 3 -conformToSmoothMeshPreview 1') + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running ExtractCurve: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_auto_snap(self, *args): + try: + AutoSnap.cmd() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running ExtractCurve: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_xgen_controller(self, *args): + try: + XgenController.create_window() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running ExtractCurve: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + # Select + def run_edge_loop_smart_select(self, *args): + try: + EdgeLoopSmartSelect.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Edge Loop Smart Select: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_select_edge(self, *args): + try: + IntervalSelectEdge.show() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Interval Select Edge: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_same_position_selector(self, *args): + try: + SamePositionSelector.show() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running SamePositionSelector: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_align_edge(self, *args): + try: + AlignEdge.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Align Edge: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + # UV + def run_uv_set_editor(self, *args): + try: + UVSetEditor.show() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while opening UV Set Editor: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_uvdeluxe(self, *args): + try: + from Modeling.UV.UVDeluxe import uvdeluxe + uvdeluxe.createUI() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while opening UVDeluxe: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + 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: + ERROR_MESSAGE = f"Error occurred while running RizomUV Bridge: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + + # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + # Rigging Functions + # **************************************************************************************************************** + 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: + ERROR_MESSAGE = f"Error occurred while running Advanced Skeleton: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + print(f"Detailed error: {traceback.format_exc()}") + # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + # Metahuman Functions + # **************************************************************************************************************** + # Preparation + def run_body_prepare(self, *args): + try: + BodyPrep.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Body Prepare: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + + # ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + # Animation Functions + # **************************************************************************************************************** + # Pose + def open_aTools(self, *args): + try: + # 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: + ERROR_MESSAGE = f"Error occurred while running aTools: {e}" + print(f"Detailed error: {traceback.format_exc()}") + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + 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: + ERROR_MESSAGE = f"Error occurred while running Keyframe Pro: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + 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: + ERROR_MESSAGE = f"Error occurred while running dwpicker: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + 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: + ERROR_MESSAGE = f"Error occurred while running Studio Library: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_anim_school_picker(self, *args): + try: + # 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(f"Anim School Picker loaded successfully from {animpicker_mll}") + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Anim School Picker: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + 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(f'source "{bhghost_mel}";') + print(f"bhGhost loaded successfully from {bhghost_mel}") + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running bhGhost: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + print(f"Detailed error: {traceback.format_exc()}") + + def run_ik_fk_switch(self, *args): + try: + from Animation import mog_ikFkSwitchFree + mog_ikFkSwitchFree.FkIk_UI() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running IK/FK Switch: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + # Blendshape + def open_epic_pose_wrangler(self, *args): + try: + 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(f"Attempting to import Epic Pose Wrangler from: {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', f'MayaUE4RBFPlugin{MAYA_VERSION}.mll', '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(f"Warning: Plugin file does not exist: {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: + ERROR_MESSAGE = f"Error occurred while running Epic Pose Wrangler: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_universal_rig_adapter(self, *args): + try: + UniversalRigAdapter.run() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Universal Rig Adapter: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_morph_shape(self, *args): + try: + MorphShape.show() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running MorphShape: {e}" + cmds.warning(ERROR_MESSAGE) + + def run_icon_viewer(self, *args): + try: + from Dev.mayaiconview import create_icon_viewer + create_icon_viewer() + except Exception as e: + ERROR_MESSAGE = f"Error occurred while running Icon Viewer: {e}" + cmds.warning(ERROR_MESSAGE) + cmds.confirmDialog(title='Error', message=ERROR_MESSAGE, button=['OK'], defaultButton='OK') + + def run_motioncap_helper(self, *args): + try: + 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: + self.show_error("MotionCap Helper", e) + + def run_spring_magic(self, *args): + try: + from Animation.springmagic import main + main.main() + except Exception as e: + self.show_error("Spring Magic", e) + + 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: + self.show_error("Ahoge", e) + + 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: + self.show_error("Quad Remesher", e) + + 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: + self.show_error("LDMT", e) + + 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='Simplify 插件已安装成功,请重启 Maya!', button=['OK'], defaultButton='OK') + except: + cmds.confirmDialog(title='提示', message='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: + self.show_error("Simplify", 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_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_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_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_ahoge_btn, + self.modeling_quad_remesher_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(f"Error during workspace control check: {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(f"MetaBox creation failed, retrying... (Attempt {retry_count + 1})") + utils.executeDeferred(lambda: create_ui(retry_count + 1, width)) + else: + print(f"Failed to create MetaBox after 3 attempts: {str(e)}") + + utils.executeDeferred(lambda: create_ui(width=current_width)) + +if __name__ == "__main__": + show() \ No newline at end of file diff --git a/Scripts/ReloadModules.py b/Scripts/ReloadModules.py new file mode 100644 index 0000000..04d58a6 --- /dev/null +++ b/Scripts/ReloadModules.py @@ -0,0 +1,91 @@ +import sys +import importlib +import os +from maya import cmds + +def get_all_py_files(start_path): + """ + 递归获取指定目录下所有的 .py 文件 + 返回: 包含所有 .py 文件路径的列表 + """ + py_files = [] + for root, dirs, files in os.walk(start_path): + # 跳过 __pycache__ 目录 + if '__pycache__' in dirs: + dirs.remove('__pycache__') + + for file in files: + if file.endswith('.py') and not file.startswith('__'): + full_path = os.path.join(root, file) + # 转换为模块路径格式 + rel_path = os.path.relpath(full_path, start_path) + module_path = os.path.splitext(rel_path)[0].replace(os.sep, '.') + module_path = module_path.replace("Scripts.", "") + py_files.append(module_path) + return py_files + +def reload_metabox(): + """ + 重新加载 MetaBox 及其所有相关模块 + """ + try: + # 关闭现有的 MetaBox 窗口 + if cmds.workspaceControl("ToolBoxWorkSpaceControl", exists=True): + cmds.deleteUI("ToolBoxWorkSpaceControl", control=True) + + # 获取 Scripts 根目录 + SCRIPTS_PATH = os.path.dirname(os.path.dirname(__file__)) + print(SCRIPTS_PATH) + + # 获取所有 .py 文件的模块路径 + modules_to_reload = get_all_py_files(SCRIPTS_PATH) + # 按模块层级排序,确保先重新加载底层模块 + modules_to_reload.sort(key=lambda x: len(x.split('.'))) + print(modules_to_reload) + + print("开始重新加载模块...") + + # 重新加载所有模块 + reloaded_modules = set() + for module_name in modules_to_reload: + try: + if module_name in sys.modules: + module = sys.modules[module_name] + importlib.reload(module) + reloaded_modules.add(module_name) + print(f"已重新加载模块: {module_name}") + except Exception as e: + print(f"重新加载模块 {module_name} 时出错: {str(e)}") + + print(f"\n成功重新加载 {len(reloaded_modules)} 个模块") + + # 最后重新加载并显示 MetaBox + if 'MetaBox' in sys.modules: + importlib.reload(sys.modules['MetaBox']) + from MetaBox import show + show() + + print("\nMetaBox 已成功重新加载!") + + except Exception as e: + error_msg = f"重新加载 MetaBox 时发生错误: {str(e)}" + print(error_msg) + cmds.warning(error_msg) + +def reload_all(): + """ + 执行重新加载并打印分隔线 + """ + print("\n" + "="*50) + print("开始重新加载 MetaBox 及其所有模块") + print("="*50 + "\n") + reload_metabox() + print("\n" + "="*50) + print("重新加载完成") + print("="*50 + "\n") + +# 执行重新加载 +# if __name__ == "__main__": + # reload_all() + +