static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& hf,
const float* bmin, const float* bmax,
const float cs, const float ics, const float ich,
const int flagMergeThr)//格栅化一个三角形
{
const int w = hf.width;
const int h = hf.height;
float tmin[3], tmax[3];
const float by = bmax[1] - bmin[1];
// Calculate the bounding box of the triangle.
rcVcopy(tmin, v0);
rcVcopy(tmax, v0);
rcVmin(tmin, v1);
rcVmin(tmin, v2);
rcVmax(tmax, v1);
rcVmax(tmax, v2);
// If the triangle does not touch the bbox of the heightfield, skip the triagle.
if (!overlapBounds(bmin, bmax, tmin, tmax))
return true;
//默认y轴朝上,这里的方法是先将整个heightfield做rowfield划分,将三角形化切成片段
//然后又对做过rowfield后的三角形片段做columnfield划分,
//这样就将原始的三角形切分到矩阵式的y cell(y轴未知,x和z长度为cell size)(等同于xz grid cell)中了,而三角形在每
//个y cell中的片段被用来计算出height范围存放到span中用于做下步计算。所以总结起来这里的目的就是用距离为cellsize的zx线网(xz grid cell)切分 空间中分布的原始的三角
//形(即格栅化三角形),并取出三角形在y cell中的对应片段的有效高度范围,并记录下来。
// Calculate the footprint of the triangle on the grid's y-axis
int y0 = (int)((tmin[2] - bmin[2])*ics);//求取三角形min点相对于整个height field的cell的z轴方向下标
int y1 = (int)((tmax[2] - bmin[2])*ics);//求取到三角形max点相对于整个height field的cell的z轴方向下标
y0 = rcClamp(y0, 0, h-1);
y1 = rcClamp(y1, 0, h-1);
// Clip the triangle into all grid cells it touches.
float buf[7*3*4];
float *in = buf, *inrow = buf+7*3, *p1 = inrow+7*3, *p2 = p1+7*3;
rcVcopy(&in[0], v0);
rcVcopy(&in[1*3], v1);
rcVcopy(&in[2*3], v2);
int nvrow, nvIn = 3;
for (int y = y0; y <= y1; ++y)
{
// Clip polygon to row. Store the remaining polygon as well
const float cz = bmin[2] + y*cs;
dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2); //将三角形划分为
//在相应的row中部分和不再row中的部分,p1存放在row中的部分,in存放不再row中的部分,以便for循环的下次运算
rcSwap(in, p1);
if (nvrow < 3) continue;
// find the horizontal bounds in the row 基于上面的z周方向裁剪划分的基础上再
//对x轴方向用同样的方法进行裁剪划分
float minX = inrow[0], maxX = inrow[0];
for (int i=1; i<nvrow; ++i)
{
if (minX > inrow[i*3]) minX = inrow[i*3];
if (maxX < inrow[i*3]) maxX = inrow[i*3];
}
int x0 = (int)((minX - bmin[0])*ics);
int x1 = (int)((maxX - bmin[0])*ics);
x0 = rcClamp(x0, 0, w-1);
x1 = rcClamp(x1, 0, w-1);
int nv, nv2 = nvrow;
for (int x = x0; x <= x1; ++x)
{
// Clip polygon to column. store the remaining polygon as well
const float cx = bmin[0] + x*cs;
dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
rcSwap(inrow, p2);
if (nv < 3) continue;
// Calculate min and max of the span.
float smin = p1[1], smax = p1[1];
for (int i = 1; i < nv; ++i)
{
smin = rcMin(smin, p1[i*3+1]);
smax = rcMax(smax, p1[i*3+1]);
}
smin -= bmin[1];
smax -= bmin[1];
// Skip the span if it is outside the heightfield bbox
if (smax < 0.0f) continue;
if (smin > by) continue;
// Clamp the span to the heightfield bbox.
if (smin < 0.0f) smin = 0;
if (smax > by) smax = by;
// Snap the span to the heightfield height grid.
unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
if (!addSpan(hf, x, y, ismin, ismax, area, flagMergeThr))//将新的span加入到span链表中。内部有合适的合并操作
return false;
}
}
return true;
}
// divides a convex polygons into two convex polygons on both sides of a line
static void dividePoly(const float* in, int nin,
float* out1, int* nout1,
float* out2, int* nout2,
float x, int axis)
{
float d[12];
for (int i = 0; i < nin; ++i)
d[i] = x - in[i*3+axis];//参考的z减去顶点的z
int m = 0, n = 0;
for (int i = 0, j = nin-1; i < nin; j=i, ++i)
{
bool ina = d[j] >= 0;
bool inb = d[i] >= 0;
if (ina != inb)
{
float s = d[j] / (d[j] - d[i]);
out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;//获取到三角形
//边与row cells交点坐标 ,out1 存放由原始三角形裁剪后剩余部分组成的新的三角形
out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
rcVcopy(out2 + n*3, out1 + m*3); //将点放到out2中,out2存放原始三角
//形在row cells 中的部分。
m++;
n++;
// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
// since these were already added above
if (d[i] > 0)
{
rcVcopy(out1 + m*3, in + i*3);
m++;
}
else if (d[i] < 0)
{
rcVcopy(out2 + n*3, in + i*3);
n++;
}
}
else // same side
{
// add the i'th point to the right polygon. Addition is done even for points on the dividing line
if (d[i] >= 0)
{
rcVcopy(out1 + m*3, in + i*3);
m++;
if (d[i] != 0)
continue;
}
rcVcopy(out2 + n*3, in + i*3);
n++;
}
}
*nout1 = m;
*nout2 = n;
}
注意area id(用于描述span的属性,比如walkable ,swiming等)是在rcRasterizeTriangles之前就进行设置的,area id在这一步中会存入到span里面去。
rcHeightfield->spans链表数组中,一个spans列表中元素是从低到高排列的。(对于有相交的区域在addspan的时候就已经合并了)
三角形在span中的片段的具体形状在整个过程(包括后面的所有过程)中并不用管,整个过程都只利用了片段的y的最大值和最小值,以及当前span的最大值余上一个span的最小值所留余的高度,以及span所在的位置。
span中的smin smax都是以cellheight为单位的,记录span的高度上的范围
当前span的top与下一个span的bottom作为可行走的区域
rcFilterLowHangingWalkableObstacles
rcFilterLedgeSpans// 找到边缘并将边缘的areaid设置成null。
rcFilterWalkableLowHeightSpans //剔除掉可行走区域高度低于walkableHeight的span