From 7a621a3a51739e85bbd333b525458ebbcf39c92c Mon Sep 17 00:00:00 2001 From: Hector <2055590199@qq.com> Date: Thu, 18 Sep 2025 10:55:06 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=9A=E7=84=A6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/event_handler.py | 60 ++++++++-------- core/selection.py | 2 +- scene/scene_manager.py | 154 ++++++++++++++++++++++++++-------------- ui/interface_manager.py | 1 - ui/property_panel.py | 18 ++--- 5 files changed, 140 insertions(+), 95 deletions(-) diff --git a/core/event_handler.py b/core/event_handler.py index 38db55fe..be0f6cc1 100644 --- a/core/event_handler.py +++ b/core/event_handler.py @@ -457,36 +457,36 @@ class EventHandler: # 更新选择状态并显示选择框和坐标轴 self.world.selection.updateSelection(selectedModel) - # # 在树形控件中查找并选中对应的项 - # if self.world.interface_manager.treeWidget: - # #print("查找树形控件中的对应项...") - # root = self.world.interface_manager.treeWidget.invisibleRootItem() - # foundItem = None - # - # for i in range(root.childCount()): - # sceneItem = root.child(i) - # if sceneItem.text(0) == "场景": - # #print(f"在场景节点下查找...") - # foundItem = self.world.interface_manager.findTreeItem(selectedModel, sceneItem) - # if foundItem: - # print(f"✓ 在树形控件中找到对应项: {foundItem.text(0)}") - # try: - # self.world.interface_manager.treeWidget.itemClicked.disconnect() - # except TypeError: - # pass - # - # self.world.interface_manager.treeWidget.setCurrentItem(foundItem) - # - # self.world.interface_manager.treeWidget.itemClicked.connect( - # self.world.interface_manager.onTreeItemClicked) - # else: - # print("× 在树形控件中没有找到对应项") - # break - # - # if not foundItem: - # print("× 没有找到场景节点或对应的树形项") - # else: - # print("× 树形控件不存在") + # 在树形控件中查找并选中对应的项 + if self.world.interface_manager.treeWidget: + #print("查找树形控件中的对应项...") + root = self.world.interface_manager.treeWidget.invisibleRootItem() + foundItem = None + + for i in range(root.childCount()): + sceneItem = root.child(i) + if sceneItem.text(0) == "场景": + #print(f"在场景节点下查找...") + foundItem = self.world.interface_manager.findTreeItem(selectedModel, sceneItem) + if foundItem: + print(f"✓ 在树形控件中找到对应项: {foundItem.text(0)}") + try: + self.world.interface_manager.treeWidget.itemClicked.disconnect() + except TypeError: + pass + + self.world.interface_manager.treeWidget.setCurrentItem(foundItem) + + self.world.interface_manager.treeWidget.itemClicked.connect( + self.world.interface_manager.onTreeItemClicked) + else: + print("× 在树形控件中没有找到对应项") + break + + if not foundItem: + print("× 没有找到场景节点或对应的树形项") + else: + print("× 树形控件不存在") else: print("× 没有找到可选择的模型节点") self.world.selection.updateSelection(None) diff --git a/core/selection.py b/core/selection.py index 91ff0941..c84b8eee 100644 --- a/core/selection.py +++ b/core/selection.py @@ -1021,7 +1021,7 @@ class SelectionSystem: ) mat.setBaseColor(adjusted_color) - mat.setEmission(Vec4(1, 1, 1, 1.0)) # 自发光 + #mat.setEmission(Vec4(1, 1, 1, 1.0)) # 自发光 # 应用材质 handle_node.setMaterial(mat, 1) diff --git a/scene/scene_manager.py b/scene/scene_manager.py index 43b26b93..cd031d65 100644 --- a/scene/scene_manager.py +++ b/scene/scene_manager.py @@ -11,8 +11,8 @@ import os from PyQt5.QtCore import Qt from panda3d.core import ( ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3, - MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, - BitMask32, TransparencyAttrib,LColor + MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, + BitMask32, TransparencyAttrib, LColor, TransformState ) import json import aiohttp @@ -141,11 +141,7 @@ class SceneManager: print("加载模型失败") return None - # 验证并修复模型变换矩阵(在任何操作之前) - # - self._validateAndFixAllTransforms(model) - self._fixModelStructure(model) # 设置模型名称 model_name = os.path.basename(filepath) @@ -238,11 +234,11 @@ class SceneManager: print(f"导入模型失败: {str(e)}") return None - def _fixModelStructure(self,model): + def _fixModelStructure(self, model): + """修复模型结构""" try: - from panda3d.core import CharacterNode,AnimBundleNode - - character_nodes = model.findAllMatches("**/+CharacterNode") + # 使用正确的方式查找动画相关节点 + character_nodes = model.findAllMatches("**/+Character") anim_bundle_nodes = model.findAllMatches("**/+AnimBundleNode") if character_nodes.getNumPaths() > 0 or anim_bundle_nodes.getNumPaths() > 0: @@ -252,65 +248,103 @@ class SceneManager: if anim_bundle_nodes.getNumPaths() > 0: print(f"AnimBundleNode数量: {anim_bundle_nodes.getNumPaths()}") - model.setTag("fixed_structure","true") + model.setTag("fixed_structure", "true") return True except Exception as e: - print(f"修复模型结构时出错{e}") + print(f"修复模型结构时出错: {e}") return False def _validateAndFixAllTransforms(self, model): - """验证并修复所有节点的变换矩阵""" + """递归验证并修复模型中所有节点的变换矩阵""" try: - def fix_node_transform(node_path, depth=0): - indent = " " * depth - try: - # 检查节点的变换矩阵是否有效 - transform = node_path.getTransform() - if not transform.isInvalid(): - # 检查是否有NaN或无穷大值 - pos = node_path.getPos() - hpr = node_path.getHpr() - scale = node_path.getScale() + fixed_count = 0 - # 检查位置 - if pos.x != pos.x or pos.y != pos.y or pos.z != pos.z: # NaN检查 - print(f"{indent}修复NaN位置: {node_path.getName()}") - node_path.setPos(0, 0, 0) + # 先处理根节点 + if not self._validateAndFixTransform(model): + fixed_count += 1 - # 检查旋转 - if hpr.x != hpr.x or hpr.y != hpr.y or hpr.z != hpr.z: # NaN检查 - print(f"{indent}修复NaN旋转: {node_path.getName()}") - node_path.setHpr(0, 0, 0) + # 递归处理所有子节点 + def process_children(node, depth=0): + nonlocal fixed_count + for i in range(node.getNumChildren()): + try: + child = node.getChild(i) + if not self._validateAndFixTransform(child): + fixed_count += 1 + # 递归处理孙节点 + process_children(child, depth + 1) + except Exception as e: + print(f"处理子节点时出错 (深度 {depth}): {e}") + continue - # 检查缩放 - if scale.x != scale.x or scale.y != scale.y or scale.z != scale.z: # NaN检查 - print(f"{indent}修复NaN缩放: {node_path.getName()}") - node_path.setScale(1, 1, 1) + process_children(model) - # 检查过大值 - if abs(pos.x) > 1e10 or abs(pos.y) > 1e10 or abs(pos.z) > 1e10: - print(f"{indent}修复过大位置值: {node_path.getName()}") - node_path.setPos(0, 0, 0) + if fixed_count > 0: + print(f"共修复了 {fixed_count} 个节点的变换") - else: - print(f"{indent}检测到无效变换矩阵: {node_path.getName()}") - node_path.setPos(0, 0, 0) - node_path.setHpr(0, 0, 0) - node_path.setScale(1, 1, 1) + return True + except Exception as e: + print(f"验证所有变换时出错: {e}") + return False - except Exception as e: - print(f"{indent}修复节点变换时出错 {node_path.getName()}: {e}") + def _validateAndFixTransform(self, node_path): + """验证并修复单个节点的变换矩阵""" + try: + node_name = node_path.getName() - # 递归处理子节点 - for child in node_path.getChildren(): - fix_node_transform(child, depth + 1) + # 获取当前变换状态 + original_pos = node_path.getPos() + original_hpr = node_path.getHpr() + original_scale = node_path.getScale() - # 从模型根节点开始修复 - fix_node_transform(model) - print(f"✓ 完成模型 {model.getName()} 的变换验证和修复") + # 检查位置是否包含无效值 + if not original_pos.isFinite(): + print(f"警告: 节点 {node_name} 位置包含无效值 {original_pos},重置为 (0,0,0)") + node_path.setPos(0, 0, 0) + return False + + # 检查旋转是否包含无效值 + if not original_hpr.isFinite(): + print(f"警告: 节点 {node_name} 旋转包含无效值 {original_hpr},重置为 (0,0,0)") + node_path.setHpr(0, 0, 0) + return False + + # 检查缩放是否包含无效值或为零 + if not original_scale.isFinite(): + print(f"警告: 节点 {node_name} 缩放包含无效值 {original_scale},重置为 (1,1,1)") + node_path.setScale(1, 1, 1) + return False + + # 检查缩放是否为零或接近零 + min_scale = 1e-10 + if (abs(original_scale.x) < min_scale or + abs(original_scale.y) < min_scale or + abs(original_scale.z) < min_scale): + print(f"警告: 节点 {node_name} 缩放接近零 {original_scale},重置为 (1,1,1)") + node_path.setScale(1, 1, 1) + return False + + # 检查缩放是否过大(防止异常大的缩放) + max_scale = 1000000 # 100万倍作为上限 + if (abs(original_scale.x) > max_scale or + abs(original_scale.y) > max_scale or + abs(original_scale.z) > max_scale): + print(f"警告: 节点 {node_name} 缩放过异常 {original_scale},重置为 (1,1,1)") + node_path.setScale(1, 1, 1) + return False + + return True except Exception as e: - print(f"验证和修复模型变换时出错: {e}") + print(f"验证/修复节点 {node_path.getName()} 变换时出错: {e}") + # 只在出现严重错误时才重置变换 + try: + node_path.setPos(0, 0, 0) + node_path.setHpr(0, 0, 0) + node_path.setScale(1, 1, 1) + except: + pass + return False def _applyModelScale(self, model, scale_factor): """应用模型特定缩放 @@ -523,6 +557,18 @@ class SceneManager: # 应用缩放 model.setScale(scale_factor) + # 应用缩放(添加异常处理) + try: + model.setScale(scale_factor) + except Exception as e: + print(f"直接设置缩放失败: {e},尝试使用变换状态") + try: + model.setTransform(TransformState.makeScale(scale_factor)) + except Exception as e2: + print(f"使用变换状态设置缩放也失败: {e2}") + + # 应用缩放后验证变换 + self._validateAndFixTransform(model) # 重新调整位置(因为缩放会影响边界) if original_bounds and not original_bounds.isEmpty(): new_bounds = model.getBounds() @@ -1504,7 +1550,7 @@ class SceneManager: if nodePath.hasTag("is_model_root"): print(f"J{indent}处理模型节点{nodePath.getName()}") - self._validateAndFixAllTransforms(nodePath) + #self._validateAndFixAllTransforms(nodePath) self._fixModelStructure(nodePath) diff --git a/ui/interface_manager.py b/ui/interface_manager.py index 8dd049eb..e5e0c626 100644 --- a/ui/interface_manager.py +++ b/ui/interface_manager.py @@ -18,7 +18,6 @@ class InterfaceManager: """设置树形控件引用并更新场景树""" self.treeWidget = treeWidget - # 添加右键菜单 # self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu) # self.treeWidget.customContextMenuRequested.connect(self.showTreeContextMenu) diff --git a/ui/property_panel.py b/ui/property_panel.py index d73175b1..d37a91b2 100644 --- a/ui/property_panel.py +++ b/ui/property_panel.py @@ -4756,12 +4756,12 @@ class PropertyPanelManager: if geom_node: geom_node_name = geom_node.getName() unique_name = f"{geom_node_name}({model_name})" - print(f"材质 {i}: 使用几何节点名称 '{geom_node_name}'") + #print(f"材质 {i}: 使用几何节点名称 '{geom_node_name}'") else: material_name = material.get_name() if hasattr(material, 'get_name') and material.get_name() else f"材质{i + 1}" unique_name = f"{material_name}({model_name})" - print(f"材质 {i}: 未找到几何节点,使用材质名称 '{material_name}'") + #print(f"材质 {i}: 未找到几何节点,使用材质名称 '{material_name}'") # 处理重复名称 if unique_name in name_counter: @@ -4800,7 +4800,7 @@ class PropertyPanelManager: # 基础颜色编辑 base_color = self._getOrCreateMaterialBaseColor(material) if base_color is not None: - print(f"材质基础颜色: {base_color}") + #print(f"材质基础颜色: {base_color}") # 基础颜色标题 color_row = 2 if material_status != "标准PBR材质" else 1 @@ -5186,7 +5186,7 @@ class PropertyPanelManager: try: # 方法1: 尝试获取base_color属性 if hasattr(material, 'base_color') and material.base_color is not None: - print(f"✓ 找到base_color属性: {material.base_color}") + #print(f"✓ 找到base_color属性: {material.base_color}") return material.base_color # 方法2: 尝试调用get_base_color方法 @@ -5204,7 +5204,7 @@ class PropertyPanelManager: try: diffuse_color = material.getDiffuse() if diffuse_color is not None: - print(f"✓ 从diffuse颜色获取: {diffuse_color}") + #print(f"✓ 从diffuse颜色获取: {diffuse_color}") # 同时设置为base_color if hasattr(material, 'set_base_color'): material.set_base_color(diffuse_color) @@ -6812,7 +6812,7 @@ class PropertyPanelManager: # print(f"找到匹配的几何节点: {geom_np.get_name()}") return geom_np - print("未找到匹配的几何节点") + #print("未找到匹配的几何节点") return None def _findSpecificGeomNodeForMaterial(self, target_material): @@ -8097,7 +8097,7 @@ class PropertyPanelManager: format_info = self._getModelFormat(origin_model) processed = [] - print(f"[动画分析] 格式: {format_info}, 原始动画名称: {anim_names}") + #print(f"[动画分析] 格式: {format_info}, 原始动画名称: {anim_names}") for name in anim_names: display_name = name @@ -8131,7 +8131,7 @@ class PropertyPanelManager: display_name = name processed.append((display_name, original_name)) - print(f"[动画分析] {original_name} → {display_name}") + #print(f"[动画分析] {original_name} → {display_name}") return processed @@ -8165,7 +8165,7 @@ class PropertyPanelManager: if frames > 1: valid_anims += 1 total_frames += frames - print(f"[动画分析] '{anim_name}': {frames} 帧") + #print(f"[动画分析] '{anim_name}': {frames} 帧") else: print(f"[动画分析] '{anim_name}': 无有效帧数 ({frames})") except Exception as e: