基于React.js/R3F+Yuka实现GLB地图Mesh两点最短路径及相机跟随
解决方案:基于React Three Fiber + Yuka实现GLB地图路径规划与相机漫游
1. 依赖安装
先安装所需开发包:
npm install react three @react-three/fiber @react-three/drei yuka
2. 核心实现步骤
2.1 加载GLB模型并构建Yuka导航网格
加载GLB地图模型,提取用于路径规划的Mesh,将其几何体转换为Yuka支持的导航网格格式,这是路径查找的核心依赖。
import { useRef, useEffect } from 'react'; import { useGLTF, useFrame } from '@react-three/fiber'; import { NavigationMesh, Pathfinder, NavMeshGeometryGenerator } from 'yuka'; export default function MapPathfinder() { const { scene } = useGLTF('/your-map.glb'); const pathfinderRef = useRef(new Pathfinder()); const pathRef = useRef([]); const cameraPathRef = useRef({ index: 0, progress: 0 }); // 初始化导航网格与路径计算 useEffect(() => { // 从GLB模型中获取预定义的导航Mesh(需确保模型中存在命名为"NavMesh"的Mesh) const navMesh = scene.getObjectByName('NavMesh'); if (!navMesh) return; // 将Three.js几何体转换为Yuka导航网格数据 const generator = new NavMeshGeometryGenerator(); const navMeshData = generator.generate(navMesh.geometry); const yukaNavMesh = new NavigationMesh(navMeshData); pathfinderRef.current.setNavigationMesh(yukaNavMesh); // 定义路径起点与终点(示例为模型中标记点的世界坐标,可替换为自定义坐标) const startPoint = scene.getObjectByName('StartMarker').position.clone(); const endPoint = scene.getObjectByName('EndMarker').position.clone(); // 计算两点间最短路径 const calculatedPath = pathfinderRef.current.findPath(startPoint, endPoint); if (calculatedPath) pathRef.current = calculatedPath; }, [scene]); // 相机沿路径平滑漫游逻辑 useFrame((state, delta) => { const { camera } = state; const path = pathRef.current; if (path.length < 2) return; const { index, progress } = cameraPathRef.current; const nextIndex = (index + 1) % path.length; const currentPoint = path[index]; const nextPoint = path[nextIndex]; // 线性插值实现平滑移动,相机始终看向路径下一个点 camera.position.lerpVectors(currentPoint, nextPoint, progress); camera.lookAt(nextPoint); // 更新移动进度,到达节点后切换到下一段路径 cameraPathRef.current.progress += delta * 0.4; if (cameraPathRef.current.progress >= 1) { cameraPathRef.current.progress = 0; cameraPathRef.current.index = nextIndex; } }); return ( <group> {/* 渲染GLB地图模型 */} <primitive object={scene} /> {/* 绘制路径线条 */} {pathRef.current.length > 1 && ( <line> <bufferGeometry> <bufferAttribute attach="attributes-position" array={new Float32Array(pathRef.current.flatMap(p => [p.x, p.y, p.z]))} count={pathRef.current.length} itemSize={3} /> </bufferGeometry> <lineBasicMaterial color="#ff4444" linewidth={3} /> </line> )} </group> ); } // 预加载GLB模型提升渲染性能 useGLTF.preload('/your-map.glb');
2.2 关键细节说明
- 导航Mesh要求:GLB模型中需包含专门的导航Mesh(建议命名为
NavMesh),该Mesh必须是封闭、无重叠的多边形面,覆盖所有可行走区域,否则Yuka无法正确构建导航区域。 - 路径计算容错:
Pathfinder.findPath()若找不到可行路径会返回null,可添加判断逻辑提示用户。 - 相机移动优化:可替换线性插值为缓动函数(如
THREE.MathUtils.smoothstep),让相机移动更自然;调整delta * 0.4中的系数可控制移动速度。 - 路径渲染:通过将Yuka路径点数组转换为Three.js的
BufferAttribute,用<line>组件渲染可视化路径。
3. 常见问题处理
- 路径查找失败:检查导航Mesh是否存在破面、重叠,或起点/终点不在导航Mesh覆盖范围内。
- 模型加载缓慢:对GLB模型进行压缩处理,或使用
useGLTF.preload提前加载资源。 - 相机抖动:降低移动速度系数,或在相机位置更新后添加微小的平滑处理。
内容的提问来源于stack exchange,提问作者Techie
相关产品推荐
相关产品推荐

