From 2a76703b892308152224ec855ed7260d8d9bb405 Mon Sep 17 00:00:00 2001 From: Hector <2055590199@qq.com> Date: Wed, 17 Sep 2025 17:48: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 | 54 ++++++++++++---------- core/selection.py | 31 +++++++------ scene/scene_manager.py | 100 ++++++++++++++++++++++++++++++++++++++--- ui/main_window.py | 2 +- ui/property_panel.py | 12 +++-- 5 files changed, 152 insertions(+), 47 deletions(-) diff --git a/core/event_handler.py b/core/event_handler.py index 91904e57..38db55fe 100644 --- a/core/event_handler.py +++ b/core/event_handler.py @@ -452,33 +452,41 @@ class EventHandler: if selectedModel: #print(f"✓ 最终选中模型: {selectedModel.getName()}") + self.world.selection.handleMouseClick(selectedModel) # 更新选择状态并显示选择框和坐标轴 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)}") - self.world.interface_manager.treeWidget.setCurrentItem(foundItem) - self.world.property_panel.updatePropertyPanel(foundItem) - 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 62986afc..91ff0941 100644 --- a/core/selection.py +++ b/core/selection.py @@ -1228,10 +1228,10 @@ class SelectionSystem: distance = self.distanceToLine( (mouseX, mouseY), center_screen, axis_screen ) - print(f"{axis_label}距离: {distance:.2f}") + #print(f"{axis_label}距离: {distance:.2f}") if distance < click_threshold: - print(f"✓ 点击了{axis_label}") + #print(f"✓ 点击了{axis_label}") return axis_name return None @@ -1930,8 +1930,10 @@ class SelectionSystem: is_double_click = self.checkDoubleClick(nodePath) if is_double_click: print(f"检测到双击 {node_name},执行聚焦") - # 启动聚焦(在下一帧执行,确保选择状态已更新) - taskMgr.doMethodLater(0.01, self._delayedFocusTask, "delayedFocus") + # 双击时直接执行聚焦,不执行选择逻辑 + self.focusCameraOnSelectedNodeAdvanced() + print("=== 选择状态更新完成 ===\n") + return # 直接返回,不执行下面的选择逻辑 self.selectedNode = nodePath # 添加兼容性属性 @@ -2596,19 +2598,22 @@ class SelectionSystem: import time current_time = time.time() - is_double_click = (self._last_clicked_node == nodePath and - current_time - self._last_click_time < self._double_click_threshold) + # 检查节点和时间 + time_diff = current_time - self._last_click_time + is_same_node = (self._last_clicked_node == nodePath) - if is_double_click: - # 双击 detected,重置状态 + # 如果是同一节点且在时间阈值内,认为是双击 + if is_same_node and time_diff < self._double_click_threshold: + # 只有在双击时才重置状态 self._last_click_time = 0 self._last_clicked_node = None + return True else: - # 更新状态为单击 - self._last_click_time = current_time - self._last_clicked_node = nodePath - - return is_double_click + # 只有在非双击情况下才更新状态 + if not is_same_node: + self._last_click_time = current_time + self._last_clicked_node = nodePath + return False except Exception as e: print(f"双击检测失败: {e}") diff --git a/scene/scene_manager.py b/scene/scene_manager.py index c5c0b810..43b26b93 100644 --- a/scene/scene_manager.py +++ b/scene/scene_manager.py @@ -143,7 +143,9 @@ class SceneManager: # 验证并修复模型变换矩阵(在任何操作之前) # - #self._validateAndFixAllTransforms(model) + self._validateAndFixAllTransforms(model) + + self._fixModelStructure(model) # 设置模型名称 model_name = os.path.basename(filepath) @@ -153,14 +155,14 @@ class SceneManager: model.setName(model_name) # 使用安全方法将模型添加到场景 - self._safeReparentTo(model, self.world.render) + #self._safeReparentTo(model, self.world.render) # 设置模型名称 model_name = os.path.basename(filepath) model.setName(model_name) # 将模型添加到场景 - #model.reparentTo(self.world.render) + model.reparentTo(self.world.render) # 保存原始路径和转换后的路径 model.setTag("model_path", filepath) model.setTag("original_path", original_filepath) @@ -236,6 +238,80 @@ class SceneManager: print(f"导入模型失败: {str(e)}") return None + def _fixModelStructure(self,model): + try: + from panda3d.core import CharacterNode,AnimBundleNode + + character_nodes = model.findAllMatches("**/+CharacterNode") + anim_bundle_nodes = model.findAllMatches("**/+AnimBundleNode") + + if character_nodes.getNumPaths() > 0 or anim_bundle_nodes.getNumPaths() > 0: + print(f"检测到模型{model.getName()}包含角色相节点:") + if character_nodes.getNumPaths() > 0: + print(f"CharacterNode数量:{character_nodes.getNumPaths()}") + if anim_bundle_nodes.getNumPaths() > 0: + print(f"AnimBundleNode数量: {anim_bundle_nodes.getNumPaths()}") + + model.setTag("fixed_structure","true") + return True + except Exception as 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() + + # 检查位置 + 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 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) + + # 检查缩放 + 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) + + # 检查过大值 + 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) + + 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) + + except Exception as e: + print(f"{indent}修复节点变换时出错 {node_path.getName()}: {e}") + + # 递归处理子节点 + for child in node_path.getChildren(): + fix_node_transform(child, depth + 1) + + # 从模型根节点开始修复 + fix_node_transform(model) + print(f"✓ 完成模型 {model.getName()} 的变换验证和修复") + + except Exception as e: + print(f"验证和修复模型变换时出错: {e}") + def _applyModelScale(self, model, scale_factor): """应用模型特定缩放 @@ -652,6 +728,8 @@ class SceneManager: def setupCollision(self, model): """为模型设置碰撞检测(增强版本)""" try: + + # 创建碰撞节点 cNode = CollisionNode(f'modelCollision_{model.getName()}') @@ -693,7 +771,7 @@ class SceneManager: # 根据调试设置决定是否显示碰撞体 if hasattr(self.world, 'debug_collision') and self.world.debug_collision: - cNodePath.show() + cNodePath.hide() else: cNodePath.hide() @@ -1424,7 +1502,17 @@ class SceneManager: # 为模型节点设置碰撞检测 if nodePath.hasTag("is_model_root"): - self.setupCollision(nodePath) + print(f"J{indent}处理模型节点{nodePath.getName()}") + + self._validateAndFixAllTransforms(nodePath) + + self._fixModelStructure(nodePath) + + if self.world.property_panel._hasCollision(nodePath): + print(f"{indent}模型{nodePath.getName()}已有碰撞体,跳过碰撞体设置") + else: + print(f"{indent}为模型{nodePath.getName()}设置碰撞检测") + self.setupCollision(nodePath) self.models.append(nodePath) # 递归处理子节点 @@ -1530,7 +1618,7 @@ class SceneManager: tags = gui_info.get("tags", {}) text = gui_info.get("text", "") image_path = gui_info.get("image_path", "") - video_path = gui_info.get("video_path","") + video_path = gui_info.get("video_path", "") bg_image_path = gui_info.get("bg_image_path", "") # 背景图片路径 panel_id = gui_info.get("panel_id", name) # 信息面板ID panel_data = gui_info.get("panel_data", None) # 面板数据 diff --git a/ui/main_window.py b/ui/main_window.py index 9d8e7bc9..4e9139b4 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -1921,7 +1921,7 @@ class MainWindow(QMainWindow): main_window.addDockWidget(Qt.RightDockWidgetArea, browser_dock) # 添加到GUI元素列表以便管理 - self.gui_elements.append(browser_dock) + self.world.gui_elements.append(browser_dock) print("✓ 网页浏览器视图已创建并集成到项目中") return browser_dock diff --git a/ui/property_panel.py b/ui/property_panel.py index 5b73d4ba..5f17f30f 100644 --- a/ui/property_panel.py +++ b/ui/property_panel.py @@ -8936,13 +8936,17 @@ except Exception as e: """检查模型是否已有碰撞体""" try: from panda3d.core import CollisionNode - + + # if model.hasTag("has_collision") and model.getTag("has_collision") == "true": + # return True + # 检查模型及其子节点是否有碰撞节点 collision_nodes = model.findAllMatches("**/+CollisionNode") has_collision = collision_nodes.getNumPaths() > 0 - - print(f"碰撞检查:模型 {model.getName()} - {'有' if has_collision else '无'}碰撞 (找到{collision_nodes.getNumPaths()}个碰撞节点)") - + + if has_collision: + print(f"检测到模型{model.getName()}已有{collision_nodes.getNumPaths()}个碰撞节点") + return has_collision except Exception as e: print(f"检查碰撞失败: {e}")