Export Recast Navigation Data from UE4

最新版本已支持 UE5,详见 github 的 UE5.0 分支:ue4-export-nav-data/tree/UE5.0

Recast Navigation是一个开源的游戏导航 / 寻路引擎,可以为游戏中的 AI 提供寻路计算。UE 和 Unity 都是集成了 RecastNavigation 来为游戏提供导航和寻路计算 (当然是修改过的版本),UE 的模块NavigationSystem 以及 NavMesh 中可以看到相关的代码实现。
最近有个需求是要将客户端的地图信息导出给非 UE 网络架构的服务端,用于在服务器上对玩家位置的校验,想到可以把客户端的生成的导航数据导出作为客户端世界的 地图 ,所以折腾了一下写了一个 UE 的插件(开源在 Github 上:**ue4-export-nav-data)实现了 直接 ** 将 UE 生成的导航数据导出,有兴趣的可以直接去看具体的代码。
根据导出的导航数据可以完整地在非 UE 网络架构的服务端上实现基于 Recast Navigation 的寻路计算,而且与 UE 无缝衔接。

**2019.12.04 Update:** 本插件已上架虚幻商城,购买链接ExportNavigation,为了程序员情怀支持开源,所以该项目在 Github 上的开源仓库不会关闭,但基本不会更新,如果该插件对你有用,欢迎在商城购买支持作者。

Recast Navigation

首先,先来简单介绍一下编译 Recast 的 github 开源版本,UE 引擎中使用的 recast 就是基于该开源版本修改的,截止到 UE_4.22.3,UE 使用的 recast 版本为v1.4(可以从Source/Runtime/Navmesh/Recast-Readme.txt 中查看不同引擎版本使用的 recast 版本信息)。
RecastNavigation 在 Github 上的源码地址:recastnavigation.
recastnavigation的代码中提供了导航网格生成与计算寻路的工具RecastDemo,可以作为在项目中集成 RecastNavigation 的案例。

README.md里面写了各个平台的编译流程,我在这里详细展开一下 Windows 下编译流程。

  1. 首先下载premake5,并将其添加到系统 PATH 路径
  2. clone RecastNavigation 的代码
  3. 下载 SDL2(选择 Development Libraries),并将其解压到recastnavigation\RecastDemo\Contrib 目录下,将文件夹改名为SDL,目录结构为:
1
2
3
4
5
6
D:\recastnavigation\RecastDemo\Contrib\SDL>tree /a
+---docs
+---include
\---lib
+---x64
\---x86
  1. recastnavigation\RecastDemo 目录下执行命令 premake5 vs2017(vs201x 取决于你当前系统中安装的版本),它会在RecastDemo 目录下创建 build/vs2017 目录,里面是 VS 项目的解决方案。

  2. 打开RecastDemo\Build\vs2017\recastnavigation.sln,编译即可。

  3. 编译出来 RecastDemo.exe 位置在RecastDemo\Bin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
C:\Users\imzlp\source\repos\recastnavigation\RecastDemo\Bin>tree /a /f
文件夹 PATH 列表
卷序列号为 000002D0 ECDB:6872
C:.
| .gitignore
| DroidSans.ttf
| RecastDemo.exe
| RecastDemo.pdb
| SDL2.dll
| Tests.exe
| Tests.pdb
|
+---Meshes
| dungeon.obj
| nav_test.obj
| undulating.obj
|
\---TestCases
movement_test.txt
nav_mesh_test.txt
raycast_test.txt

其中关键的几个文件:DroidSans.ttf/RecastDemo.exe/SDL2.dll/Meshs/

注意:必须把 obj 文件放到 Meshs/ 目录下才可以被 RecastDemo 识别。

之后就可以打开 RecastDemo.exe 在默认提供的三个 obj 的模型上进行导航数据生成的测试了,通过 Build 生成,然后 Save 保存会在 RecastDemo.exe 所在的目录产生一个 .bin 文件,即使用 recast 生成的导航数据。

注意 :从 UE 导出 Navmesh 的含义是,把 UE 寻路范围内的模型导出,再通过RecastDemo 在该模型的基础上生成寻路数据。这也导致了在 UE 中添加影响寻路的框,导出 Navmesh 在 RecastDemo 生成时无法生效。

Plugin: ue-export-nav-data

该插件是从 UE 中导出 RecastNavigation 的工具,分为两个模块:ExportNavRuntimeExportNavEditor,编辑器模块提供了 UE 中编辑器ToolBar 的按钮,在编辑器中导出导航数据。

点击之后选择路径,会在选择的路径下生成两个文件:.binobj,在 Windows 下会自动在资源管理器中打开导出目录。

  • bin:UE 构建完成的导航数据,给外部服务器使用。
  • obj:UE 中放置寻路的 Mesh,可以从 RecastDemo 中生成 bin 文件。


另外,我提供了 NavData 可以在运行时导出,但是 NavMesh 不支持,因为 UE 的导航是预计算的,具体可以看 UFlibExportNavData 中提供的方法。

