This commit is contained in:
2025-05-02 00:14:28 +08:00
commit 6f27dc11e3
132 changed files with 28609 additions and 0 deletions

2156
scripts/ui/Qt.py Normal file

File diff suppressed because it is too large Load Diff

4
scripts/ui/__init__.py Normal file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from . import *

233
scripts/ui/behaviour.py Normal file
View File

@@ -0,0 +1,233 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Behaviour UI Module for Plugin
行为系统UI模块 - 负责显示角色行为编辑界面和基础操作
基本功能:
- Blendshape自动加载刷新筛选
- 次级Blendshape自动加载刷新筛选
- Blendshape批量导出和导入
- Blendshape范围编辑
- Blendshape镜像
- Blendshape查找翻转目标
- Blendshape重建
- 表情控制器还原默认表情
- 查找选择表情
- 控制面板查找
- 选择关联关节
- 写入当前表情
- 写入镜像表情
"""
#===================================== IMPORT MODULES =====================================
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import sys
import os
#===================================== IMPORT FUNCTIONS ===================================
from scripts.utils import utils_behaviour as utils_behaviour
from scripts.ui import ui_utils
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
blendshape_tree = None
sub_blendshape_tree = None
blendshape_slider = None
blendshape_preview = None
behaviour_buttons = {}
def widgets():
"""
创建行为系统UI控件
"""
global blendshape_tree, sub_blendshape_tree, blendshape_slider, blendshape_preview, behaviour_buttons
# 混合变形树形视图
blendshape_tree = QtWidgets.QTreeWidget()
blendshape_tree.setHeaderLabels(["混合变形名称", "权重", "类型"])
blendshape_tree.setMinimumHeight(200)
blendshape_tree.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
blendshape_tree.header().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) # 列自动拉伸
# 次级混合变形树形视图
sub_blendshape_tree = QtWidgets.QTreeWidget()
sub_blendshape_tree.setHeaderLabels(["次级混合变形", "权重", "目标"])
sub_blendshape_tree.setMinimumHeight(150)
sub_blendshape_tree.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sub_blendshape_tree.header().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) # 列自动拉伸
# 混合变形滑块
blendshape_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
blendshape_slider.setMinimum(0)
blendshape_slider.setMaximum(100)
blendshape_slider.setValue(0)
blendshape_slider.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# 预览区域
blendshape_preview = QtWidgets.QLabel("预览区域")
blendshape_preview.setAlignment(QtCore.Qt.AlignCenter)
blendshape_preview.setStyleSheet("background-color: #333333; color: white;")
blendshape_preview.setMinimumHeight(150)
blendshape_preview.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 功能按钮 - 设置统一的大小策略
button_names = [
"refresh_blendshapes", "refresh_sub_blendshapes", "export_blendshapes", "import_blendshapes",
"edit_range", "mirror_blendshape", "find_flip_target", "rebuild_blendshape",
"reset_controller", "find_expression", "find_control_panel", "select_related_joints",
"write_current_expression", "write_mirror_expression"
]
button_texts = {
"refresh_blendshapes": "刷新混合变形",
"refresh_sub_blendshapes": "刷新次级混合变形",
"export_blendshapes": "导出混合变形",
"import_blendshapes": "导入混合变形",
"edit_range": "范围编辑",
"mirror_blendshape": "混合变形镜像",
"find_flip_target": "查找翻转目标",
"rebuild_blendshape": "重建混合变形",
"reset_controller": "还原默认表情",
"find_expression": "查找选择表情",
"find_control_panel": "控制面板查找",
"select_related_joints": "选择关联关节",
"write_current_expression": "写入当前表情",
"write_mirror_expression": "写入镜像表情"
}
for button_name in button_names:
behaviour_buttons[button_name] = QtWidgets.QPushButton(button_texts[button_name])
behaviour_buttons[button_name].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
behaviour_buttons[button_name].setMinimumWidth(120)
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建行为系统UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的behaviour_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("behaviour_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
main_layout = QtWidgets.QVBoxLayout(parent_tab)
main_layout.setContentsMargins(4, 4, 4, 4)
main_layout.setSpacing(4)
main_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) # 设置布局约束为默认,允许自适应
# 创建主分割控件
main_splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
# 左侧区域 - 混合变形列表
left_widget = QtWidgets.QWidget()
left_layout = QtWidgets.QVBoxLayout(left_widget)
left_layout.setContentsMargins(2, 2, 2, 2)
# 混合变形列表区域
blendshape_group = QtWidgets.QGroupBox("混合变形列表")
blendshape_layout = QtWidgets.QVBoxLayout(blendshape_group)
# 添加刷新按钮
refresh_layout = QtWidgets.QHBoxLayout()
refresh_layout.addWidget(behaviour_buttons["refresh_blendshapes"])
refresh_layout.addWidget(behaviour_buttons["refresh_sub_blendshapes"])
blendshape_layout.addLayout(refresh_layout)
# 创建列表分割控件
list_splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
list_splitter.addWidget(blendshape_tree)
list_splitter.addWidget(sub_blendshape_tree)
blendshape_layout.addWidget(list_splitter)
# 添加滑块
slider_layout = QtWidgets.QHBoxLayout()
slider_layout.addWidget(QtWidgets.QLabel("权重:"))
slider_layout.addWidget(blendshape_slider)
slider_layout.addWidget(QtWidgets.QLabel("0"))
blendshape_layout.addLayout(slider_layout)
left_layout.addWidget(blendshape_group)
# 左侧按钮组
left_buttons_layout = QtWidgets.QGridLayout()
left_buttons_layout.addWidget(behaviour_buttons["export_blendshapes"], 0, 0)
left_buttons_layout.addWidget(behaviour_buttons["import_blendshapes"], 0, 1)
left_buttons_layout.addWidget(behaviour_buttons["edit_range"], 1, 0)
left_buttons_layout.addWidget(behaviour_buttons["mirror_blendshape"], 1, 1)
left_buttons_layout.addWidget(behaviour_buttons["find_flip_target"], 2, 0)
left_buttons_layout.addWidget(behaviour_buttons["rebuild_blendshape"], 2, 1)
left_layout.addLayout(left_buttons_layout)
# 右侧区域 - 预览和工具
right_widget = QtWidgets.QWidget()
right_layout = QtWidgets.QVBoxLayout(right_widget)
right_layout.setContentsMargins(2, 2, 2, 2)
# 预览区域
preview_group = QtWidgets.QGroupBox("预览")
preview_layout = QtWidgets.QVBoxLayout(preview_group)
preview_layout.addWidget(blendshape_preview)
right_layout.addWidget(preview_group)
# 右侧按钮组
right_buttons_layout = QtWidgets.QGridLayout()
right_buttons_layout.addWidget(behaviour_buttons["reset_controller"], 0, 0)
right_buttons_layout.addWidget(behaviour_buttons["find_expression"], 0, 1)
right_buttons_layout.addWidget(behaviour_buttons["find_control_panel"], 1, 0)
right_buttons_layout.addWidget(behaviour_buttons["select_related_joints"], 1, 1)
right_buttons_layout.addWidget(behaviour_buttons["write_current_expression"], 2, 0)
right_buttons_layout.addWidget(behaviour_buttons["write_mirror_expression"], 2, 1)
right_layout.addLayout(right_buttons_layout)
# 添加到主分割控件
main_splitter.addWidget(left_widget)
main_splitter.addWidget(right_widget)
# 设置分割比例
main_splitter.setSizes([int(parent_tab.width() * 0.6), int(parent_tab.width() * 0.4)])
# 添加到主布局
main_layout.addWidget(main_splitter)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接行为系统UI信号和槽
"""
# 连接按钮点击事件到占位函数
behaviour_buttons["refresh_blendshapes"].clicked.connect(lambda: print("刷新混合变形功能待实现"))
behaviour_buttons["refresh_sub_blendshapes"].clicked.connect(lambda: print("刷新次级混合变形功能待实现"))
behaviour_buttons["export_blendshapes"].clicked.connect(lambda: print("导出混合变形功能待实现"))
behaviour_buttons["import_blendshapes"].clicked.connect(lambda: print("导入混合变形功能待实现"))
behaviour_buttons["edit_range"].clicked.connect(lambda: print("范围编辑功能待实现"))
behaviour_buttons["mirror_blendshape"].clicked.connect(lambda: print("混合变形镜像功能待实现"))
behaviour_buttons["find_flip_target"].clicked.connect(lambda: print("查找翻转目标功能待实现"))
behaviour_buttons["rebuild_blendshape"].clicked.connect(lambda: print("重建混合变形功能待实现"))
behaviour_buttons["reset_controller"].clicked.connect(lambda: print("还原默认表情功能待实现"))
behaviour_buttons["find_expression"].clicked.connect(lambda: print("查找选择表情功能待实现"))
behaviour_buttons["find_control_panel"].clicked.connect(lambda: print("控制面板查找功能待实现"))
behaviour_buttons["select_related_joints"].clicked.connect(lambda: print("选择关联关节功能待实现"))
behaviour_buttons["write_current_expression"].clicked.connect(lambda: print("写入当前表情功能待实现"))
behaviour_buttons["write_mirror_expression"].clicked.connect(lambda: print("写入镜像表情功能待实现"))
# 连接树形视图选择事件
blendshape_tree.itemSelectionChanged.connect(lambda: print("混合变形选择已更改"))
sub_blendshape_tree.itemSelectionChanged.connect(lambda: print("次级混合变形选择已更改"))
# 连接滑块值变化事件
blendshape_slider.valueChanged.connect(lambda value: print(f"混合变形权重已更改为: {value/100.0}"))
#===================================== PLACEHOLDER FUNCTION ===================================
def behaviour_temp_function():
return utils_behaviour.behaviour_temp_utils_function()

