You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:45:10