我在 C++ 和蓝图中也提供了从导出的 bin 中验证位置是否是合法的寻路位置的两种方法:

1
2
bool UFlibExportNavData::IsValidNavigationPointInNavbin(const FString& InNavBinPath, const FVector& Point, const FVector InExtern = FVector::ZeroVector);
bool UFlibExportNavData::IsValidNavigationPointInNavObj(class UdtNavMeshWrapper* InDtNavObject ,const FVector& Point, const FVector InExtern = FVector::ZeroVector);

可以与 UE 中提供的 UNavigationSystemV1::ProjectPointToNavigation 来对比验证导出数据是否匹配。

还有一个传入起始点来获取导航路径点的方法:

1
bool FindDetourPathByNavMesh(dtNavMesh* InNavMesh ,const FVector3& InStart, const FVector3& InEnd, std::vector<FVector3>& OutPaths);

可以与引擎中 UNavigationSystemV1::FindPathToLocationSynchrously 的结果一致,传入游戏中的世界坐标,函数内部有转换,返回的也是世界坐标。

该插件其优点为:

  • 并非先从 UE 导出 NavMesh 的 .obj 再使用 RecastDemo 生成,而是直接从 UE 导出bin,当然我也保留了导出 NavMesh 为obj
  • 因为是直接从 UE 生成之后的导航数据导出,所以是所见即所得,解决导出 NavMesh 再 RecastDemo 生成导航网格时无法避免某些区域不生成寻路,以及避免 UE 与 RecastDemo 各种寻路参数的不一致产生的寻路数据不一致;
  • 额外抽取出 ue 的 ue-detour 版本,可以无缝集成到外部服务器中,客户端坐标与服务端坐标无需转换(当然 UE 的坐标与 Recast 的坐标需要转换,但是内部已经处理,使用时不需要手动转换)。

UE 的坐标系与 Recast 的坐标系之间的转换可以使用 UE4RecastHelper 的两个函数:

1
2
3
4
5
6
7
8
9
10
11
12
namespace UE4RecastHelper
{
FCustomVector Recast2UnrealPoint(const FCustomVector& Vector)
{
return FCustomVector(-Vector.X, -Vector.Z, Vector.Y);
}

FCustomVector Unreal2RecastPoint(const FCustomVector& Vector)
{
return FCustomVector(-Vector.X, Vector.Z, -Vector.Y);
}
};

Library: ue-recast-detour

这个是我从 UE 代码中抽取出的 recast detour 库,在 UE 源码的路径下为Runtime/Navmesh/Detour,主要目的是保证 UE 客户端与外部服务器的验证方法一致。

因为在 github 上的 RecastNavigation 要高于 UE 使用的版本,而且前面提到 UE 在 recast 的基础上做了不少改动,为了防止代码的差异造成的不同结果,我将 ue 使用 (以及魔改) 过的版本抽出来供外部使用,这样可以确保客户端和服务端的结果是一致的。

代码放在了 github:ue4-recast-detour,该仓库的 Detour/ 目录下为 Detour 的库的全部代码。
其余的代码是我实现的与 UE 进行验证和 UE 与 Recast 坐标转换的库 UE4RecastHelper 类以及实现的一个简单的命令行程序,用来测试 UE 中的世界位置是否在 bin 中的寻路数据中合法。

UE4RecastHelper目前 (2019.11.01) 提供了 dtNavMeshbin文件之间 serialize/deserialize 的方法;以及与 UE 中函数 UNavigationSystemV1::ProjectPointToNavigation 实现方法相同的函数UE4RecastHelper::dtIsValidNavigationPoint,用来验证点是否是合法的寻路点,保证了 UE 客户端与外部服务器的验证方法一致。

Detour所支持的操作都可以在服务器上实现(因为已经从 UE 里拿到了导航数据),可以根据需求扩展。

再简单说一下 ue-detour.exe 这个工具怎么用,直接在命令行启动 ue4-detour.exe 会提示用法。
首先,要先从 UE 中将导航数据导出,这里需要用到的只有 .bin 文件,如生成在 D:\NavData
然后找到 ue4-detour.exe 就可以使用下列命令了:

1
2
3
4
5
6
D:\>ue4-detour.exe
Usage:
ue4-detour.exe dtNavMesh.bin Loc.X Loc.Y,loc.Z Extren.X Extern.Y Extren.Z
PS:{Extern.X Extern.Y Extern.Z} can be ignored,default is {10.f 10.f 10.f}
For Example:
ue4-detour.exe dtNavMesh.bin -770.003 -593.709 130.267 10.0 10.0 10.0


在蓝图中也可以直接加载 .bin 进行测试:

End

本篇文章用到的开源仓库:

Update

2021.05.27 Update

  • 插件支持 UE5,支持导出 UE5 的 NavMesh 数据及导航网格
  • 数据与 ue-detour 验证成功