#!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys from PySide2 import QtCore, QtGui, QtWidgets # 添加项目根目录到 Python 路径 ROOT_DIR = os.path.dirname(os.path.dirname(__file__)) if ROOT_DIR not in sys.path: sys.path.insert(0, ROOT_DIR) from config import data from dna_utils import DNAManager QtCore, QtGui, QtWidgets = data.Qt() #===================================== 2. Global Variables ===================================== TOOL_NAME = data.TOOL_NAME TOOL_VERSION = data.TOOL_VERSION TOOL_AUTHOR = data.TOOL_AUTHOR TOOL_LANG = data.TOOL_LANG TOOL_WSCL_NAME = data.TOOL_WSCL_NAME TOOL_HELP_URL = data.TOOL_HELP_URL SCRIPTS_PATH = data.SCRIPTS_PATH ICONS_PATH = data.ICONS_PATH TOOL_MAIN_SCRIPT = data.TOOL_MAIN_SCRIPT TOOL_MOD_FILENAME = data.TOOL_MOD_FILENAME TOOL_ICON = data.TOOL_ICON TOOL_COMMAND_ICON = data.TOOL_COMMAND_ICON DNA_PATH = data.DNA_PATH DNA_IMG_PATH = data.DNA_IMG_PATH main_window = None class MetaFusionWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super(MetaFusionWindow, self).__init__(parent) self.setWindowTitle("MetaFusion") self.resize(800, 600) # 加载样式表 self.load_stylesheet() # 创建UI self.setup_ui() def load_stylesheet(self): """加载QSS样式表""" style_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "styles", "style.qss") if os.path.exists(style_file): with open(style_file, 'r', encoding='utf-8') as f: self.setStyleSheet(f.read()) def setup_ui(self): """设置UI结构""" # 创建中心部件 central_widget = QtWidgets.QWidget() self.setCentralWidget(central_widget) # 创建主布局 main_layout = QtWidgets.QVBoxLayout(central_widget) # 创建菜单栏 self.create_menu_bar() # 创建工具栏 self.create_tool_bar() # 创建标签页 self.create_tabs() def create_menu_bar(self): """创建菜单栏""" menubar = self.menuBar() # 文件菜单 file_menu = menubar.addMenu("文件") file_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "open.png")), "打开DNA") file_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "save.png")), "保存DNA") file_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "open.png")), "加载当前项目的DNA") file_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "rename.png")), "修改混合目标名称") file_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "resetname.png")), "重置混合目标名称") file_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "export.png")), "导出FBX") file_menu.addSeparator() file_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "exit.png")), "退出") # 编辑菜单 edit_menu = menubar.addMenu("编辑") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "connect.png")), "创建RL4节点") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "disconnect.png")), "删除RL4节点") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "mirrorL.png")), "镜像左至右") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "mirrorR.png")), "镜像右至左") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "pose_A_To_T.png")), "姿势由A型转T型") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "pose_T_To_A.png")), "姿势由T型转A型") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "locator.png")), "传输LOD贴图") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "color.png")), "设置关节颜色") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "unmark_all.png")), "取消全部标记") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "rebuildTargets.png")), "重建所有目标") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "bakeAnimation.png")), "为所有表情设置关键帧") edit_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "centerCurrentTime.png")), "烘焙所有表情的关键帧") # 工具菜单 tool_menu = menubar.addMenu("工具") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "export_skin.png")), "导出蒙皮") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "import_skin.png")), "导入蒙皮") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "copy_skin.png")), "拷贝装皮") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "blendShape.png")), "RBF变形器") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "clothing_weight.png")), "快速绑定服装") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "blendShape.png")), "克隆混合变形") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "repair_vertex_order.png")), "UV传递点序") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "controller.png")), "面部生成控制器") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "ARKit52.png")), "提取52BS") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "joint.png")), "关节轴向修复") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "create_body_ctrl.png")), "生成身体控制器") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "import_face_anim.png")), "导入面部动画") tool_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "import_body_anim.png")), "导入身体动画") # 语言菜单 lang_menu = menubar.addMenu("语言") lang_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "chinese.png")), "中文") lang_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "english.png")), "English") # 帮助菜单 help_menu = menubar.addMenu("帮助") help_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "help.png")), "帮助文档") help_menu.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "warning.png")), "关于") def create_tool_bar(self): """创建工具栏""" toolbar = self.addToolBar("主工具栏") toolbar.setMovable(False) # 添加工具栏按钮 toolbar.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "save.png")), "保存DNA") toolbar.addAction(QtGui.QIcon(os.path.join(ICONS_PATH, "open.png")), "加载当前项目DNA") def create_tabs(self): """创建标签页""" self.tab_widget = QtWidgets.QTabWidget() self.centralWidget().layout().addWidget(self.tab_widget) # 创建四个主要标签页 self.model_tab = QtWidgets.QWidget() self.rig_tab = QtWidgets.QWidget() self.adjust_tab = QtWidgets.QWidget() self.define_tab = QtWidgets.QWidget() # 添加标签页到标签页控件 self.tab_widget.addTab(self.model_tab, "模型") self.tab_widget.addTab(self.rig_tab, "绑定") self.tab_widget.addTab(self.adjust_tab, "调整") self.tab_widget.addTab(self.define_tab, "定义") # 设置各个标签页的内容 self.setup_model_tab() self.setup_rig_tab() self.setup_adjust_tab() self.setup_define_tab() def setup_model_tab(self): """设置模型标签页内容""" layout = QtWidgets.QVBoxLayout(self.model_tab) # 创建 LOD 分栏 self.lod_tabs = QtWidgets.QTabWidget() layout.addWidget(self.lod_tabs) # 添加 LOD 分页 for i in range(8): lod_tab = QtWidgets.QWidget() lod_layout = QtWidgets.QVBoxLayout(lod_tab) # 添加删除按钮 delete_btn = QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "delete.png")), "删除") lod_layout.addWidget(delete_btn) # 添加模型输入框和加载按钮 for part in ["头部", "牙齿", "牙龈", "左眼", "右眼", "虹膜", "睫毛", "眼睑", "软骨", "身体"]: part_layout = QtWidgets.QHBoxLayout() part_input = QtWidgets.QLineEdit() load_btn = QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "target.png")), "加载") part_layout.addWidget(part_input) part_layout.addWidget(load_btn) lod_layout.addLayout(part_layout) self.lod_tabs.addTab(lod_tab, f"LOD{i}") # 添加 LOD 功能按钮 lod_func_layout = QtWidgets.QHBoxLayout() lod_func_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "load_meshes.png")), "自定加载模型")) lod_func_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "standardized_naming.png")), "标准化命名")) lod_func_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "automatic_groupingg.png")), "自动分组")) layout.addLayout(lod_func_layout) # 添加模型工具 model_tool_layout = QtWidgets.QHBoxLayout() model_tool_layout.addWidget(QtWidgets.QComboBox()) # 拓扑结构下拉菜单 model_tool_layout.addWidget(QtWidgets.QComboBox()) # 选择LOD下拉菜单 model_tool_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "polySplitVertex.png")), "模型分离")) model_tool_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "supplement_meshes.png")), "生成面部配件")) model_tool_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "repair_normals.png")), "修复法线")) model_tool_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "repair_vertex_order.png")), "修复点序")) model_tool_layout.addWidget(QtWidgets.QPushButton(QtGui.QIcon(os.path.join(ICONS_PATH, "polyChipOff.png")), "修复接缝")) layout.addLayout(model_tool_layout) def setup_rig_tab(self): """设置绑定标签页内容""" layout = QtWidgets.QVBoxLayout(self.rig_tab) # 添加 DNA 浏览器 self.dna_browser = QtWidgets.QListWidget() self.dna_browser.setIconSize(QtCore.QSize(64, 64)) layout.addWidget(self.dna_browser) # 添加 DNA 图标缩放滑块 self.dna_scale_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) self.dna_scale_slider.setMinimum(50) self.dna_scale_slider.setMaximum(200) self.dna_scale_slider.setValue(100) self.dna_scale_slider.valueChanged.connect(self.on_dna_scale_changed) layout.addWidget(self.dna_scale_slider) # 添加导入/导出按钮 button_layout = QtWidgets.QHBoxLayout() import_btn = QtWidgets.QPushButton("导入设置") export_btn = QtWidgets.QPushButton("导出设置") import_btn.clicked.connect(self.on_import_settings) export_btn.clicked.connect(self.on_export_settings) button_layout.addWidget(import_btn) button_layout.addWidget(export_btn) layout.addLayout(button_layout) # 初始化 DNA 浏览器 self.init_dna_browser() def init_dna_browser(self): """初始化 DNA 浏览器""" # 清空现有内容 self.dna_browser.clear() # 获取 DNA 文件列表 dna_files = os.listdir(DNA_PATH) img_files = os.listdir(DNA_IMG_PATH) # 添加 DNA 项目 for dna_file in dna_files: item = QtWidgets.QListWidgetItem(dna_file) # 查找对应的图片 img_name = os.path.splitext(dna_file)[0] + ".png" if img_name in img_files: item.setIcon(QtGui.QIcon(os.path.join(data.DNA_IMG_PATH, img_name))) self.dna_browser.addItem(item) def on_dna_scale_changed(self, value): """处理 DNA 图标缩放""" size = int(64 * (value / 100)) self.dna_browser.setIconSize(QtCore.QSize(size, size)) def on_import_settings(self): """导入设置""" # TODO: 实现导入设置功能 pass def on_export_settings(self): """导出设置""" # TODO: 实现导出设置功能 pass def setup_adjust_tab(self): """设置调整标签页内容""" layout = QtWidgets.QVBoxLayout(self.adjust_tab) # 添加BlendShape列表 blend_list = QtWidgets.QListWidget() layout.addWidget(blend_list) # 添加滑块组 slider_layout = QtWidgets.QVBoxLayout() for i in range(5): slider = QtWidgets.QSlider(QtCore.Qt.Horizontal) slider_layout.addWidget(slider) layout.addLayout(slider_layout) # 添加按钮组 button_layout = QtWidgets.QHBoxLayout() edit_btn = QtWidgets.QPushButton("编辑BlendShape") save_btn = QtWidgets.QPushButton("保存设置") button_layout.addWidget(edit_btn) button_layout.addWidget(save_btn) layout.addLayout(button_layout) def setup_define_tab(self): """设置定义标签页内容""" layout = QtWidgets.QVBoxLayout(self.define_tab) # 添加DNA编辑区域 self.dna_edit = QtWidgets.QTextEdit() layout.addWidget(self.dna_edit) # 添加按钮组 button_layout = QtWidgets.QHBoxLayout() self.load_btn = QtWidgets.QPushButton("载入DNA") self.save_btn = QtWidgets.QPushButton("保存DNA") self.export_btn = QtWidgets.QPushButton("导出FBX") # 连接信号槽 self.load_btn.clicked.connect(self.on_load_dna) self.save_btn.clicked.connect(self.on_save_dna) self.export_btn.clicked.connect(self.on_export_fbx) button_layout.addWidget(self.load_btn) button_layout.addWidget(self.save_btn) button_layout.addWidget(self.export_btn) layout.addLayout(button_layout) # 创建DNA管理器 self.dna_manager = DNAManager() def on_load_dna(self): """处理载入DNA事件""" file_path, _ = QtWidgets.QFileDialog.getOpenFileName( self, "选择DNA文件", "", "DNA Files (*.dna)") if file_path: if self.dna_manager.load_dna(file_path): self.dna_edit.setText(f"已加载DNA文件: {file_path}") else: QtWidgets.QMessageBox.warning( self, "错误", "DNA文件加载失败") def on_save_dna(self): """处理保存DNA事件""" file_path, _ = QtWidgets.QFileDialog.getSaveFileName( self, "保存DNA文件", "", "DNA Files (*.dna)") if file_path: if self.dna_manager.save_dna(file_path): QtWidgets.QMessageBox.information( self, "成功", "DNA文件保存成功") else: QtWidgets.QMessageBox.warning( self, "错误", "DNA文件保存失败") def on_export_fbx(self): """处理导出FBX事件""" file_path, _ = QtWidgets.QFileDialog.getSaveFileName( self, "导出FBX", "", "FBX Files (*.fbx)") if file_path: if self.dna_manager.export_fbx(file_path): QtWidgets.QMessageBox.information( self, "成功", "FBX导出成功") else: QtWidgets.QMessageBox.warning( self, "错误", "FBX导出失败") def show(): """显示主窗口""" global main_window try: main_window.close() except: pass main_window = MetaFusionWindow() main_window.show() return main_window if __name__ == "__main__": app = QtWidgets.QApplication([]) window = show() app.exec_()