Fix for issue #38 and improvements to detail mesh tessellation

- do circumCircle calculations relative to first vertex for adde
precision
- improved the results of triangulateHull(), produces less degen
triangles
- fixed case with contour merging when outline is null
This commit is contained in:
Mikko Mononen 2014-06-24 15:23:47 +03:00
parent 480f56e94d
commit 129efa5833
2 changed files with 134 additions and 142 deletions

View File

@ -188,27 +188,6 @@ static float distancePtSeg(const int x, const int z,
const int px, const int pz, const int px, const int pz,
const int qx, const int qz) const int qx, const int qz)
{ {
/* float pqx = (float)(qx - px);
float pqy = (float)(qy - py);
float pqz = (float)(qz - pz);
float dx = (float)(x - px);
float dy = (float)(y - py);
float dz = (float)(z - pz);
float d = pqx*pqx + pqy*pqy + pqz*pqz;
float t = pqx*dx + pqy*dy + pqz*dz;
if (d > 0)
t /= d;
if (t < 0)
t = 0;
else if (t > 1)
t = 1;
dx = px + t*pqx - x;
dy = py + t*pqy - y;
dz = pz + t*pqz - z;
return dx*dx + dy*dy + dz*dz;*/
float pqx = (float)(qx - px); float pqx = (float)(qx - px);
float pqz = (float)(qz - pz); float pqz = (float)(qz - pz);
float dx = (float)(x - px); float dx = (float)(x - px);
@ -1102,8 +1081,20 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
// Finally merge each regions holes into the outline. // Finally merge each regions holes into the outline.
for (int i = 0; i < nregions; i++) for (int i = 0; i < nregions; i++)
{ {
if (regions[i].nholes > 0) rcContourRegion& reg = regions[i];
mergeRegionHoles(ctx, regions[i]); if (!reg.nholes) continue;
if (reg.outline)
{
mergeRegionHoles(ctx, reg);
}
else
{
// The region does not have an outline.
// This can happen if the contour becaomes selfoverlapping because of
// too aggressive simplification settings.
ctx->log(RC_LOG_ERROR, "rcBuildContours: Bad outline for region %d, contour simplification is likely too aggressive.", i);
}
} }
} }

View File

@ -68,21 +68,27 @@ static bool circumCircle(const float* p1, const float* p2, const float* p3,
float* c, float& r) float* c, float& r)
{ {
static const float EPS = 1e-6f; static const float EPS = 1e-6f;
// Calculate the circle relative to p1, to avoid some precision issues.
const float v1[3] = {0,0,0};
float v2[3], v3[3];
rcVsub(v2, p2,p1);
rcVsub(v3, p3,p1);
const float cp = vcross2(p1, p2, p3); const float cp = vcross2(v1, v2, v3);
if (fabsf(cp) > EPS) if (fabsf(cp) > EPS)
{ {
const float p1Sq = vdot2(p1,p1); const float v1Sq = vdot2(v1,v1);
const float p2Sq = vdot2(p2,p2); const float v2Sq = vdot2(v2,v2);
const float p3Sq = vdot2(p3,p3); const float v3Sq = vdot2(v3,v3);
c[0] = (p1Sq*(p2[2]-p3[2]) + p2Sq*(p3[2]-p1[2]) + p3Sq*(p1[2]-p2[2])) / (2*cp); c[0] = (v1Sq*(v2[2]-v3[2]) + v2Sq*(v3[2]-v1[2]) + v3Sq*(v1[2]-v2[2])) / (2*cp);
c[2] = (p1Sq*(p3[0]-p2[0]) + p2Sq*(p1[0]-p3[0]) + p3Sq*(p2[0]-p1[0])) / (2*cp); c[1] = 0;
r = vdist2(c, p1); c[2] = (v1Sq*(v3[0]-v2[0]) + v2Sq*(v1[0]-v3[0]) + v3Sq*(v2[0]-v1[0])) / (2*cp);
r = vdist2(c, v1);
rcVadd(c, c, p1);
return true; return true;
} }
c[0] = p1[0]; rcVcopy(c, p1);
c[2] = p1[2];
r = 0; r = 0;
return false; return false;
} }
@ -223,15 +229,6 @@ static unsigned short getHeight(const float fx, const float fy, const float fz,
h = nh; h = nh;
dmin = d; dmin = d;
} }
/* const float dx = (nx+0.5f)*cs - fx;
const float dz = (nz+0.5f)*cs - fz;
const float d = dx*dx+dz*dz;
if (d < dmin)
{
h = nh;
dmin = d;
} */
} }
} }
return h; return h;
@ -524,15 +521,17 @@ static void triangulateHull(const int nverts, const float* verts, const int nhul
{ {
int start = 0, left = 1, right = nhull-1; int start = 0, left = 1, right = nhull-1;
// Start from shortest ear. // Start from an ear with shortest perimeter.
float dmin = FLT_MAX; // This tends to favor well formed triangles as starting point.
float dmin = 0;
for (int i = 0; i < nhull; i++) for (int i = 0; i < nhull; i++)
{ {
int pi = prev(i, nhull); int pi = prev(i, nhull);
int ni = next(i, nhull); int ni = next(i, nhull);
const float* pv = &verts[hull[pi]*3]; const float* pv = &verts[hull[pi]*3];
const float* cv = &verts[hull[i]*3];
const float* nv = &verts[hull[ni]*3]; const float* nv = &verts[hull[ni]*3];
const float d = vdistSq2(pv, nv); const float d = vdist2(pv,cv) + vdist2(cv,nv) + vdist2(nv,pv);
if (d < dmin) if (d < dmin)
{ {
start = i; start = i;
@ -548,8 +547,10 @@ static void triangulateHull(const int nverts, const float* verts, const int nhul
tris.push(hull[right]); tris.push(hull[right]);
tris.push(0); tris.push(0);
// Triangulate the polygon by adding the shortest diagonal // Triangulate the polygon by moving left or right,
// 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) while (next(left, nhull) != right)
{ {
// Check to see if se should advance left or right. // Check to see if se should advance left or right.
@ -560,9 +561,9 @@ static void triangulateHull(const int nverts, const float* verts, const int nhul
const float* nvleft = &verts[hull[nleft]*3]; const float* nvleft = &verts[hull[nleft]*3];
const float* cvright = &verts[hull[right]*3]; const float* cvright = &verts[hull[right]*3];
const float* nvright = &verts[hull[nright]*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);
const float dleft = vdistSq2(nvleft, cvright);
const float dright = vdistSq2(cvleft, nvright);
if (dleft < dright) if (dleft < dright)
{ {
tris.push(hull[left]); tris.push(hull[left]);