截止到2018 /9/12最新版的recastnavigation
racastNavigation实际上是有三部分。
第一部分是recast 建立寻路模型(navmesh),可以参看我的前面1 到5篇博客。这一步其实可以简化成让美术去手动创建模型,不过对模型网格是有一定要求的,需要指定一个美术规范,然后在用recast后面部分的代码创建recastmesh对象。
第二部分是detour,寻路,从一个点到另一个点是否可达,并且寻找出路径。
第三部分detoucrowd,控制多个物体走到目的地。不同于控制一个物体走到目的地,需要考虑控制对象之间的碰撞问题。控制物体到达目的地,有一个专门的名词steer。
https://www.jianshu.com/p/490a9128b248
http://www.critterai.org/projects/nmgen_study/
1、理解射线与包围盒的交叉碰撞检测 slab 理解法: https://blog.csdn.net/ring0hx/article/details/7677418
另一种理解:二维中线段(A,B) 和 边与轴平行的矩形(min(X1,Y1),max(X2,T2))相交,如下图(只考虑相交的情况),ab投影到x,y 分别为o2,o1,与矩形边的共同投影分别为g2,g1; g2 ,g1 映射回AB,就变成了b2,b1。AB 与变相交为t0,t1 。主要计算(A,t0)区间与AB的比值的范围(只取0~1之间) 和(B,t1)区间与AB的比值的范围有相交,即可证明AB与四边形相交。利用三角形相似原理前面的求区间范围等价于 求取o2的端点到g2起点的比值范围 和 求取o1的端点到 g1起点 的比值范围 的区间有交叉。取两者的min的最大值作为min 和max的最小值作为max,min<max 就说明相交。
//主要原理是将三维降成一维来计算,可以通过上面博客中的slab来理解,也可以通过上面的线段比值关系来理解。
//包围盒也是需要边界与轴平行,后面的简化计算才有意义。
float d[3];
d[0] = sq[0] - sp[0];
d[1] = sq[1] - sp[1];
d[2] = sq[2] - sp[2];
tmin = 0.0; //将整个sq 到 sp 线段的区域 理解成0~1的区间
tmax = 1.0f;
for (int i = 0; i < 3; i++)
{
if (fabsf(d[i]) < EPS)
{
if (sp[i] < amin[i] || sp[i] > amax[i]) //sp[i] 与sq[i]在该轴向垂直的平面上
return false;
}
else
{
const float ood = 1.0f / d[i];
float t1 = (amin[i] - sp[i]) * ood; //求取amin[i]-sp[i] 与sq[i]-sp[i] 的比值。
float t2 = (amax[i] - sp[i]) * ood; //求取amax[i]-sp[i] 与sq[i]-sp[i] 的比值。
if (t1 > t2) { float tmp = t1; t1 = t2; t2 = tmp; } //求取到比值范围,大小位置做个调整
if (t1 > tmin) tmin = t1; //获取最新的最小值
if (t2 < tmax) tmax = t2; //获取最新的最大值
if (tmin > tmax) return false; //无相交的,退出
}
}
inline unsigned int dtNextPow2(unsigned int v) //求取大于等于v的2的最低次数幂,只要考虑最高位的1,其他的位数都不考虑就容易理解了。过程就是将最高位的1逐次成倍的往后面复制,达到最高位1后面全是1的结果。然后再加1。前面减1是考虑数本身刚好是2的次数幂。
{
v--;
v |= v >> 1; //如果存在大于等于1位的数,将1{x}(n)最高位1,复制到次高位变成11{x}(n-1)
v |= v >> 2; //如果存在大于等于2位的数,将[1]1{x}(n-1)高位的至少一个1,复制到第三[第四]位[1]1[1]1{x}(n-1)
v |= v >> 4; //........将11{x}(n-1)高位的两个1,复制到第三第四位
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
对每个 三角形求取aabb范围并保存
solomesh中的第一步通过rcMarkWalkableTriangles设置三角形的area判断依据为三角形的slope,初始只有两个极端的值,表示可行走还是不可行走
solomesh中的rcRasterizeTriangles 函数,如果有图来进行展示会非常好理解,具体思路和操作是
1、将整个模型所在的box进行分条,如果按 俯视图来看, 分成长宽相等的cell(空间中可想象cell为长方体俯视图是边长为cellsize的正方形),整个模型所在的box刚好完全切分成cell。代码中体现在 双重for循环的x,y
2、左上角(或右上角或其他角)开始,从上致下,从左致右的顺序,查看所有三角形与该cell是否相交,如果相交,取出三角形在该cell空间范围内的aabb,并作为一个span(rcSpan类型)保存。总的是一个cell count个头的散列表。x*y作为散列表的关键值,span是一个是散列表中item。并同时将三角形的area传递给span。
3、一个cell中可能同时与多个三角形有相交,也就是有多个span,将新增的span保存到对应的 散列表中,并做好排序,范围小的在表的最上方。
solomesh中的rcFilterLowHangingWalkableObstacles,看注释吧
solomesh 中的rcFilterLedgeSpans,看注释和代码吧
solomesh中的rcFilterWalkableLowHeightSpans,看注释和代码
rcBuildCompactHeightfield,作用是将sheildheight转为compactsheildheight,换一种存储方式。方便后面的使用。
rcErodeWalkableArea,腐蚀能走的区域,思路和原因和平面中的 腐蚀作用类型。
rcMarkConvexPolyArea, 更改area的值,该值作为权限使用。
SAMPLE_PARTITION_WATERSHED
rcBuildDistanceField,计算每个span离边缘的距离。