3.5 KiB
3.5 KiB
射线显示坐标系统修复说明
🔍 问题描述
用户发现射线显示时是从场景中心点射出,而不是从相机位置射出。这违反了鼠标点击射线的基本原理。
⚡ 问题原因
1. 坐标系混淆
# 原始错误代码
nearPoint = Point3()
farPoint = Point3()
self.world.cam.node().getLens().extrude(Point2(mx, my), nearPoint, farPoint)
# 直接使用相机坐标系的点显示射线(错误!)
self.showClickRay(nearPoint, farPoint, hitPos)
2. 坐标系不匹配
lens.extrude()返回的是相机坐标系中的点- 射线显示节点挂在
render下,使用世界坐标系 - 直接使用相机坐标系的点会导致射线从错误位置显示
🛠 修复方案
1. 正确的坐标变换
# 获取相机坐标系中的射线点
nearPoint = Point3()
farPoint = Point3()
self.world.cam.node().getLens().extrude(Point2(mx, my), nearPoint, farPoint)
# 转换到世界坐标系用于显示
worldNearPoint = self.world.render.getRelativePoint(self.world.cam, nearPoint)
worldFarPoint = self.world.render.getRelativePoint(self.world.cam, farPoint)
# 使用世界坐标系的点显示射线
self.showClickRay(worldNearPoint, worldFarPoint, hitPos)
2. 碰撞检测保持不变
# 碰撞检测仍使用相机坐标系(正确!)
pickerNode = CollisionNode('mouseRay')
pickerNP = self.world.cam.attachNewNode(pickerNode) # 相机子节点
direction = farPoint - nearPoint
direction.normalize()
pickerNode.addSolid(CollisionRay(nearPoint, direction)) # 相机坐标系
📐 坐标系统详解
相机坐标系 vs 世界坐标系
| 坐标系 | 用途 | 特点 |
|---|---|---|
| 相机坐标系 | 碰撞检测 | 以相机为原点,Z轴向前 |
| 世界坐标系 | 射线显示 | 以场景为原点,固定坐标 |
为什么需要不同坐标系?
-
碰撞检测:
- 碰撞节点是相机的子节点
- 使用相机坐标系可以跟随相机移动
- 射线方向相对于相机计算
-
射线显示:
- 射线节点是render的子节点
- 需要在世界坐标系中显示固定位置
- 从相机真实位置到点击点
🎯 修复效果
修复前
射线起点: (相机坐标系原点) = 场景中心附近
射线方向: 正确,但起点错误
显示效果: 射线从场景中心发射 ❌
修复后
射线起点: (相机世界位置) = 真实相机位置
射线方向: 正确,指向鼠标点击方向
显示效果: 射线从相机位置发射 ✅
🧪 验证方法
-
启动射线测试:
python demo/ray_display_test.py -
按R键开启射线显示
-
移动相机到不同位置
-
点击鼠标观察射线:
- 射线应该从当前相机位置开始
- 射线应该指向鼠标点击的方向
- 相机移动后射线起点应该跟随变化
📋 技术要点
关键API使用
# 获取相机坐标系中的射线
lens.extrude(screen_point, near_point, far_point)
# 坐标系转换
world_point = render.getRelativePoint(camera, camera_point)
# 反向转换
camera_point = camera.getRelativePoint(render, world_point)
调试输出
现在会显示两套坐标:
相机坐标系射线起点: (0, 1, 0)
世界坐标系射线起点: (-15.2, -42.3, 18.7)
这样您就可以清楚地看到射线现在是从真实的相机位置发射,而不是从场景中心发射了!🎯