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

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值