NavCat:纯 JavaScript 的 3D 导航网格构建与查询库

游戏开发
Three.js
开源
TOOL
2026/10/17
·

阅读时间: 大约 10 分钟

NavCat:纯 JavaScript 的 3D 导航网格构建与查询库

NavCat 从关卡几何生成的导航网格线框:白色多边形覆盖在灰色可走表面之上,不可达区域被排除

NavCat 是一个面向 3D 地面导航的 JavaScript 导航网格(navigation mesh,navmesh)构建与查询库,官网 navcat.dev,核心定位是”在纯 JS 里完成 navmesh 生成与寻路查询”,且与渲染/游戏引擎解耦。它的体素化生成路线借鉴了经典的 recastnavigation 库,但官方明确说明不是 recast 的直接移植。本文基于官方 README 与文档,解析其管线、参数体系与边界。

一、背景:JS 3D 寻路的空白

在 2D 俯视角里,寻路用格子图或导航多边形就够;一旦进入 3D(Three.js/Babylon.js 做的室内导航、网页 3D 展厅、轻量游戏),角色要沿地面走、绕开墙体、爬得上台阶、上不去陡坡,就需要一张”可走表面图”。C# 生态有 Unity 的 NavMesh + recast 成熟方案,原生 C++ 有 recastnavigation,而浏览器侧长期缺少一个既能离线烘焙 navmesh、又能在运行时做 A* 查询的纯 JS 实现。NavCat 填的就是这个位置。

二、它是什么:生成 + 查询一体,引擎无关

官方 Features 列出的能力:

  • 从 3D 几何构建导航网格;
  • 导航网格查询(寻路等);
  • 单块(single-tile)与多块(tiled)导航网格;
  • 数据结构完全 JSON 可序列化;
  • 纯 JS,面向 tree-shaking 设计;
  • 与任何 JS 引擎配合:Babylon.js、PlayCanvas、Three.js,或自研引擎;
  • 提供 navcat/three 入口的 Three.js 专用工具。

底层结构上,navmesh 由一个或多个 tile 组成,每个 tile 内含可走多边形与高度细节;NavCat 在背后维护一张”节点(多边形)—连接(多边形邻接)“图,寻路查询就是在这张图上搜索。大多数项目用覆盖整关的单块即可,大世界/动态场景才需要分块。

三、八步生成管线(recast 体素化路线)

官方 Deep Dive 把生成拆成八步,核心是把三角形几何栅格化成体素/高度场,再过滤、分区、抽边、三角化:

  1. 标记可走三角形:按坡度等条件先在输入几何上筛出角色能站的面;
  2. 栅格化为高度场并过滤:把可走三角形 voxelize 进 heightfield,移除角色站不住的跨度与悬垂;
  3. 构建紧凑高度场、按角色半径腐蚀、标记区域:只保留顶层可走面,按 agent 半径内缩留出墙体间隙;
  4. 构建区域(regions):先算距离场,再用 watershed 或单调分区把可走面切成无洞区域;
  5. 由区域构建轮廓(contours);
  6. 由轮廓生成多边形网格,并构建细节高度网格;
  7. 把构建期 poly mesh 与 detail mesh 转成运行时 tile 格式;
  8. 组装最终导航网格。

findPath 查询结果:蓝色为可达多边形区域,黄色折线为 A* 选出的路径,红色圆点为路径途经点

运行时查询的最小调用形如:

import { DEFAULT_QUERY_FILTER, findPath } from 'navcat';
const path = findPath(navMesh, start, end, halfExtents, DEFAULT_QUERY_FILTER);

返回结果除了路径点,还带 nodePath(A* 搜索节点),官方提供 createSearchNodesHelper 把搜索过程可视化。

四、关键参数:以 1 米人形角色为基准的启发式

官方参数表给出了 1=1m 世界、人形 agent 的起步区间:

参数含义官方建议区间(1m 人形)
cellSize水平体素尺寸(XZ),越小越精细、生成越慢约 walkableRadiusWorld / 3
cellHeight垂直体素尺寸(Y)约 walkableClimbWorld / 2
walkableRadiusWorld角色半径(半宽),决定墙体间隙0.2–0.5 m
walkableHeightWorld角色身高,低于此净高的区域排除1.6–2.0 m
walkableSlopeAngleDegrees可走最大坡度35–50°
walkableClimbWorld可上下的最大台阶高度0.3–0.5 m
minRegionArea保留的最小孤立区域(体素)4–16
mergeRegionArea小于此并入邻居的区域(体素)8–32
maxSimplificationError边简化容差,越大网格越简1–2
maxEdgeLength多边形边超长则拆分8–24
maxVerticesPerPoly每个多边形最大顶点数3–6

这些是起步启发式,官方强烈建议配合库自带的 debug 可视化工具逐关微调,而不是一套参数通吃。

人群模拟示例:红、蓝、绿三个角色在同一张 navmesh 上各自寻路并相互避让

五、集成口径与注意事项

  • 坐标约定:NavCat 遵循 OpenGL 约定——右手坐标系、索引逆时针环绕;若你的环境用其他坐标系,进出库都要做坐标变换。
  • 外部导入要求:导入外部制作的 navmesh 时,多边形顶点必须共享(相邻多边形共用顶点),不能各自重复。
  • 输入几何要干净:README 提醒不要把树叶、小装饰道具这类不该参与可走面生成的几何喂进去。
  • 多 agent 腐蚀:erodeAndMarkWalkableAreas 支持按不同半径分级标记窄道,官方特别提示 cellSize 要足够小才能表达窄通道,阈值 1–2 体素容易产生坏区域,可改用 buildRegionsMonotone。

六、局限与口径

  • 离线烘焙假设:管线面向静态关卡的构建期生成,动态障碍物、实时重建不在默认能力内;tiled navmesh 支持分块重烤与流式,但需要自己组织。
  • 参数调优成本:没有”默认参数即完美”,窄门、斜坡、台阶的取舍高度依赖 debug 迭代,小团队容易在调参上耗时。
  • 非 recast 直移植:行为细节与 C#/C++ 版不完全等价,迁移经验不能照搬;官方称核心思路同源但实现独立。
  • 人群模拟是示例层:图中的避让效果来自示例与查询 API 组合,不是内置的成熟 crowd 避障引擎,复杂群体行为需自行扩展。
  • 性能数字官方未给统一基准:不同几何规模下的生成耗时与查询延迟需在自己关卡上实测,本文不引用具体毫秒数。

七、适用与不适用

适合:Three.js/Babylon.js 的室内 3D 导航、网页展厅/沙盘的角色行走、轻量 3D 游戏寻路;需要 navmesh 数据 JSON 序列化、可在前后端之间传递的场景;希望引擎无关、自行控制渲染的团队。

不适合:开放大世界的实时动态寻路;需要成熟 crowd 避障/群体调度引擎;2D 俯视角(格子图更简单);追求零配置开箱即用的非技术团队。

八、它意味着什么

NavCat 的意义在于把 recast 这套经过二十年验证的体素化 navmesh 方法论落到了纯 JS,让浏览器 3D 场景第一次有了不依赖 WASM 移植、可 tree-shake、引擎无关的生成与查询工具。它不是游戏引擎级的完整寻路中间件,而是一块扎实的基础设施积木,适合有能力自行调参与扩展的团队。

参考来源