Files
MetaFusion/scripts/ui/definition.py
2025-05-08 23:57:22 +08:00

417 lines
21 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Definition UI Module for Plugin
定义系统UI模块 - 负责显示DNA定义编辑界面和基础操作
基本功能:
- LOD, Meshes, Joints, Blendshape, AnimatedMap 加载和刷新
- 写入: 写入关节默认位置,写入几何体,写入蒙皮,写入混合变形目标
- 创建:创建混合变形,绑定蒙皮,取消蒙皮
- 工具:重新定位头部关节,重新定位身体关节,重新定位全身关节,快速创建预设
"""
#========================================= IMPORT =========================================
from scripts.ui.Qt import QtWidgets, QtCore, QtGui
from scripts.ui.Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import maya.cmds as cmds
import maya.mel as mel
import maya.utils as utils
import webbrowser
import subprocess
import importlib
import traceback
import locale
import sys
import os
from scripts.ui import ui_utils
from scripts.utils import utils_definition
#========================================== CONFIG ========================================
import config
TOOL_NAME = config.TOOL_NAME
TOOL_VERSION = config.TOOL_VERSION
TOOL_AUTHOR = config.TOOL_AUTHOR
TOOL_YEAR = config.TOOL_YEAR
TOOL_MOD_FILENAME = config.TOOL_MOD_FILENAME
TOOL_LANG = config.TOOL_LANG
TOOL_WSCL_NAME = config.TOOL_WSCL_NAME
TOOL_HELP_URL = config.TOOL_HELP_URL
TOOL_PATH = config.TOOL_PATH
SCRIPTS_PATH = config.SCRIPTS_PATH
TOOL_MAIN_SCRIPT = config.TOOL_MAIN_SCRIPT
UI_PATH = config.UI_PATH
STYLE_FILE = config.STYLE_FILE
ICONS_PATH = config.ICONS_PATH
TOOL_ICON = config.TOOL_ICON
ASSETS_PATH = config.ASSETS_PATH
DNA_FILE_PATH = config.DNA_FILE_PATH
DNA_IMG_PATH = config.DNA_IMG_PATH
TOOL_COMMAND_ICON = config.TOOL_COMMAND_ICON
TOOL_WIDTH = config.TOOL_WIDTH
TOOL_HEIGHT = config.TOOL_HEIGHT
#========================================= LOCATION =======================================
from scripts.ui import localization
TEXT = localization.TEXT
class DefinitionUI(ui_utils.BaseUI):
"""
定义系统UI类 - 负责显示DNA定义编辑界面和基础操作
继承自BaseUI类实现DNA定义相关的UI功能
"""
#========================================== INIT ========================================
def __init__(self, parent=None):
"""
初始化定义系统UI
"""
super().__init__(parent)
# 创建主控件
self.main_widget = QtWidgets.QWidget()
self.main_widget.setObjectName("definitionMainWidget")
# 创建UI组件
self.create_widgets()
self.create_layouts()
self.create_connections()
# 更新UI文本
self.update_language()
#========================================= WIDGET =======================================
def create_widgets(self):
"""
创建定义系统UI控件
包括按钮、标签、列表等
"""
# 标题标签 - 使用HTML格式化标题
title_text = f"<h4 style='margin:0;padding:5px;'>{TEXT('definition_title', 'DNA定义')}</h4>"
self.controls["title_label"] = QtWidgets.QLabel(title_text)
self.controls["title_label"].setObjectName("definitionTitleLabel")
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
self.controls["title_label"].setMaximumHeight(30) # 限制标题高度
# 主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("definitionMainSplitter")
self.splitters["main_splitter"].setHandleWidth(6) # 设置分割器手柄宽度
self.splitters["main_splitter"].setChildrenCollapsible(False) # 禁止子部件折叠
self.splitters["main_splitter"].setOpaqueResize(True) # 实时显示调整效果
# 左侧面板
self.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("definitionLeftPanel")
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("definitionRightPanel")
# 左侧面板控件
# LODs组
self.controls["lods_group"] = QtWidgets.QGroupBox("LODs")
self.controls["lods_group"].setObjectName("lodsGroup")
# LODs列表
self.controls["lods_list"] = QtWidgets.QListWidget()
self.controls["lods_list"].setObjectName("lodsList")
# 定义LOD关联按钮
self.buttons["define_lod_relations"] = QtWidgets.QPushButton(TEXT("define_lod_relations", "定义LOD关联"))
self.buttons["define_lod_relations"].setIcon(ui_utils.load_icon("layerEditor.png"))
self.buttons["define_lod_relations"].setObjectName("defineLodRelationsButton")
# Meshes组
self.controls["meshes_group"] = QtWidgets.QGroupBox("Meshes [000]")
self.controls["meshes_group"].setObjectName("meshesGroup")
# Meshes列表
self.controls["meshes_list"] = QtWidgets.QListWidget()
self.controls["meshes_list"].setObjectName("meshesList")
# 创建几何体按钮
self.buttons["create_geometry"] = QtWidgets.QPushButton(TEXT("create_geometry", "创建几何体"))
self.buttons["create_geometry"].setIcon(ui_utils.load_icon("polyCube.png"))
self.buttons["create_geometry"].setObjectName("createGeometryButton")
# 右侧面板控件
# Joints组
self.controls["joints_group"] = QtWidgets.QGroupBox("Joints [000]")
self.controls["joints_group"].setObjectName("jointsGroup")
# Joints列表
self.controls["joints_list"] = QtWidgets.QListWidget()
self.controls["joints_list"].setObjectName("jointsList")
# BlendShapes组
self.controls["blendshapes_group"] = QtWidgets.QGroupBox("BlendShapes [000]")
self.controls["blendshapes_group"].setObjectName("blendshapesGroup")
# BlendShapes列表
self.controls["blendshapes_list"] = QtWidgets.QListWidget()
self.controls["blendshapes_list"].setObjectName("blendshapesList")
# AnimatedMap组
self.controls["animatedmap_group"] = QtWidgets.QGroupBox("AnimatedMap [000]")
self.controls["animatedmap_group"].setObjectName("animatedmapGroup")
# AnimatedMap列表
self.controls["animatedmap_list"] = QtWidgets.QListWidget()
self.controls["animatedmap_list"].setObjectName("animatedmapList")
# 底部工具面板
# 写入部分
self.controls["write_label"] = QtWidgets.QLabel(TEXT("Write", "写入"))
self.controls["write_label"].setObjectName("WriteLabel")
self.controls["write_label"].setAlignment(QtCore.Qt.AlignCenter)
self.buttons["write_neutral_pose_joint_position"] = QtWidgets.QPushButton(TEXT("Write Neutral Pose Joint Position", "写入中性Pose关节位置"))
self.buttons["write_neutral_pose_joint_position"].setIcon(ui_utils.load_icon("HIKCharacterToolBodyPart.png"))
self.buttons["write_neutral_pose_joint_position"].setObjectName("WriteNeutralPoseJointPositionButton")
self.buttons["write_geometry"] = QtWidgets.QPushButton(TEXT("Write Geometry", "写入几何体"))
self.buttons["write_geometry"].setIcon(ui_utils.load_icon("polyCube.png"))
self.buttons["write_geometry"].setObjectName("WriteGeometryButton")
self.buttons["write_skin_weight"] = QtWidgets.QPushButton(TEXT("Write Skin Weight", "写入蒙皮权重"))
self.buttons["write_skin_weight"].setIcon(ui_utils.load_icon("paintSkinWeights.png"))
self.buttons["write_skin_weight"].setObjectName("WriteSkinWeightButton")
self.buttons["write_blendshape_target"] = QtWidgets.QPushButton(TEXT("Write Blendshape Target", "写入BS对象"))
self.buttons["write_blendshape_target"].setIcon(ui_utils.load_icon("blendShape.png"))
self.buttons["write_blendshape_target"].setObjectName("WriteBlendshapeTargetButton")
# 创建部分
self.controls["create_label"] = QtWidgets.QLabel(TEXT("Create", "创建"))
self.controls["create_label"].setObjectName("CreateLabel")
self.controls["create_label"].setAlignment(QtCore.Qt.AlignCenter)
self.buttons["create_blendshapes_for_mesh"] = QtWidgets.QPushButton(TEXT("Create Blendshapes For Mesh", "为模型创建Blendshape"))
self.buttons["create_blendshapes_for_mesh"].setIcon(ui_utils.load_icon("blendShapeEditor.png"))
self.buttons["create_blendshapes_for_mesh"].setObjectName("CreateBlendshapeForMeshButton")
self.buttons["create_skin_for_mesh"] = QtWidgets.QPushButton(TEXT("Create Skin For Mesh", "为模型创建绑定蒙皮"))
self.buttons["create_skin_for_mesh"].setIcon(ui_utils.load_icon("smoothSkin.png"))
self.buttons["create_skin_for_mesh"].setObjectName("CreateSkinForMeshButton")
self.buttons["unbind_skin_for_mesh"] = QtWidgets.QPushButton(TEXT("Unbind Skin For Mesh", "为模型取消绑定蒙皮"))
self.buttons["unbind_skin_for_mesh"].setIcon(ui_utils.load_icon("detachSkin.png"))
self.buttons["unbind_skin_for_mesh"].setObjectName("UnbindSkinForMeshButton")
# 工具部分
self.controls["tools_label"] = QtWidgets.QGroupBox(TEXT("Tools", "工具"))
self.controls["tools_label"].setObjectName("ToolsLabel")
self.controls["tools_label"].setAlignment(QtCore.Qt.AlignCenter)
self.buttons["new_head_netural_joint_transform"] = QtWidgets.QPushButton(TEXT("New Head Netural Joint Transform", "重新定位头部关节"))
self.buttons["new_head_netural_joint_transform"].setIcon(ui_utils.load_icon("HIKCharacterToolSkeleton.png"))
self.buttons["new_head_netural_joint_transform"].setObjectName("NewHeadNeturalJointTransformButton")
self.buttons["new_body_netural_joint_transform"] = QtWidgets.QPushButton(TEXT("New Body Netural Joint Transform", "重新定位身体关节"))
self.buttons["new_body_netural_joint_transform"].setIcon(ui_utils.load_icon("HIKCharacterToolSkeleton.png"))
self.buttons["new_body_netural_joint_transform"].setObjectName("NewBodyNeturalJointTransformButton")
self.buttons["new_netural_joint_transform"] = QtWidgets.QPushButton(TEXT("New Netural Joint Transform", "重新定位全身关节"))
self.buttons["new_netural_joint_transform"].setIcon(ui_utils.load_icon("HIKCharacterToolSkeleton.png"))
self.buttons["new_netural_joint_transform"].setObjectName("NewNeturalJointTransformButton")
self.buttons["quick_create_preset"] = QtWidgets.QPushButton(TEXT("Quick Create Preset", "快速创建预设"))
self.buttons["quick_create_preset"].setIcon(ui_utils.load_icon("QR_QuickRigTool.png"))
self.buttons["quick_create_preset"].setObjectName("QuickCreatePreset")
#========================================= LAYOUT =======================================
def create_layouts(self):
"""
创建定义系统UI布局
组织控件的排列和层次结构
"""
# 创建主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["main_layout"].setSpacing(5)
# 添加标题标签到主布局
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 添加主分割器到主布局
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
# 左侧面板布局
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
self.layouts["left_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["left_layout"].setSpacing(5)
# 左侧分割器
self.splitters["left_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical)
self.splitters["left_splitter"].setObjectName("definitionLeftSplitter")
self.layouts["left_layout"].addWidget(self.splitters["left_splitter"])
# LODs组布局
self.layouts["lods_layout"] = QtWidgets.QVBoxLayout(self.controls["lods_group"])
self.layouts["lods_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["lods_layout"].setSpacing(5)
# 添加LODs列表
self.layouts["lods_layout"].addWidget(self.controls["lods_list"])
# 定义LOD关联按钮
self.layouts["lods_layout"].addWidget(self.buttons["define_lod_relations"])
# Meshes组布局
self.layouts["meshes_layout"] = QtWidgets.QVBoxLayout(self.controls["meshes_group"])
self.layouts["meshes_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["meshes_layout"].setSpacing(5)
# 添加Meshes列表
self.layouts["meshes_layout"].addWidget(self.controls["meshes_list"])
# 创建几何体按钮
self.layouts["meshes_layout"].addWidget(self.buttons["create_geometry"])
# 添加到左侧分割器
self.splitters["left_splitter"].addWidget(self.controls["lods_group"])
self.splitters["left_splitter"].addWidget(self.controls["meshes_group"])
# 右侧面板布局
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["right_layout"].setSpacing(5)
# 右侧分割器
self.splitters["right_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical)
self.splitters["right_splitter"].setObjectName("definitionRightSplitter")
self.layouts["right_layout"].addWidget(self.splitters["right_splitter"])
# Joints组布局
self.layouts["joints_layout"] = QtWidgets.QVBoxLayout(self.controls["joints_group"])
self.layouts["joints_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["joints_layout"].setSpacing(5)
# 添加Joints列表
self.layouts["joints_layout"].addWidget(self.controls["joints_list"])
# BlendShapes组布局
self.layouts["blendshapes_layout"] = QtWidgets.QVBoxLayout(self.controls["blendshapes_group"])
self.layouts["blendshapes_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["blendshapes_layout"].setSpacing(5)
# 添加BlendShapes列表
self.layouts["blendshapes_layout"].addWidget(self.controls["blendshapes_list"])
# AnimatedMap组布局
self.layouts["animatedmap_layout"] = QtWidgets.QVBoxLayout(self.controls["animatedmap_group"])
self.layouts["animatedmap_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["animatedmap_layout"].setSpacing(5)
# 添加AnimatedMap列表
self.layouts["animatedmap_layout"].addWidget(self.controls["animatedmap_list"])
# 添加到右侧分割器
self.splitters["right_splitter"].addWidget(self.controls["joints_group"])
self.splitters["right_splitter"].addWidget(self.controls["blendshapes_group"])
self.splitters["right_splitter"].addWidget(self.controls["animatedmap_group"])
# 底部工具面板
self.layouts["bottom_panel"] = QtWidgets.QHBoxLayout()
self.layouts["bottom_panel"].setContentsMargins(0, 10, 0, 0)
self.layouts["bottom_panel"].setSpacing(10)
# 写入部分QGroupBox
self.controls["write_group"] = QtWidgets.QGroupBox(TEXT("Write", "写入"))
self.controls["write_group"].setObjectName("writeGroup")
self.layouts["write_layout"] = QtWidgets.QVBoxLayout()
self.layouts["write_layout"].setSpacing(5)
self.layouts["write_layout"].addWidget(self.buttons["write_neutral_pose_joint_position"])
self.layouts["write_layout"].addWidget(self.buttons["write_geometry"])
self.layouts["write_layout"].addWidget(self.buttons["write_skin_weight"])
self.layouts["write_layout"].addWidget(self.buttons["write_blendshape_target"])
self.layouts["write_layout"].addStretch(1)
self.controls["write_group"].setLayout(self.layouts["write_layout"])
# 创建部分QGroupBox
self.controls["create_group"] = QtWidgets.QGroupBox(TEXT("Create", "创建"))
self.controls["create_group"].setObjectName("createGroup")
self.layouts["create_layout"] = QtWidgets.QVBoxLayout()
self.layouts["create_layout"].setSpacing(5)
self.layouts["create_layout"].addWidget(self.buttons["create_blendshapes_for_mesh"])
self.layouts["create_layout"].addWidget(self.buttons["create_skin_for_mesh"])
self.layouts["create_layout"].addWidget(self.buttons["unbind_skin_for_mesh"])
self.layouts["create_layout"].addStretch(1)
self.controls["create_group"].setLayout(self.layouts["create_layout"])
# 工具部分QGroupBox
self.controls["tools_group"] = QtWidgets.QGroupBox(TEXT("Tools", "工具"))
self.controls["tools_group"].setObjectName("toolsGroup")
self.layouts["tools_layout"] = QtWidgets.QVBoxLayout()
self.layouts["tools_layout"].setSpacing(5)
self.layouts["tools_layout"].addWidget(self.buttons["new_head_netural_joint_transform"])
self.layouts["tools_layout"].addWidget(self.buttons["new_body_netural_joint_transform"])
self.layouts["tools_layout"].addWidget(self.buttons["new_netural_joint_transform"])
self.layouts["tools_layout"].addWidget(self.buttons["quick_create_preset"])
self.layouts["tools_layout"].addStretch(1)
self.controls["tools_group"].setLayout(self.layouts["tools_layout"])
# 添加三组到底部面板
self.layouts["bottom_panel"].addWidget(self.controls["write_group"])
self.layouts["bottom_panel"].addWidget(self.controls["create_group"])
self.layouts["bottom_panel"].addWidget(self.controls["tools_group"])
# 添加底部面板到主布局
self.layouts["main_layout"].addLayout(self.layouts["bottom_panel"])
# 添加左右面板到分割器 - 移动到这里
self.splitters["main_splitter"].addWidget(self.controls["left_panel"])
self.splitters["main_splitter"].addWidget(self.controls["right_panel"])
# 强制更新分割器大小 - 添加这一行,使用比例设置
QtCore.QTimer.singleShot(100, lambda: ui_utils.set_splitter_proportions(self.splitters["main_splitter"], [0.5, 0.5]))
#======================================= CONNECTION =====================================
def create_connections(self):
"""
连接信号和槽
设置UI控件的交互行为
"""
# 左侧面板连接
# LODs列表连接
self.controls["lods_list"].itemClicked.connect(utils_definition.lod_selected)
self.controls["lods_list"].itemSelectionChanged.connect(utils_definition.update_lod_selection)
# 定义LOD关联按钮连接
self.buttons["define_lod_relations"].clicked.connect(utils_definition.define_lod_relations)
# Meshes列表连接
self.controls["meshes_list"].itemClicked.connect(utils_definition.mesh_selected)
self.controls["meshes_list"].itemSelectionChanged.connect(utils_definition.update_mesh_selection)
# 创建几何体按钮连接
self.buttons["create_geometry"].clicked.connect(utils_definition.create_geometry)
# 右侧面板连接
# Joints列表连接
self.controls["joints_list"].itemClicked.connect(utils_definition.joint_selected)
self.controls["joints_list"].itemSelectionChanged.connect(utils_definition.update_joint_selection)
# BlendShapes列表连接
self.controls["blendshapes_list"].itemClicked.connect(utils_definition.blendshape_selected)
self.controls["blendshapes_list"].itemSelectionChanged.connect(utils_definition.update_blendshape_selection)
# AnimatedMap列表连接
self.controls["animatedmap_list"].itemClicked.connect(utils_definition.animatedmap_selected)
self.controls["animatedmap_list"].itemSelectionChanged.connect(utils_definition.update_animatedmap_selection)
# 底部工具面板连接
# 导入部分按钮连接
self.buttons["write_neutral_pose_joint_position"].clicked.connect(utils_definition.write_neutral_pose_joint_position)
self.buttons["write_geometry"].clicked.connect(utils_definition.write_geometry)
self.buttons["write_skin_weight"].clicked.connect(utils_definition.write_skin_weight)
self.buttons["write_blendshape_target"].clicked.connect(utils_definition.write_blendshape_target)
# 创建部分按钮连接
self.buttons["create_blendshapes_for_mesh"].clicked.connect(utils_definition.create_blendshapes_for_mesh)
self.buttons["create_skin_for_mesh"].clicked.connect(utils_definition.create_skin_for_mesh)
self.buttons["unbind_skin_for_mesh"].clicked.connect(utils_definition.unbind_skin_for_mesh)
# 工具部分按钮连接
self.buttons["new_head_netural_joint_transform"].clicked.connect(utils_definition.new_head_netural_joint_transform)
self.buttons["new_body_netural_joint_transform"].clicked.connect(utils_definition.new_body_netural_joint_transform)
self.buttons["new_netural_joint_transform"].clicked.connect(utils_definition.new_netural_joint_transform)
self.buttons["quick_create_preset"].clicked.connect(utils_definition.quick_create_preset)