recast navigation navmesh导航网格算法源码分析
Author: 林绍川
recast navigation navmesh是unity3d ue4内置的寻路算法
本文为了方便,引用了一些网上的相关图片
图片出处:Recast源码解析(二):NavMesh导航网格生成原理(上) - 程序员大本营 特此致谢
1 加载.obj文件
InputGeom::load--->InputGeom::loadMesh负责加载所有三角形
取obj文件中顶点数据,和顶点索引数据
1.1 obj的格式:
v 6.5 0.07999992 20.5
...(每行以v开头,连着三个浮点数,为一个顶点坐标)
f 1 2 3
...(每行以f开头,连着三个整数,为顶点索引)
1.2 三角形空间分割
rcCreateChunkyTriMesh,这个函数为之后建立高度场时,能快速索引出对应的三角形
按如下步骤:
1 此函数会为加载的三角形计算aabb盒(其实是xz坐标的包围矩形)
2 以aabb哪个轴长(x轴方向长),就按哪个轴进行排序,然按三角形数量1分为2
3 如此循环,直到划分的节点里三角形个数小于某个阀值(256)
2 建立高度场
结束加载obj,就要开始建立高度场
1 Recast navmesh是将场景中的三角形光栅光,形成高度场体素,
2 然后根据高度场计算layer,还生成导航多边形数据
为何不直接利用obj中的三角形数据,原因可能如下:
1 obj中的三角形数据可能细节更多,而导航寻路可以适当简化多边形细节,提高效率
2 寻路有对象宽度限制,体素化利于处理
3 obj中没有包含layer信息,需要处理
layer是recast navmesh里的一个概念,是导入obj里,一些独立,不连通的区域,或者不同的层,彼此之间寻路上不能互通,
或者通过port互通
此处以 Sample_TempObstacles::handleBuild为例,说明这一过程
这个sample支持动态创建障碍物,具体的处理方向如下步骤:
1 将高度场数据划分成tile,
2 障碍物改变与其相交的高度场体素,将处于障碍物(包围盒/或者圆柱体)中的体素标记为不可走
3 然后将受影响的tile重新计算,局部重新生成导航多边形数据
2.1 rasterizeTileLayers光栅化tile内三角形
光栅化场景中的三角形,即用一个正方形单元(xz平面),对场景中三角形数据进行采样高度数据,此处借用网上的一个图,形象表示如下:

图1
对图中的每个小方格,以下会以span这一称呼来代替,
一个span是xz大小固定的单元格,在y方向不固定
(根据光栅光时,截取到的多边形高范围,记录ymax ymin)
2.2 划分tile
Sample_TempObstacles为了动态重新开销减少,需要划分tile,
即将整个场景算出一个aabb,在xz平面上按固定大小分tile
每个tile内包含一个span体素数组
即tile是一个块, span则是一个最小的体素点,
二维的span组成一个tile
二维的tile组成一个场景
2.3 rasterizeTileLayers的参数 rcConfig
这个参数部分重要成员变量含义:
cs:
体素化的单位xz的量化(每个span在xz平面的长宽,为一个正方向)
ch:
y方向的量化单位
walkableSlopeAngle:
可攀爬的角度(0-90度),用来判断一个span是否可以行走(太斜了,就不能行走)
walkableHeight:
寻路单位的高度,高度不够,不能走, 例如:一个身高两米的人,不能通过只有1米高的门框之类的
walkableClimb:
同上,高度差小于此值,认为两个span是可以行走的
walkableHeight walkableClimb会被ch量化,例如:
ch=0.5 walkableHeight=2.0 那么 walkableHeight = walkableHeight / ch,
最终walkableHeight =4;
walkableRadius:
可行走的宽度,即一个太窄,狭小的地方认为不能走
walkableRadius会被cs量化
例如:
cs = 0.5 walkableRadius = 2.0
walkableRadius = walkableRadius / cs 即walkableRadius = 4
borderSize:
为每个tile多准备一些span数据,相当于边框,值会设成比walkableRadius大,避免把一些span错误置成不可行走
2.4 rcGetChunksOverlappingRect
此函数比较简单,计算当前tile范围,将tile包含的三角形找出来
2.5 rcMarkWalkableTriangles
依据walkableSlopeAngle,根据法线,判断哪些三角形不能走
2.6 rcRasterizeTriangles
对每个三角形调用rasterizeTri光栅化(或者说体素化),
形成一个高度场,(x,z)单元格,一个格子对应一个链表,链表里的数据按高度从小到大排列
2.7 rasterizeTri
对单个三角形进行光栅化(见图1)

在xz平面,对三角形进行分割,
循环调用dividePoly,先平行x轴模向切割, 再平行z轴纵切
2.7.1 dividePoly
分割多边形,以沿z轴平行分割为例,有如下 图2 图3两种情况

本文对recast navigation navmesh导航网格算法源码进行分析。先介绍加载.obj文件和三角形空间分割,接着阐述建立高度场的过程,包括光栅化、划分tile等。然后说明从压缩高度场重建导航数据,最后讲解寻路功能,涉及网格寻路和寻找拐点,还介绍了相关工具函数。
最低0.47元/天 解锁文章
792

被折叠的 条评论
为什么被折叠?



