如何将Three.js Raycaster绑定到可旋转拖拽的物体上?
如何将Raycaster绑定到旋转的Object3D对象上?
我明白你的问题了——当Object3D以非90度步进旋转时,Raycaster的原点位置就会出错,这是因为你当前的实现依赖于轴对齐的方向判断逻辑,一旦旋转角度脱离90度倍数,那些条件分支就无法正确定位射线起点了。要让Raycaster真正"绑定"到对象上,应该基于对象的局部坐标系来计算射线参数,而不是硬编码判断方向。
核心思路
- 在对象的局部坐标系中定义四个射线的起点(对应对象前后左右边缘的中心位置)
- 通过
localToWorld()方法将局部坐标转换为世界坐标(自动继承对象的位置、旋转和缩放) - 直接获取对象的世界空间方向向量,作为射线的发射方向
- 避免使用条件判断硬编码不同方向的坐标计算
改进后的实现代码
/*** Returns 4 Raycasters as array. Raycasters cast from right,left,front and back of the object */ createCasters(obj: THREE.Object3D, helper: THREE.BoxHelper): THREE.Raycaster[] { // 获取对象的包围盒(局部空间) const bb = helper.geometry.boundingBox; if (!bb) return []; // 计算局部空间中四个射线起点:前后左右边缘的中心 const halfSize = bb.getSize(new THREE.Vector3()).multiplyScalar(0.5); const localPoints = { right: new THREE.Vector3(halfSize.x, 0, 0), // 右侧边缘中心 left: new THREE.Vector3(-halfSize.x, 0, 0), // 左侧边缘中心 front: new THREE.Vector3(0, 0, halfSize.z), // 前侧边缘中心 back: new THREE.Vector3(0, 0, -halfSize.z) // 后侧边缘中心 }; // 将局部点转换为世界坐标(自动应用对象的位置、旋转、缩放) const worldPoints = { right: obj.localToWorld(localPoints.right.clone()), left: obj.localToWorld(localPoints.left.clone()), front: obj.localToWorld(localPoints.front.clone()), back: obj.localToWorld(localPoints.back.clone()) }; // 获取对象的世界空间方向向量 const worldDirection = obj.getWorldDirection(new THREE.Vector3()); const worldRight = new THREE.Vector3(1, 0, 0).applyQuaternion(obj.quaternion); // 对象局部右方向转世界方向 const worldLeft = worldRight.clone().negate(); // 前方向直接用对象的世界方向,后方向取反 const worldFront = worldDirection.clone(); const worldBack = worldFront.clone().negate(); // 创建射线 const raycasterRight = new THREE.Raycaster(worldPoints.right, worldRight); const raycasterLeft = new THREE.Raycaster(worldPoints.left, worldLeft); const raycasterFront = new THREE.Raycaster(worldPoints.front, worldFront); const raycasterBack = new THREE.Raycaster(worldPoints.back, worldBack); return [raycasterLeft, raycasterRight, raycasterFront, raycasterBack]; }
关键改进点说明
- 局部坐标转世界坐标:使用
obj.localToWorld()方法,无论对象旋转多少度,都能正确计算出射线起点在世界空间中的位置,完全避免了原代码中复杂且易出错的条件判断。 - 方向向量的正确获取:通过
obj.quaternion来旋转局部方向向量,或者直接用getWorldDirection(),确保射线方向始终跟随对象的旋转。 - 简化逻辑:不再依赖轴对齐的方向判断,所有旋转角度下都能正确工作,包括60度、45度等非90度步进的情况。
额外提示
- 确保每次对象旋转或移动后,都重新调用这个函数更新Raycaster的参数,因为对象的世界坐标和方向会变化。
- 如果对象有缩放,
localToWorld()也会自动处理缩放带来的尺寸变化,不需要手动计算缩放因子。
内容的提问来源于stack exchange,提问作者EnginO
相关产品推荐
相关产品推荐

