MetaFusion/scripts/ui/rigging.py

371 lines
14 KiB
Python
Raw Normal View History

2025-02-09 22:11:50 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#===================================== 1. Module Imports =====================================
import maya.OpenMayaUI as omui
from scripts import config
import maya.cmds as cmds
import maya.mel as mel
import webbrowser
import sys
import os
from scripts import config
try:
from PySide2 import QtCore, QtGui, QtWidgets
from shiboken2 import wrapInstance
print("从PySide2加载Qt和shiboken2")
except ImportError:
try:
from PySide6 import QtCore, QtGui, QtWidgets
from shiboken6 import wrapInstance
print("从PySide6加载Qt和shiboken6")
except ImportError:
try:
from PySide import QtCore, QtGui, QtWidgets
from shiboken import wrapInstance
print("从PySide加载Qt和shiboken")
except ImportError as e:
print(f"Qt加载失败: {str(e)}")
QtCore = QtGui = QtWidgets = None
wrapInstance = None
class RiggingTab(QtWidgets.QWidget):
2025-02-09 23:22:48 +08:00
def __init__(self, parent=None):
super(RiggingTab, self).__init__(parent)
self._setup_ui()
self._create_connections()
def _setup_ui(self):
"""设置UI布局"""
# === Main Layout ===
2025-02-10 03:19:08 +08:00
self.main_layout = QtWidgets.QVBoxLayout(self)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.setSpacing(0)
2025-02-09 23:22:48 +08:00
2025-02-10 03:19:08 +08:00
# === DNA预览区域 ===
self.preview_area = self._create_preview_area()
2025-02-09 23:22:48 +08:00
2025-02-10 03:19:08 +08:00
# === 设置区域 ===
self.settings_area = QtWidgets.QWidget()
settings_layout = QtWidgets.QVBoxLayout(self.settings_area)
settings_layout.setContentsMargins(8, 8, 8, 8)
settings_layout.setSpacing(4)
2025-02-09 23:22:48 +08:00
2025-02-10 03:19:08 +08:00
# === 资产设置 ===
asset_group = QtWidgets.QWidget()
asset_layout = QtWidgets.QGridLayout(asset_group)
asset_layout.setContentsMargins(0, 0, 0, 0)
asset_layout.setSpacing(4)
2025-02-09 23:22:48 +08:00
2025-02-10 03:19:08 +08:00
# 项目路径
path_label = QtWidgets.QLabel("项目路径:")
self.path_edit = QtWidgets.QLineEdit()
self.path_edit.setText("D:/Personal/Document/maya/SuperRiggingEditor/files/data/MetaHuman")
self.path_btn = QtWidgets.QPushButton("加载...")
self.path_btn.setIcon(QtGui.QIcon(":fileOpen.png")) # 使用Maya内置图标
self.path_btn.setFixedWidth(60) # 调整按钮宽度
self.path_btn.setFixedHeight(24)
2025-02-09 23:22:48 +08:00
2025-02-10 03:19:08 +08:00
# 预设文件
preset_label = QtWidgets.QLabel("预设文件:")
self.preset_edit = QtWidgets.QLineEdit()
self.preset_edit.setText("nal/Document/maya/SuperRiggingEditor/files/presets/metahuman/MH_Ada.dna")
self.preset_btn = QtWidgets.QPushButton("加载...")
self.preset_btn.setIcon(QtGui.QIcon(":fileOpen.png")) # 使用Maya内置图标
self.preset_btn.setFixedWidth(60) # 调整按钮宽度
self.preset_btn.setFixedHeight(24)
# 数据分层
layer_label = QtWidgets.QLabel("数据分层:")
self.layer_combo = QtWidgets.QComboBox()
self.layer_combo.addItem("行为(包括基础定义)")
self.override_check = QtWidgets.QCheckBox("覆盖表情")
self.override_check.setChecked(True)
self.override_check.setStyleSheet("""
QCheckBox {
background: transparent;
}
QCheckBox::indicator {
width: 16px;
height: 16px;
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
}
QCheckBox::indicator:checked {
background: #3D3D3D;
image: url(:checkboxChecked.png);
}
QCheckBox::indicator:unchecked {
background: #3D3D3D;
image: url(:checkboxUnchecked.png);
}
QCheckBox::indicator:hover {
border: 1px solid #666666;
}
""")
# 添加到资产布局
asset_layout.addWidget(path_label, 0, 0)
asset_layout.addWidget(self.path_edit, 0, 1)
asset_layout.addWidget(self.path_btn, 0, 2)
asset_layout.addWidget(preset_label, 1, 0)
asset_layout.addWidget(self.preset_edit, 1, 1)
asset_layout.addWidget(self.preset_btn, 1, 2)
asset_layout.addWidget(layer_label, 2, 0)
asset_layout.addWidget(self.layer_combo, 2, 1)
asset_layout.addWidget(self.override_check, 2, 2)
# === 描述设置 ===
desc_group = QtWidgets.QWidget()
desc_layout = QtWidgets.QGridLayout(desc_group)
desc_layout.setContentsMargins(0, 0, 0, 0)
desc_layout.setSpacing(4)
# 设置列的拉伸因子,使左右两侧均等
desc_layout.setColumnStretch(0, 0) # 左侧标签不拉伸
desc_layout.setColumnStretch(1, 1) # 左侧控件拉伸
desc_layout.setColumnStretch(2, 0) # 右侧标签不拉伸
desc_layout.setColumnStretch(3, 1) # 右侧控件拉伸
# 左侧设置
left_settings = [
("名称:", "Archetype", "line"),
("原型:", "其他", "combo"),
("性别:", "女性", "combo"),
("年龄:", "24", "spin")
]
# 右侧设置
right_settings = [
("变换单位:", "厘米", "combo"),
("旋转单位:", "角度", "combo"),
("向上轴:", "Z轴向上", "combo"),
("LOD计数:", "8", "spin")
]
# 添加左侧设置
for row, (label_text, default_value, control_type) in enumerate(left_settings):
label = QtWidgets.QLabel(label_text)
label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) # 标签左对齐
label.setFixedWidth(50) # 固定标签宽度
if control_type == "line":
control = QtWidgets.QLineEdit(default_value)
elif control_type == "combo":
control = QtWidgets.QComboBox()
control.addItem(default_value)
elif control_type == "spin":
control = QtWidgets.QSpinBox()
control.setValue(int(default_value))
desc_layout.addWidget(label, row, 0)
desc_layout.addWidget(control, row, 1)
# 添加右侧设置
for row, (label_text, default_value, control_type) in enumerate(right_settings):
label = QtWidgets.QLabel(label_text)
label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) # 标签左对齐
label.setFixedWidth(70) # 固定标签宽度,右侧标签略宽
if control_type == "line":
control = QtWidgets.QLineEdit(default_value)
elif control_type == "combo":
control = QtWidgets.QComboBox()
control.addItem(default_value)
elif control_type == "spin":
control = QtWidgets.QSpinBox()
control.setValue(int(default_value))
desc_layout.addWidget(label, row, 2)
desc_layout.addWidget(control, row, 3)
# 设置列间距
desc_layout.setHorizontalSpacing(8) # 增加列之间的间距
# === 底部按钮 ===
button_group = QtWidgets.QWidget()
button_layout = QtWidgets.QHBoxLayout(button_group)
button_layout.setContentsMargins(8, 4, 8, 4)
button_layout.setSpacing(4) # 减小按钮间距
# 创建功能按钮
self.clear_btn = self._create_tool_button("清空选项", "delete.png", "delete.png")
self.import_btn = self._create_tool_button("导入骨架", "HIKCharacterToolSkeleton.png", "kinJoint.png")
self.create_btn = self._create_tool_button("创建骨架", "HIKcreateControlRig.png", "kinHandle.png")
# 设置按钮的大小策略
for btn in [self.clear_btn, self.import_btn, self.create_btn]:
btn.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
btn.setMinimumHeight(32)
button_layout.addWidget(btn)
if btn != self.create_btn:
button_layout.addSpacing(4)
# === 添加到主设置布局 ===
settings_layout.addWidget(asset_group)
settings_layout.addWidget(desc_group)
settings_layout.addStretch()
settings_layout.addWidget(button_group)
# === 添加到主布局 ===
self.main_layout.addWidget(self.preview_area, stretch=1)
self.main_layout.addWidget(self.settings_area)
# === 设置样式 ===
self._setup_style()
def _create_preview_area(self):
"""创建DNA预览区域"""
2025-02-09 23:22:48 +08:00
widget = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout(widget)
2025-02-10 03:19:08 +08:00
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# 预览区域 - 单个大框
preview_widget = QtWidgets.QFrame()
preview_widget.setStyleSheet("""
QFrame {
background: #1D1D1D;
border: 1px solid #555555;
}
""")
preview_widget.setMinimumHeight(300) # 调整预览区域高度
# 底部控制区域
control_widget = QtWidgets.QWidget()
control_layout = QtWidgets.QHBoxLayout(control_widget)
control_layout.setContentsMargins(8, 4, 8, 4)
control_layout.setSpacing(8)
# 左侧数值显示和滑块
value_widget = QtWidgets.QWidget()
value_layout = QtWidgets.QHBoxLayout(value_widget)
value_layout.setContentsMargins(0, 0, 0, 0)
value_layout.setSpacing(4)
self.scale_value = QtWidgets.QLabel("90")
self.scale_value.setFixedWidth(30)
self.scale_value.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.scale_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.scale_slider.setRange(0, 100)
self.scale_slider.setValue(90)
self.scale_slider.valueChanged.connect(self._on_scale_changed) # 添加滑块值变化事件
value_layout.addWidget(self.scale_value)
value_layout.addWidget(self.scale_slider)
# 右侧按钮
self.export_btn = QtWidgets.QPushButton("导出预设")
self.export_btn.setIcon(QtGui.QIcon(":save.png")) # 使用Maya内置图标
self.export_btn.setFixedHeight(24)
self.export_btn.setMinimumWidth(80) # 设置最小宽度
self.import_btn = QtWidgets.QPushButton("导入预设")
self.import_btn.setIcon(QtGui.QIcon(":fileOpen.png")) # 使用Maya内置图标
self.import_btn.setFixedHeight(24)
self.import_btn.setMinimumWidth(80) # 设置最小宽度
# 添加到控制布局
# 设置这行高度
control_layout.setContentsMargins(0, 0, 0, 0)
control_layout.setSpacing(4)
control_layout.addWidget(value_widget)
control_layout.addWidget(self.export_btn)
control_layout.addWidget(self.import_btn)
2025-02-09 23:22:48 +08:00
2025-02-10 03:19:08 +08:00
# 添加到主布局
layout.addWidget(preview_widget)
layout.addWidget(control_widget)
2025-02-09 23:22:48 +08:00
return widget
2025-02-10 03:19:08 +08:00
def _create_tool_button(self, text, icon_name, fallback_icon=None):
"""创建工具按钮"""
btn = QtWidgets.QPushButton(text)
# 尝试使用自定义图标如果失败则使用Maya内置图标
icon_path = f"{config.ICONS_PATH}/{icon_name}"
if os.path.exists(icon_path):
btn.setIcon(QtGui.QIcon(icon_path))
elif fallback_icon:
btn.setIcon(QtGui.QIcon(f":{fallback_icon}"))
return btn
def _setup_style(self):
"""设置样式"""
self.setStyleSheet("""
QWidget {
background: #2D2D2D;
color: #CCCCCC;
}
QLabel {
background: transparent;
}
QLineEdit, QComboBox {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px;
color: #CCCCCC;
min-height: 22px;
}
QPushButton {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px 8px;
color: #CCCCCC;
}
QPushButton:hover {
background: #454545;
}
QPushButton:pressed {
background: #2A2A2A;
}
QCheckBox {
spacing: 8px;
background: transparent;
}
QCheckBox::indicator {
width: 16px;
height: 16px;
}
QSlider::groove:horizontal {
border: 1px solid #555555;
height: 4px;
background: #3D3D3D;
margin: 0px;
border-radius: 2px;
}
QSlider::handle:horizontal {
background: #CCCCCC;
border: 1px solid #555555;
width: 12px;
height: 12px;
margin: -4px 0;
border-radius: 6px;
}
QSlider::handle:horizontal:hover {
background: #FFFFFF;
}
""")
def _on_scale_changed(self, value):
"""滑块值变化事件处理"""
self.scale_value.setText(str(value))
2025-02-09 23:22:48 +08:00
def _create_connections(self):
"""创建信号连接"""
2025-02-10 03:19:08 +08:00
# 滑块值变化事件
self.scale_slider.valueChanged.connect(self._on_scale_changed)
# TODO: 添加信号连接
2025-02-09 23:22:48 +08:00
pass
2025-02-09 22:11:50 +08:00
if __name__ == "__main__":
pass