MetaFusion/scripts/ui/meshes.py
2025-02-10 01:21:32 +08:00

559 lines
19 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 -*-
#===================================== 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 MeshItem(QtWidgets.QWidget):
"""单个网格项控件"""
def __init__(self, mesh_name, parent=None):
super(MeshItem, self).__init__(parent)
self._setup_ui(mesh_name)
self._create_connections()
def _setup_ui(self, mesh_name):
"""设置UI布局"""
# === Main Layout ===
self.main_layout = QtWidgets.QHBoxLayout(self)
self.main_layout.setContentsMargins(2, 2, 2, 2)
self.main_layout.setSpacing(4)
# === Widgets ===
# 网格名称标签
self.name_label = QtWidgets.QLabel(mesh_name)
self.name_label.setMinimumWidth(100)
# 网格路径输入框
self.path_edit = QtWidgets.QLineEdit()
self.path_edit.setReadOnly(True)
# 添加按钮
self.add_btn = QtWidgets.QPushButton("添加...")
self.add_btn.setFixedWidth(60)
# === Layout ===
self.main_layout.addWidget(self.name_label)
self.main_layout.addWidget(self.path_edit)
self.main_layout.addWidget(self.add_btn)
# === Style ===
self._setup_style()
def _setup_style(self):
"""设置样式"""
self.setStyleSheet("""
QWidget {
background: #2D2D2D;
}
QLabel {
color: #CCCCCC;
font-size: 12px;
}
QLineEdit {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px 8px;
color: #CCCCCC;
}
QPushButton {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px 12px;
color: #CCCCCC;
min-width: 60px;
}
QPushButton:hover {
background: #454545;
}
QPushButton:pressed {
background: #2A2A2A;
}
""")
def _create_connections(self):
"""创建信号连接"""
self.add_btn.clicked.connect(self._on_add_clicked)
def _on_add_clicked(self):
"""添加按钮点击"""
# TODO: 实现添加逻辑
pass
class MeshesTab(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MeshesTab, self).__init__(parent)
self._setup_ui()
self._create_connections()
def _setup_ui(self):
"""设置UI布局"""
# === Main Layout ===
self.main_layout = QtWidgets.QVBoxLayout(self)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.setSpacing(0)
# === 顶部工具栏 ===
self.toolbar = QtWidgets.QWidget()
toolbar_layout = QtWidgets.QHBoxLayout(self.toolbar)
toolbar_layout.setContentsMargins(4, 4, 4, 4)
toolbar_layout.setSpacing(4)
# Meta-Human下拉框
self.preset_combo = QtWidgets.QComboBox()
self.preset_combo.addItem("Meta-Human")
self.preset_combo.setFixedWidth(120)
# 删除按钮移到LOD页面的功能按钮区域
toolbar_layout.addStretch()
# === 中间内容区 ===
self.content = QtWidgets.QWidget()
content_layout = QtWidgets.QVBoxLayout(self.content)
content_layout.setContentsMargins(0, 0, 0, 0)
content_layout.setSpacing(0)
# LOD标签页
self.lod_tabs = QtWidgets.QTabWidget()
for i in range(8):
tab = self._create_lod_page(i)
self.lod_tabs.addTab(tab, f"LOD{i}")
content_layout.addWidget(self.lod_tabs)
# === 底部工具栏 ===
self.bottom_toolbar = self._create_bottom_toolbar()
# === 添加到主布局 ===
self.main_layout.addWidget(self.toolbar)
self.main_layout.addWidget(self.content)
self.main_layout.addWidget(self.bottom_toolbar)
# === 设置样式 ===
self._setup_style()
def _create_lod_page(self, lod_index):
"""创建单个LOD页面"""
# === Widget ===
widget = QtWidgets.QWidget()
# === Main Layout ===
layout = QtWidgets.QVBoxLayout(widget)
layout.setContentsMargins(8, 8, 8, 8)
layout.setSpacing(12) # 增加间距
# === 网格列表区域 ===
scroll = QtWidgets.QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QtWidgets.QFrame.NoFrame)
content = QtWidgets.QWidget()
content_layout = QtWidgets.QVBoxLayout(content)
content_layout.setContentsMargins(0, 0, 0, 0)
content_layout.setSpacing(2) # 调整项目间距
# 创建网格项
meshes = config.LOD_MESHES[f"LOD{lod_index}"]
for mesh in meshes:
item = self._create_mesh_item(mesh)
content_layout.addWidget(item)
content_layout.addStretch()
scroll.setWidget(content)
# === 底部功能按钮 ===
buttons = QtWidgets.QWidget()
button_layout = QtWidgets.QHBoxLayout(buttons)
button_layout.setContentsMargins(0, 8, 0, 8)
button_layout.setSpacing(8) # 统一按钮间距为8
# 创建功能按钮
load_btn = self._create_tool_button("自动加载模型", "load_meshes.png", "fileOpen.png")
standardize_btn = self._create_tool_button("标准化命名", "standardized_naming.png", "setEdNormalize.png")
group_btn = self._create_tool_button("自动分组", "auto_group.png", "menuIconEdit.png")
delete_btn = self._create_tool_button("清理", "delete.png", "delete.png")
# 设置按钮固定宽度
button_width = (widget.width() - 32) // 4 # 32是左右边距和3个按钮间距(8*3)的总和
for btn in [load_btn, standardize_btn, group_btn, delete_btn]:
btn.setFixedWidth(button_width)
button_layout.addWidget(btn)
# === 添加到主布局 ===
layout.addWidget(scroll)
layout.addWidget(buttons)
return widget
def _create_mesh_item(self, mesh_name):
"""创建网格项"""
item = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout(item)
layout.setContentsMargins(4, 2, 4, 2) # 减小上下边距
layout.setSpacing(8)
# 网格名称标签
name_label = QtWidgets.QLabel(mesh_name)
name_label.setMinimumWidth(100)
# 网格路径输入框 - 可编辑
path_edit = QtWidgets.QLineEdit()
path_edit.setPlaceholderText("输入或选择模型路径...")
# 添加按钮
add_btn = QtWidgets.QPushButton()
add_btn.setIcon(QtGui.QIcon(":fileOpen.png"))
add_btn.setToolTip("浏览...")
add_btn.setFixedSize(24, 24) # 减小按钮大小
layout.addWidget(name_label)
layout.addWidget(path_edit)
layout.addWidget(add_btn)
# 设置样式
item.setStyleSheet("""
QWidget {
background: #2D2D2D;
}
QLabel {
color: #CCCCCC;
font-size: 12px;
}
QLineEdit {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px 8px;
color: #CCCCCC;
}
QLineEdit:hover {
border: 1px solid #666666;
}
QLineEdit:focus {
border: 1px solid #777777;
background: #404040;
}
QPushButton {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
}
QPushButton:hover {
background: #454545;
}
QPushButton:pressed {
background: #2A2A2A;
}
""")
return item
def _create_tool_button(self, text, icon_name, fallback_icon=None):
"""创建工具按钮"""
btn = QtWidgets.QPushButton(text)
# 尝试使用自定义图标如果失败则使用Maya内置图标
icon_path = f"{config.ICONS_PATH}/{icon_name}"
print(f"尝试加载图标: {icon_path}") # 添加调试输出
if os.path.exists(icon_path):
btn.setIcon(QtGui.QIcon(icon_path))
print(f"成功加载自定义图标: {icon_path}")
elif fallback_icon:
btn.setIcon(QtGui.QIcon(f":{fallback_icon}"))
print(f"使用Maya内置图标: {fallback_icon}")
else:
print(f"未能找到图标: {icon_path}")
btn.setStyleSheet("""
QPushButton {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px 8px;
color: #CCCCCC;
text-align: left;
icon-size: 16px;
min-height: 32px; # 统一按钮高度
}
QPushButton:hover {
background: #454545;
}
QPushButton:pressed {
background: #2A2A2A;
}
""")
return btn
def _create_bottom_toolbar(self):
"""创建底部工具栏"""
# === Widget ===
widget = QtWidgets.QWidget()
widget.setFixedHeight(180) # 增加高度
# === Main Layout ===
layout = QtWidgets.QVBoxLayout(widget)
layout.setContentsMargins(8, 8, 8, 8) # 增加边距
layout.setSpacing(8)
# === 第一行工具栏 - 预设和LOD ===
first_row = QtWidgets.QWidget()
first_layout = QtWidgets.QHBoxLayout(first_row)
first_layout.setContentsMargins(4, 0, 4, 0)
first_layout.setSpacing(4)
# 预设名称
self.preset_label = QtWidgets.QLabel("预设名称:")
self.preset_name_combo = QtWidgets.QComboBox()
self.preset_name_combo.addItem("Meta-Human")
self.preset_name_combo.setFixedWidth(150)
# 选择LOD
self.lod_label = QtWidgets.QLabel("选择LOD:")
self.lod_combo = QtWidgets.QComboBox()
self.lod_combo.addItems(["全部"] + [f"LOD{i}" for i in range(8)])
self.lod_combo.setFixedWidth(100)
# 创建LOD按钮
self.create_lod_btn = QtWidgets.QPushButton()
self.create_lod_btn.setIcon(QtGui.QIcon(f"{config.ICONS_PATH}/create_lod.png"))
self.create_lod_btn.setText("生成当前LOD")
first_layout.addWidget(self.preset_label)
first_layout.addWidget(self.preset_name_combo)
first_layout.addStretch()
first_layout.addWidget(self.lod_label)
first_layout.addWidget(self.lod_combo)
first_layout.addWidget(self.create_lod_btn)
# === 功能按钮区域 ===
buttons_widget = QtWidgets.QWidget()
buttons_layout = QtWidgets.QVBoxLayout(buttons_widget)
buttons_layout.setContentsMargins(4, 4, 4, 4)
buttons_layout.setSpacing(8)
# 创建按钮行
row1 = QtWidgets.QWidget()
row1_layout = QtWidgets.QHBoxLayout(row1)
row1_layout.setContentsMargins(0, 0, 0, 0)
row1_layout.setSpacing(8)
row2 = QtWidgets.QWidget()
row2_layout = QtWidgets.QHBoxLayout(row2)
row2_layout.setContentsMargins(0, 0, 0, 0)
row2_layout.setSpacing(8)
row3 = QtWidgets.QWidget()
row3_layout = QtWidgets.QHBoxLayout(row3)
row3_layout.setContentsMargins(0, 0, 0, 0)
row3_layout.setSpacing(8)
# 创建按钮
self.separate_btn = self._create_tool_button("模型分离", "separate.png", "polySplitVertex.png")
self.face_accessory_btn = self._create_tool_button("生成面部配件", "supplement_meshes.png", "polyCreateFacet.png")
self.fix_normal_btn = self._create_tool_button("修复法线", "repair_normals.png", "polyNormal.png")
self.fix_vertex_order_btn = self._create_tool_button("修复点序", "repair_vertex_order.png", "polyNormalPerVertex.png")
self.fix_seam_btn = self._create_tool_button("修复接缝", "fix_seam.png", "polyChipOff.png")
# 设置按钮固定宽度
button_width = (widget.width() - 24) // 2 # 24是左右边距和按钮间距(8)的总和
for btn in [self.separate_btn, self.face_accessory_btn,
self.fix_normal_btn, self.fix_vertex_order_btn,
self.fix_seam_btn]:
btn.setFixedWidth(button_width)
# 添加按钮到行
row1_layout.addStretch()
row1_layout.addWidget(self.separate_btn)
row1_layout.addWidget(self.face_accessory_btn)
row1_layout.addStretch()
row2_layout.addStretch()
row2_layout.addWidget(self.fix_normal_btn)
row2_layout.addWidget(self.fix_vertex_order_btn)
row2_layout.addStretch()
# 修复接缝按钮不居中
row3_layout.addWidget(self.fix_seam_btn)
row3_layout.addStretch()
# 添加行到布局
buttons_layout.addWidget(row1)
buttons_layout.addWidget(row2)
buttons_layout.addWidget(row3)
# === 添加到主布局 ===
layout.addWidget(first_row)
layout.addWidget(buttons_widget)
# 添加窗口大小变化事件处理
widget.resizeEvent = lambda event: self._adjust_button_widths(event, [
self.separate_btn, self.face_accessory_btn,
self.fix_normal_btn, self.fix_vertex_order_btn,
self.fix_seam_btn
])
return widget
def _adjust_button_widths(self, event, buttons):
"""调整按钮宽度以适应窗口大小"""
width = event.size().width()
button_width = (width - 24) // 2 # 24是左右边距和按钮间距(8)的总和
for btn in buttons:
btn.setFixedWidth(button_width)
def _setup_style(self):
"""设置样式"""
# 工具栏样式
self.toolbar.setStyleSheet("""
QWidget {
background: #2D2D2D;
}
QComboBox {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px;
color: #CCCCCC;
}
""")
# 标签页样式
self.lod_tabs.setStyleSheet("""
QTabWidget::pane {
border: none;
background: #2D2D2D;
}
QTabBar::tab {
background: #3D3D3D;
border: none;
min-width: 40px; # 减小最小宽度
padding: 4px 8px; # 减小内边距
color: #CCCCCC;
margin-right: 1px;
}
QTabBar::tab:selected {
background: #4D4D4D;
color: #FFFFFF;
}
QTabBar::tab:hover:!selected {
background: #454545;
}
QTabBar::tab:first {
margin-left: 0px;
}
""")
# 应用样式到下拉框
for combo in [self.preset_combo, self.preset_name_combo, self.lod_combo]:
combo.setStyleSheet("""
QComboBox {
background: #3D3D3D;
border: 1px solid #555555;
border-radius: 2px;
padding: 4px;
color: #CCCCCC;
}
""")
# 应用样式到标签
for label in [self.preset_label, self.lod_label]:
label.setStyleSheet("color: #CCCCCC;")
def _create_connections(self):
"""创建信号连接"""
# 顶部工具栏
self.preset_combo.currentIndexChanged.connect(self._on_preset_changed)
# 底部工具栏
self.create_lod_btn.clicked.connect(self._on_create_lod)
self.separate_btn.clicked.connect(self._on_separate)
self.face_accessory_btn.clicked.connect(self._on_face_accessory)
self.fix_normal_btn.clicked.connect(self._on_fix_normal)
self.fix_vertex_order_btn.clicked.connect(self._on_fix_vertex_order)
self.fix_seam_btn.clicked.connect(self._on_fix_seam)
# === Event Handlers ===
def _on_preset_changed(self, index):
"""预设改变"""
# TODO: 实现预设切换
pass
def _on_create_lod(self):
"""生成当前LOD"""
# TODO: 实现生成当前LOD
pass
def _on_separate(self):
"""模型分离"""
# TODO: 实现模型分离
pass
def _on_face_accessory(self):
"""生成面部配件"""
# TODO: 实现生成面部配件
pass
def _on_fix_normal(self):
"""修复法线"""
# TODO: 实现修复法线
pass
def _on_fix_vertex_order(self):
"""修复点序"""
# TODO: 实现修复点序
pass
def _on_fix_seam(self):
"""修复接缝"""
# TODO: 实现修复接缝
pass
def _on_load_meshes(self, lod_index):
"""自动加载模型"""
# TODO: 实现自动加载模型
print(f"加载 LOD{lod_index} 的模型")
pass
def _on_standardize_names(self, lod_index):
"""标准化命名"""
# TODO: 实现标准化命名
print(f"标准化 LOD{lod_index} 的命名")
pass
def _on_auto_group(self, lod_index):
"""自动分组"""
# TODO: 实现自动分组
print(f"自动分组 LOD{lod_index}")
pass
if __name__ == "__main__":
pass