unity 导航跟寻路
之前面试问了A*,这里跟A*一起看看
组成
- 导航网格(NavMesh)是一种数据结构,用于描述游戏世界的可行走表面,并允许在游戏世界中寻找从一个可行走位置到另一个可行走位置的路径。该数据结构是从关卡几何体自动构建或烘焙的。
- 导航网格代理 (NavMesh Agent) 组件可帮助您创建在朝目标移动时能够彼此避开的角色。代理使用导航网格来推断游戏世界,并知道如何避开彼此以及移动的障碍物。
- 网格外链接 (Off-Mesh Link) 组件允许您合并无法使用可行走表面来表示的导航捷径。例如,跳过沟渠或围栏,或在通过门之前打开门,全都可以描述为网格外链接。
- 导航网格障碍物 (NavMesh Obstacle) 组件可用于描述代理在世界中导航时应避开的移动障碍物。由物理系统控制的木桶或板条箱便是障碍物的典型例子。障碍物正在移动时,代理将尽力避开它,但是障碍物一旦变为静止状态,便会在导航网格中雕刻一个孔,从而使代理能够改变自己的路径来绕过它,或者如果静止的障碍物阻挡了路径,则代理可寻找其他不同的路线。
一种寻路的常用算法是 A*(发音为“A star”),这也是 Unity 使用的算法。
生成
GameObject > AI > NavMesh Surface
1.选择应影响导航的场景几何体:可行走表面和障碍物。
2.选中 Navigation Static 复选框以便在导航网格烘焙过程中包括所选对象。
3.调整烘焙设置以匹配代理大小。 - Agent Radius 定义代理中心与墙壁或窗台的接近程度。 - Agent Height 定义代理可以达到的空间有多低。 - Max Slope 定义代理走上坡道的陡峭程度。 - Step Height 定义代理可以踏上的障碍物的高度。
4.单击 Bake 以构建导航网格。
获取对应的navmesh的所有信息
public static NavMeshTriangulation CalculateTriangulation();
采样最近的点,这里需要高度的高
public static bool SamplePosition(Vector3 sourcePosition, out NavMeshHit hit, float maxDistance, int areaMask);
public static bool SamplePosition(Vector3 sourcePosition, out NavMeshHit hit, float maxDistance, NavMeshQueryFilter filter);
NavMesh.SamplePosition
NavMeshHit hit;
RaycastHit[] raycast_hit = Physics.RaycastAll
NAVMESH寻路网格生成
今天面试官问了一个问题,怎么生产的navmesh,所以我这里大概整理一下,由于才能浅薄,有啥不对的,希望指正
这里成为NMGen(NavMesh Gen)
主要流程如下所示:
1. 体素化。从源几何体构造实心的高度场,用来表示不可行走的空间。
2. 生成地区。将实心高度场的上表面中连续的区间合并为地区。
3. 生成轮廓。检测地区的轮廓,并构造成简单多边形。
4. 生成多边形网格。将轮廓分割成凸多边形。
5. 生成高度细节。将多边形网格三角化,得到高度细节。
一、体素化(Voxelization,使用类Heightfield)
在体素(体素是空间中的一个有大小的点)化阶段,源几何体被转换成高度场,用来表示不可行走的空间。一些不可走的表面在这个阶段会被剔除掉(比如坡度过大的面 )。
对于源几何体上的每个三角形,使用“保守体素化算法”(Conservative Voxelization)分割成体素,并加入到高度场中。保守体素化算法确保了每个三角形面,都会被生成的体素完全包围。
体素化阶段后,实心高度场(solid heightfield)包含了很多的区间(span),覆盖了源几何体上的所有面。
二、生成地区(Region Generation 使用类 CompactHeightfield)
这一阶段的目标是,近一步定义实体表面上哪部分是可以行走的,以及将这些可行走的部分划分成连续的地区,这些地区可以最终构成简单多边形。
首先,将实心的高度场,转换成一个开放的高度场(open heightfield),用来表示实体表面上那些可以行走的部分。一个开放的高度场,表示位于实体空间表面的地表部分。
然后,进一步剔除掉不可行走的区域。在计算完成的时候,开放区间中那些认为可以行走的部分,应该通过下面的测试:
+ 该区域不能紧挨着障碍物(如,墙,家具等)(使用WalkableRadius作为距离阀值)
+ 该区域在表面之上没有足够的开放空间(非碰撞区域)。(人在不碰撞到其他物体的情况下,能够合法的移动)(使用WalkableHeight作为高度阀值)
为剩下的所有区间生成邻接信息,用于把他们合并成一个大的面片。该算法使用一个最大垂直步长(WalkableStep4)来决定哪些区间是可以连在一起的。
三、生成轮廓(Contour Generation 实用类ContourSet)
轮廓就是沿着地区边缘“行走”,构成简单多边形。这是从体素空间转换回向量空间的第一步处理。
首先,从地区生成非常精细的多边形。
然后,使用多种算法来完成下面的步骤:
+ 简化相邻多边形的边缘(地区之间的部分)
+ 简化边界(边界是没有邻接或邻接了障碍物的轮廓)(EdgeMaxDeviation)
+ 优化边界的长度。(边界如果太长,不能得到最优的三角形)
四、生成凸多边形(Convex Polygon Generation 使用类PolyMesh)
许多算法只能用于凸多边形。因此,这一步需要把轮廓构成的简单多边形转换成凸多边形网格。
在该阶段的结尾,一个凸多边形网格代表了可以行走的表面。
五、生成高度细节(Height Detail Generation核心类PolyMeshDetail)
在这最后的阶段,凸多边形网格会被Delaunay三角化算法三角化,于是可以增加高度的细节。在多边形的内部或者边缘添加顶点,来确保网格与原始几何体表面等价。(DetailSampleDistance和DetailMaxDeviation)