forked from Rowland/EG
4.9 KiB
4.9 KiB
选择功能修复说明
问题描述
用户反馈点击模型后没有反应,应该要能够选中模型并显示选择框和坐标轴。
问题分析
通过分析代码发现了几个关键问题:
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)
选择系统工作流程
- 鼠标点击 →
mousePressEventLeft() - 坐标转换 → 屏幕坐标转世界坐标
- 创建射线 → 相机位置到点击位置
- 碰撞检测 → 射线与模型碰撞体检测
- 选择处理 →
_handleSelectionClick() - 更新UI → 选择框、坐标轴、属性面板
测试验证
创建了专用测试脚本 demo/selection_test.py:
测试功能
- 创建多个测试立方体模型
- 验证碰撞检测设置
- 测试点击选择功能
- 显示选择框和坐标轴
测试控制
- 鼠标左键:点击选择模型
- I键:显示当前选择信息
- C键:显示碰撞检测信息
- S键:切换碰撞体显示(调试)
- R键:切换射线显示
- Q键:退出
运行测试
cd demo
python selection_test.py
修复效果
修复前:
- 点击模型无反应
- 无法选中任何物体
- 选择框和坐标轴不显示
修复后:
- ✅ 点击模型正确选中
- ✅ 显示橙色选择框
- ✅ 显示彩色坐标轴(红X、绿Y、蓝Z)
- ✅ 树形控件同步选择
- ✅ 属性面板更新显示
- ✅ 坐标轴支持拖拽变换
相关功能
选择功能修复后,以下功能也恢复正常:
- 坐标轴拖拽:点击坐标轴可拖拽移动物体
- 属性编辑:选中后可在属性面板编辑位置、旋转、缩放
- 场景树同步:点击模型会在场景树中高亮对应项
- 射线调试:按R键可显示点击射线用于调试
技术要点
- 碰撞掩码一致性:射线检测和模型碰撞体必须使用相同的掩码位
- 碰撞体覆盖:包围球体确保模型的所有部分都可点击
- 工具状态管理:默认工具状态影响事件处理逻辑
- 模块化设计:碰撞设置在所有模型加载路径中都要调用
这次修复确保了3D编辑器的核心交互功能正常工作,为后续的编辑操作打下了坚实基础。