buildPolyDetail() 传入的是contours,先对过长的边进行插值,通过”int nn = 1 + (int)floorf(d/sampleDist);“ 进行判断需要划分多少段,这个过程也对点的y轴进行了设置。然后按原来的方向顺序将点的下标放到hull中,形成一个精细化的三维的contours(hull)。
然后进行triangulatehull过程。
再然后,对整个contours进行均匀的网状的划分,找出其中的网的所有交点,这些交点与contours的边的距离(在xz平面上)大于 “-sampleDist/2”
然后循环进行 (每次从采样点中选取 与 上次deluanay划分计算出的mesh 距离最大的点 ,放入到verts中,然后又将所有verts中的点进行deluanay划分)的操作。最后一次的deluanay划分出来的tris就是buildPolyDetail所求。
getHeightData() ,基本上注释说得很明确。
while (head*3 < queue.size()) //在上面先求出满足要求的顶点,再基于这些顶点用广度优先算法一圈一圈的向外扩展,按这样的方式对获取所有有效顶点的高度,并保存到hp.data中
triangulateHull 创建修长的三角形网格,主要代码如下
tris.push(hull[start]);
tris.push(hull[left]);
tris.push(hull[right]);
tris.push(0);
// Triangulate the polygon by moving left or right,
// depending on which triangle has shorter perimeter.
// This heuristic was chose emprically, since it seems
// handle tesselated straight edges well.
while (next(left, nhull) != right)
{
// Check to see if se should advance left or right.
int nleft = next(left, nhull);
int nright = prev(right, nhull);
const float* cvleft = &verts[hull[left]*3];
const float* nvleft = &verts[hull[nleft]*3];
const float* cvright = &verts[hull[right]*3];
const float* nvright = &verts[hull[nright]*3];
const float dleft = vdist2(cvleft, nvleft) + vdist2(nvleft, cvright);
const float dright = vdist2(cvright, nvright) + vdist2(cvleft, nvright);
if (dleft < dright)
{
tris.push(hull[left]);
tris.push(hull[nleft]);
tris.push(hull[right]);
tris.push(0);
left = nleft;
}
else
{
tris.push(hull[left]);
tris.push(hull[nright]);
tris.push(hull[right]);
tris.push(0);
right = nright;
}
}
每次找最左右未取到的相对更短边与上一步新加的边组成新的三角形,根据这个逻辑,结果类似这样:(实际点是三维的,在y轴是不共面的)
这里使用triangulateHull而不使用delaunayhull原因如下:
// Tessellate the base mesh.
// We're using the triangulateHull instead of delaunayHull as it tends to
// create a bit better triangulation for long thin triangles when there
// are no internal points.
delaunayHull()//对poly进行德洛内三角划分,得出poly的三角行和顶点,存放到tris和verts中。首先将最外围的一圈点链接起来,再对所有点进行三角划分,将信息存放到edge中。最后再edge中的信息放到tris中
里面主要理解的是edges。 一条边,由四个变量组成,起点,终点,边的左边三角形面id,边的右边三角形面id。默认面id为EV_UNDEF或者EV_HULL(边界的edges)。组装点edge的时候采用逆时针方向进行组装的,所以初始的时候的hull边界的left为EV_HULL。而right正是将要 求取 的,设置为EV_UNDEF。
int currentEdge = 0;
while (currentEdge < nedges)
{
if (edges[currentEdge*4+2] == EV_UNDEF)
completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
//找出一个三角形 ,对nedges会做修改 ,nfaces 会增1,并将face id存放到相关的edge中(edge[2],edge[3])。
if (edges[currentEdge*4+3] == EV_UNDEF)
completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
currentEdge++;
}
completeFacet,采用的方法是 计算该边与所有其他点的最小外接圆。
rcBuildPolyMeshDetail,将上面的rcBuildPolyMesh 计算出来的poly 信息存放到 rcPolyMeshDetail中。逐个poly的进行buildpolydetail计算。
dmesh,meshes存放submesh,实际是存放poly信息。
dmesh.nmeshes = mesh.npolys; //num sub mesh
dmesh.nverts = 0; //dmesh总的顶点数
dmesh.ntris = 0;//dmesh总的triangle数
dmesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*dmesh.nmeshes*4, RC_ALLOC_PERM);
for (int i = 0; i < mesh.npolys; ++i){
。。。。
dmesh.meshes[i*4+0] = (unsigned int)dmesh.nverts;//存放poly的vert在dmesh->verts中的存放的起点位置
dmesh.meshes[i*4+1] = (unsigned int)nverts;//存放这个poly的verts数量
dmesh.meshes[i*4+2] = (unsigned int)dmesh.ntris;//存放poly的triangle在dmesh->tris中存放的起点位置
dmesh.meshes[i*4+3] = (unsigned int)ntris;//存放这个poly triangle数量
。。。。