1
0
forked from Rowland/EG
EG/demo/选择功能修复说明.md
2025-07-10 09:19:51 +08:00

4.9 KiB
Raw Permalink Blame History

选择功能修复说明

问题描述

用户反馈点击模型后没有反应,应该要能够选中模型并显示选择框和坐标轴。

问题分析

通过分析代码发现了几个关键问题:

1. 缺少碰撞检测设置

问题:模型导入时没有设置碰撞检测,导致射线检测无法检测到模型。

  • scene_manager.py 中的 importModel 方法没有调用 setupCollision
  • 所有模型加载方法都缺少碰撞设置

2. 默认工具未设置

问题tool_manager.py 中默认工具为 None,而选择功能需要当前工具为"选择"。

  • 事件处理器中的条件 if self.world.currentTool == "选择" 永远不成立

3. 碰撞掩码不匹配

问题:射线检测和模型碰撞体使用不同的碰撞掩码。

  • 模型碰撞体使用 BitMask32.bit(2)
  • 射线检测使用 GeomNode.getDefaultCollideMask()

修复方案

1. 为所有模型添加碰撞检测

修复位置scene/scene_manager.py

在以下方法中添加碰撞检测设置:

  • importModel() - 主要模型导入方法
  • loadScene() - 场景加载时为每个模型设置碰撞
  • processLoadedModel() - 异步加载回调
  • loadAnimatedModel() - 动画模型加载
# 设置碰撞检测(重要!用于选择功能)
print("\n=== 设置碰撞检测 ===")
self.setupCollision(model)

2. 设置默认工具为选择

修复位置core/tool_manager.py

def __init__(self, world):
    """初始化工具管理器"""
    self.world = world
    self.currentTool = "选择"  # 默认工具为选择工具

3. 统一碰撞掩码设置

修复位置core/event_handler.py

# 设置射线的碰撞掩码匹配模型的碰撞掩码第2位
from panda3d.core import BitMask32
pickerNode.setFromCollideMask(BitMask32.bit(2))

碰撞检测系统工作原理

模型碰撞体设置

每个模型都会创建一个包围球体作为碰撞体:

def setupCollision(self, model):
    # 创建碰撞节点
    cNode = CollisionNode(f'modelCollision_{model.getName()}')
    cNode.setIntoCollideMask(BitMask32.bit(2))  # 使用第2位
    
    # 获取模型边界并创建碰撞球体
    bounds = model.getBounds()
    center = bounds.getCenter()
    radius = bounds.getRadius()
    cSphere = CollisionSphere(center, radius)
    cNode.addSolid(cSphere)
    
    # 附加到模型
    cNodePath = model.attachNewNode(cNode)

射线检测机制

鼠标点击时创建射线进行碰撞检测:

# 创建射线检测
picker = CollisionTraverser()
queue = CollisionHandlerQueue()

pickerNode = CollisionNode('mouseRay')
pickerNP = self.world.cam.attachNewNode(pickerNode)
pickerNode.setFromCollideMask(BitMask32.bit(2))  # 匹配模型掩码

# 创建射线几何体
direction = farPoint - nearPoint
direction.normalize()
pickerNode.addSolid(CollisionRay(nearPoint, direction))

# 执行碰撞检测
picker.addCollider(pickerNP, queue)
picker.traverse(self.world.render)

选择系统工作流程

  1. 鼠标点击mousePressEventLeft()
  2. 坐标转换 → 屏幕坐标转世界坐标
  3. 创建射线 → 相机位置到点击位置
  4. 碰撞检测 → 射线与模型碰撞体检测
  5. 选择处理_handleSelectionClick()
  6. 更新UI → 选择框、坐标轴、属性面板

测试验证

创建了专用测试脚本 demo/selection_test.py

测试功能

  • 创建多个测试立方体模型
  • 验证碰撞检测设置
  • 测试点击选择功能
  • 显示选择框和坐标轴

测试控制

  • 鼠标左键:点击选择模型
  • I键:显示当前选择信息
  • C键:显示碰撞检测信息
  • S键:切换碰撞体显示(调试)
  • R键:切换射线显示
  • Q键:退出

运行测试

cd demo
python selection_test.py

修复效果

修复前

  • 点击模型无反应
  • 无法选中任何物体
  • 选择框和坐标轴不显示

修复后

  • 点击模型正确选中
  • 显示橙色选择框
  • 显示彩色坐标轴红X、绿Y、蓝Z
  • 树形控件同步选择
  • 属性面板更新显示
  • 坐标轴支持拖拽变换

相关功能

选择功能修复后,以下功能也恢复正常:

  • 坐标轴拖拽:点击坐标轴可拖拽移动物体
  • 属性编辑:选中后可在属性面板编辑位置、旋转、缩放
  • 场景树同步:点击模型会在场景树中高亮对应项
  • 射线调试按R键可显示点击射线用于调试

技术要点

  1. 碰撞掩码一致性:射线检测和模型碰撞体必须使用相同的掩码位
  2. 碰撞体覆盖:包围球体确保模型的所有部分都可点击
  3. 工具状态管理:默认工具状态影响事件处理逻辑
  4. 模块化设计:碰撞设置在所有模型加载路径中都要调用

这次修复确保了3D编辑器的核心交互功能正常工作为后续的编辑操作打下了坚实基础。