recast SoloMesh生成过程详解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/buck84/article/details/78563599

最近游戏中需要使用navmesh,阅读recast过程中顺手把学习记录写下来,方便以后查看。
使用过程主要需要理解每个数据含义,至于生成过程,不做深入研究。
相关资料
recast源码
很好的参考资料

主要的生成过程是handleBuild函数,一共分成8步,里面虽然有些注释,但是新人想看懂,太难了。

Step 1. Initialize build config.

这个没啥好说的,很简单,就是初始化

Step 2. Rasterize input polygon soup.

难度来了,这一步主要是生成rcHeightField,这一步主要用到配置中的cellSize和cellHeight,rcHeightField是个什么样子呢,是一个width*height大小的数组,数据存储在spans中,每一个元素是一个链表,链表的每一个元素对应相应位置有几个阻挡块,具体什么样子可以参考上面的链接。至于pools和freelist是辅助生成spans的,本身没什么用处。
这一步主要有2个函数:
rcMarkWalkableTriangles
根据walkableSlopeAngle,判断输入数据中的每一个三角形是否可以行走,信息存储在m_triareas中
rcRasterizeTriangles
扫描输入mesh中每个三角形,生成rcHeightField。这一步主要的处理函数是rasterizeTri,把一个三角形放到对应的格子中,然后计算参数,进行addSpan,如果一个格子里面有多个span,则链表链起来,链表头指向最下面的span
这一步完了以后,m_triareas没用了,可以删了

Step 3. Filter walkables surfaces.

这一步3个函数都是对上面生成的rcHeightField进行一些处理
rcFilterLowHangingWalkableObstacles
如果一个格子本身不可走,但是旁边格子可走,而且与其高度差小于walkableClimb,则标记其为可走
rcFilterLedgeSpans
这个懒得细看了,影响不大
rcFilterWalkableLowHeightSpans
如果一个格子两个span高度差小于walkableHeight,将其设置为不可走

Step 4. Partition walkable surface to simple regions.

生成rcCompactHeightField,其中数据主要保存在spans中,与rcHeightField中的rcSpan正好相反,这里面保存的数据是可以走的span,参考文档中叫做open HeightField,rcSpan中是阻挡物的span。cells中保存每个小格子中是否有span,有多少个,index为spans中起始位置,count为数量,一个cell中count个span在spans中是连续保存的。rcCompactSpan中每个span其实点为y,高度为h,con表示与周围4个span的连接关系,每个用6位表示连接的块:连接的块index-第一个index,因为每个方向连接的第一个index是可以直接计算得到的,只需要保存偏移即可,共24bit位。reg表示其对应的region,后面会用到。
rcBuildCompactHeightfield
这个函数就是根据rcHeightField生成rcCompactHeightField,首先计算得到y h,然后得到con。
然后,rcHeightField就没用了。
rcErodeWalkableArea
根据角色半径,设置那些靠边半径范围内的span为不可走
首先判断每个格子是否边界,保存在dist中。
然后两次遍历计算靠近边界距离,保存在dist中。
最后根据dist中的值是否小于玩家直径,如果是则将其设置为不可走。
接下来是3种划分方法,用来生成reg(唯一的region id),这块感觉是最难的一块了,用了各种处理图像的方法来划分区域,不过不理解也不要紧,可以跳过,不影响,只需要知道生成了reg即可。
第一种方法Watershed partitioning,可以参考文章Volumetric cell-and-portal generation。
生成region分2步,第一步是生成distance field,就是每个点到边界的距离,位于calculateDistanceField,首先判断边界(根据周围4个方向是否与当前块可达),然后根据边界计算每个点到边界的距离。

Step 5. Trace and simplify region contours.

这一步是根据rcCompactSpan.reg生成contours,其数据结构很简单,verts rverts分别包含点,nverts和nrverts是点的数量,主要的一点是rcContour.verts[3+4n]用来表示contour邻接region id(rcContour.reg),并且可能设置标记位RC_BORDER_VERTEX
rcBuildContours首先将每个span的基于reg的联通情况保存在flags中,0表示不需要考虑,非0表示是边界,用于生成contours,具体生成方法参见参考资料

Step 6. Build polygons mesh from contours.

第6步和第7步是后面decour用的最多的数据结构,前面的contour虽然也可能有用,在高阶用法里面,但是通常来说不用。
第6步生成rcPolyMesh,用于生成凸包,方便后面各种算法处理,每个凸包最多包含6个顶点,如果超过6个,则后面不能生成navmesh。
verts是所有顶点
polys是npolys个凸包的数据,每个凸包包含2*nvp=12个数据,前6个为顶点在verts中的index,后面6个顶点分两种情况:如果设置位0x20000,表示是边界。如果设置位0x8000,则说明当前边是边界,最低4位如果不是0xf则为0-7,表示是portal:8个方向相邻tile的连接关系,x轴为0,顺时针每45°加1;否则说明当前顶点所在边是两个凸包之间的连接,表示的是邻接的哪个poly。
reg是region index
flags是用户数据
areas是区域可行走状态

Step 7. Create detail mesh which allows to access approximate height on each polygon.

生成rcPolyMeshDetail,这个是一个大mesh
其中主要数据是
meshes,每个mesh包含4个数据
verts起始index
vert数量
tris起始index
tri数量
tris前3个数据是三角形顶点index,第4项是个8位的比特位,其中6位表示三条边分别是否边界,如果是则为1

Step 8. Create Detour data from Recast poly mesh.

这一步是使用上面的数据生成用来寻路的数据
dtPoly中只包含poly信息,detailTris里面是详细mesh,用来精确计算高度
dtMeshTile
salt //
linksFreeList //
verts // 每个poly是个凸多边形,其顶点数据
links //
detailMeshes // detailMesh信息
detailVerts // 由于凸多边形不够精确,会保存其中更多顶点
detailTris // 对应detailVerts,第4位类似rcPolyMeshDetail.tris,保存是否边界信息
offMeshCons //

dtPoly
firstLink // 第一个poly间连接关系,tile->links中index
verts // dtMeshTile.verts中index
vertCount // verts中有效数量
neis // 掩码0x8000表示与外面tile连接,低位表示连接方向

neis // 0x8000表示是与其它tile相邻边界,最低4位表示4个方向是否连接,0表示真实边界,非0表示内部线

dtLink
ref // 根据ref可以计算出相邻tile和poly getTileAndPolyByRefUnsafe
next // 在tile->links中index
edge // 连接另一端的polygon index
side // 不是0xff表示是tile边界,0 2 4 6 表示4个方向
bmin bmax // 表示与其它link公用边的话,所在范围,比如当前tile一条边连着相邻tile多条

展开阅读全文

没有更多推荐了,返回首页