197
scripts/ui/definition.py Normal file
View File

@@ -0,0 +1,197 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Definition UI Module for Plugin
定义系统UI模块 - 负责显示DNA定义编辑界面和基础操作
基本功能:
- LOD, Meshes, Joints, Blendshape, AnimatedMap 加载和刷新
- 写入: 写入关节默认位置,写入几何体,写入蒙皮,写入混合变形目标
- 创建:创建混合变形,绑定蒙皮,取消蒙皮
- 工具:重新定位头部关节,重新定位身体关节,重新定位全身关节,快速创建预设
"""
#===================================== IMPORT MODULES =====================================
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import sys
import os
#===================================== IMPORT FUNCTIONS ===================================
from scripts.utils import utils_definition as utils_definition
from scripts.ui import ui_utils
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
definition_tabs = None
dna_elements = {}
definition_buttons = {}
def widgets():
"""
创建定义系统UI控件
"""
global definition_tabs, dna_elements, definition_buttons
# 创建子标签页
definition_tabs = QtWidgets.QTabWidget()
# 创建各类元素列表
dna_elements["lod_list"] = QtWidgets.QListWidget()
dna_elements["mesh_list"] = QtWidgets.QListWidget()
dna_elements["joint_list"] = QtWidgets.QListWidget()
dna_elements["blendshape_list"] = QtWidgets.QListWidget()
dna_elements["animmap_list"] = QtWidgets.QListWidget()
# 创建元素信息面板
dna_elements["element_info"] = QtWidgets.QTextEdit()
dna_elements["element_info"].setReadOnly(True)
# 功能按钮
definition_buttons["write_joint_defaults"] = QtWidgets.QPushButton("写入关节默认位置")
definition_buttons["write_geometry"] = QtWidgets.QPushButton("写入几何体")
definition_buttons["write_skinning"] = QtWidgets.QPushButton("写入蒙皮")
definition_buttons["write_blendshapes"] = QtWidgets.QPushButton("写入混合变形目标")
definition_buttons["create_blendshapes"] = QtWidgets.QPushButton("创建混合变形")
definition_buttons["bind_skin"] = QtWidgets.QPushButton("绑定蒙皮")
definition_buttons["unbind_skin"] = QtWidgets.QPushButton("取消蒙皮")
definition_buttons["reposition_head"] = QtWidgets.QPushButton("重新定位头部关节")
definition_buttons["reposition_body"] = QtWidgets.QPushButton("重新定位身体关节")
definition_buttons["reposition_all"] = QtWidgets.QPushButton("重新定位全身关节")
definition_buttons["quick_preset"] = QtWidgets.QPushButton("快速创建预设")
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建定义系统UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的definition_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("definition_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
print("父容器没有布局,布局创建失败")
return
# 创建元素标签页
elements_tab = QtWidgets.QWidget()
elements_layout = QtWidgets.QVBoxLayout(elements_tab)
# 创建分割控件
elements_splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
# 创建元素列表标签页
lists_tabs = QtWidgets.QTabWidget()
# 创建各类元素列表标签页
lod_tab = QtWidgets.QWidget()
lod_layout = QtWidgets.QVBoxLayout(lod_tab)
lod_layout.addWidget(dna_elements["lod_list"])
lists_tabs.addTab(lod_tab, "LOD")
mesh_tab = QtWidgets.QWidget()
mesh_layout = QtWidgets.QVBoxLayout(mesh_tab)
mesh_layout.addWidget(dna_elements["mesh_list"])
lists_tabs.addTab(mesh_tab, "Meshes")
joint_tab = QtWidgets.QWidget()
joint_layout = QtWidgets.QVBoxLayout(joint_tab)
joint_layout.addWidget(dna_elements["joint_list"])
lists_tabs.addTab(joint_tab, "Joints")
blendshape_tab = QtWidgets.QWidget()
blendshape_layout = QtWidgets.QVBoxLayout(blendshape_tab)
blendshape_layout.addWidget(dna_elements["blendshape_list"])
lists_tabs.addTab(blendshape_tab, "Blendshapes")
animmap_tab = QtWidgets.QWidget()
animmap_layout = QtWidgets.QVBoxLayout(animmap_tab)
animmap_layout.addWidget(dna_elements["animmap_list"])
lists_tabs.addTab(animmap_tab, "AnimatedMaps")
# 信息面板
info_group = QtWidgets.QGroupBox("元素信息")
info_layout = QtWidgets.QVBoxLayout(info_group)
info_layout.addWidget(dna_elements["element_info"])
# 添加到分割控件
elements_splitter.addWidget(lists_tabs)
elements_splitter.addWidget(info_group)
elements_layout.addWidget(elements_splitter)
# 创建工具标签页
tools_tab = QtWidgets.QWidget()
tools_layout = QtWidgets.QVBoxLayout(tools_tab)
# 创建工具分组
write_group = QtWidgets.QGroupBox("写入")
write_layout = QtWidgets.QVBoxLayout(write_group)
write_layout.addWidget(definition_buttons["write_joint_defaults"])
write_layout.addWidget(definition_buttons["write_geometry"])
write_layout.addWidget(definition_buttons["write_skinning"])
write_layout.addWidget(definition_buttons["write_blendshapes"])
create_group = QtWidgets.QGroupBox("创建")
create_layout = QtWidgets.QVBoxLayout(create_group)
create_layout.addWidget(definition_buttons["create_blendshapes"])
create_layout.addWidget(definition_buttons["bind_skin"])
create_layout.addWidget(definition_buttons["unbind_skin"])
tools_group = QtWidgets.QGroupBox("工具")
tools_layout2 = QtWidgets.QVBoxLayout(tools_group)
tools_layout2.addWidget(definition_buttons["reposition_head"])
tools_layout2.addWidget(definition_buttons["reposition_body"])
tools_layout2.addWidget(definition_buttons["reposition_all"])
tools_layout2.addWidget(definition_buttons["quick_preset"])
# 添加到工具标签页
tools_layout.addWidget(write_group)
tools_layout.addWidget(create_group)
tools_layout.addWidget(tools_group)
tools_layout.addStretch()
# 添加标签页到主标签控件
definition_tabs.addTab(elements_tab, "元素")
definition_tabs.addTab(tools_tab, "工具")
# 添加到主布局
main_layout.addWidget(definition_tabs)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接定义系统UI信号和槽
"""
# 连接按钮点击事件到占位函数
definition_buttons["write_joint_defaults"].clicked.connect(lambda: print("写入关节默认位置功能待实现"))
definition_buttons["write_geometry"].clicked.connect(lambda: print("写入几何体功能待实现"))
definition_buttons["write_skinning"].clicked.connect(lambda: print("写入蒙皮功能待实现"))
definition_buttons["write_blendshapes"].clicked.connect(lambda: print("写入混合变形目标功能待实现"))
definition_buttons["create_blendshapes"].clicked.connect(lambda: print("创建混合变形功能待实现"))
definition_buttons["bind_skin"].clicked.connect(lambda: print("绑定蒙皮功能待实现"))
definition_buttons["unbind_skin"].clicked.connect(lambda: print("取消蒙皮功能待实现"))
definition_buttons["reposition_head"].clicked.connect(lambda: print("重新定位头部关节功能待实现"))
definition_buttons["reposition_body"].clicked.connect(lambda: print("重新定位身体关节功能待实现"))
definition_buttons["reposition_all"].clicked.connect(lambda: print("重新定位全身关节功能待实现"))
definition_buttons["quick_preset"].clicked.connect(lambda: print("快速创建预设功能待实现"))
# 连接列表选择事件
for key, widget in dna_elements.items():
if isinstance(widget, QtWidgets.QListWidget):
widget.itemSelectionChanged.connect(lambda k=key: print(f"{k} 选择已更改"))
# 连接标签页切换事件
definition_tabs.currentChanged.connect(lambda index: print(f"切换到标签页: {definition_tabs.tabText(index)}"))
#===================================== PLACEHOLDER FUNCTION ===================================
def definition_temp_function():
utils_definition.definition_temp_utils_function

