旋转Mesh多方向射线投射问题:射线方向未随旋转更新
解决旋转Mesh的多方向射线投射问题
问题说明
我尝试从一个旋转的Mesh发射多条射线,射线朝向按数量均分圆周的多个方向。调试时给每条射线添加了ArrowHelpers,预期箭头命中物体时变为红色、未命中时为白色,长度随命中距离变化,未命中时保持射线的最大长度(far)。但目前所有射线始终检测Mesh的同一前方方向,尝试过object3D.localToGlobal、Vector3.applyQuaternion等方法,因数学基础不足未能解决。
错误原因
原代码存在两个核心问题:
- 循环处理射线时,错误复用第一条射线的方向向量做变换,导致所有射线方向完全一致
- 方向变换逻辑错误,没有正确将Mesh本地坐标系下的射线方向转换为世界坐标系方向
修正后的代码
import { RefObject } from "react"; import * as THREE from "three"; import React from "react"; import { useFrame, useThree } from "@react-three/fiber"; export type RayCastResult = { hit: boolean; angle: number; direction: THREE.Vector3; distance: number; }; export const useRaycasts = ({ count = 4, near = 1, far = 10, obj }: { count?: number; near?: number; far?: number; obj: RefObject<THREE.Mesh>; }): { rays: RayCastResult[] } => { const rays = React.useMemo(() => { const rays: RayCastResult[] = []; let angle = 0; const step = (2 * Math.PI) / count; for (let i = 0; i < count; i++) { // 初始化Mesh本地坐标系下的射线方向(绕Y轴均分圆周) rays.push({ hit: false, angle: angle, direction: new THREE.Vector3( Math.cos(angle), 0, Math.sin(angle) ).normalize(), distance: far }); angle += step; } return rays; }, [count, far]); const pos = React.useMemo(() => new THREE.Vector3(), []); // 临时向量,避免修改原射线的本地方向数据 const worldDir = React.useMemo(() => new THREE.Vector3(), []); const { scene, raycaster } = useThree(); useFrame(() => { if (!obj.current) return; const mesh = obj.current; mesh.getWorldPosition(pos); const quaternion = mesh.quaternion; raycaster.near = near; raycaster.far = far; rays.forEach((rayResult, i) => { // 将本地方向应用Mesh的四元数,转换为世界空间下的方向 worldDir.copy(rayResult.direction).applyQuaternion(quaternion).normalize(); raycaster.set(pos, worldDir); // 第二个参数设为true,确保检测场景中所有嵌套子物体 const intersects = raycaster.intersectObjects(scene.children, true); // 更新射线检测结果 if (intersects.length > 0) { rayResult.hit = true; rayResult.distance = intersects[0].distance; } else { rayResult.hit = false; rayResult.distance = far; } }); }); return { rays }; };
关键修正点
- 本地方向转世界方向:使用
Vector3.applyQuaternion(quaternion)是将物体本地方向转换为世界方向的标准方法,能正确继承Mesh的所有旋转信息 - 避免复用错误:循环中使用当前索引
i对应的射线本地方向,不再固定复用第一条 - 数据隔离:用
worldDir临时向量存储转换后的方向,防止修改原射线的基础方向数据 - 优化检测范围:
intersectObjects传入第二个参数true,确保检测场景中所有嵌套的子物体(如果你的Mesh有层级结构)
内容的提问来源于stack exchange,提问作者Diederik Van Remoortere
相关产品推荐
相关产品推荐

