[unity3d]recast navigation navmesh 导航网格 寻路算法 源码分析

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

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两种情况

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值