169
scripts/ui/geometry.py Normal file
View File

@@ -0,0 +1,169 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Geometry UI Module for Plugin
几何模型UI模块 - 负责显示几何模型编辑界面和基础操作
基本功能:
- 模型拾取以及加载
- LOD模型分级过滤
- LOD模型创建
- 自动加载模型
- 标准化命名
- 自动分组
- 生成面部配件(睫毛,舌头,泪腺 等)
- 修复接缝(修复法线)
- 修复点序
"""
#===================================== IMPORT MODULES =====================================
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import sys
import os
#===================================== IMPORT FUNCTIONS ===================================
from scripts.utils import utils_geometry as utils_geometry
from scripts.ui import ui_utils
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
model_tree = None
lod_combo = None
model_buttons = {}
model_info_panel = None
def widgets():
"""
创建几何模型UI控件
"""
global model_tree, lod_combo, model_buttons, model_info_panel
# LOD选择下拉菜单
lod_combo = QtWidgets.QComboBox()
lod_combo.addItems(["LOD0", "LOD1", "LOD2", "LOD3", "LOD4"])
lod_combo.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
lod_combo.setMinimumWidth(100)
# 模型树形视图
model_tree = QtWidgets.QTreeWidget()
model_tree.setHeaderLabels(["模型名称", "顶点数", "面数"])
model_tree.setMinimumHeight(250)
model_tree.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
model_tree.header().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) # 列自动拉伸
# 模型信息面板
model_info_panel = QtWidgets.QTextEdit()
model_info_panel.setReadOnly(True)
model_info_panel.setMinimumHeight(100)
model_info_panel.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
# 功能按钮 - 设置统一的大小策略
for button_name in ["load_model", "create_lod", "auto_load", "standardize_name",
"auto_group", "generate_accessories", "fix_seams", "fix_vertex_order"]:
model_buttons[button_name] = QtWidgets.QPushButton({
"load_model": "加载模型",
"create_lod": "创建LOD",
"auto_load": "自动加载",
"standardize_name": "标准化命名",
"auto_group": "自动分组",
"generate_accessories": "生成面部配件",
"fix_seams": "修复接缝",
"fix_vertex_order": "修复点序"
}[button_name])
model_buttons[button_name].setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
model_buttons[button_name].setMinimumWidth(120)
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建几何模型UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的geometry_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("geometry_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
main_layout = QtWidgets.QVBoxLayout(parent_tab)
main_layout.setContentsMargins(4, 4, 4, 4)
main_layout.setSpacing(4)
main_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) # 设置布局约束为默认,允许自适应
# 创建分割控件
splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
# 上部区域 - LOD选择和模型树
top_widget = QtWidgets.QWidget()
top_layout = QtWidgets.QVBoxLayout(top_widget)
top_layout.setContentsMargins(0, 0, 0, 0)
# LOD选择区域
lod_layout = QtWidgets.QHBoxLayout()
lod_layout.addWidget(QtWidgets.QLabel("LOD级别:"))
lod_layout.addWidget(lod_combo)
lod_layout.addStretch()
top_layout.addLayout(lod_layout)
# 模型树区域
model_group = QtWidgets.QGroupBox("模型列表")
model_layout = QtWidgets.QVBoxLayout(model_group)
model_layout.addWidget(model_tree)
top_layout.addWidget(model_group)
# 下部区域 - 模型信息
model_info_group = QtWidgets.QGroupBox("模型信息")
model_info_layout = QtWidgets.QVBoxLayout(model_info_group)
model_info_layout.addWidget(model_info_panel)
# 添加到分割控件
splitter.addWidget(top_widget)
splitter.addWidget(model_info_group)
# 按钮区域
button_layout = QtWidgets.QGridLayout()
button_layout.addWidget(model_buttons["load_model"], 0, 0)
button_layout.addWidget(model_buttons["create_lod"], 0, 1)
button_layout.addWidget(model_buttons["auto_load"], 1, 0)
button_layout.addWidget(model_buttons["standardize_name"], 1, 1)
button_layout.addWidget(model_buttons["auto_group"], 2, 0)
button_layout.addWidget(model_buttons["generate_accessories"], 2, 1)
button_layout.addWidget(model_buttons["fix_seams"], 3, 0)
button_layout.addWidget(model_buttons["fix_vertex_order"], 3, 1)
# 添加到主布局
main_layout.addWidget(splitter)
main_layout.addLayout(button_layout)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接几何模型UI信号和槽
"""
# 连接按钮点击事件到占位函数
model_buttons["load_model"].clicked.connect(lambda: print("加载模型功能待实现"))
model_buttons["create_lod"].clicked.connect(lambda: print("创建LOD功能待实现"))
model_buttons["auto_load"].clicked.connect(lambda: print("自动加载功能待实现"))
model_buttons["standardize_name"].clicked.connect(lambda: print("标准化命名功能待实现"))
model_buttons["auto_group"].clicked.connect(lambda: print("自动分组功能待实现"))
model_buttons["generate_accessories"].clicked.connect(lambda: print("生成面部配件功能待实现"))
model_buttons["fix_seams"].clicked.connect(lambda: print("修复接缝功能待实现"))
model_buttons["fix_vertex_order"].clicked.connect(lambda: print("修复点序功能待实现"))
# 连接LOD选择事件
lod_combo.currentIndexChanged.connect(lambda index: print(f"选择的LOD级别: {lod_combo.currentText()}"))
# 连接模型树选择事件
model_tree.itemSelectionChanged.connect(lambda: print("模型选择已更改"))
#===================================== PLACEHOLDER FUNCTION ===================================
def geometry_temp_function():
return utils_geometry.geometry_temp_utils_function()

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Localization module
"""
LANG = {
"en_US": {
},
"zh_CN": {
}
}

147
scripts/ui/rigging.py Normal file
View File

@@ -0,0 +1,147 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Rigging UI Module for Plugin
绑定系统UI模块 - 负责显示骨骼绑定编辑界面和基础操作
基本功能:
- DNA浏览器
- 根据DNA导入骨骼
- 根据DNA生成身体
- DNA校准
- 骨骼位置校准
- 创建绑定
- 复制蒙皮
"""
#===================================== IMPORT MODULES =====================================
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import sys
import os
#===================================== IMPORT FUNCTIONS ===================================
from scripts.utils import utils_rigging as utils_rigging
from scripts.ui import ui_utils
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
dna_browser_tree = None
joint_list = None
dna_info_panel = None
rig_buttons = {}
def widgets():
"""
创建绑定系统UI控件
"""
global dna_browser_tree, joint_list, dna_info_panel, rig_buttons
# DNA浏览器树形视图
dna_browser_tree = QtWidgets.QTreeWidget()
dna_browser_tree.setHeaderLabels(["DNA文件", "版本", "修改日期"])
dna_browser_tree.setMinimumHeight(200)
# 关节列表
joint_list = QtWidgets.QListWidget()
joint_list.setMinimumHeight(150)
# DNA信息面板
dna_info_panel = QtWidgets.QTextEdit()
dna_info_panel.setReadOnly(True)
dna_info_panel.setMinimumHeight(100)
# 功能按钮
rig_buttons["load_dna"] = QtWidgets.QPushButton("加载DNA")
rig_buttons["import_joints"] = QtWidgets.QPushButton("导入骨骼")
rig_buttons["generate_body"] = QtWidgets.QPushButton("生成身体")
rig_buttons["calibrate_dna"] = QtWidgets.QPushButton("DNA校准")
rig_buttons["calibrate_joints"] = QtWidgets.QPushButton("骨骼位置校准")
rig_buttons["create_binding"] = QtWidgets.QPushButton("创建绑定")
rig_buttons["copy_skinning"] = QtWidgets.QPushButton("复制蒙皮")
rig_buttons["save_dna"] = QtWidgets.QPushButton("保存DNA")
#========================================== LAYOUTS ==========================================
def layouts(parent_tab=None):
"""
创建绑定系统UI布局
Args:
parent_tab: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的rigging_tab
if not parent_tab:
parent_tab = ui_utils.get_parent_widget("rigging_tab")
if not parent_tab:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_tab.layout()
if not main_layout:
print("父容器没有布局,布局创建失败")
return
# 创建分割控件
splitter = QtWidgets.QSplitter(QtCore.Qt.Vertical)
# 上部区域 - DNA浏览器
dna_browser_group = QtWidgets.QGroupBox("DNA浏览器")
dna_browser_layout = QtWidgets.QVBoxLayout(dna_browser_group)
dna_browser_layout.addWidget(dna_browser_tree)
# 中部区域 - 关节列表
joint_list_group = QtWidgets.QGroupBox("骨骼列表")
joint_list_layout = QtWidgets.QVBoxLayout(joint_list_group)
joint_list_layout.addWidget(joint_list)
# 下部区域 - DNA信息
dna_info_group = QtWidgets.QGroupBox("DNA信息")
dna_info_layout = QtWidgets.QVBoxLayout(dna_info_group)
dna_info_layout.addWidget(dna_info_panel)
# 添加到分割控件
splitter.addWidget(dna_browser_group)
splitter.addWidget(joint_list_group)
splitter.addWidget(dna_info_group)
# 按钮区域
button_layout = QtWidgets.QGridLayout()
button_layout.addWidget(rig_buttons["load_dna"], 0, 0)
button_layout.addWidget(rig_buttons["import_joints"], 0, 1)
button_layout.addWidget(rig_buttons["generate_body"], 1, 0)
button_layout.addWidget(rig_buttons["calibrate_dna"], 1, 1)
button_layout.addWidget(rig_buttons["calibrate_joints"], 2, 0)
button_layout.addWidget(rig_buttons["create_binding"], 2, 1)
button_layout.addWidget(rig_buttons["copy_skinning"], 3, 0)
button_layout.addWidget(rig_buttons["save_dna"], 3, 1)
# 添加到主布局
main_layout.addWidget(splitter)
main_layout.addLayout(button_layout)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接绑定系统UI信号和槽
"""
# 连接按钮点击事件到占位函数
rig_buttons["load_dna"].clicked.connect(lambda: print("加载DNA功能待实现"))
rig_buttons["import_joints"].clicked.connect(lambda: print("导入骨骼功能待实现"))
rig_buttons["generate_body"].clicked.connect(lambda: print("生成身体功能待实现"))
rig_buttons["calibrate_dna"].clicked.connect(lambda: print("DNA校准功能待实现"))
rig_buttons["calibrate_joints"].clicked.connect(lambda: print("骨骼位置校准功能待实现"))
rig_buttons["create_binding"].clicked.connect(lambda: print("创建绑定功能待实现"))
rig_buttons["copy_skinning"].clicked.connect(lambda: print("复制蒙皮功能待实现"))
rig_buttons["save_dna"].clicked.connect(lambda: print("保存DNA功能待实现"))
# 连接树形视图选择事件
dna_browser_tree.itemSelectionChanged.connect(lambda: print("DNA文件选择已更改"))
# 连接关节列表选择事件
joint_list.itemSelectionChanged.connect(lambda: print("骨骼选择已更改"))
#===================================== PLACEHOLDER FUNCTION ===================================
def rigging_temp_function():
return utils_rigging.rigging_temp_utils_function()

