679 lines
33 KiB
Python
679 lines
33 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Rigging UI Module for Plugin
|
||
绑定系统UI模块 - 负责显示骨骼绑定编辑界面和基础操作
|
||
基本功能:
|
||
- DNA浏览器
|
||
- 根据DNA导入骨骼
|
||
- 根据DNA生成身体
|
||
- DNA校准
|
||
- 骨骼位置校准
|
||
- 创建绑定
|
||
- 复制蒙皮
|
||
"""
|
||
#========================================= IMPORT =========================================
|
||
from Qt import QtWidgets, QtCore, QtGui
|
||
from Qt.QtCompat import wrapInstance
|
||
from maya import OpenMayaUI as omui
|
||
import maya.cmds as cmds
|
||
import maya.mel as mel
|
||
import maya.utils as utils
|
||
import webbrowser
|
||
import subprocess
|
||
import importlib
|
||
import traceback
|
||
import locale
|
||
import sys
|
||
import os
|
||
from scripts.ui import ui_utils
|
||
from scripts.utils import utils_rigging
|
||
#========================================== 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
|
||
LANG = localization.LANG
|
||
|
||
class RiggingUI(ui_utils.BaseUI):
|
||
"""
|
||
绑定系统UI类 - 负责显示骨骼绑定编辑界面和基础操作
|
||
继承自BaseUI类,实现绑定系统相关的UI功能
|
||
"""
|
||
#========================================== INIT ========================================
|
||
def __init__(self):
|
||
"""
|
||
初始化绑定系统UI
|
||
创建主控件和布局,并连接信号和槽
|
||
"""
|
||
super(RiggingUI, self).__init__()
|
||
|
||
# 初始化字典
|
||
self.controls = {}
|
||
self.layouts = {}
|
||
self.buttons = {}
|
||
self.splitters = {}
|
||
self.inputs = {}
|
||
self.labels = {}
|
||
|
||
# 创建主控件
|
||
self.main_widget = QtWidgets.QWidget()
|
||
self.main_widget.setObjectName("riggingMainWidget")
|
||
|
||
# 初始化UI
|
||
self.create_widgets()
|
||
self.create_layouts()
|
||
self.create_connections()
|
||
|
||
#========================================= WIDGET =======================================
|
||
def create_widgets(self):
|
||
"""
|
||
创建绑定系统UI控件
|
||
包括按钮、标签、列表等
|
||
"""
|
||
# 标题标签 - 使用HTML格式化标题
|
||
title_text = f"<h4 style='margin:0;padding:5px;'>{LANG.get('rigging_title', '骨骼绑定')}</h4>"
|
||
self.controls["title_label"] = QtWidgets.QLabel(title_text)
|
||
self.controls["title_label"].setObjectName("riggingTitleLabel")
|
||
self.controls["title_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||
self.controls["title_label"].setMaximumHeight(30) # 限制标题高度
|
||
|
||
# 创建主分割器
|
||
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Vertical)
|
||
self.splitters["main_splitter"].setObjectName("riggingMainSplitter")
|
||
|
||
# 1. Presets 面板
|
||
self.controls["presets_panel"] = QtWidgets.QWidget()
|
||
self.controls["presets_panel"].setObjectName("presetsPanel")
|
||
|
||
# Presets 组
|
||
self.controls["presets_group"] = QtWidgets.QGroupBox(LANG.get("presets", "Presets"))
|
||
self.controls["presets_group"].setObjectName("presetsGroup")
|
||
|
||
# 创建预设显示区域
|
||
self.controls["presets_scroll_area"] = QtWidgets.QScrollArea()
|
||
self.controls["presets_scroll_area"].setWidgetResizable(True)
|
||
self.controls["presets_scroll_area"].setObjectName("presetsScrollArea")
|
||
|
||
# 预设内容区域
|
||
self.controls["presets_content"] = QtWidgets.QWidget()
|
||
self.controls["presets_content"].setObjectName("presetsContent")
|
||
|
||
# 预设流布局
|
||
self.controls["presets_flow_layout"] = QtWidgets.QGridLayout(self.controls["presets_content"])
|
||
self.controls["presets_flow_layout"].setObjectName("presetsFlowLayout")
|
||
self.controls["presets_flow_layout"].setContentsMargins(5, 5, 5, 5)
|
||
self.controls["presets_flow_layout"].setSpacing(10)
|
||
|
||
# 添加测试预设项
|
||
for i in range(6): # 添加6个预设项,如图中所示
|
||
col = i % 6
|
||
row = i // 6
|
||
|
||
preset_widget = QtWidgets.QWidget()
|
||
preset_widget.setObjectName(f"preset_{i}")
|
||
preset_widget.setMinimumSize(120, 150) # 设置预设项大小
|
||
preset_widget.setMaximumSize(120, 150)
|
||
|
||
# 预设布局
|
||
preset_layout = QtWidgets.QVBoxLayout(preset_widget)
|
||
preset_layout.setContentsMargins(0, 0, 0, 0)
|
||
preset_layout.setSpacing(2)
|
||
|
||
# 预设图片
|
||
preset_image = QtWidgets.QLabel()
|
||
preset_image.setObjectName(f"preset_image_{i}")
|
||
preset_image.setMinimumSize(120, 120)
|
||
preset_image.setMaximumSize(120, 120)
|
||
preset_image.setScaledContents(True)
|
||
preset_image.setStyleSheet("background-color: #333333; border: 1px solid #555555;")
|
||
|
||
# 加载测试图片
|
||
pixmap = QtGui.QPixmap(os.path.join(ASSETS_PATH, "metahuman_placeholder.png"))
|
||
if not pixmap.isNull():
|
||
preset_image.setPixmap(pixmap)
|
||
|
||
# 预设标签
|
||
preset_label = QtWidgets.QLabel("METAHUMAN")
|
||
preset_label.setObjectName(f"preset_label_{i}")
|
||
preset_label.setAlignment(QtCore.Qt.AlignCenter)
|
||
preset_label.setStyleSheet("color: white; background-color: rgba(0, 0, 0, 128);")
|
||
|
||
# 添加到布局
|
||
preset_layout.addWidget(preset_image)
|
||
preset_layout.addWidget(preset_label)
|
||
|
||
# 添加到流布局
|
||
self.controls["presets_flow_layout"].addWidget(preset_widget, row, col)
|
||
|
||
# 设置滚动区域内容
|
||
self.controls["presets_scroll_area"].setWidget(self.controls["presets_content"])
|
||
|
||
# 预设底部滑块和按钮
|
||
self.controls["presets_slider_layout"] = QtWidgets.QHBoxLayout()
|
||
self.controls["presets_slider_layout"].setContentsMargins(5, 5, 5, 5)
|
||
self.controls["presets_slider_layout"].setSpacing(5)
|
||
|
||
# 数量显示
|
||
self.controls["presets_count_label"] = QtWidgets.QLabel("99")
|
||
self.controls["presets_count_label"].setObjectName("presetsCountLabel")
|
||
self.controls["presets_count_label"].setAlignment(QtCore.Qt.AlignCenter)
|
||
self.controls["presets_count_label"].setStyleSheet("font-weight: bold;")
|
||
|
||
# 滑块
|
||
self.controls["presets_slider"] = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||
self.controls["presets_slider"].setObjectName("presetsSlider")
|
||
self.controls["presets_slider"].setMinimum(0)
|
||
self.controls["presets_slider"].setMaximum(100)
|
||
self.controls["presets_slider"].setValue(50)
|
||
|
||
# 导出预设按钮
|
||
self.buttons["export_presets"] = QtWidgets.QPushButton(LANG.get("export_presets", "导出预设"))
|
||
self.buttons["export_presets"].setObjectName("exportPresetsButton")
|
||
self.buttons["export_presets"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "export.png")))
|
||
|
||
# 导入预设按钮
|
||
self.buttons["import_presets"] = QtWidgets.QPushButton(LANG.get("import_presets", "导入预设"))
|
||
self.buttons["import_presets"].setObjectName("importPresetsButton")
|
||
self.buttons["import_presets"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "import.png")))
|
||
|
||
# 添加到滑块布局
|
||
self.controls["presets_slider_layout"].addWidget(self.controls["presets_count_label"])
|
||
self.controls["presets_slider_layout"].addWidget(self.controls["presets_slider"])
|
||
self.controls["presets_slider_layout"].addWidget(self.buttons["export_presets"])
|
||
self.controls["presets_slider_layout"].addWidget(self.buttons["import_presets"])
|
||
|
||
# 2. Assets 面板
|
||
self.controls["assets_panel"] = QtWidgets.QWidget()
|
||
self.controls["assets_panel"].setObjectName("assetsPanel")
|
||
|
||
# Assets 组
|
||
self.controls["assets_group"] = QtWidgets.QGroupBox(LANG.get("assets", "Assets"))
|
||
self.controls["assets_group"].setObjectName("assetsGroup")
|
||
|
||
# 项目路径标签和输入框
|
||
self.controls["project_path_label"] = QtWidgets.QLabel(LANG.get("project_path", "项目路径:"))
|
||
self.controls["project_path_label"].setObjectName("projectPathLabel")
|
||
|
||
self.controls["project_path_input"] = QtWidgets.QLineEdit()
|
||
self.controls["project_path_input"].setObjectName("projectPathInput")
|
||
self.controls["project_path_input"].setText("D:/Personal/Document/maya/SuperRiggingEditor/files/data/MetaHuman")
|
||
|
||
# 浏览按钮
|
||
self.buttons["browse_path"] = QtWidgets.QPushButton("...")
|
||
self.buttons["browse_path"].setObjectName("browsePathButton")
|
||
self.buttons["browse_path"].setFixedWidth(30)
|
||
|
||
# Presets DNA 标签和输入框
|
||
self.controls["presets_dna_label"] = QtWidgets.QLabel(LANG.get("presets_dna", "Presets DNA:"))
|
||
self.controls["presets_dna_label"].setObjectName("presetsDnaLabel")
|
||
|
||
self.controls["presets_dna_input"] = QtWidgets.QLineEdit()
|
||
self.controls["presets_dna_input"].setObjectName("presetsDnaInput")
|
||
|
||
# 浏览按钮
|
||
self.buttons["browse_dna"] = QtWidgets.QPushButton("...")
|
||
self.buttons["browse_dna"].setObjectName("browseDnaButton")
|
||
self.buttons["browse_dna"].setFixedWidth(30)
|
||
|
||
# 3. Descriptor 面板
|
||
self.controls["descriptor_panel"] = QtWidgets.QWidget()
|
||
self.controls["descriptor_panel"].setObjectName("descriptorPanel")
|
||
|
||
# Descriptor 组
|
||
self.controls["descriptor_group"] = QtWidgets.QGroupBox(LANG.get("descriptor", "Descriptor"))
|
||
self.controls["descriptor_group"].setObjectName("descriptorGroup")
|
||
|
||
# 名称标签和输入框
|
||
self.controls["name_label"] = QtWidgets.QLabel(LANG.get("name", "名称:"))
|
||
self.controls["name_label"].setObjectName("nameLabel")
|
||
|
||
self.controls["name_input"] = QtWidgets.QLineEdit()
|
||
self.controls["name_input"].setObjectName("nameInput")
|
||
|
||
# 原型标签和下拉框
|
||
self.controls["archetype_label"] = QtWidgets.QLabel(LANG.get("archetype", "原型:"))
|
||
self.controls["archetype_label"].setObjectName("archetypeLabel")
|
||
|
||
self.controls["archetype_combo"] = QtWidgets.QComboBox()
|
||
self.controls["archetype_combo"].setObjectName("archetypeCombo")
|
||
self.controls["archetype_combo"].addItem("asian")
|
||
self.controls["archetype_combo"].addItem("caucasian")
|
||
self.controls["archetype_combo"].addItem("african")
|
||
|
||
# 性别标签和下拉框
|
||
self.controls["gender_label"] = QtWidgets.QLabel(LANG.get("gender", "性别:"))
|
||
self.controls["gender_label"].setObjectName("genderLabel")
|
||
|
||
self.controls["gender_combo"] = QtWidgets.QComboBox()
|
||
self.controls["gender_combo"].setObjectName("genderCombo")
|
||
self.controls["gender_combo"].addItem("female")
|
||
self.controls["gender_combo"].addItem("male")
|
||
|
||
# 年龄标签和输入框
|
||
self.controls["age_label"] = QtWidgets.QLabel(LANG.get("age", "年龄:"))
|
||
self.controls["age_label"].setObjectName("ageLabel")
|
||
|
||
self.controls["age_spinner"] = QtWidgets.QSpinBox()
|
||
self.controls["age_spinner"].setObjectName("ageSpinner")
|
||
self.controls["age_spinner"].setMinimum(1)
|
||
self.controls["age_spinner"].setMaximum(100)
|
||
self.controls["age_spinner"].setValue(18)
|
||
|
||
# 平移单位标签和下拉框
|
||
self.controls["translation_unit_label"] = QtWidgets.QLabel(LANG.get("translation_unit", "平移单位:"))
|
||
self.controls["translation_unit_label"].setObjectName("translationUnitLabel")
|
||
|
||
self.controls["translation_unit_combo"] = QtWidgets.QComboBox()
|
||
self.controls["translation_unit_combo"].setObjectName("translationUnitCombo")
|
||
self.controls["translation_unit_combo"].addItem("cm")
|
||
self.controls["translation_unit_combo"].addItem("mm")
|
||
self.controls["translation_unit_combo"].addItem("m")
|
||
|
||
# 旋转单位标签和下拉框
|
||
self.controls["rotation_unit_label"] = QtWidgets.QLabel(LANG.get("rotation_unit", "旋转单位:"))
|
||
self.controls["rotation_unit_label"].setObjectName("rotationUnitLabel")
|
||
|
||
self.controls["rotation_unit_combo"] = QtWidgets.QComboBox()
|
||
self.controls["rotation_unit_combo"].setObjectName("rotationUnitCombo")
|
||
self.controls["rotation_unit_combo"].addItem("degrees")
|
||
self.controls["rotation_unit_combo"].addItem("radians")
|
||
|
||
# 坐标系统标签和下拉框
|
||
self.controls["coordinate_system_label"] = QtWidgets.QLabel(LANG.get("coordinate_system", "坐标系统:"))
|
||
self.controls["coordinate_system_label"].setObjectName("coordinateSystemLabel")
|
||
|
||
self.controls["coordinate_system_combo"] = QtWidgets.QComboBox()
|
||
self.controls["coordinate_system_combo"].setObjectName("coordinateSystemCombo")
|
||
self.controls["coordinate_system_combo"].addItem("YAxisUp")
|
||
self.controls["coordinate_system_combo"].addItem("ZAxisUp")
|
||
|
||
# LOD数量标签和输入框
|
||
self.controls["lod_count_label"] = QtWidgets.QLabel(LANG.get("lod_count", "LOD数量:"))
|
||
self.controls["lod_count_label"].setObjectName("lodCountLabel")
|
||
|
||
self.controls["lod_count_spinner"] = QtWidgets.QSpinBox()
|
||
self.controls["lod_count_spinner"].setObjectName("lodCountSpinner")
|
||
self.controls["lod_count_spinner"].setMinimum(0)
|
||
self.controls["lod_count_spinner"].setMaximum(8)
|
||
self.controls["lod_count_spinner"].setValue(0)
|
||
|
||
# 底部按钮区域
|
||
self.controls["bottom_buttons_panel"] = QtWidgets.QWidget()
|
||
self.controls["bottom_buttons_panel"].setObjectName("bottomButtonsPanel")
|
||
|
||
# 删除所有按钮
|
||
self.buttons["remove_all"] = QtWidgets.QPushButton(LANG.get("remove_all", "删除所有"))
|
||
self.buttons["remove_all"].setObjectName("removeAllButton")
|
||
self.buttons["remove_all"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "delete.png")))
|
||
|
||
# 导入骨骼按钮
|
||
self.buttons["import_skeleton"] = QtWidgets.QPushButton(LANG.get("import_skeleton", "导入骨骼"))
|
||
self.buttons["import_skeleton"].setObjectName("importSkeletonButton")
|
||
self.buttons["import_skeleton"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "import_skeleton.png")))
|
||
|
||
# 生成绑定按钮
|
||
self.buttons["build_rigging"] = QtWidgets.QPushButton(LANG.get("build_rigging", "生成绑定"))
|
||
self.buttons["build_rigging"].setObjectName("buildRiggingButton")
|
||
self.buttons["build_rigging"].setIcon(QtGui.QIcon(os.path.join(ICONS_PATH, "build_rigging.png")))
|
||
|
||
# 左侧面板控件 - 控制器列表
|
||
self.controls["controller_group"] = QtWidgets.QGroupBox("Controllers [000]")
|
||
self.controls["controller_group"].setObjectName("controllerGroup")
|
||
|
||
# 控制器列表
|
||
self.controls["controller_list"] = QtWidgets.QListWidget()
|
||
self.controls["controller_list"].setObjectName("controllerList")
|
||
|
||
# 添加测试项目
|
||
for i in range(3):
|
||
item = QtWidgets.QListWidgetItem(f"Controller_{i}")
|
||
self.controls["controller_list"].addItem(item)
|
||
|
||
# 控制器操作按钮
|
||
self.buttons["add_controller"] = QtWidgets.QPushButton(LANG.get("add_controller", "添加控制器"))
|
||
self.buttons["add_controller"].setObjectName("addControllerButton")
|
||
|
||
self.buttons["remove_controller"] = QtWidgets.QPushButton(LANG.get("remove_controller", "移除控制器"))
|
||
self.buttons["remove_controller"].setObjectName("removeControllerButton")
|
||
|
||
self.buttons["duplicate_controller"] = QtWidgets.QPushButton(LANG.get("duplicate_controller", "复制控制器"))
|
||
self.buttons["duplicate_controller"].setObjectName("duplicateControllerButton")
|
||
|
||
# 右侧面板控件 - 关节属性
|
||
self.controls["joint_properties_group"] = QtWidgets.QGroupBox(LANG.get("joint_properties", "关节属性"))
|
||
self.controls["joint_properties_group"].setObjectName("jointPropertiesGroup")
|
||
|
||
# 关节名称标签和输入框
|
||
self.controls["joint_name_label"] = QtWidgets.QLabel(LANG.get("name", "名称:"))
|
||
self.controls["joint_name_label"].setObjectName("jointNameLabel")
|
||
|
||
self.controls["joint_name_input"] = QtWidgets.QLineEdit()
|
||
self.controls["joint_name_input"].setObjectName("jointNameInput")
|
||
self.controls["joint_name_input"].setPlaceholderText(LANG.get("enter_joint_name", "输入关节名称"))
|
||
|
||
# 关节位置标签和输入框
|
||
self.controls["joint_position_label"] = QtWidgets.QLabel(LANG.get("position", "位置:"))
|
||
self.controls["joint_position_label"].setObjectName("jointPositionLabel")
|
||
|
||
# X坐标
|
||
self.controls["joint_x_label"] = QtWidgets.QLabel("X:")
|
||
self.controls["joint_x_label"].setObjectName("jointXLabel")
|
||
|
||
self.controls["joint_x_input"] = QtWidgets.QLineEdit("0.0")
|
||
self.controls["joint_x_input"].setObjectName("jointXInput")
|
||
|
||
# Y坐标
|
||
self.controls["joint_y_label"] = QtWidgets.QLabel("Y:")
|
||
self.controls["joint_y_label"].setObjectName("jointYLabel")
|
||
|
||
self.controls["joint_y_input"] = QtWidgets.QLineEdit("0.0")
|
||
self.controls["joint_y_input"].setObjectName("jointYInput")
|
||
|
||
# Z坐标
|
||
self.controls["joint_z_label"] = QtWidgets.QLabel("Z:")
|
||
self.controls["joint_z_label"].setObjectName("jointZLabel")
|
||
|
||
self.controls["joint_z_input"] = QtWidgets.QLineEdit("0.0")
|
||
self.controls["joint_z_input"].setObjectName("jointZInput")
|
||
|
||
# 关节旋转标签和输入框
|
||
self.controls["joint_rotation_label"] = QtWidgets.QLabel(LANG.get("rotation", "旋转:"))
|
||
self.controls["joint_rotation_label"].setObjectName("jointRotationLabel")
|
||
|
||
# X旋转
|
||
self.controls["joint_rx_label"] = QtWidgets.QLabel("X:")
|
||
self.controls["joint_rx_label"].setObjectName("jointRXLabel")
|
||
|
||
self.controls["joint_rx_input"] = QtWidgets.QLineEdit("0.0")
|
||
self.controls["joint_rx_input"].setObjectName("jointRXInput")
|
||
|
||
# Y旋转
|
||
self.controls["joint_ry_label"] = QtWidgets.QLabel("Y:")
|
||
self.controls["joint_ry_label"].setObjectName("jointRYLabel")
|
||
|
||
self.controls["joint_ry_input"] = QtWidgets.QLineEdit("0.0")
|
||
self.controls["joint_ry_input"].setObjectName("jointRYInput")
|
||
|
||
# Z旋转
|
||
self.controls["joint_rz_label"] = QtWidgets.QLabel("Z:")
|
||
self.controls["joint_rz_label"].setObjectName("jointRZLabel")
|
||
|
||
self.controls["joint_rz_input"] = QtWidgets.QLineEdit("0.0")
|
||
self.controls["joint_rz_input"].setObjectName("jointRZInput")
|
||
|
||
# 关节缩放标签和输入框
|
||
self.controls["joint_scale_label"] = QtWidgets.QLabel(LANG.get("scale", "缩放:"))
|
||
self.controls["joint_scale_label"].setObjectName("jointScaleLabel")
|
||
|
||
# X缩放
|
||
self.controls["joint_sx_label"] = QtWidgets.QLabel("X:")
|
||
self.controls["joint_sx_label"].setObjectName("jointSXLabel")
|
||
|
||
self.controls["joint_sx_input"] = QtWidgets.QLineEdit("1.0")
|
||
self.controls["joint_sx_input"].setObjectName("jointSXInput")
|
||
|
||
# Y缩放
|
||
self.controls["joint_sy_label"] = QtWidgets.QLabel("Y:")
|
||
self.controls["joint_sy_label"].setObjectName("jointSYLabel")
|
||
|
||
self.controls["joint_sy_input"] = QtWidgets.QLineEdit("1.0")
|
||
self.controls["joint_sy_input"].setObjectName("jointSYInput")
|
||
|
||
# Z缩放
|
||
self.controls["joint_sz_label"] = QtWidgets.QLabel("Z:")
|
||
self.controls["joint_sz_label"].setObjectName("jointSZLabel")
|
||
|
||
self.controls["joint_sz_input"] = QtWidgets.QLineEdit("1.0")
|
||
self.controls["joint_sz_input"].setObjectName("jointSZInput")
|
||
|
||
# 关节属性按钮
|
||
self.buttons["apply_joint_properties"] = QtWidgets.QPushButton(LANG.get("apply", "应用"))
|
||
self.buttons["apply_joint_properties"].setObjectName("applyJointPropertiesButton")
|
||
|
||
self.buttons["reset_joint_properties"] = QtWidgets.QPushButton(LANG.get("reset", "重置"))
|
||
self.buttons["reset_joint_properties"].setObjectName("resetJointPropertiesButton")
|
||
|
||
# 右侧面板控件 - 绑定工具
|
||
self.controls["binding_tools_group"] = QtWidgets.QGroupBox(LANG.get("binding_tools", "绑定工具"))
|
||
self.controls["binding_tools_group"].setObjectName("bindingToolsGroup")
|
||
|
||
# 绑定工具按钮
|
||
self.buttons["create_binding"] = QtWidgets.QPushButton(LANG.get("create_binding", "创建绑定"))
|
||
self.buttons["create_binding"].setObjectName("createBindingButton")
|
||
|
||
self.buttons["copy_skin"] = QtWidgets.QPushButton(LANG.get("copy_skin", "复制蒙皮"))
|
||
self.buttons["copy_skin"].setObjectName("copySkinButton")
|
||
|
||
self.buttons["mirror_skin"] = QtWidgets.QPushButton(LANG.get("mirror_skin", "镜像蒙皮"))
|
||
self.buttons["mirror_skin"].setObjectName("mirrorSkinButton")
|
||
|
||
self.buttons["paint_weights"] = QtWidgets.QPushButton(LANG.get("paint_weights", "绘制权重"))
|
||
self.buttons["paint_weights"].setObjectName("paintWeightsButton")
|
||
|
||
# 底部工具面板
|
||
# DNA部分
|
||
self.controls["dna_group"] = QtWidgets.QGroupBox(LANG.get("dna", "DNA"))
|
||
self.controls["dna_group"].setObjectName("dnaGroup")
|
||
|
||
self.buttons["import_dna"] = QtWidgets.QPushButton(LANG.get("import_dna", "导入DNA"))
|
||
self.buttons["import_dna"].setObjectName("importDnaButton")
|
||
|
||
self.buttons["export_dna"] = QtWidgets.QPushButton(LANG.get("export_dna", "导出DNA"))
|
||
self.buttons["export_dna"].setObjectName("exportDnaButton")
|
||
|
||
self.buttons["calibrate_dna"] = QtWidgets.QPushButton(LANG.get("calibrate_dna", "校准DNA"))
|
||
self.buttons["calibrate_dna"].setObjectName("calibrateDnaButton")
|
||
|
||
# 骨骼部分
|
||
self.controls["skeleton_tools_group"] = QtWidgets.QGroupBox(LANG.get("skeleton_tools", "骨骼工具"))
|
||
self.controls["skeleton_tools_group"].setObjectName("skeletonToolsGroup")
|
||
|
||
self.buttons["import_skeleton"] = QtWidgets.QPushButton(LANG.get("import_skeleton", "导入骨骼"))
|
||
self.buttons["import_skeleton"].setObjectName("importSkeletonButton")
|
||
|
||
self.buttons["export_skeleton"] = QtWidgets.QPushButton(LANG.get("export_skeleton", "导出骨骼"))
|
||
self.buttons["export_skeleton"].setObjectName("exportSkeletonButton")
|
||
|
||
self.buttons["calibrate_skeleton"] = QtWidgets.QPushButton(LANG.get("calibrate_skeleton", "校准骨骼"))
|
||
self.buttons["calibrate_skeleton"].setObjectName("calibrateSkeletonButton")
|
||
|
||
# 工具部分
|
||
self.controls["rigging_tools_group"] = QtWidgets.QGroupBox(LANG.get("rigging_tools", "绑定工具"))
|
||
self.controls["rigging_tools_group"].setObjectName("riggingToolsGroup")
|
||
|
||
self.buttons["generate_controllers"] = QtWidgets.QPushButton(LANG.get("generate_controllers", "生成控制器"))
|
||
self.buttons["generate_controllers"].setObjectName("generateControllersButton")
|
||
|
||
self.buttons["generate_body"] = QtWidgets.QPushButton(LANG.get("generate_body", "生成身体"))
|
||
self.buttons["generate_body"].setObjectName("generateBodyButton")
|
||
|
||
self.buttons["clean_rigging"] = QtWidgets.QPushButton(LANG.get("clean_rigging", "清理绑定"))
|
||
self.buttons["clean_rigging"].setObjectName("cleanRiggingButton")
|
||
|
||
#========================================= LAYOUT =======================================
|
||
def create_layouts(self):
|
||
"""
|
||
创建绑定系统UI布局
|
||
组织控件的排列和层次结构
|
||
"""
|
||
# 创建主布局
|
||
main_layout = QtWidgets.QVBoxLayout(self.main_widget)
|
||
main_layout.setContentsMargins(5, 5, 5, 5)
|
||
main_layout.setSpacing(5)
|
||
|
||
# 添加标题
|
||
main_layout.addWidget(self.controls["title_label"])
|
||
|
||
# 添加主分割器到主布局
|
||
main_layout.addWidget(self.splitters["main_splitter"])
|
||
|
||
# 1. Presets 面板布局
|
||
presets_layout = QtWidgets.QVBoxLayout(self.controls["presets_panel"])
|
||
presets_layout.setContentsMargins(0, 0, 0, 0)
|
||
presets_layout.setSpacing(5)
|
||
|
||
# Presets 组布局
|
||
presets_group_layout = QtWidgets.QVBoxLayout(self.controls["presets_group"])
|
||
presets_group_layout.setContentsMargins(5, 5, 5, 5)
|
||
presets_group_layout.setSpacing(5)
|
||
|
||
# 添加预设滚动区域
|
||
presets_group_layout.addWidget(self.controls["presets_scroll_area"])
|
||
|
||
# 添加预设底部滑块布局
|
||
presets_group_layout.addLayout(self.controls["presets_slider_layout"])
|
||
|
||
# 添加Presets组到Presets面板
|
||
presets_layout.addWidget(self.controls["presets_group"])
|
||
|
||
# 2. Assets 面板布局
|
||
assets_layout = QtWidgets.QVBoxLayout(self.controls["assets_panel"])
|
||
assets_layout.setContentsMargins(0, 0, 0, 0)
|
||
assets_layout.setSpacing(5)
|
||
|
||
# Assets 组布局
|
||
assets_group_layout = QtWidgets.QGridLayout(self.controls["assets_group"])
|
||
assets_group_layout.setContentsMargins(5, 5, 5, 5)
|
||
assets_group_layout.setSpacing(5)
|
||
|
||
# 添加项目路径标签和输入框
|
||
assets_group_layout.addWidget(self.controls["project_path_label"], 0, 0)
|
||
assets_group_layout.addWidget(self.controls["project_path_input"], 0, 1)
|
||
assets_group_layout.addWidget(self.buttons["browse_path"], 0, 2)
|
||
|
||
# 添加Presets DNA标签和输入框
|
||
assets_group_layout.addWidget(self.controls["presets_dna_label"], 1, 0)
|
||
assets_group_layout.addWidget(self.controls["presets_dna_input"], 1, 1)
|
||
assets_group_layout.addWidget(self.buttons["browse_dna"], 1, 2)
|
||
|
||
# 添加Assets组到Assets面板
|
||
assets_layout.addWidget(self.controls["assets_group"])
|
||
|
||
# 3. Descriptor 面板布局
|
||
descriptor_layout = QtWidgets.QVBoxLayout(self.controls["descriptor_panel"])
|
||
descriptor_layout.setContentsMargins(0, 0, 0, 0)
|
||
descriptor_layout.setSpacing(5)
|
||
|
||
# Descriptor 组布局
|
||
descriptor_group_layout = QtWidgets.QGridLayout(self.controls["descriptor_group"])
|
||
descriptor_group_layout.setContentsMargins(5, 5, 5, 5)
|
||
descriptor_group_layout.setSpacing(5)
|
||
|
||
# 添加名称标签和输入框
|
||
descriptor_group_layout.addWidget(self.controls["name_label"], 0, 0)
|
||
descriptor_group_layout.addWidget(self.controls["name_input"], 0, 1, 1, 3)
|
||
|
||
# 添加原型标签和下拉框
|
||
descriptor_group_layout.addWidget(self.controls["archetype_label"], 1, 0)
|
||
descriptor_group_layout.addWidget(self.controls["archetype_combo"], 1, 1)
|
||
|
||
# 添加性别标签和下拉框
|
||
descriptor_group_layout.addWidget(self.controls["gender_label"], 1, 2)
|
||
descriptor_group_layout.addWidget(self.controls["gender_combo"], 1, 3)
|
||
|
||
# 添加年龄标签和输入框
|
||
descriptor_group_layout.addWidget(self.controls["age_label"], 2, 0)
|
||
descriptor_group_layout.addWidget(self.controls["age_spinner"], 2, 1)
|
||
|
||
# 添加平移单位标签和下拉框
|
||
descriptor_group_layout.addWidget(self.controls["translation_unit_label"], 3, 0)
|
||
descriptor_group_layout.addWidget(self.controls["translation_unit_combo"], 3, 1)
|
||
|
||
# 添加旋转单位标签和下拉框
|
||
descriptor_group_layout.addWidget(self.controls["rotation_unit_label"], 3, 2)
|
||
descriptor_group_layout.addWidget(self.controls["rotation_unit_combo"], 3, 3)
|
||
|
||
# 添加坐标系统标签和下拉框
|
||
descriptor_group_layout.addWidget(self.controls["coordinate_system_label"], 4, 0)
|
||
descriptor_group_layout.addWidget(self.controls["coordinate_system_combo"], 4, 1)
|
||
|
||
# 添加LOD数量标签和输入框
|
||
descriptor_group_layout.addWidget(self.controls["lod_count_label"], 4, 2)
|
||
descriptor_group_layout.addWidget(self.controls["lod_count_spinner"], 4, 3)
|
||
|
||
# 添加Descriptor组到Descriptor面板
|
||
descriptor_layout.addWidget(self.controls["descriptor_group"])
|
||
|
||
# 添加各个面板到主分割器
|
||
self.splitters["main_splitter"].addWidget(self.controls["presets_panel"])
|
||
self.splitters["main_splitter"].addWidget(self.controls["assets_panel"])
|
||
self.splitters["main_splitter"].addWidget(self.controls["descriptor_panel"])
|
||
|
||
# 底部按钮区域布局
|
||
bottom_buttons_layout = QtWidgets.QHBoxLayout(self.controls["bottom_buttons_panel"])
|
||
bottom_buttons_layout.setContentsMargins(5, 5, 5, 5)
|
||
bottom_buttons_layout.setSpacing(10)
|
||
|
||
# 添加底部按钮
|
||
bottom_buttons_layout.addWidget(self.buttons["remove_all"])
|
||
bottom_buttons_layout.addStretch(1) # 添加弹性空间
|
||
bottom_buttons_layout.addWidget(self.buttons["import_skeleton"])
|
||
bottom_buttons_layout.addWidget(self.buttons["build_rigging"])
|
||
|
||
# 添加底部按钮区域到主布局
|
||
main_layout.addWidget(self.controls["bottom_buttons_panel"])
|
||
|
||
# 设置分割器初始大小
|
||
self.splitters["main_splitter"].setSizes([400, 100, 200])
|
||
|
||
# 设置分割器的伸缩因子
|
||
for i in range(self.splitters["main_splitter"].count()):
|
||
self.splitters["main_splitter"].setStretchFactor(i, 1)
|
||
|
||
#======================================= FUNCTIONS ======================================
|
||
def create_connections(self):
|
||
"""
|
||
创建信号连接
|
||
"""
|
||
# 创建信号映射字典
|
||
signal_mapping = {
|
||
'buttons': {
|
||
# 绑定所有功能按钮
|
||
'add_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.add_joint},
|
||
'remove_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.remove_joint},
|
||
'duplicate_joint_btn': {'signal': 'clicked', 'handler': utils_rigging.duplicate_joint},
|
||
'add_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.add_controller},
|
||
'remove_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.remove_controller},
|
||
'duplicate_controller_btn': {'signal': 'clicked', 'handler': utils_rigging.duplicate_controller},
|
||
'import_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.import_dna},
|
||
'export_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.export_dna},
|
||
'calibrate_dna_btn': {'signal': 'clicked', 'handler': utils_rigging.calibrate_dna},
|
||
|
||
# 已创建的按钮
|
||
'browse_path': {'signal': 'clicked', 'handler': lambda: utils_rigging.browse_file(self, "项目路径", self.controls["project_path_input"])},
|
||
'browse_dna': {'signal': 'clicked', 'handler': lambda: utils_rigging.browse_file(self, "DNA文件", self.controls["presets_dna_input"], "dna")},
|
||
'export_presets': {'signal': 'clicked', 'handler': utils_rigging.export_presets},
|
||
'import_presets': {'signal': 'clicked', 'handler': utils_rigging.import_presets},
|
||
},
|
||
'splitters': {
|
||
'main_splitter': {'signal': 'splitterMoved', 'handler': lambda pos, index: ui_utils.on_splitter_moved(self, pos, index)},
|
||
}
|
||
}
|
||
|
||
# 使用ui_utils中的通用函数连接信号
|
||
ui_utils.connect_ui_signals(self, signal_mapping)
|
||
|
||
# 连接Maya选择变化事件
|
||
ui_utils.connect_maya_selection_changed(self, lambda: utils_rigging.on_selection_changed(self), self.main_widget) |