本文翻译自:http://critterai.org/projects/nmgen_study/voxelization.html
NMGen是一个开源项目,包括Java版的recast静态网格生成代码,以及详细介绍生成过程的文章。因为在阅读过程中觉得对理解recast原理非常有用,所以决定将其翻译在自己blog上。
原blog上完整的目录包括:
- 高度域介绍(Introduction to Heightfields)
- 总体过程概述(The High Level Process)
- 配置参数(Configuration Parameter)
- 体素化过程(The Voxelization Process)
- 区域生成(Region Generation)
- 轮廓生成(Contour Generation)
- 凸多边形生成(Convex Polygon Generation)
- 细节网格生成(Detail Mesh Generation)
其中第一篇、第二篇已经由游蓝海做了翻译。这里从第四篇开始,分步骤详细讲述NavMesh的生成过程。翻译时力求忠实于原意,且尽量通俗易懂。译文如下:
概述
构造导航网格的第一步是使用体素化(voxelization)创建实心高度域(solid heightfield)。
构造类: SolidHeightfieldBuilder
数据类: SolidHeightfield
如果你需要回忆体素化的执行过程,请回到总体概述。
创建实心高度域
当我们创建了源网格(source mesh)的AABB包围盒和容纳体素信息的实心高度域后,为每个源网格中的多边形执行下列操作:
确定多边形在高度域格子上的投影(footprint)——也就是多边形的AABB包围盒在2D坐标系下的投影。因为求取多边形投影覆盖的格子需要交集测试,这样做的好处是可以降低交集测试的数量。
遍历投影覆盖的所有高度域格子列(grid column),并求出源多边形与列相交的比例。如果出现一次相交,那么得到一个新的“裁剪过的”(clipped)多边形。然后确定这个多边形的最低和最高的高度。这就代表着格子列被源多边形占据的比例。
我们基于以下信息来为高度域添加区间(span):
- 与多边形有交集的格子列
- 裁剪得到的多边形的最低和最高高度范围(格子列被占据的比例)
- 裁剪多边形的表面是否可行走(traversable)
其中最后一条信息取决于源多边形在y轴的倾斜度(slope)和配置的maxTraversableSlope属性值。如果前者小于后者(例如45度),那么表面可行走。
当新的区间数据添加到高度域时,会做如下事情:
如果新的区间不与任何现存的区间相交,那么创建一个新的区间。否则合并两个区间。
当两个区间合并时,必须验证合并后的区间是否可经过。可行走标志(traversable flag)只应用在区间的上表面。如果设置了该标志,那么就意味着区间的顶端多边形有较低的倾斜度,因此可行走。
如果新区间的顶端高于要合并到的区间顶端,那么将新区间的可行走标志应用到合并后的区间上。
如果新区间的顶端低于要合并到的区间顶端,那么我们不用关心新区间的可行走标志,直接丢弃。
如果新区间的顶端与要合并到的区间高度一致,那么只要两者中任何一个可行走,那么合并后的区间也是可行走的。
更多的高度域区间标志
技术上来说,源网格的体素化已经完成,而且高度域已包含占据空间的实心体素区间。区间也有标志代表顶端表面是否可行走。但是这个标志的设置只考虑了与区间相交的多边形的倾斜度。现在是时候做更多的过滤了:从一些区间上移除可行走标志。
两种类型的过滤:
首先,当区间上方有非常近的障碍物时,它的顶端表面也不可行走。想象地板上的一张桌子。虽然桌子下面的地板是平坦的,但仍然不可行走(因为容纳的高度不够)。
一个可选择的过滤与凸起(ledge)检测有关。如果从区间的顶端到相邻的区间下降的距离超过了一定阈值,那么这个区间被认为是个凸起,也不可行走。
目前的进展
在这一步结尾,我们构造了一个代表源网格占据区域的高度域。执行初步的过滤后,占据区域的顶端表面被标记为是否可行走。