当当当当裤裆坦 发表于 2021-2-24 12:47

Unity 寻路系统学习总结

概述

寻路是大部分类型的游戏都需要支持的基本功能,Unity 为我们提供了现成的寻路系统,该系统主要由以下四部分组成
NavMesh,用于描述可行走表面的数据结构,既可以自动烘焙,也可以手动构建。NavMesh Agent,寻路目标的代理,可以用来让目标寻路至指定位置,并且在过程中回避其他 Agent 或者动态的障碍物。Off-Mesh Link,可以在 NavMesh 之间建立连接路径。NavMesh Obstacle,代表障碍物,动态移动的障碍,Agent 会尽力尝试规避,静态的障碍物,则会通过“挖空” NevMesh 来对寻路结果产生影响。
内部实现

可行走区域(Walkable Areas)
寻路系统需要用它自己的数据来表达世界的可行走区域,walkable areas 定义了场景中 agent 可以站立与移动的表面。在 Unity 中 使用一个圆柱体来代表 agent 。walkable areas 通过测试场景中 agent 的可站立位置自动构建,然后这些位置会连接成一个场景几何之上的表面,简称之为 NevMesh(navigation mesh)。
NevMesh 以一个凸包集合的形式储存,因为凸包具有如下良好性质,凸包内的任意两点之间没有阻隔。此外还要保存凸包之间的邻接关系。
路径查找(Finding Paths)

为了找到场景里两点之间的路径,首先需要把起点与终点映射到最近的凸包,然后找出这两个凸包之间的最短路径。查找这样的路径,Unity 使用的是名为 A 星的通用寻路算法。这样得到的凸包序列构成的路径称之为 corridor。
跟随路径

对于简单的,不需要回避其他 agent的游戏,只需要把 agent 沿着各个拐角构成的线段移动即可,在各个拐角播放动画,切换方向。
但是在处理有多个 agent 的情况时,因为需要动态回避其他 agent ,同样的方法就会可能导致问题。因为 agent每帧只移动一点点,我们可以在需要做出调整(比如为了回避其他 Agent)时利用凸包之间的连接去调整路径,从而快速找到下一个拐角。
障碍回避(Avoiding Obstacles)

转向(steering )逻辑根据下一个拐角计算出到达目标需要的方向与速率,而使用计算出的结果去移动 agent 可能会导致与 agent 发生碰撞。
障碍回避会在移动到目标方向与避开可能的碰撞之间做一个平衡,从而得到一个速度,Unity 使用 reciprocal velocity obstacles (RVO) 去预测可能的碰撞。
移动 Agent

最终转向与障碍回避计算出需要的速度,在 unity 中使用简单的动态模型模拟 agent,也会考虑加速度从而使移动更加平滑自然。
在这个阶段你可以将从模拟的 agent 获得速度的反馈,并且将其传达给动画系统并使用 root motion 来移动角色,也可以把这一任务交给寻路系统。
此外移动的坐标会被寻路系统限制,从而保证功能的健壮。
全局与局部

理解全局与局部寻路的区别是最重要的一点。
全局寻路会找到 corridor,这个过程开销相当大,corridor 会受到 agent 当前位置的影响动态调整,局部寻路会在避免碰撞的前提下尝试计算出如何更有效地朝下一个拐角移动。
两个障碍物的案例

除了其他移动代理,大部分应用程序还要求要求的障碍类型,全局寻路会利用静态的障碍物查找路径,局部寻路会对动态的障碍物进行规避。
对于移动的障碍物,使用局部障碍规避处理,这种方式下 agent 可以预测并躲避障碍物。而静态的障碍物,则应该依靠全局寻路处理,也就是说,影响的应该是 NevMesh ,影响的方式是会在 NevMesh 上 “挖出” 一个个空洞,这个过程称为 carving,开销相当地大,一般都是预先烘焙处理。
局部碰撞规避算法是局部的,只会考虑下一个直接的碰撞,无法处理类似陷阱或者道路阻塞这类全局情况,所以需要考虑使用 carving。
描述 Off-mesh Links

寻路系统里使用 links 来描述 NevMesh 多边形之间的连接。有时这对于将 agent 导航跨越不可行走区域是必要的。比如跳过篱笆、沟壑、关闭的门等等。这些案例需要知道坐标的行为。
这些行为可以使用 Off-Mesh Links 注解,这将告诉寻路系统通过特定的 link 有特殊的路线,这些 link 会在寻路时被访问,并且触发特殊的 action。
NevMesh 的构建

使用 Unity 的寻路系统需要依赖于 NevMesh,而 NevMesh 的构建则需要在场景中准备好标记为 Navigation Static 的 Mesh Render 和 Terrains,它会收集这些对象然后生成合适的 NevMesh,这个过程被称为 NavMesh Baking(烘焙)。
除了标记 Navigation Static的对象之外,还需要打开 Navgation 窗口,调整如下属性
Agent 的半径,影响 Agent 的中心到边缘的距离Agent 的高度,影响 Agent 能到达多低的地方最大斜率,影响 Agent 能到达平面的陡峭程度阶梯高度,影响 Agent 能够跨越的最大障碍物高度
最后点击 bake 按钮就会进行 NevMesh 的烘焙。
之后就能在 Scene 视图里看见覆盖在场景几何上的蓝色的可行走区域(前提是打开者 Navigation 窗口)。
可行走区域会比几何小一圈,因为虽然我们为 Agent 指定了半径,但是为了方便处理,Unity 的寻路系统还是会将当作点处理(出于性能等考虑),并且沿着几何的边向内将 NevMesh 缩小。
NevMesh 是 可行走区域表面的近似,为了减少数据,会将凹凸的斜坡处理为平滑的斜面(依据给出的阶梯高度),将带有小坑的凹凸不平的地面处理为平面。
当烘焙完成后在场景文件所在目录下的场景同名目录里可以找到 NavMesh 的 asset 文件。
总结

Unity 的寻路系统使用 NavMesh 作为寻路的数据依据,用户通过 Agent 来使用相关服务,Agent 会根据 NavMesh 、起点、目标点,通过 A* 得到 凸包路径,然后依据其他 Agent 的情况及自身设置,进行动态规避,在过程中依据情况重复上述过程,直至移动至指定目标或者被阻塞。
我们需要提供 Agent 以及对场景物体做标记得到 NavMesh 的数据。这套工作流可以解决大部分游戏开发遇到的问题,但是有些情况我们需要更强大的功能,比如运行时动态修改 NevMesh,多种类型的寻路,非平行于地面的 walkable area 等等。这些是上述的简单传统工作流不支持的,我们需要 Unity 提供更强大的支持。
参考

ffycxyw2274436 发表于 2021-2-24 12:52

这图片是谁呢 这也太可爱了

快乐人L 发表于 2021-2-24 13:01

是我老婆

seedees3 发表于 2021-7-12 21:56

正在学寻路
页: [1]
查看完整版本: Unity 寻路系统学习总结