321
scripts/ui/style.qss Normal file
View File

@@ -0,0 +1,321 @@
/* Plugin 统一样式表 */
/* 全局样式 */
QWidget {
font-family: "Microsoft YaHei", "SimHei", sans-serif;
font-size: 9pt;
color: #E0E0E0;
background-color: #333333;
}
/* 菜单样式 */
QMenuBar {
background-color: #2D2D30;
color: #E0E0E0;
}
QMenuBar::item {
background-color: transparent;
padding: 5px 10px;
}
QMenuBar::item:selected {
background-color: #007ACC;
color: white;
}
QMenu {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
}
QMenu::item {
padding: 5px 30px 5px 20px;
}
QMenu::item:selected {
background-color: #007ACC;
color: white;
}
/* 工具栏样式 */
QToolBar {
background-color: #2D2D30;
border: 1px solid #3F3F46;
spacing: 3px;
}
QToolBar::separator {
background-color: #3F3F46;
width: 1px;
height: 20px;
}
/* 标签页样式 */
QTabWidget::pane {
border: 1px solid #3F3F46;
background-color: #2D2D30;
}
QTabBar::tab {
background-color: #252526;
color: #E0E0E0;
border: 1px solid #3F3F46;
border-bottom: none;
padding: 5px 10px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
min-width: 80px;
}
QTabBar::tab:selected {
background-color: #007ACC;
color: white;
}
QTabBar::tab:hover:!selected {
background-color: #3E3E40;
}
/* 分组框样式 */
QGroupBox {
border: 1px solid #3F3F46;
border-radius: 3px;
margin-top: 10px;
padding-top: 10px;
font-weight: bold;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top left;
padding: 0 5px;
color: #E0E0E0;
}
/* 下拉框样式 */
QComboBox {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
border-radius: 3px;
padding: 3px 18px 3px 3px;
min-width: 6em;
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border-left: 1px solid #3F3F46;
}
QComboBox QAbstractItemView {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
selection-background-color: #264F78;
selection-color: white;
}
/* 按钮样式 */
QPushButton {
background-color: #0E639C;
color: white;
border: 1px solid #0E639C;
border-radius: 3px;
padding: 5px 10px;
min-width: 80px;
}
QPushButton:hover {
background-color: #1177BB;
border: 1px solid #1177BB;
}
QPushButton:pressed {
background-color: #00578A;
border: 1px solid #00578A;
}
QPushButton:disabled {
background-color: #3F3F46;
color: #9D9D9D;
border: 1px solid #3F3F46;
}
/* 输入框样式 */
QLineEdit, QTextEdit, QPlainTextEdit {
background-color: #1E1E1E;
color: #E0E0E0;
border: 1px solid #3F3F46;
border-radius: 3px;
padding: 3px;
selection-background-color: #264F78;
}
/* 单选框样式 */
QRadioButton {
color: #E0E0E0;
spacing: 5px;
}
QRadioButton::indicator {
width: 13px;
height: 13px;
}
/* 复选框样式 */
QCheckBox {
color: #E0E0E0;
spacing: 5px;
}
QCheckBox::indicator {
width: 13px;
height: 13px;
}
/* 滑块样式 */
QSlider::groove:horizontal {
border: 1px solid #3F3F46;
height: 8px;
background: #1E1E1E;
margin: 2px 0;
border-radius: 4px;
}
QSlider::handle:horizontal {
background: #007ACC;
border: 1px solid #007ACC;
width: 14px;
height: 14px;
margin: -4px 0;
border-radius: 7px;
}
QSlider::handle:horizontal:hover {
background: #1177BB;
border: 1px solid #1177BB;
}
/* 进度条样式 */
QProgressBar {
border: 1px solid #3F3F46;
border-radius: 3px;
background-color: #1E1E1E;
text-align: center;
color: white;
}
QProgressBar::chunk {
background-color: #007ACC;
width: 10px;
}
/* 列表和树视图样式 */
QTreeView, QListView, QTableView {
background-color: #1E1E1E;
alternate-background-color: #262626;
color: #E0E0E0;
border: 1px solid #3F3F46;
selection-background-color: #264F78;
selection-color: white;
outline: none;
}
QTreeView::item, QListView::item, QTableView::item {
padding: 3px;
}
QTreeView::item:selected, QListView::item:selected, QTableView::item:selected {
background-color: #264F78;
color: white;
}
QTreeView::item:hover, QListView::item:hover, QTableView::item:hover {
background-color: #2A2D2E;
}
QHeaderView::section {
background-color: #252526;
color: #E0E0E0;
padding: 3px;
border: 1px solid #3F3F46;
}
/* 滚动条样式 */
QScrollBar:vertical {
background-color: #1E1E1E;
width: 14px;
margin: 14px 0 14px 0;
border: 1px solid #3F3F46;
}
QScrollBar::handle:vertical {
background-color: #3E3E42;
min-height: 20px;
}
QScrollBar::add-line:vertical {
border: 1px solid #3F3F46;
background-color: #3E3E42;
height: 14px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
border: 1px solid #3F3F46;
background-color: #3E3E42;
height: 14px;
subcontrol-position: top;
subcontrol-origin: margin;
}
QScrollBar:horizontal {
background-color: #1E1E1E;
height: 14px;
margin: 0 14px 0 14px;
border: 1px solid #3F3F46;
}
QScrollBar::handle:horizontal {
background-color: #3E3E42;
min-width: 20px;
}
QScrollBar::add-line:horizontal {
border: 1px solid #3F3F46;
background-color: #3E3E42;
width: 14px;
subcontrol-position: right;
subcontrol-origin: margin;
}
QScrollBar::sub-line:horizontal {
border: 1px solid #3F3F46;
background-color: #3E3E42;
width: 14px;
subcontrol-position: left;
subcontrol-origin: margin;
}
/* 状态栏样式 */
QStatusBar {
background-color: #007ACC;
color: white;
}
QStatusBar::item {
border: none;
}
/* 提示框样式 */
QToolTip {
background-color: #2D2D30;
color: #E0E0E0;
border: 1px solid #3F3F46;
padding: 3px;
}

