一、基本导航
- 构建导航网格
拖拽NavMeshBoundsVolume
到关卡内。
自动更新导航网格: 在 编辑器设置(Editor Settings)->Level Editor->Miscellaneous-> 启用自动更新导航(Update Navigation Automatically)。
- 可视化导航网格
关卡中找到RecastNavMesh-Default
,并在Detail里勾选Draw Poly Edges
或Draw Tile Bounds
。
Draw Poly Edges: 绘制组成网格的多边形。
Draw Tile Bounds: 可视化单个Navigation Tiles
二、修改导航网格
1.使用Navigation Modifier Volumes
AreaClass
应用于导航网格,用于更改体积空间内多边形的属性以修改其通过成本。
Area Class | 描述 |
---|---|
NavArea_Default | 默认情况下,将相同的导航成本分配给体积内的区域和导航网格。 |
NavArea_LowHeight | 代表一个区域符合低高度通过条件,防止Agent通过它。导航网格不会在该体积内生成导航数据。 |
NavArea_Null | 表示体积内的空白区域。 导航网格不会在该体积内生成导航数据。 |
NavArea_Obstacle | 为体积内的区域分配高导航成本。如果有通路走通路,没通路才会走这条路 |
2.使用Nav Link Proxy
2.1 连接两个导航区域
Nav Link Proxy连接导航网格中两个不相连的导航区域。 在搜索路径时,Nav Link Proxy用作Agent到达其目的地的额外连接。指示代理在没有可用的连续导航路径时可以从平台跌落或跳向目标。
Note: 如果 Nav Link Proxy 未与 Navigation Mesh 的表面连接,
黑色
箭头将消失。(在UE4里是绿色箭头)
黑色箭头是实际AI的导航路径
。
2.2 修改连接方向
在SimpleLink
里,可以修改连接方向。
2.3 使用SmartLink
使用SmartLink,让Agent跳到高处
。
逻辑:
Warning
: Nav Link Proxy只能连接相邻的导航网格Tile Bounds。您可以通过选择“WorldOutliner”–>“RecastNavMesh-Default”–>启用“Draw Tile Bounds”来可视化Tile Bounds。
3 实时生成导航模型
Generation Mode | 描述 |
---|---|
Static | 导航网格离线生成,并与关卡一起保存。 在运行时加载,无法更改。 |
Dynamic | 离线生成并与关卡一起保存或在运行时构建。 在运行时,可以实时更新并生成导航相关数据。 |
Dynamic Modifiers Only | 导航网格是离线生成的,并与关卡一起保存。 在运行时,只有 Navigation Modifiers(如 Navigation Areas、Navigation Links 和动态对象)可以通过更改成本或块区域来修改现有 Navigation Mesh。 运行时不会生成新的导航网格表面。 这种方法允许导航网格缓存碰撞数据,并且可以使受影响图块的处理成本降低 50%。 高级用户应在仔细考虑其优点和限制后使用此模式。 |
Dynamic Modifiers Only
设置实时生成方式。项目设置–>NavigationMesh–>Runtime Generation。
只有当Actor拥有NavModifier
组件时有效。
注意关卡中没有生成新的导航网格(正在生成的图块显示为红色)。 导航修改器只是更改现有的导航网格。
示例中,目前同时加RotatingMovement组件有效,单加NavModifier无效,原因未知。
Dynamic
设置实时生成方式。项目设置–>NavigationMesh–>Runtime Generation。
Note: 强制生成具有高计算成本的导航网格。
三、自定义导航区域和查询筛选器
1. 自定义区域类(Nav Area)
将NavModifierVolume
拖动到关卡中。创建蓝图继承NavArea
,命名为BP_Area_Neutral。打开BP_Area_Neutral,修改默认成本乘数和固定区域输入成本。选择颜色,编译并保存。
将创建好的NavArea添加到NavModifierVolume中的AreaClass里。
2. 创建导航查询筛选器(Navigation Query Filter)
创建蓝图继承NavigationQueryFilter
,命名为BP_QueryFilter1。打开BP_QueryFilter1,添加并修改Areas数组,加入上一步创建的AreaClass,重写通过成本,
由于BP_QueryFilter1 BP_Area_Lane2是最便宜的路线,因此Agent使用它来到达球体。
四、在导航系统中使用回避
方法 | 描述 | 局限性 |
---|---|---|
Reciprocal Velocity Obstacles (RVO) 相互速度障碍 | - 代理通过在指定半径内使用速度矢量来避开障碍物。 -包含在角色类的角色移动组件中。 | - 与绕行人群管理器相比,配置较少。 - 仅限于角色类。 - 不使用导航网格进行回避 ,因此代理可能会“越界”。 |
Detour Crowd Manager 人群绕行 | - 代理通过使用路径优化以及指定半径内的速度矢量来避开障碍物。 - 包含在绕道拥挤的AI控制器类中 | 具有在项目设置中定义的固定最大代理数。 |
1. 使用RVO避免(Reciprocal Velocity Obstacles)
打开角色蓝图,选择Character Movement Component
,导航到“角色移动:回避”部分,启用“UseRVOAvoidance”
复选框,并将“回避考虑半径”设置为 100。
效果如下
2. 使用人群绕行避免(Detour Crowd Manager)
打开角色蓝图,将AIController替换为Detour Crowd AI Controller
,运行即可。
也可以调整绕行人群管理器系统的多个设置,例如系统使用的最大代理数和用于避免计算的最大代理半径。
五、使用Navigation Invokers
概述
- 这是一种仅围绕特定目标本地构建导航的方法。
在Actor上添加Navigation Invoker组件,用于在运行时围绕代理生成导航网格。此方法不再需要在编辑器中构建导航网格,还可以限制在运行时生成的切片数。
非常适合在编辑器中构建导航网格不切实际的大型关卡
。
设置
- 向关卡中拖入导航网格。
- 项目设置–>NavigationSystem—>启用
Generate Navigation Only Around Navigation Invokers
。 - 项目设置–>NavigationMesh—>Runtime Generation—>Dynamic。
4.添加组件Navigation Invoker
。打开细节面板,根据需求更改切片生成半径(用于生成导航网格切片的参与者周围的半径)和切片删除半径(用于删除导航网格切片的参与者的半径)。
效果如下:
六、优化导航网格生成速度
Note: 最新版本可在引擎中找到。目录如下:Engine\Source\Runtime\NavigationSystem\DevDocs\How To Optimize Navmesh Generation.md
导航系统提供了各种设置,高级用户可以使用这些设置来修改关卡中导航的计算方式。
1. 建议
1.1 尽可能使用最高Cell Size和Cell Height
Cell Size
和Cell Height
定义了用于生成导航切片的体素大小(Cells)。体素越小,获得的精度就越高,障碍物周围的导航就越准确。但是,体素越小,在运行时重新构建导航网格时需要的处理就越多。
Cell Size=19
Cell Size=64
因此,在Agent所需的精度下,CellSize尽可能调大。
1.2 限制Tile Size
导航网格分为多个tiles,由于每个tiles都是从cells构建的,因此重新构建导航tiles将导致使用新的碰撞信息重新创建其所有cells。
较大的tiles包含更多的cells,重建成本高于较小的tiles。但是,在处理tiles时,系统还会处理其边缘上的连续cells。在设置切片大小时,应考虑此开销成本,因为在某些情况下,处理许多较小tiles的开销成本可能大于重建单个大型tiles的成本。
建议:tiles大小应设置为每侧
32
到128
个cells之间。这将在运行时重建tiles时提供最佳性能。
即Cell Size=64时,TileSizeUU>2048 (6432),且TileSizeUU<8192 (64128)。
1.3 对网格使用简化碰撞
导航系统使用每个对象的碰撞数据来生成导航网格。
因此, 碰撞网格中使用的三角形计数越低,生成速度就越快。
1.4 减少影响导航网格的对象数
默认情况下,关卡中的蓝图Actor和静态网格体会影响导航。影响导航tiles的对象数对生成该tiles的成本有直接影响。
因此, 选择任何不应影响导航网格的Actor
,在细节面板中,禁用Can Ever Affect Navigation
。
如果可能,应避免同时影响大型tiles区域或多个tiles。
2. 用于管理导航生成的有用开发人员工具
在战略时期锁定和解锁导航网格生成
可以手动控制在所有资源完成加载后解锁导航网格生成。此方法可防止导航系统多次重建同一tiles。
锁定
导航网格生成,设置bInitialBuildingLocked=true;解锁
生成,调用ReleaseInitialBuildingLock()。解锁后,导航网格将重建所有被加载的资源标记为脏的tiles。- 为了防止这种情况,可以在解锁之前,调用DefaultDirtyAreasController.Reset()。
启用多线程导航网格生成
您可以通过在"项目设置"–>NavigationSystem中的MaxSimultaneousTileGenerationJobsCount
来控制多线程导航网格的生成。请注意,这受到 FRecastNavMeshGenerator::Init()
中工作线程总数的限制。
将动态障碍物与全动态导航网格生成结合使用
您可以将关卡中的Actor标记为动态障碍物,Actor需要有Collision组件
。动态障碍物标记需要重建生成的导航网格表面。这可以防止重新生成整个导航tiles。
使用此方法比生成完整的导航tiles成本更低,当移动障碍物顶部不需要导航网格表面时,应使用此方法。
用法猜测,当Actor顶部有导航网格,却不想用时,添加Collision组件,将AreaClass改成NavArea_Null,再启用DynamicObstacle。这样Actor顶部的导航网格就去掉了。
将数据块流用于在子关卡中加载的静态导航网格体
如果对导航网格体的唯一更改来自加载和卸载子关卡
,则可以将导航网格体生成方法设置为静态并使用 NavMesh 数据块流式处理,而不是使用动态导航网格体。
使用此方法,导航网格将在编辑器中完全构建,并且只有相关部分将在运行时loaded in and out。