Files
MetaFusion/scripts/ui/rigging.py
2025-05-05 21:38:04 +08:00

836 lines
36 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 -*-
"""
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
#========================================= LOCATION =======================================
from scripts.ui import localization
LANG = localization.LANG
class RiggingUI(ui_utils.BaseUI):
"""
绑定系统UI类 - 负责显示骨骼绑定编辑界面和基础操作
继承自BaseUI类实现绑定系统相关的UI功能
"""
#======================================= FUNCTIONS ======================================
def on_show_event(self, event):
"""
显示事件处理
当面板显示时重置分割器大小
"""
self.reset_splitter_sizes()
super(RiggingUI, self).showEvent(event)
def reset_splitter_sizes(self):
"""
重置分割器大小,确保左右栏宽度均等
"""
if self.splitters["main_splitter"]:
width = self.splitters["main_splitter"].width()
self.splitters["main_splitter"].setSizes([width // 2, width // 2])
def on_splitter_moved(self, pos, index):
"""
分割器移动事件处理
记录当前分割器位置
"""
utils_rigging.update_splitter_position(self.splitters["main_splitter"])
# 左侧面板 - 骨骼列表操作
def add_joint(self):
"""
添加关节
"""
utils_rigging.add_joint(self.controls["skeleton_list"])
def remove_joint(self):
"""
移除关节
"""
utils_rigging.remove_joint(self.controls["skeleton_list"])
def duplicate_joint(self):
"""
复制关节
"""
utils_rigging.duplicate_joint(self.controls["skeleton_list"])
def on_joint_selection_changed(self):
"""
关节选择变化事件
更新关节属性面板
"""
utils_rigging.update_joint_properties(
self.controls["skeleton_list"],
self.controls["joint_name_input"],
self.controls["joint_x_input"],
self.controls["joint_y_input"],
self.controls["joint_z_input"],
self.controls["joint_rx_input"],
self.controls["joint_ry_input"],
self.controls["joint_rz_input"],
self.controls["joint_sx_input"],
self.controls["joint_sy_input"],
self.controls["joint_sz_input"]
)
# 左侧面板 - 控制器列表操作
def add_controller(self):
"""
添加控制器
"""
utils_rigging.add_controller(self.controls["controller_list"])
def remove_controller(self):
"""
移除控制器
"""
utils_rigging.remove_controller(self.controls["controller_list"])
def duplicate_controller(self):
"""
复制控制器
"""
utils_rigging.duplicate_controller(self.controls["controller_list"])
def on_controller_selection_changed(self):
"""
控制器选择变化事件
更新控制器属性
"""
utils_rigging.update_controller_properties(self.controls["controller_list"])
# 右侧面板 - 关节属性
def on_joint_name_changed(self):
"""
关节名称变化事件
"""
utils_rigging.update_joint_name(
self.controls["skeleton_list"],
self.controls["joint_name_input"]
)
def on_joint_position_changed(self, axis):
"""
关节位置变化事件
"""
utils_rigging.update_joint_position(
self.controls["skeleton_list"],
axis,
self.controls[f"joint_{axis}_input"]
)
def on_joint_rotation_changed(self, axis):
"""
关节旋转变化事件
"""
utils_rigging.update_joint_rotation(
self.controls["skeleton_list"],
axis,
self.controls[f"joint_r{axis}_input"]
)
def on_joint_scale_changed(self, axis):
"""
关节缩放变化事件
"""
utils_rigging.update_joint_scale(
self.controls["skeleton_list"],
axis,
self.controls[f"joint_s{axis}_input"]
)
def apply_joint_properties(self):
"""
应用关节属性
"""
utils_rigging.apply_joint_properties(
self.controls["skeleton_list"],
self.controls["joint_name_input"],
self.controls["joint_x_input"],
self.controls["joint_y_input"],
self.controls["joint_z_input"],
self.controls["joint_rx_input"],
self.controls["joint_ry_input"],
self.controls["joint_rz_input"],
self.controls["joint_sx_input"],
self.controls["joint_sy_input"],
self.controls["joint_sz_input"]
)
def reset_joint_properties(self):
"""
重置关节属性
"""
utils_rigging.reset_joint_properties(
self.controls["skeleton_list"],
self.controls["joint_name_input"],
self.controls["joint_x_input"],
self.controls["joint_y_input"],
self.controls["joint_z_input"],
self.controls["joint_rx_input"],
self.controls["joint_ry_input"],
self.controls["joint_rz_input"],
self.controls["joint_sx_input"],
self.controls["joint_sy_input"],
self.controls["joint_sz_input"]
)
# 右侧面板 - 绑定工具
def create_binding(self):
"""
创建绑定
"""
utils_rigging.create_binding()
def copy_skin(self):
"""
复制蒙皮
"""
utils_rigging.copy_skin()
def mirror_skin(self):
"""
镜像蒙皮
"""
utils_rigging.mirror_skin()
def paint_weights(self):
"""
绘制权重
"""
utils_rigging.paint_weights()
# 底部工具面板 - DNA操作
def import_dna(self):
"""
导入DNA
"""
utils_rigging.import_dna()
def export_dna(self):
"""
导出DNA
"""
utils_rigging.export_dna()
def calibrate_dna(self):
"""
校准DNA
"""
utils_rigging.calibrate_dna()
# 底部工具面板 - 骨骼工具
def import_skeleton(self):
"""
导入骨骼
"""
utils_rigging.import_skeleton()
def export_skeleton(self):
"""
导出骨骼
"""
utils_rigging.export_skeleton()
def calibrate_skeleton(self):
"""
校准骨骼
"""
utils_rigging.calibrate_skeleton()
# 底部工具面板 - 绑定工具
def generate_controllers(self):
"""
生成控制器
"""
utils_rigging.generate_controllers()
def generate_body(self):
"""
生成身体
"""
utils_rigging.generate_body()
def clean_rigging(self):
"""
清理绑定
"""
utils_rigging.clean_rigging()
#========================================== INIT ========================================
def __init__(self):
"""
初始化绑定系统UI
创建主控件和布局,并连接信号和槽
"""
super(RiggingUI, self).__init__()
# 创建主控件
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.controls["left_panel"] = QtWidgets.QWidget()
self.controls["left_panel"].setObjectName("riggingLeftPanel")
# 右侧面板
self.controls["right_panel"] = QtWidgets.QWidget()
self.controls["right_panel"].setObjectName("riggingRightPanel")
# 左侧面板控件 - 骨骼列表
self.controls["skeleton_group"] = QtWidgets.QGroupBox("Skeleton [000]")
self.controls["skeleton_group"].setObjectName("skeletonGroup")
# 骨骼列表
self.controls["skeleton_list"] = QtWidgets.QListWidget()
self.controls["skeleton_list"].setObjectName("skeletonList")
# 添加测试项目
for i in range(5):
item = QtWidgets.QListWidgetItem(f"Joint_{i}")
self.controls["skeleton_list"].addItem(item)
# 骨骼操作按钮
self.buttons["add_joint"] = QtWidgets.QPushButton(LANG.get("add_joint", "添加关节"))
self.buttons["add_joint"].setObjectName("addJointButton")
self.buttons["remove_joint"] = QtWidgets.QPushButton(LANG.get("remove_joint", "移除关节"))
self.buttons["remove_joint"].setObjectName("removeJointButton")
self.buttons["duplicate_joint"] = QtWidgets.QPushButton(LANG.get("duplicate_joint", "复制关节"))
self.buttons["duplicate_joint"].setObjectName("duplicateJointButton")
# 左侧面板控件 - 控制器列表
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布局
组织控件的排列和层次结构
"""
# 主布局
self.layouts["main_layout"] = QtWidgets.QVBoxLayout(self.main_widget)
self.layouts["main_layout"].setContentsMargins(2, 2, 2, 2)
self.layouts["main_layout"].setSpacing(2)
# 添加标题标签
self.layouts["main_layout"].addWidget(self.controls["title_label"])
# 创建主分割器
self.splitters["main_splitter"] = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
self.splitters["main_splitter"].setObjectName("riggingMainSplitter")
self.layouts["main_layout"].addWidget(self.splitters["main_splitter"])
# 左侧面板布局
self.layouts["left_layout"] = QtWidgets.QVBoxLayout(self.controls["left_panel"])
self.layouts["left_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["left_layout"].setSpacing(5)
# 骨骼组布局
self.layouts["skeleton_group_layout"] = QtWidgets.QVBoxLayout(self.controls["skeleton_group"])
self.layouts["skeleton_group_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["skeleton_group_layout"].setSpacing(5)
# 骨骼列表
self.layouts["skeleton_group_layout"].addWidget(self.controls["skeleton_list"])
# 骨骼操作按钮行
self.layouts["skeleton_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["skeleton_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["skeleton_buttons_layout"].setSpacing(2)
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["add_joint"])
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["remove_joint"])
self.layouts["skeleton_buttons_layout"].addWidget(self.buttons["duplicate_joint"])
self.layouts["skeleton_group_layout"].addLayout(self.layouts["skeleton_buttons_layout"])
# 控制器组布局
self.layouts["controller_group_layout"] = QtWidgets.QVBoxLayout(self.controls["controller_group"])
self.layouts["controller_group_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["controller_group_layout"].setSpacing(5)
# 控制器列表
self.layouts["controller_group_layout"].addWidget(self.controls["controller_list"])
# 控制器操作按钮行
self.layouts["controller_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["controller_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["controller_buttons_layout"].setSpacing(2)
self.layouts["controller_buttons_layout"].addWidget(self.buttons["add_controller"])
self.layouts["controller_buttons_layout"].addWidget(self.buttons["remove_controller"])
self.layouts["controller_buttons_layout"].addWidget(self.buttons["duplicate_controller"])
self.layouts["controller_group_layout"].addLayout(self.layouts["controller_buttons_layout"])
# 添加组到左侧面板
self.layouts["left_layout"].addWidget(self.controls["skeleton_group"])
self.layouts["left_layout"].addWidget(self.controls["controller_group"])
# 右侧面板布局
self.layouts["right_layout"] = QtWidgets.QVBoxLayout(self.controls["right_panel"])
self.layouts["right_layout"].setContentsMargins(5, 5, 5, 5)
self.layouts["right_layout"].setSpacing(5)
# 关节属性组布局
self.layouts["joint_properties_layout"] = QtWidgets.QVBoxLayout(self.controls["joint_properties_group"])
self.layouts["joint_properties_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["joint_properties_layout"].setSpacing(5)
# 关节名称行
self.layouts["joint_name_layout"] = QtWidgets.QHBoxLayout()
self.layouts["joint_name_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_name_layout"].setSpacing(5)
self.layouts["joint_name_layout"].addWidget(self.controls["joint_name_label"])
self.layouts["joint_name_layout"].addWidget(self.controls["joint_name_input"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_name_layout"])
# 关节位置行
self.layouts["joint_position_layout"] = QtWidgets.QVBoxLayout()
self.layouts["joint_position_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_position_layout"].setSpacing(2)
self.layouts["joint_position_layout"].addWidget(self.controls["joint_position_label"])
# 位置坐标行
self.layouts["position_coords_layout"] = QtWidgets.QGridLayout()
self.layouts["position_coords_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["position_coords_layout"].setSpacing(5)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_x_label"], 0, 0)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_x_input"], 0, 1)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_y_label"], 1, 0)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_y_input"], 1, 1)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_z_label"], 2, 0)
self.layouts["position_coords_layout"].addWidget(self.controls["joint_z_input"], 2, 1)
self.layouts["joint_position_layout"].addLayout(self.layouts["position_coords_layout"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_position_layout"])
# 关节旋转行
self.layouts["joint_rotation_layout"] = QtWidgets.QVBoxLayout()
self.layouts["joint_rotation_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_rotation_layout"].setSpacing(2)
self.layouts["joint_rotation_layout"].addWidget(self.controls["joint_rotation_label"])
# 旋转坐标行
self.layouts["rotation_coords_layout"] = QtWidgets.QGridLayout()
self.layouts["rotation_coords_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["rotation_coords_layout"].setSpacing(5)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rx_label"], 0, 0)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rx_input"], 0, 1)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_ry_label"], 1, 0)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_ry_input"], 1, 1)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rz_label"], 2, 0)
self.layouts["rotation_coords_layout"].addWidget(self.controls["joint_rz_input"], 2, 1)
self.layouts["joint_rotation_layout"].addLayout(self.layouts["rotation_coords_layout"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_rotation_layout"])
# 关节缩放行
self.layouts["joint_scale_layout"] = QtWidgets.QVBoxLayout()
self.layouts["joint_scale_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["joint_scale_layout"].setSpacing(2)
self.layouts["joint_scale_layout"].addWidget(self.controls["joint_scale_label"])
# 缩放坐标行
self.layouts["scale_coords_layout"] = QtWidgets.QGridLayout()
self.layouts["scale_coords_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["scale_coords_layout"].setSpacing(5)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sx_label"], 0, 0)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sx_input"], 0, 1)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sy_label"], 1, 0)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sy_input"], 1, 1)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sz_label"], 2, 0)
self.layouts["scale_coords_layout"].addWidget(self.controls["joint_sz_input"], 2, 1)
self.layouts["joint_scale_layout"].addLayout(self.layouts["scale_coords_layout"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["joint_scale_layout"])
# 属性按钮行
self.layouts["properties_buttons_layout"] = QtWidgets.QHBoxLayout()
self.layouts["properties_buttons_layout"].setContentsMargins(0, 0, 0, 0)
self.layouts["properties_buttons_layout"].setSpacing(5)
self.layouts["properties_buttons_layout"].addWidget(self.buttons["apply_joint_properties"])
self.layouts["properties_buttons_layout"].addWidget(self.buttons["reset_joint_properties"])
self.layouts["joint_properties_layout"].addLayout(self.layouts["properties_buttons_layout"])
# 绑定工具组布局
self.layouts["binding_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["binding_tools_group"])
self.layouts["binding_tools_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["binding_tools_layout"].setSpacing(5)
# 绑定工具按钮网格
self.layouts["binding_tools_grid"] = QtWidgets.QGridLayout()
self.layouts["binding_tools_grid"].setContentsMargins(0, 0, 0, 0)
self.layouts["binding_tools_grid"].setSpacing(5)
self.layouts["binding_tools_grid"].addWidget(self.buttons["create_binding"], 0, 0)
self.layouts["binding_tools_grid"].addWidget(self.buttons["copy_skin"], 0, 1)
self.layouts["binding_tools_grid"].addWidget(self.buttons["mirror_skin"], 1, 0)
self.layouts["binding_tools_grid"].addWidget(self.buttons["paint_weights"], 1, 1)
self.layouts["binding_tools_layout"].addLayout(self.layouts["binding_tools_grid"])
# 添加组到右侧面板
self.layouts["right_layout"].addWidget(self.controls["joint_properties_group"])
self.layouts["right_layout"].addWidget(self.controls["binding_tools_group"])
# 底部工具面板
self.layouts["bottom_panel"] = QtWidgets.QHBoxLayout()
self.layouts["bottom_panel"].setContentsMargins(2, 2, 2, 2)
self.layouts["bottom_panel"].setSpacing(5)
# DNA组布局
self.layouts["dna_layout"] = QtWidgets.QVBoxLayout(self.controls["dna_group"])
self.layouts["dna_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["dna_layout"].setSpacing(5)
self.layouts["dna_layout"].addWidget(self.buttons["import_dna"])
self.layouts["dna_layout"].addWidget(self.buttons["export_dna"])
self.layouts["dna_layout"].addWidget(self.buttons["calibrate_dna"])
# 骨骼工具组布局
self.layouts["skeleton_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["skeleton_tools_group"])
self.layouts["skeleton_tools_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["skeleton_tools_layout"].setSpacing(5)
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["import_skeleton"])
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["export_skeleton"])
self.layouts["skeleton_tools_layout"].addWidget(self.buttons["calibrate_skeleton"])
# 绑定工具组布局
self.layouts["rigging_tools_layout"] = QtWidgets.QVBoxLayout(self.controls["rigging_tools_group"])
self.layouts["rigging_tools_layout"].setContentsMargins(5, 10, 5, 5)
self.layouts["rigging_tools_layout"].setSpacing(5)
self.layouts["rigging_tools_layout"].addWidget(self.buttons["generate_controllers"])
self.layouts["rigging_tools_layout"].addWidget(self.buttons["generate_body"])
self.layouts["rigging_tools_layout"].addWidget(self.buttons["clean_rigging"])
# 添加组到底部面板
self.layouts["bottom_panel"].addWidget(self.controls["dna_group"])
self.layouts["bottom_panel"].addWidget(self.controls["skeleton_tools_group"])
self.layouts["bottom_panel"].addWidget(self.controls["rigging_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"])
# 设置分割器初始大小和伸缩因子
self.splitters["main_splitter"].setSizes([500, 500])
# 设置分割器的伸缩因子,确保左右栏能够自动调整宽度
for i in range(self.splitters["main_splitter"].count()):
self.splitters["main_splitter"].setStretchFactor(i, 1)
#======================================= CONNECTION =====================================
def create_connections(self):
"""
创建绑定系统UI信号和槽连接
将按钮点击等事件与相应的处理函数连接
"""
# 左侧面板 - 骨骼列表操作
self.buttons["add_joint"].clicked.connect(self.add_joint)
self.buttons["remove_joint"].clicked.connect(self.remove_joint)
self.buttons["duplicate_joint"].clicked.connect(self.duplicate_joint)
self.controls["skeleton_list"].itemSelectionChanged.connect(self.on_joint_selection_changed)
# 左侧面板 - 控制器列表操作
self.buttons["add_controller"].clicked.connect(self.add_controller)
self.buttons["remove_controller"].clicked.connect(self.remove_controller)
self.buttons["duplicate_controller"].clicked.connect(self.duplicate_controller)
self.controls["controller_list"].itemSelectionChanged.connect(self.on_controller_selection_changed)
# 右侧面板 - 关节属性
self.buttons["apply_joint_properties"].clicked.connect(self.apply_joint_properties)
self.buttons["reset_joint_properties"].clicked.connect(self.reset_joint_properties)
# 坐标输入框修改事件
self.controls["joint_name_input"].textChanged.connect(self.on_joint_name_changed)
self.controls["joint_x_input"].textChanged.connect(lambda: self.on_joint_position_changed("x"))
self.controls["joint_y_input"].textChanged.connect(lambda: self.on_joint_position_changed("y"))
self.controls["joint_z_input"].textChanged.connect(lambda: self.on_joint_position_changed("z"))
self.controls["joint_rx_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("x"))
self.controls["joint_ry_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("y"))
self.controls["joint_rz_input"].textChanged.connect(lambda: self.on_joint_rotation_changed("z"))
self.controls["joint_sx_input"].textChanged.connect(lambda: self.on_joint_scale_changed("x"))
self.controls["joint_sy_input"].textChanged.connect(lambda: self.on_joint_scale_changed("y"))
self.controls["joint_sz_input"].textChanged.connect(lambda: self.on_joint_scale_changed("z"))
# 右侧面板 - 绑定工具
self.buttons["create_binding"].clicked.connect(self.create_binding)
self.buttons["copy_skin"].clicked.connect(self.copy_skin)
self.buttons["mirror_skin"].clicked.connect(self.mirror_skin)
self.buttons["paint_weights"].clicked.connect(self.paint_weights)
# 底部工具面板 - DNA操作
self.buttons["import_dna"].clicked.connect(self.import_dna)
self.buttons["export_dna"].clicked.connect(self.export_dna)
self.buttons["calibrate_dna"].clicked.connect(self.calibrate_dna)
# 底部工具面板 - 骨骼工具
self.buttons["import_skeleton"].clicked.connect(self.import_skeleton)
self.buttons["export_skeleton"].clicked.connect(self.export_skeleton)
self.buttons["calibrate_skeleton"].clicked.connect(self.calibrate_skeleton)
# 底部工具面板 - 绑定工具
self.buttons["generate_controllers"].clicked.connect(self.generate_controllers)
self.buttons["generate_body"].clicked.connect(self.generate_body)
self.buttons["clean_rigging"].clicked.connect(self.clean_rigging)
# 分割器移动事件
self.splitters["main_splitter"].splitterMoved.connect(self.on_splitter_moved)
# 添加显示事件处理
self.showEvent = self.on_show_event