895 lines
27 KiB
Python
895 lines
27 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
Rigging function module
|
||
绑定系统功能模块 - 提供绑定系统相关的功能函数
|
||
"""
|
||
|
||
#===================================== IMPORT MODULES =====================================
|
||
import maya.cmds as cmds
|
||
import pymel.core as pm
|
||
import maya.mel as mel
|
||
from maya import OpenMayaUI as omui
|
||
from scripts.ui.Qt import QtWidgets, QtCore, QtGui
|
||
from scripts.ui.Qt.QtCompat import wrapInstance
|
||
import webbrowser
|
||
import subprocess
|
||
import importlib
|
||
import traceback
|
||
import sys
|
||
import os
|
||
# 导入配置
|
||
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
|
||
# Localization
|
||
from scripts.ui import localization
|
||
TEXT = localization.TEXT
|
||
|
||
#========================================== GLOBALS ========================================
|
||
# 存储当前选中的关节和控制器信息
|
||
selected_joint = None
|
||
selected_controller = None
|
||
|
||
# 存储关节和控制器的原始属性,用于撤销操作
|
||
original_joint_properties = {}
|
||
original_controller_properties = {}
|
||
|
||
#========================================== FUNCTIONS ========================================
|
||
|
||
#------------------------------------ UI UTILITIES ------------------------------------
|
||
def handle_ui_event(event_type, event_data):
|
||
"""
|
||
处理UI事件
|
||
|
||
Args:
|
||
event_type: 事件类型
|
||
event_data: 事件数据
|
||
"""
|
||
if event_type == "button_click":
|
||
# 处理按钮点击事件
|
||
print(f"Button clicked: {event_data}")
|
||
elif event_type == "slider_change":
|
||
# 处理滑条改变事件
|
||
print(f"Slider changed: {event_data}")
|
||
else:
|
||
print(f"Unknown event type: {event_type}")
|
||
|
||
def connect_ui_signals(ui_widget, event_type, event_handler):
|
||
"""
|
||
连接UI信号
|
||
|
||
Args:
|
||
ui_widget: UI控件
|
||
event_type: 事件类型
|
||
event_handler: 事件处理函数
|
||
"""
|
||
if event_type == "button_click":
|
||
# 连接按钮点击信号
|
||
ui_widget.clicked.connect(event_handler)
|
||
elif event_type == "slider_change":
|
||
# 连接滑条改变信号
|
||
ui_widget.valueChanged.connect(event_handler)
|
||
else:
|
||
print(f"Unknown event type: {event_type}")
|
||
|
||
#------------------------------------ JOINT OPERATIONS ------------------------------------
|
||
def add_joint():
|
||
"""
|
||
添加关节
|
||
|
||
在场景中创建新的关节并添加到骨骼层级结构中
|
||
"""
|
||
# 在场景中创建新的关节
|
||
try:
|
||
# 创建新关节
|
||
new_joint = cmds.joint(name="joint1", position=[0, 0, 0])
|
||
print(f"成功创建关节: {new_joint}")
|
||
return new_joint
|
||
except Exception as e:
|
||
print(f"创建关节失败: {str(e)}")
|
||
return None
|
||
|
||
def remove_joint():
|
||
"""
|
||
移除选中的关节
|
||
|
||
从场景中删除选中的关节
|
||
"""
|
||
# 获取当前选中的关节
|
||
selected = cmds.ls(selection=True, type="joint")
|
||
if not selected:
|
||
print("没有选中关节")
|
||
return False
|
||
|
||
try:
|
||
# 删除选中的关节
|
||
for joint in selected:
|
||
cmds.delete(joint)
|
||
print(f"成功删除关节: {selected}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"删除关节失败: {str(e)}")
|
||
return False
|
||
|
||
def duplicate_joint():
|
||
"""
|
||
复制选中的关节
|
||
|
||
复制场景中选中的关节及其属性
|
||
"""
|
||
# 获取当前选中的关节
|
||
selected = cmds.ls(selection=True, type="joint")
|
||
if not selected:
|
||
print("没有选中关节")
|
||
return None
|
||
|
||
try:
|
||
# 复制选中的关节
|
||
duplicated = cmds.duplicate(selected, returnRootsOnly=True)
|
||
print(f"成功复制关节: {duplicated}")
|
||
return duplicated
|
||
except Exception as e:
|
||
print(f"复制关节失败: {str(e)}")
|
||
return None
|
||
|
||
def update_joint_properties(joint_name, position=None, rotation=None, scale=None):
|
||
"""
|
||
更新关节属性
|
||
|
||
Args:
|
||
joint_name: 关节名称
|
||
position: 位置坐标 [x, y, z]
|
||
rotation: 旋转角度 [rx, ry, rz]
|
||
scale: 缩放比例 [sx, sy, sz]
|
||
"""
|
||
if not cmds.objExists(joint_name):
|
||
print(f"关节不存在: {joint_name}")
|
||
return False
|
||
|
||
try:
|
||
# 更新位置
|
||
if position:
|
||
cmds.setAttr(f"{joint_name}.translateX", position[0])
|
||
cmds.setAttr(f"{joint_name}.translateY", position[1])
|
||
cmds.setAttr(f"{joint_name}.translateZ", position[2])
|
||
|
||
# 更新旋转
|
||
if rotation:
|
||
cmds.setAttr(f"{joint_name}.rotateX", rotation[0])
|
||
cmds.setAttr(f"{joint_name}.rotateY", rotation[1])
|
||
cmds.setAttr(f"{joint_name}.rotateZ", rotation[2])
|
||
|
||
# 更新缩放
|
||
if scale:
|
||
cmds.setAttr(f"{joint_name}.scaleX", scale[0])
|
||
cmds.setAttr(f"{joint_name}.scaleY", scale[1])
|
||
cmds.setAttr(f"{joint_name}.scaleZ", scale[2])
|
||
|
||
print(f"成功更新关节属性: {joint_name}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"更新关节属性失败: {str(e)}")
|
||
return False
|
||
|
||
def reset_joint_properties(joint_name):
|
||
"""
|
||
重置关节属性
|
||
|
||
Args:
|
||
joint_name: 关节名称
|
||
"""
|
||
if not cmds.objExists(joint_name):
|
||
print(f"关节不存在: {joint_name}")
|
||
return False
|
||
|
||
try:
|
||
# 重置位置
|
||
cmds.setAttr(f"{joint_name}.translateX", 0)
|
||
cmds.setAttr(f"{joint_name}.translateY", 0)
|
||
cmds.setAttr(f"{joint_name}.translateZ", 0)
|
||
|
||
# 重置旋转
|
||
cmds.setAttr(f"{joint_name}.rotateX", 0)
|
||
cmds.setAttr(f"{joint_name}.rotateY", 0)
|
||
cmds.setAttr(f"{joint_name}.rotateZ", 0)
|
||
|
||
# 重置缩放
|
||
cmds.setAttr(f"{joint_name}.scaleX", 1)
|
||
cmds.setAttr(f"{joint_name}.scaleY", 1)
|
||
cmds.setAttr(f"{joint_name}.scaleZ", 1)
|
||
|
||
print(f"成功重置关节属性: {joint_name}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"重置关节属性失败: {str(e)}")
|
||
return False
|
||
|
||
#------------------------------------ CONTROLLER OPERATIONS ------------------------------------
|
||
def add_controller():
|
||
"""
|
||
添加控制器
|
||
|
||
在场景中创建新的控制器
|
||
"""
|
||
try:
|
||
# 创建控制器曲线
|
||
circle = cmds.circle(name="controller1", normal=[0, 1, 0], radius=1)[0]
|
||
print(f"成功创建控制器: {circle}")
|
||
return circle
|
||
except Exception as e:
|
||
print(f"创建控制器失败: {str(e)}")
|
||
return None
|
||
|
||
def remove_controller():
|
||
"""
|
||
移除选中的控制器
|
||
|
||
从场景中删除选中的控制器
|
||
"""
|
||
# 获取当前选中的控制器
|
||
selected = cmds.ls(selection=True, type="transform")
|
||
if not selected:
|
||
print("没有选中控制器")
|
||
return False
|
||
|
||
try:
|
||
# 删除选中的控制器
|
||
for ctrl in selected:
|
||
cmds.delete(ctrl)
|
||
print(f"成功删除控制器: {selected}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"删除控制器失败: {str(e)}")
|
||
return False
|
||
|
||
def duplicate_controller():
|
||
"""
|
||
复制选中的控制器
|
||
|
||
复制场景中选中的控制器及其属性
|
||
"""
|
||
# 获取当前选中的控制器
|
||
selected = cmds.ls(selection=True, type="transform")
|
||
if not selected:
|
||
print("没有选中控制器")
|
||
return None
|
||
|
||
try:
|
||
# 复制选中的控制器
|
||
duplicated = cmds.duplicate(selected, returnRootsOnly=True)
|
||
print(f"成功复制控制器: {duplicated}")
|
||
return duplicated
|
||
except Exception as e:
|
||
print(f"复制控制器失败: {str(e)}")
|
||
return None
|
||
|
||
def update_controller_properties(controller_name, position=None, rotation=None, scale=None, color=None):
|
||
"""
|
||
更新控制器属性
|
||
|
||
Args:
|
||
controller_name: 控制器名称
|
||
position: 位置坐标 [x, y, z]
|
||
rotation: 旋转角度 [rx, ry, rz]
|
||
scale: 缩放比例 [sx, sy, sz]
|
||
color: 控制器颜色索引
|
||
"""
|
||
if not cmds.objExists(controller_name):
|
||
print(f"控制器不存在: {controller_name}")
|
||
return False
|
||
|
||
try:
|
||
# 更新位置
|
||
if position:
|
||
cmds.setAttr(f"{controller_name}.translateX", position[0])
|
||
cmds.setAttr(f"{controller_name}.translateY", position[1])
|
||
cmds.setAttr(f"{controller_name}.translateZ", position[2])
|
||
|
||
# 更新旋转
|
||
if rotation:
|
||
cmds.setAttr(f"{controller_name}.rotateX", rotation[0])
|
||
cmds.setAttr(f"{controller_name}.rotateY", rotation[1])
|
||
cmds.setAttr(f"{controller_name}.rotateZ", rotation[2])
|
||
|
||
# 更新缩放
|
||
if scale:
|
||
cmds.setAttr(f"{controller_name}.scaleX", scale[0])
|
||
cmds.setAttr(f"{controller_name}.scaleY", scale[1])
|
||
cmds.setAttr(f"{controller_name}.scaleZ", scale[2])
|
||
|
||
# 更新颜色
|
||
if color is not None:
|
||
shapes = cmds.listRelatives(controller_name, shapes=True)
|
||
if shapes:
|
||
for shape in shapes:
|
||
cmds.setAttr(f"{shape}.overrideEnabled", 1)
|
||
cmds.setAttr(f"{shape}.overrideColor", color)
|
||
|
||
print(f"成功更新控制器属性: {controller_name}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"更新控制器属性失败: {str(e)}")
|
||
return False
|
||
|
||
def reset_controller_properties(controller_name):
|
||
"""
|
||
重置控制器属性
|
||
|
||
Args:
|
||
controller_name: 控制器名称
|
||
"""
|
||
if not cmds.objExists(controller_name):
|
||
print(f"控制器不存在: {controller_name}")
|
||
return False
|
||
|
||
try:
|
||
# 重置位置
|
||
cmds.setAttr(f"{controller_name}.translateX", 0)
|
||
cmds.setAttr(f"{controller_name}.translateY", 0)
|
||
cmds.setAttr(f"{controller_name}.translateZ", 0)
|
||
|
||
# 重置旋转
|
||
cmds.setAttr(f"{controller_name}.rotateX", 0)
|
||
cmds.setAttr(f"{controller_name}.rotateY", 0)
|
||
cmds.setAttr(f"{controller_name}.rotateZ", 0)
|
||
|
||
# 重置缩放
|
||
cmds.setAttr(f"{controller_name}.scaleX", 1)
|
||
cmds.setAttr(f"{controller_name}.scaleY", 1)
|
||
cmds.setAttr(f"{controller_name}.scaleZ", 1)
|
||
|
||
print(f"成功重置控制器属性: {controller_name}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"重置控制器属性失败: {str(e)}")
|
||
return False
|
||
|
||
#------------------------------------ DNA OPERATIONS ------------------------------------
|
||
def import_dna():
|
||
"""
|
||
导入DNA文件
|
||
|
||
从文件中导入DNA数据
|
||
"""
|
||
try:
|
||
# 打开文件对话框选择DNA文件
|
||
file_path = cmds.fileDialog2(fileFilter="DNA Files (*.dna);;All Files (*.*)", dialogStyle=2, fileMode=1)
|
||
if not file_path:
|
||
return None
|
||
|
||
file_path = file_path[0] # 获取选中的文件路径
|
||
|
||
# 这里应该调用DNA导入API
|
||
# 暂时使用打印信息代替
|
||
print(f"导入DNA文件: {file_path}")
|
||
return file_path
|
||
except Exception as e:
|
||
print(f"导入DNA文件失败: {str(e)}")
|
||
return None
|
||
|
||
def export_dna():
|
||
"""
|
||
导出DNA文件
|
||
|
||
将当前绑定数据导出为DNA文件
|
||
"""
|
||
try:
|
||
# 打开文件对话框选择保存路径
|
||
file_path = cmds.fileDialog2(fileFilter="DNA Files (*.dna);;All Files (*.*)", dialogStyle=2, fileMode=0)
|
||
if not file_path:
|
||
return None
|
||
|
||
file_path = file_path[0] # 获取选中的文件路径
|
||
|
||
# 确保文件扩展名为.dna
|
||
if not file_path.lower().endswith(".dna"):
|
||
file_path += ".dna"
|
||
|
||
# 这里应该调用DNA导出API
|
||
# 暂时使用打印信息代替
|
||
print(f"导出DNA文件: {file_path}")
|
||
return file_path
|
||
except Exception as e:
|
||
print(f"导出DNA文件失败: {str(e)}")
|
||
return None
|
||
|
||
def calibrate_dna():
|
||
"""
|
||
校准DNA数据
|
||
|
||
校准当前绑定数据与DNA标准
|
||
"""
|
||
try:
|
||
# 这里应该调用DNA校准API
|
||
# 暂时使用打印信息代替
|
||
print("校准DNA数据")
|
||
return True
|
||
except Exception as e:
|
||
print(f"校准DNA数据失败: {str(e)}")
|
||
return False
|
||
|
||
#------------------------------------ UTILITY FUNCTIONS ------------------------------------
|
||
def update_ui_list(list_widget, items):
|
||
"""
|
||
更新UI列表控件
|
||
|
||
Args:
|
||
list_widget: 列表控件
|
||
items: 要添加的项目列表
|
||
"""
|
||
if not list_widget:
|
||
return
|
||
|
||
# 清空列表
|
||
list_widget.clear()
|
||
|
||
# 添加项目
|
||
for item in items:
|
||
list_widget.addItem(item)
|
||
|
||
def update_group_count(list_widget, group_name):
|
||
"""
|
||
更新组标题中的计数
|
||
|
||
Args:
|
||
list_widget: 列表控件
|
||
group_name: 组名称
|
||
"""
|
||
if not list_widget:
|
||
return
|
||
|
||
# 获取列表项目数量
|
||
count = list_widget.count()
|
||
|
||
# 更新组标题
|
||
group_box = list_widget.parent()
|
||
if isinstance(group_box, QtWidgets.QGroupBox):
|
||
group_box.setTitle(f"{group_name} ({count})")
|
||
|
||
#------------------------------------ UI EVENT HANDLERS ------------------------------------
|
||
def handle_joint_name_changed(ui_widget):
|
||
"""
|
||
处理关节名称变化事件
|
||
|
||
Args:
|
||
ui_widget: UI控件,应该是一个文本输入框
|
||
"""
|
||
global selected_joint
|
||
# 获取当前选中的关节和新名称
|
||
if selected_joint and ui_widget:
|
||
new_name = ui_widget.text()
|
||
if new_name and new_name != selected_joint:
|
||
try:
|
||
# 重命名关节
|
||
cmds.rename(selected_joint, new_name)
|
||
selected_joint = new_name
|
||
return True
|
||
except Exception as e:
|
||
print(f"重命名关节失败: {str(e)}")
|
||
return False
|
||
return False
|
||
|
||
def handle_joint_position_changed(axis, value=None, ui_widgets=None):
|
||
"""
|
||
处理关节位置变化事件
|
||
|
||
Args:
|
||
axis: 轴向 (0=X, 1=Y, 2=Z)
|
||
value: 新的位置值,如果为None则从ui_widgets中获取
|
||
ui_widgets: UI控件列表 [x_spin, y_spin, z_spin]
|
||
"""
|
||
global selected_joint
|
||
if not selected_joint:
|
||
return False
|
||
|
||
# 获取当前位置
|
||
pos = [
|
||
cmds.getAttr(f"{selected_joint}.translateX"),
|
||
cmds.getAttr(f"{selected_joint}.translateY"),
|
||
cmds.getAttr(f"{selected_joint}.translateZ")
|
||
]
|
||
|
||
# 更新指定轴向的位置
|
||
if value is not None:
|
||
pos[axis] = value
|
||
elif ui_widgets and len(ui_widgets) >= 3:
|
||
if axis == 0 and ui_widgets[0]:
|
||
pos[0] = ui_widgets[0].value()
|
||
elif axis == 1 and ui_widgets[1]:
|
||
pos[1] = ui_widgets[1].value()
|
||
elif axis == 2 and ui_widgets[2]:
|
||
pos[2] = ui_widgets[2].value()
|
||
else:
|
||
return False
|
||
|
||
# 更新关节属性
|
||
return update_joint_properties(selected_joint, position=pos)
|
||
|
||
def handle_joint_rotation_changed(axis, value=None, ui_widgets=None):
|
||
"""
|
||
处理关节旋转变化事件
|
||
|
||
Args:
|
||
axis: 轴向 (0=X, 1=Y, 2=Z)
|
||
value: 新的旋转值,如果为None则从ui_widgets中获取
|
||
ui_widgets: UI控件列表 [x_spin, y_spin, z_spin]
|
||
"""
|
||
global selected_joint
|
||
if not selected_joint:
|
||
return False
|
||
|
||
# 获取当前旋转
|
||
rot = [
|
||
cmds.getAttr(f"{selected_joint}.rotateX"),
|
||
cmds.getAttr(f"{selected_joint}.rotateY"),
|
||
cmds.getAttr(f"{selected_joint}.rotateZ")
|
||
]
|
||
|
||
# 更新指定轴向的旋转
|
||
if value is not None:
|
||
rot[axis] = value
|
||
elif ui_widgets and len(ui_widgets) >= 3:
|
||
if axis == 0 and ui_widgets[0]:
|
||
rot[0] = ui_widgets[0].value()
|
||
elif axis == 1 and ui_widgets[1]:
|
||
rot[1] = ui_widgets[1].value()
|
||
elif axis == 2 and ui_widgets[2]:
|
||
rot[2] = ui_widgets[2].value()
|
||
else:
|
||
return False
|
||
|
||
# 更新关节属性
|
||
return update_joint_properties(selected_joint, rotation=rot)
|
||
|
||
def handle_joint_scale_changed(axis, value=None, ui_widgets=None):
|
||
"""
|
||
处理关节缩放变化事件
|
||
|
||
Args:
|
||
axis: 轴向 (0=X, 1=Y, 2=Z)
|
||
value: 新的缩放值,如果为None则从ui_widgets中获取
|
||
ui_widgets: UI控件列表 [x_spin, y_spin, z_spin]
|
||
"""
|
||
global selected_joint
|
||
if not selected_joint:
|
||
return False
|
||
|
||
# 获取当前缩放
|
||
scale = [
|
||
cmds.getAttr(f"{selected_joint}.scaleX"),
|
||
cmds.getAttr(f"{selected_joint}.scaleY"),
|
||
cmds.getAttr(f"{selected_joint}.scaleZ")
|
||
]
|
||
|
||
# 更新指定轴向的缩放
|
||
if value is not None:
|
||
scale[axis] = value
|
||
elif ui_widgets and len(ui_widgets) >= 3:
|
||
if axis == 0 and ui_widgets[0]:
|
||
scale[0] = ui_widgets[0].value()
|
||
elif axis == 1 and ui_widgets[1]:
|
||
scale[1] = ui_widgets[1].value()
|
||
elif axis == 2 and ui_widgets[2]:
|
||
scale[2] = ui_widgets[2].value()
|
||
else:
|
||
return False
|
||
|
||
# 更新关节属性
|
||
return update_joint_properties(selected_joint, scale=scale)
|
||
|
||
def apply_joint_properties_from_ui(pos_widgets=None, rot_widgets=None, scale_widgets=None):
|
||
"""
|
||
从UI控件中应用关节属性
|
||
|
||
Args:
|
||
pos_widgets: 位置控件列表 [x_spin, y_spin, z_spin]
|
||
rot_widgets: 旋转控件列表 [x_spin, y_spin, z_spin]
|
||
scale_widgets: 缩放控件列表 [x_spin, y_spin, z_spin]
|
||
"""
|
||
global selected_joint
|
||
if not selected_joint:
|
||
return False
|
||
|
||
# 获取UI中的属性值
|
||
pos = None
|
||
rot = None
|
||
scale = None
|
||
|
||
if pos_widgets and len(pos_widgets) >= 3:
|
||
pos = [
|
||
pos_widgets[0].value() if pos_widgets[0] else 0,
|
||
pos_widgets[1].value() if pos_widgets[1] else 0,
|
||
pos_widgets[2].value() if pos_widgets[2] else 0
|
||
]
|
||
|
||
if rot_widgets and len(rot_widgets) >= 3:
|
||
rot = [
|
||
rot_widgets[0].value() if rot_widgets[0] else 0,
|
||
rot_widgets[1].value() if rot_widgets[1] else 0,
|
||
rot_widgets[2].value() if rot_widgets[2] else 0
|
||
]
|
||
|
||
if scale_widgets and len(scale_widgets) >= 3:
|
||
scale = [
|
||
scale_widgets[0].value() if scale_widgets[0] else 1,
|
||
scale_widgets[1].value() if scale_widgets[1] else 1,
|
||
scale_widgets[2].value() if scale_widgets[2] else 1
|
||
]
|
||
|
||
# 更新关节属性
|
||
return update_joint_properties(selected_joint, position=pos, rotation=rot, scale=scale)
|
||
|
||
def reset_joint_properties_ui(pos_widgets=None, rot_widgets=None, scale_widgets=None):
|
||
"""
|
||
重置关节属性UI
|
||
|
||
Args:
|
||
pos_widgets: 位置控件列表 [x_spin, y_spin, z_spin]
|
||
rot_widgets: 旋转控件列表 [x_spin, y_spin, z_spin]
|
||
scale_widgets: 缩放控件列表 [x_spin, y_spin, z_spin]
|
||
"""
|
||
global selected_joint
|
||
if not selected_joint:
|
||
return False
|
||
|
||
# 重置关节属性
|
||
reset_joint_properties(selected_joint)
|
||
|
||
# 更新UI显示
|
||
if pos_widgets and len(pos_widgets) >= 3:
|
||
if pos_widgets[0]:
|
||
pos_widgets[0].setValue(0)
|
||
if pos_widgets[1]:
|
||
pos_widgets[1].setValue(0)
|
||
if pos_widgets[2]:
|
||
pos_widgets[2].setValue(0)
|
||
|
||
if rot_widgets and len(rot_widgets) >= 3:
|
||
if rot_widgets[0]:
|
||
rot_widgets[0].setValue(0)
|
||
if rot_widgets[1]:
|
||
rot_widgets[1].setValue(0)
|
||
if rot_widgets[2]:
|
||
rot_widgets[2].setValue(0)
|
||
|
||
if scale_widgets and len(scale_widgets) >= 3:
|
||
if scale_widgets[0]:
|
||
scale_widgets[0].setValue(1)
|
||
if scale_widgets[1]:
|
||
scale_widgets[1].setValue(1)
|
||
if scale_widgets[2]:
|
||
scale_widgets[2].setValue(1)
|
||
|
||
return True
|
||
|
||
def update_joint_ui(joint_name, name_widget=None, pos_widgets=None, rot_widgets=None, scale_widgets=None):
|
||
"""
|
||
更新关节UI
|
||
|
||
Args:
|
||
joint_name: 关节名称
|
||
name_widget: 名称控件
|
||
pos_widgets: 位置控件列表 [x_spin, y_spin, z_spin]
|
||
rot_widgets: 旋转控件列表 [x_spin, y_spin, z_spin]
|
||
scale_widgets: 缩放控件列表 [x_spin, y_spin, z_spin]
|
||
"""
|
||
global selected_joint
|
||
if not cmds.objExists(joint_name):
|
||
return False
|
||
|
||
# 更新选中的关节
|
||
selected_joint = joint_name
|
||
|
||
# 更新名称控件
|
||
if name_widget:
|
||
name_widget.setText(joint_name)
|
||
|
||
# 获取关节属性
|
||
pos = [
|
||
cmds.getAttr(f"{joint_name}.translateX"),
|
||
cmds.getAttr(f"{joint_name}.translateY"),
|
||
cmds.getAttr(f"{joint_name}.translateZ")
|
||
]
|
||
|
||
rot = [
|
||
cmds.getAttr(f"{joint_name}.rotateX"),
|
||
cmds.getAttr(f"{joint_name}.rotateY"),
|
||
cmds.getAttr(f"{joint_name}.rotateZ")
|
||
]
|
||
|
||
scale = [
|
||
cmds.getAttr(f"{joint_name}.scaleX"),
|
||
cmds.getAttr(f"{joint_name}.scaleY"),
|
||
cmds.getAttr(f"{joint_name}.scaleZ")
|
||
]
|
||
|
||
# 更新UI控件
|
||
if pos_widgets and len(pos_widgets) >= 3:
|
||
if pos_widgets[0]:
|
||
pos_widgets[0].setValue(pos[0])
|
||
if pos_widgets[1]:
|
||
pos_widgets[1].setValue(pos[1])
|
||
if pos_widgets[2]:
|
||
pos_widgets[2].setValue(pos[2])
|
||
|
||
if rot_widgets and len(rot_widgets) >= 3:
|
||
if rot_widgets[0]:
|
||
rot_widgets[0].setValue(rot[0])
|
||
if rot_widgets[1]:
|
||
rot_widgets[1].setValue(rot[1])
|
||
if rot_widgets[2]:
|
||
rot_widgets[2].setValue(rot[2])
|
||
|
||
if scale_widgets and len(scale_widgets) >= 3:
|
||
if scale_widgets[0]:
|
||
scale_widgets[0].setValue(scale[0])
|
||
if scale_widgets[1]:
|
||
scale_widgets[1].setValue(scale[1])
|
||
if scale_widgets[2]:
|
||
scale_widgets[2].setValue(scale[2])
|
||
|
||
return True
|
||
|
||
def on_selection_changed():
|
||
"""
|
||
选择变化事件处理
|
||
当Maya中的选择变化时更新UI
|
||
"""
|
||
global selected_joint, selected_controller
|
||
|
||
# 获取当前选中的对象
|
||
selected = cmds.ls(selection=True)
|
||
|
||
if not selected:
|
||
# 清除选中状态
|
||
selected_joint = None
|
||
selected_controller = None
|
||
return
|
||
|
||
# 检查选中的对象类型
|
||
for obj in selected:
|
||
# 检查是否是关节
|
||
if cmds.objectType(obj) == "joint":
|
||
selected_joint = obj
|
||
# 可以在这里添加代码来更新UI
|
||
print(f"选中关节: {selected_joint}")
|
||
break
|
||
|
||
# 检查是否是控制器(通常是transform节点)
|
||
elif cmds.objectType(obj) == "transform":
|
||
# 这里可以添加额外的检查来确定是否是控制器
|
||
# 例如检查是否有特定的属性或命名规则
|
||
selected_controller = obj
|
||
# 可以在这里添加代码来更新UI
|
||
print(f"选中控制器: {selected_controller}")
|
||
break
|
||
|
||
def browse_file(ui_instance, title, input_widget, file_filter=None):
|
||
"""浏览文件或目录
|
||
|
||
Args:
|
||
ui_instance: UI实例,用于获取主窗口
|
||
title (str): 对话框标题
|
||
input_widget (QLineEdit): 用于显示路径的输入框控件
|
||
file_filter (str, optional): 文件过滤器,如果为None则浏览目录,否则浏览文件
|
||
"""
|
||
from Qt import QtWidgets
|
||
import os
|
||
|
||
current_path = input_widget.text() or os.path.expanduser("~")
|
||
|
||
if file_filter:
|
||
# 浏览文件
|
||
if file_filter == "dna":
|
||
file_filter = "DNA文件 (*.dna);;所有文件 (*.*)"
|
||
elif file_filter == "json":
|
||
file_filter = "JSON文件 (*.json);;所有文件 (*.*)"
|
||
else:
|
||
file_filter = "所有文件 (*.*)"
|
||
|
||
file_path, _ = QtWidgets.QFileDialog.getOpenFileName(
|
||
ui_instance.main_widget, title, current_path, file_filter
|
||
)
|
||
|
||
if file_path:
|
||
input_widget.setText(file_path)
|
||
else:
|
||
# 浏览目录
|
||
dir_path = QtWidgets.QFileDialog.getExistingDirectory(
|
||
ui_instance.main_widget, title, current_path
|
||
)
|
||
|
||
if dir_path:
|
||
input_widget.setText(dir_path)
|
||
|
||
def on_selection_changed(ui_instance=None):
|
||
"""处理Maya选择变化事件
|
||
|
||
Args:
|
||
ui_instance: UI实例,可选
|
||
"""
|
||
import maya.cmds as cmds
|
||
|
||
# 获取当前选择
|
||
selection = cmds.ls(selection=True)
|
||
if not selection:
|
||
return
|
||
|
||
# 更新UI显示
|
||
print(f"当前选择: {selection}")
|
||
# 这里可以添加更多的选择处理逻辑
|
||
|
||
# 如果提供了UI实例,可以更新UI
|
||
if ui_instance:
|
||
# 更新UI显示
|
||
pass
|
||
|
||
def export_presets(*args):
|
||
"""导出预设"""
|
||
print("导出预设")
|
||
# 实现导出预设的功能
|
||
|
||
def import_presets(*args):
|
||
"""导入预设"""
|
||
print("导入预设")
|
||
# 实现导入预设的功能
|
||
|
||
# ======================================= 占位函数 =======================================
|
||
# 以下是未实现功能的占位函数,用于连接未创建的按钮
|
||
|
||
def add_joint(*args):
|
||
"""添加关节(占位函数)"""
|
||
print("添加关节功能尚未实现")
|
||
|
||
def remove_joint(*args):
|
||
"""删除关节(占位函数)"""
|
||
print("删除关节功能尚未实现")
|
||
|
||
def duplicate_joint(*args):
|
||
"""复制关节(占位函数)"""
|
||
print("复制关节功能尚未实现")
|
||
|
||
def add_controller(*args):
|
||
"""添加控制器(占位函数)"""
|
||
print("添加控制器功能尚未实现")
|
||
|
||
def remove_controller(*args):
|
||
"""删除控制器(占位函数)"""
|
||
print("删除控制器功能尚未实现")
|
||
|
||
def duplicate_controller(*args):
|
||
"""复制控制器(占位函数)"""
|
||
print("复制控制器功能尚未实现")
|
||
|
||
def import_dna(*args):
|
||
"""导入DNA(占位函数)"""
|
||
print("导入DNA功能尚未实现")
|
||
|
||
def export_dna(*args):
|
||
"""导出DNA(占位函数)"""
|
||
print("导出DNA功能尚未实现")
|
||
|
||
def calibrate_dna(*args):
|
||
"""校准DNA(占位函数)"""
|
||
print("校准DNA功能尚未实现") |