1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
From c393777d26d2ff6519ac23612abf8af42678c9dd Mon Sep 17 00:00:00 2001
From: Jakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
Date: Wed, 20 Dec 2023 06:46:50 +0100
Subject: [PATCH 15/36] Make detail mesh edge detection more robust (#657)
Instead of using a distance check which can fail at large magnitudes due
to low precision we can check whether the edges are actually on the
hull.
---
Recast/Source/RecastMeshDetail.cpp | 64 ++++++++++++++++++------------
1 file changed, 38 insertions(+), 26 deletions(-)
diff --git a/Recast/Source/RecastMeshDetail.cpp b/Recast/Source/RecastMeshDetail.cpp
index 479037a..957245c 100644
--- a/Recast/Source/RecastMeshDetail.cpp
+++ b/Recast/Source/RecastMeshDetail.cpp
@@ -634,6 +634,40 @@ inline float getJitterY(const int i)
return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
}
+static bool onHull(int a, int b, int nhull, int* hull)
+{
+ // All internal sampled points come after the hull so we can early out for those.
+ if (a >= nhull || b >= nhull)
+ return false;
+
+ for (int j = nhull - 1, i = 0; i < nhull; j = i++)
+ {
+ if (a == hull[j] && b == hull[i])
+ return true;
+ }
+
+ return false;
+}
+
+// Find edges that lie on hull and mark them as such.
+static void setTriFlags(rcIntArray& tris, int nhull, int* hull)
+{
+ // Matches DT_DETAIL_EDGE_BOUNDARY
+ const int DETAIL_EDGE_BOUNDARY = 0x1;
+
+ for (int i = 0; i < tris.size(); i += 4)
+ {
+ int a = tris[i + 0];
+ int b = tris[i + 1];
+ int c = tris[i + 2];
+ unsigned short flags = 0;
+ flags |= (onHull(a, b, nhull, hull) ? DETAIL_EDGE_BOUNDARY : 0) << 0;
+ flags |= (onHull(b, c, nhull, hull) ? DETAIL_EDGE_BOUNDARY : 0) << 2;
+ flags |= (onHull(c, a, nhull, hull) ? DETAIL_EDGE_BOUNDARY : 0) << 4;
+ tris[i + 3] = (int)flags;
+ }
+}
+
static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
const float sampleDist, const float sampleMaxError,
const int heightSearchRadius, const rcCompactHeightfield& chf,
@@ -771,6 +805,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
if (minExtent < sampleDist*2)
{
triangulateHull(nverts, verts, nhull, hull, nin, tris);
+ setTriFlags(tris, nhull, hull);
return true;
}
@@ -875,6 +910,8 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
tris.resize(MAX_TRIS*4);
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Shrinking triangle count from %d to max %d.", ntris, MAX_TRIS);
}
+
+ setTriFlags(tris, nhull, hull);
return true;
}
@@ -1137,31 +1174,6 @@ static void getHeightData(rcContext* ctx, const rcCompactHeightfield& chf,
}
}
-static unsigned char getEdgeFlags(const float* va, const float* vb,
- const float* vpoly, const int npoly)
-{
- // The flag returned by this function matches dtDetailTriEdgeFlags in Detour.
- // Figure out if edge (va,vb) is part of the polygon boundary.
- static const float thrSqr = rcSqr(0.001f);
- for (int i = 0, j = npoly-1; i < npoly; j=i++)
- {
- if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr &&
- distancePtSeg2d(vb, &vpoly[j*3], &vpoly[i*3]) < thrSqr)
- return 1;
- }
- return 0;
-}
-
-static unsigned char getTriFlags(const float* va, const float* vb, const float* vc,
- const float* vpoly, const int npoly)
-{
- unsigned char flags = 0;
- flags |= getEdgeFlags(va,vb,vpoly,npoly) << 0;
- flags |= getEdgeFlags(vb,vc,vpoly,npoly) << 2;
- flags |= getEdgeFlags(vc,va,vpoly,npoly) << 4;
- return flags;
-}
-
/// @par
///
/// See the #rcConfig documentation for more information on the configuration parameters.
@@ -1377,7 +1389,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
dmesh.tris[dmesh.ntris*4+0] = (unsigned char)t[0];
dmesh.tris[dmesh.ntris*4+1] = (unsigned char)t[1];
dmesh.tris[dmesh.ntris*4+2] = (unsigned char)t[2];
- dmesh.tris[dmesh.ntris*4+3] = getTriFlags(&verts[t[0]*3], &verts[t[1]*3], &verts[t[2]*3], poly, npoly);
+ dmesh.tris[dmesh.ntris*4+3] = (unsigned char)t[3];
dmesh.ntris++;
}
}
--
2.43.0
|