Changed to reuse samples and edges list in BuildPolyDetail()

This commit is contained in:
ikpil 2024-06-08 12:08:31 +09:00
parent 759e335961
commit face8eb48e
4 changed files with 69 additions and 66 deletions

View File

@ -13,7 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Nothing - Nothing
### Changed ### Changed
- Nothing - Changed to reuse samples and edges list in BuildPolyDetail()
### Removed ### Removed
- Removed RcVecUtils.Dot() - Removed RcVecUtils.Dot()

View File

@ -63,17 +63,6 @@ namespace DotRecast.Core.Numerics
@this.Z * v[vi + 2]; @this.Z * v[vi + 2];
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RcVec3f Add(RcVec3f a, float[] verts, int i)
{
return new RcVec3f(
a.X + verts[i],
a.Y + verts[i + 1],
a.Z + verts[i + 2]
);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Cross(float[] dest, float[] v1, float[] v2) public static void Cross(float[] dest, float[] v1, float[] v2)
{ {

View File

@ -0,0 +1,8 @@
namespace DotRecast.Recast
{
public static class EdgeValues
{
public const int EV_UNDEF = -1;
public const int EV_HULL = -2;
}
}

View File

@ -27,50 +27,43 @@ using DotRecast.Core.Numerics;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
using static RcRecast; using static RcRecast;
using static EdgeValues;
public static class RcMeshDetails public static class RcMeshDetails
{ {
public const int MAX_VERTS = 127; public const int RC_UNSET_HEIGHT = RC_SPAN_MAX_HEIGHT;
public const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
public const int MAX_VERTS_PER_EDGE = 32;
public const int RC_UNSET_HEIGHT = RcRecast.RC_SPAN_MAX_HEIGHT; public static float Vdot2(RcVec3f a, RcVec3f b)
public const int EV_UNDEF = -1;
public const int EV_HULL = -2;
private static float Vdot2(RcVec3f a, RcVec3f b)
{ {
return a.X * b.X + a.Z * b.Z; return a.X * b.X + a.Z * b.Z;
} }
private static float VdistSq2(float[] verts, int p, int q) public static float VdistSq2(float[] verts, int p, int q)
{ {
float dx = verts[q + 0] - verts[p + 0]; float dx = verts[q + 0] - verts[p + 0];
float dy = verts[q + 2] - verts[p + 2]; float dy = verts[q + 2] - verts[p + 2];
return dx * dx + dy * dy; return dx * dx + dy * dy;
} }
private static float Vdist2(float[] verts, int p, int q) public static float Vdist2(float[] verts, int p, int q)
{ {
return MathF.Sqrt(VdistSq2(verts, p, q)); return MathF.Sqrt(VdistSq2(verts, p, q));
} }
private static float VdistSq2(RcVec3f p, RcVec3f q) public static float VdistSq2(RcVec3f p, RcVec3f q)
{ {
float dx = q.X - p.X; float dx = q.X - p.X;
float dy = q.Z - p.Z; float dy = q.Z - p.Z;
return dx * dx + dy * dy; return dx * dx + dy * dy;
} }
private static float Vdist2(RcVec3f p, RcVec3f q) public static float Vdist2(RcVec3f p, RcVec3f q)
{ {
return MathF.Sqrt(VdistSq2(p, q)); return MathF.Sqrt(VdistSq2(p, q));
} }
private static float Vcross2(float[] verts, int p1, int p2, int p3) public static float Vcross2(float[] verts, int p1, int p2, int p3)
{ {
float u1 = verts[p2 + 0] - verts[p1 + 0]; float u1 = verts[p2 + 0] - verts[p1 + 0];
float v1 = verts[p2 + 2] - verts[p1 + 2]; float v1 = verts[p2 + 2] - verts[p1 + 2];
@ -79,7 +72,7 @@ namespace DotRecast.Recast
return u1 * v2 - v1 * u2; return u1 * v2 - v1 * u2;
} }
private static float Vcross2(RcVec3f p1, RcVec3f p2, RcVec3f p3) public static float Vcross2(RcVec3f p1, RcVec3f p2, RcVec3f p3)
{ {
float u1 = p2.X - p1.X; float u1 = p2.X - p1.X;
float v1 = p2.Z - p1.Z; float v1 = p2.Z - p1.Z;
@ -89,7 +82,7 @@ namespace DotRecast.Recast
} }
private static bool CircumCircle(RcVec3f p1, RcVec3f p2, RcVec3f p3, ref RcVec3f c, out float r) public static bool CircumCircle(RcVec3f p1, RcVec3f p2, RcVec3f p3, ref RcVec3f c, out float r)
{ {
const float EPS = 1e-6f; const float EPS = 1e-6f;
// Calculate the circle relative to p1, to avoid some precision issues. // Calculate the circle relative to p1, to avoid some precision issues.
@ -116,7 +109,7 @@ namespace DotRecast.Recast
return false; return false;
} }
private static float DistPtTri(RcVec3f p, RcVec3f a, RcVec3f b, RcVec3f c) public static float DistPtTri(RcVec3f p, RcVec3f a, RcVec3f b, RcVec3f c)
{ {
var v0 = c - a; var v0 = c - a;
var v1 = b - a; var v1 = b - a;
@ -144,7 +137,7 @@ namespace DotRecast.Recast
return float.MaxValue; return float.MaxValue;
} }
private static float DistancePtSeg(float[] verts, int pt, int p, int q) public static float DistancePtSeg(float[] verts, int pt, int p, int q)
{ {
float pqx = verts[q + 0] - verts[p + 0]; float pqx = verts[q + 0] - verts[p + 0];
float pqy = verts[q + 1] - verts[p + 1]; float pqy = verts[q + 1] - verts[p + 1];
@ -175,7 +168,7 @@ namespace DotRecast.Recast
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
private static float DistancePtSeg2d(RcVec3f verts, float[] poly, int p, int q) public static float DistancePtSeg2d(RcVec3f verts, float[] poly, int p, int q)
{ {
float pqx = poly[q + 0] - poly[p + 0]; float pqx = poly[q + 0] - poly[p + 0];
float pqz = poly[q + 2] - poly[p + 2]; float pqz = poly[q + 2] - poly[p + 2];
@ -203,7 +196,7 @@ namespace DotRecast.Recast
return dx * dx + dz * dz; return dx * dx + dz * dz;
} }
private static float DistancePtSeg2d(float[] verts, int pt, float[] poly, int p, int q) public static float DistancePtSeg2d(float[] verts, int pt, float[] poly, int p, int q)
{ {
float pqx = poly[q + 0] - poly[p + 0]; float pqx = poly[q + 0] - poly[p + 0];
float pqz = poly[q + 2] - poly[p + 2]; float pqz = poly[q + 2] - poly[p + 2];
@ -231,7 +224,7 @@ namespace DotRecast.Recast
return dx * dx + dz * dz; return dx * dx + dz * dz;
} }
private static float DistToTriMesh(RcVec3f p, float[] verts, int nverts, List<int> tris, int ntris) public static float DistToTriMesh(RcVec3f p, float[] verts, int nverts, List<int> tris, int ntris)
{ {
float dmin = float.MaxValue; float dmin = float.MaxValue;
for (int i = 0; i < ntris; ++i) for (int i = 0; i < ntris; ++i)
@ -254,7 +247,7 @@ namespace DotRecast.Recast
return dmin; return dmin;
} }
private static float DistToPoly(int nvert, float[] verts, RcVec3f p) public static float DistToPoly(int nvert, float[] verts, RcVec3f p)
{ {
float dmin = float.MaxValue; float dmin = float.MaxValue;
int i, j; int i, j;
@ -275,7 +268,7 @@ namespace DotRecast.Recast
return c ? -dmin : dmin; return c ? -dmin : dmin;
} }
private static int GetHeight(float fx, float fy, float fz, float cs, float ics, float ch, int radius, public static int GetHeight(float fx, float fy, float fz, float cs, float ics, float ch, int radius,
RcHeightPatch hp) RcHeightPatch hp)
{ {
int ix = (int)MathF.Floor(fx * ics + 0.01f); int ix = (int)MathF.Floor(fx * ics + 0.01f);
@ -358,7 +351,7 @@ namespace DotRecast.Recast
return h; return h;
} }
private static int FindEdge(List<int> edges, int s, int t) public static int FindEdge(List<int> edges, int s, int t)
{ {
for (int i = 0; i < edges.Count / 4; i++) for (int i = 0; i < edges.Count / 4; i++)
{ {
@ -372,7 +365,7 @@ namespace DotRecast.Recast
return EV_UNDEF; return EV_UNDEF;
} }
private static void AddEdge(RcContext ctx, List<int> edges, int maxEdges, int s, int t, int l, int r) public static void AddEdge(RcContext ctx, List<int> edges, int maxEdges, int s, int t, int l, int r)
{ {
if (edges.Count / 4 >= maxEdges) if (edges.Count / 4 >= maxEdges)
{ {
@ -390,7 +383,7 @@ namespace DotRecast.Recast
} }
} }
private static void UpdateLeftFace(List<int> edges, int e, int s, int t, int f) public static void UpdateLeftFace(List<int> edges, int e, int s, int t, int f)
{ {
if (edges[e + 0] == s && edges[e + 1] == t && edges[e + 2] == EV_UNDEF) if (edges[e + 0] == s && edges[e + 1] == t && edges[e + 2] == EV_UNDEF)
{ {
@ -402,7 +395,7 @@ namespace DotRecast.Recast
} }
} }
private static bool OverlapSegSeg2d(float[] verts, int a, int b, int c, int d) public static bool OverlapSegSeg2d(float[] verts, int a, int b, int c, int d)
{ {
float a1 = Vcross2(verts, a, b, d); float a1 = Vcross2(verts, a, b, d);
float a2 = Vcross2(verts, a, b, c); float a2 = Vcross2(verts, a, b, c);
@ -419,7 +412,7 @@ namespace DotRecast.Recast
return false; return false;
} }
private static bool OverlapEdges(float[] pts, List<int> edges, int s1, int t1) public static bool OverlapEdges(float[] pts, List<int> edges, int s1, int t1)
{ {
for (int i = 0; i < edges.Count / 4; ++i) for (int i = 0; i < edges.Count / 4; ++i)
{ {
@ -440,7 +433,7 @@ namespace DotRecast.Recast
return false; return false;
} }
static int CompleteFacet(RcContext ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e) public static int CompleteFacet(RcContext ctx, float[] pts, int npts, List<int> edges, int maxEdges, int nfaces, int e)
{ {
const float EPS = 1e-5f; const float EPS = 1e-5f;
@ -561,7 +554,7 @@ namespace DotRecast.Recast
return nfaces; return nfaces;
} }
private static void DelaunayHull(RcContext ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris) public static void DelaunayHull(RcContext ctx, int npts, float[] pts, int nhull, int[] hull, List<int> tris)
{ {
int nfaces = 0; int nfaces = 0;
int maxEdges = npts * 10; int maxEdges = npts * 10;
@ -657,7 +650,7 @@ namespace DotRecast.Recast
} }
// Calculate minimum extend of the polygon. // Calculate minimum extend of the polygon.
private static float PolyMinExtent(float[] verts, int nverts) public static float PolyMinExtent(float[] verts, int nverts)
{ {
float minDist = float.MaxValue; float minDist = float.MaxValue;
for (int i = 0; i < nverts; i++) for (int i = 0; i < nverts; i++)
@ -683,7 +676,7 @@ namespace DotRecast.Recast
return MathF.Sqrt(minDist); return MathF.Sqrt(minDist);
} }
private static void TriangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris) public static void TriangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris)
{ {
int start = 0, left = 1, right = nhull - 1; int start = 0, left = 1, right = nhull - 1;
@ -755,33 +748,37 @@ namespace DotRecast.Recast
} }
} }
private static float GetJitterX(int i) public static float GetJitterX(int i)
{ {
return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f; return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
} }
private static float GetJitterY(int i) public static float GetJitterY(int i)
{ {
return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f; return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
} }
static int BuildPolyDetail(RcContext ctx, float[] @in, int nin, float sampleDist, float sampleMaxError, public static int BuildPolyDetail(RcContext ctx, float[] @in, int nin,
int heightSearchRadius, RcCompactHeightfield chf, RcHeightPatch hp, float[] verts, List<int> tris) float sampleDist, float sampleMaxError,
int heightSearchRadius, RcCompactHeightfield chf,
RcHeightPatch hp, float[] verts,
ref List<int> tris, ref List<int> edges, ref List<int> samples)
{ {
List<int> samples = new List<int>(512); const int MAX_VERTS = 127;
const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
int nverts = 0; const int MAX_VERTS_PER_EDGE = 32;
float[] edge = new float[(MAX_VERTS_PER_EDGE + 1) * 3]; float[] edge = new float[(MAX_VERTS_PER_EDGE + 1) * 3];
int[] hull = new int[MAX_VERTS]; int[] hull = new int[MAX_VERTS];
int nhull = 0; int nhull = 0;
nverts = nin; int nverts = nin;
for (int i = 0; i < nin; ++i) for (int i = 0; i < nin; ++i)
{ {
RcVecUtils.Copy(verts, i * 3, @in, i * 3); RcVecUtils.Copy(verts, i * 3, @in, i * 3);
} }
edges.Clear();
tris.Clear(); tris.Clear();
float cs = chf.cs; float cs = chf.cs;
@ -1042,7 +1039,7 @@ namespace DotRecast.Recast
return nverts; return nverts;
} }
static bool OnHull(int a, int b, int nhull, int[] hull) public 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. // All internal sampled points come after the hull so we can early out for those.
if (a >= nhull || b >= nhull) if (a >= nhull || b >= nhull)
@ -1058,7 +1055,7 @@ namespace DotRecast.Recast
} }
// Find edges that lie on hull and mark them as such. // Find edges that lie on hull and mark them as such.
static void SetTriFlags(List<int> tris, int nhull, int[] hull) public static void SetTriFlags(List<int> tris, int nhull, int[] hull)
{ {
// Matches DT_DETAIL_EDGE_BOUNDARY // Matches DT_DETAIL_EDGE_BOUNDARY
const int DETAIL_EDGE_BOUNDARY = 0x1; const int DETAIL_EDGE_BOUNDARY = 0x1;
@ -1077,7 +1074,7 @@ namespace DotRecast.Recast
} }
static void SeedArrayWithPolyCenter(RcContext ctx, RcCompactHeightfield chf, int[] meshpoly, int poly, int npoly, public static void SeedArrayWithPolyCenter(RcContext ctx, RcCompactHeightfield chf, int[] meshpoly, int poly, int npoly,
int[] verts, int bs, RcHeightPatch hp, List<int> array) int[] verts, int bs, RcHeightPatch hp, List<int> array)
{ {
// Note: Reads to the compact heightfield are offset by border size (bs) // Note: Reads to the compact heightfield are offset by border size (bs)
@ -1226,22 +1223,25 @@ namespace DotRecast.Recast
hp.data[cx - hp.xmin + (cy - hp.ymin) * hp.width] = cs2.y; hp.data[cx - hp.xmin + (cy - hp.ymin) * hp.width] = cs2.y;
} }
const int RETRACT_SIZE = 256;
static void Push3(List<int> queue, int v1, int v2, int v3) public static void Push3(List<int> queue, int v1, int v2, int v3)
{ {
queue.Add(v1); queue.Add(v1);
queue.Add(v2); queue.Add(v2);
queue.Add(v3); queue.Add(v3);
} }
static void GetHeightData(RcContext ctx, RcCompactHeightfield chf, int[] meshpolys, int poly, int npoly, int[] verts, public static void GetHeightData(RcContext ctx, RcCompactHeightfield chf,
int bs, RcHeightPatch hp, int region) int[] meshpolys, int poly, int npoly,
int[] verts, int bs,
ref RcHeightPatch hp, ref List<int> queue,
int region)
{ {
// Note: Reads to the compact heightfield are offset by border size (bs) // Note: Reads to the compact heightfield are offset by border size (bs)
// since border size offset is already removed from the polymesh vertices. // since border size offset is already removed from the polymesh vertices.
List<int> queue = new List<int>(512); queue.Clear();
// Set all heights to RC_UNSET_HEIGHT.
Array.Fill(hp.data, RC_UNSET_HEIGHT, 0, (hp.width * hp.height) - (0)); Array.Fill(hp.data, RC_UNSET_HEIGHT, 0, (hp.width * hp.height) - (0));
bool empty = true; bool empty = true;
@ -1307,6 +1307,7 @@ namespace DotRecast.Recast
SeedArrayWithPolyCenter(ctx, chf, meshpolys, poly, npoly, verts, bs, hp, queue); SeedArrayWithPolyCenter(ctx, chf, meshpolys, poly, npoly, verts, bs, hp, queue);
} }
const int RETRACT_SIZE = 256;
int head = 0; int head = 0;
// We assume the seed is centered in the polygon, so a BFS to collect // We assume the seed is centered in the polygon, so a BFS to collect
@ -1378,7 +1379,10 @@ namespace DotRecast.Recast
int borderSize = mesh.borderSize; int borderSize = mesh.borderSize;
int heightSearchRadius = (int)Math.Max(1, MathF.Ceiling(mesh.maxEdgeError)); int heightSearchRadius = (int)Math.Max(1, MathF.Ceiling(mesh.maxEdgeError));
List<int> edges = new List<int>(64);
List<int> tris = new List<int>(512); List<int> tris = new List<int>(512);
List<int> arr = new List<int>(512);
List<int> samples = new List<int>(512);
float[] verts = new float[256 * 3]; float[] verts = new float[256 * 3];
RcHeightPatch hp = new RcHeightPatch(); RcHeightPatch hp = new RcHeightPatch();
int nPolyVerts = 0; int nPolyVerts = 0;
@ -1463,18 +1467,20 @@ namespace DotRecast.Recast
hp.ymin = bounds[i * 4 + 2]; hp.ymin = bounds[i * 4 + 2];
hp.width = bounds[i * 4 + 1] - bounds[i * 4 + 0]; hp.width = bounds[i * 4 + 1] - bounds[i * 4 + 0];
hp.height = bounds[i * 4 + 3] - bounds[i * 4 + 2]; hp.height = bounds[i * 4 + 3] - bounds[i * 4 + 2];
GetHeightData(ctx, chf, mesh.polys, p, npoly, mesh.verts, borderSize, hp, mesh.regs[i]); GetHeightData(ctx, chf, mesh.polys, p, npoly, mesh.verts, borderSize, ref hp, ref arr, mesh.regs[i]);
// Build detail mesh. // Build detail mesh.
int nverts = BuildPolyDetail(ctx, poly, npoly, sampleDist, sampleMaxError, heightSearchRadius, chf, hp, int nverts = BuildPolyDetail(ctx, poly, npoly,
verts, tris); sampleDist, sampleMaxError,
heightSearchRadius, chf, hp,
verts, ref tris,
ref edges, ref samples);
// Move detail verts to world space. // Move detail verts to world space.
for (int j = 0; j < nverts; ++j) for (int j = 0; j < nverts; ++j)
{ {
verts[j * 3 + 0] += orig.X; verts[j * 3 + 0] += orig.X;
verts[j * 3 + 1] += orig.Y + chf.ch; // Is this offset necessary? See verts[j * 3 + 1] += orig.Y + chf.ch; // Is this offset necessary? See
// https://groups.google.com/d/msg/recastnavigation/UQFN6BGCcV0/-1Ny4koOBpkJ
verts[j * 3 + 2] += orig.Z; verts[j * 3 + 2] += orig.Z;
} }
@ -1551,7 +1557,7 @@ namespace DotRecast.Recast
} }
/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail /// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
private static RcPolyMeshDetail MergePolyMeshDetails(RcContext ctx, RcPolyMeshDetail[] meshes, int nmeshes) public static RcPolyMeshDetail MergePolyMeshDetails(RcContext ctx, RcPolyMeshDetail[] meshes, int nmeshes)
{ {
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESHDETAIL); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_MERGE_POLYMESHDETAIL);