138
scripts/ui/toolbar.py Normal file
View File

@@ -0,0 +1,138 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Toolbar UI Module for Plugin
工具栏UI模块 - 负责显示工具栏界面和基础操作
基本功能:
- 加载预设
- 保存预设
- 导入DNA
- 导出DNA
- 创建RL4节点用于切换DNA编辑的状态
- 删除RL4节点用于切换DNA编辑的状态
"""
#===================================== IMPORT MODULES =====================================
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import sys
import os
#===================================== IMPORT FUNCTIONS ===================================
from scripts.utils import utils_toolbar as utils_toolbar
from scripts.ui import ui_utils
#========================================== WIDGETS ==========================================
# 全局变量存储UI控件
toolbar_buttons = {}
dna_dropdown = None
status_label = None
def widgets():
"""
创建工具栏UI控件
"""
global toolbar_buttons, dna_dropdown, status_label
# 工具栏按钮
toolbar_buttons["load_preset"] = QtWidgets.QPushButton("加载预设")
toolbar_buttons["load_preset"].setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
toolbar_buttons["load_preset"].setMinimumWidth(80)
toolbar_buttons["save_preset"] = QtWidgets.QPushButton("保存预设")
toolbar_buttons["save_preset"].setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
toolbar_buttons["save_preset"].setMinimumWidth(80)
toolbar_buttons["import_dna"] = QtWidgets.QPushButton("导入DNA")
toolbar_buttons["import_dna"].setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
toolbar_buttons["import_dna"].setMinimumWidth(80)
toolbar_buttons["export_dna"] = QtWidgets.QPushButton("导出DNA")
toolbar_buttons["export_dna"].setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
toolbar_buttons["export_dna"].setMinimumWidth(80)
toolbar_buttons["create_rl4"] = QtWidgets.QPushButton("创建RL4节点")
toolbar_buttons["create_rl4"].setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
toolbar_buttons["create_rl4"].setMinimumWidth(100)
toolbar_buttons["delete_rl4"] = QtWidgets.QPushButton("删除RL4节点")
toolbar_buttons["delete_rl4"].setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
toolbar_buttons["delete_rl4"].setMinimumWidth(100)
# DNA下拉菜单
dna_dropdown = QtWidgets.QComboBox()
dna_dropdown.addItem("选择DNA文件...")
dna_dropdown.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
dna_dropdown.setMinimumWidth(150)
# 状态标签
status_label = QtWidgets.QLabel("就绪")
status_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
status_label.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
#========================================== LAYOUTS ==========================================
def layouts(parent_frame=None):
"""
创建工具栏UI布局
Args:
parent_frame: 父容器控件由Main.py传入
"""
# 获取父容器在Main.py中创建的toolbar_frame
if not parent_frame:
parent_frame = ui_utils.get_parent_widget("toolbar_frame")
if not parent_frame:
print("无法获取父容器,布局创建失败")
return
# 创建主布局
main_layout = parent_frame.layout()
if not main_layout:
print("父容器没有布局,布局创建失败")
return
# 创建工具栏布局
toolbar_layout = QtWidgets.QHBoxLayout()
toolbar_layout.setContentsMargins(2, 2, 2, 2)
toolbar_layout.setSpacing(4)
toolbar_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) # 设置布局约束为默认,允许自适应
# 添加按钮到工具栏
toolbar_layout.addWidget(toolbar_buttons["load_preset"])
toolbar_layout.addWidget(toolbar_buttons["save_preset"])
toolbar_layout.addWidget(QtWidgets.QLabel("|"))
toolbar_layout.addWidget(toolbar_buttons["import_dna"])
toolbar_layout.addWidget(toolbar_buttons["export_dna"])
toolbar_layout.addWidget(QtWidgets.QLabel("|"))
toolbar_layout.addWidget(toolbar_buttons["create_rl4"])
toolbar_layout.addWidget(toolbar_buttons["delete_rl4"])
toolbar_layout.addWidget(QtWidgets.QLabel("|"))
toolbar_layout.addWidget(QtWidgets.QLabel("DNA文件:"))
toolbar_layout.addWidget(dna_dropdown)
toolbar_layout.addStretch()
toolbar_layout.addWidget(status_label)
# 添加到主布局
main_layout.addLayout(toolbar_layout)
#========================================== CONNECTIONS ==========================================
def connections():
"""
连接工具栏UI信号和槽
"""
# 连接按钮点击事件到占位函数
toolbar_buttons["load_preset"].clicked.connect(lambda: print("加载预设功能待实现"))
toolbar_buttons["save_preset"].clicked.connect(lambda: print("保存预设功能待实现"))
toolbar_buttons["import_dna"].clicked.connect(lambda: print("导入DNA功能待实现"))
toolbar_buttons["export_dna"].clicked.connect(lambda: print("导出DNA功能待实现"))
toolbar_buttons["create_rl4"].clicked.connect(lambda: print("创建RL4节点功能待实现"))
toolbar_buttons["delete_rl4"].clicked.connect(lambda: print("删除RL4节点功能待实现"))
# 连接下拉菜单选择事件
dna_dropdown.currentIndexChanged.connect(lambda index: print(f"选择的DNA文件索引: {index}"))
#===================================== PLACEHOLDER FUNCTION ===================================
def toolbar_temp_function():
return utils_toolbar.toolbar_temp_utils_function()

62
scripts/ui/ui_utils.py Normal file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
UI Utilities Module for Plugin
UI工具模块 - 提供UI相关的通用函数
"""
#===================================== IMPORT MODULES =====================================
from Qt import QtWidgets, QtCore, QtGui
from Qt.QtCompat import wrapInstance
from maya import OpenMayaUI as omui
import sys
import os
import config
#===================================== UI UTILITY FUNCTIONS ===================================
TOOL_NAME = config.TOOL_NAME
def get_parent_widget(widget_name):
"""
根据控件名称查找父容器控件
Args:
widget_name (str): 控件名称
Returns:
QWidget: 找到的父容器控件如果未找到则返回None
"""
# 查找主窗口中的所有控件
main_window = None
for widget in QtWidgets.QApplication.topLevelWidgets():
if widget.objectName() == f"{TOOL_NAME}MainWindow" or widget.objectName().endswith("MainWindow"):
main_window = widget
break
if not main_window:
print(f"无法找到主窗口,无法获取父容器: {widget_name}")
return None
# 在主窗口中查找指定名称的控件
found_widget = main_window.findChild(QtWidgets.QWidget, widget_name)
if found_widget:
return found_widget
# 如果未找到精确匹配,尝试模糊匹配
for child in main_window.findChildren(QtWidgets.QWidget):
if widget_name.lower() in child.objectName().lower():
return child
print(f"无法找到控件: {widget_name}")
return None
def get_maya_main_window():
"""
获取Maya主窗口
Returns:
QWidget: Maya主窗口控件
"""
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)