forked from mirror/DotRecast
Changed DtNavMeshQuery.GetPolyWallSegments() to use Span<T> for enhanced performance, memory efficiency.
This commit is contained in:
parent
84419b1d52
commit
cf7aec90ee
|
@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Changed data structure of 'neis' from List<byte> to byte[] for optimized memory usage and improved access speed in `DtLayerMonotoneRegion`
|
- Changed data structure of 'neis' from List<byte> to byte[] for optimized memory usage and improved access speed in `DtLayerMonotoneRegion`
|
||||||
- Changed new RcVec3f[3] to stackalloc RcVec3f[3] in DtNavMesh.GetPolyHeight() to reduce heap allocation
|
- Changed new RcVec3f[3] to stackalloc RcVec3f[3] in DtNavMesh.GetPolyHeight() to reduce heap allocation
|
||||||
- Changed memory handling to use stackalloc in DtNavMeshQuery.GetPolyWallSegments for reducing SOH
|
- Changed memory handling to use stackalloc in DtNavMeshQuery.GetPolyWallSegments for reducing SOH
|
||||||
|
- Changed DtNavMeshQuery.GetPolyWallSegments() to use Span<T> for enhanced performance, memory efficiency.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Nothing
|
- Nothing
|
||||||
|
|
|
@ -18,6 +18,7 @@ freely, subject to the following restrictions:
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using DotRecast.Core.Numerics;
|
using DotRecast.Core.Numerics;
|
||||||
|
@ -90,6 +91,8 @@ namespace DotRecast.Detour.Crowd
|
||||||
|
|
||||||
public void Update(long startRef, RcVec3f pos, float collisionQueryRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
public void Update(long startRef, RcVec3f pos, float collisionQueryRange, DtNavMeshQuery navquery, IDtQueryFilter filter)
|
||||||
{
|
{
|
||||||
|
const int MAX_SEGS_PER_POLY = DtDetour.DT_VERTS_PER_POLYGON * 3;
|
||||||
|
|
||||||
if (startRef == 0)
|
if (startRef == 0)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -104,18 +107,17 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
// Secondly, store all polygon edges.
|
// Secondly, store all polygon edges.
|
||||||
m_segs.Clear();
|
m_segs.Clear();
|
||||||
|
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS_PER_POLY];
|
||||||
var segmentVerts = new List<RcSegmentVert>();
|
int nsegs = 0;
|
||||||
var segmentRefs = new List<long>();
|
|
||||||
|
|
||||||
for (int j = 0; j < m_polys.Count; ++j)
|
for (int j = 0; j < m_polys.Count; ++j)
|
||||||
{
|
{
|
||||||
var result = navquery.GetPolyWallSegments(m_polys[j], false, filter, ref segmentVerts, ref segmentRefs);
|
var result = navquery.GetPolyWallSegments(m_polys[j], filter, segs, null, ref nsegs, MAX_SEGS_PER_POLY);
|
||||||
if (result.Succeeded())
|
if (result.Succeeded())
|
||||||
{
|
{
|
||||||
for (int k = 0; k < segmentRefs.Count; ++k)
|
for (int k = 0; k < nsegs; ++k)
|
||||||
{
|
{
|
||||||
RcSegmentVert s = segmentVerts[k];
|
ref RcSegmentVert s = ref segs[k];
|
||||||
var s0 = s.vmin;
|
var s0 = s.vmin;
|
||||||
var s3 = s.vmax;
|
var s3 = s.vmax;
|
||||||
|
|
||||||
|
|
|
@ -3138,11 +3138,11 @@ namespace DotRecast.Detour
|
||||||
/// @param[out] segmentCount The number of segments returned.
|
/// @param[out] segmentCount The number of segments returned.
|
||||||
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
||||||
/// @returns The status flags for the query.
|
/// @returns The status flags for the query.
|
||||||
public DtStatus GetPolyWallSegments(long refs, bool storePortals, IDtQueryFilter filter,
|
public DtStatus GetPolyWallSegments(long refs, IDtQueryFilter filter,
|
||||||
ref List<RcSegmentVert> segmentVerts, ref List<long> segmentRefs)
|
Span<RcSegmentVert> segmentVerts, Span<long> segmentRefs, ref int segmentCount,
|
||||||
|
int maxSegments)
|
||||||
{
|
{
|
||||||
segmentVerts.Clear();
|
segmentCount = 0;
|
||||||
segmentRefs.Clear();
|
|
||||||
|
|
||||||
DtStatus status = m_nav.GetTileAndPolyByRef(refs, out var tile, out var poly);
|
DtStatus status = m_nav.GetTileAndPolyByRef(refs, out var tile, out var poly);
|
||||||
if (status.Failed())
|
if (status.Failed())
|
||||||
|
@ -3160,6 +3160,8 @@ namespace DotRecast.Detour
|
||||||
Span<DtSegInterval> ints = stackalloc DtSegInterval[MAX_INTERVAL];
|
Span<DtSegInterval> ints = stackalloc DtSegInterval[MAX_INTERVAL];
|
||||||
int nints;
|
int nints;
|
||||||
|
|
||||||
|
bool storePortals = segmentRefs != null;
|
||||||
|
|
||||||
status = DtStatus.DT_SUCCESS;
|
status = DtStatus.DT_SUCCESS;
|
||||||
|
|
||||||
for (int i = 0, j = poly.vertCount - 1; i < poly.vertCount; j = i++)
|
for (int i = 0, j = poly.vertCount - 1; i < poly.vertCount; j = i++)
|
||||||
|
@ -3205,16 +3207,26 @@ namespace DotRecast.Detour
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n < maxSegments)
|
||||||
|
{
|
||||||
int ivj = poly.verts[j] * 3;
|
int ivj = poly.verts[j] * 3;
|
||||||
int ivi = poly.verts[i] * 3;
|
int ivi = poly.verts[i] * 3;
|
||||||
var seg = new RcSegmentVert();
|
var seg = new RcSegmentVert();
|
||||||
seg.vmin = RcVec.Create(tile.data.verts, ivj);
|
seg.vmin = RcVec.Create(tile.data.verts, ivj);
|
||||||
seg.vmax = RcVec.Create(tile.data.verts, ivi);
|
seg.vmax = RcVec.Create(tile.data.verts, ivi);
|
||||||
// RcArrays.Copy(tile.data.verts, ivj, seg, 0, 3);
|
segmentVerts[n] = seg;
|
||||||
// RcArrays.Copy(tile.data.verts, ivi, seg, 3, 3);
|
if (null != segmentRefs)
|
||||||
segmentVerts.Add(seg);
|
{
|
||||||
segmentRefs.Add(neiRef);
|
segmentRefs[n] = neiRef;
|
||||||
|
}
|
||||||
|
|
||||||
n++;
|
n++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status |= DtStatus.DT_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3232,13 +3244,26 @@ namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
float tmin = ints[k].tmin / 255.0f;
|
float tmin = ints[k].tmin / 255.0f;
|
||||||
float tmax = ints[k].tmax / 255.0f;
|
float tmax = ints[k].tmax / 255.0f;
|
||||||
|
|
||||||
|
if (n < maxSegments)
|
||||||
|
{
|
||||||
var seg = new RcSegmentVert();
|
var seg = new RcSegmentVert();
|
||||||
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
||||||
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
||||||
segmentVerts.Add(seg);
|
segmentVerts[n] = seg;
|
||||||
segmentRefs.Add(ints[k].refs);
|
|
||||||
|
if (null != segmentRefs)
|
||||||
|
{
|
||||||
|
segmentRefs[n] = ints[k].refs;
|
||||||
|
}
|
||||||
|
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status |= DtStatus.DT_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wall segment.
|
// Wall segment.
|
||||||
int imin = ints[k - 1].tmax;
|
int imin = ints[k - 1].tmax;
|
||||||
|
@ -3247,15 +3272,30 @@ namespace DotRecast.Detour
|
||||||
{
|
{
|
||||||
float tmin = imin / 255.0f;
|
float tmin = imin / 255.0f;
|
||||||
float tmax = imax / 255.0f;
|
float tmax = imax / 255.0f;
|
||||||
|
|
||||||
|
if (n < maxSegments)
|
||||||
|
{
|
||||||
var seg = new RcSegmentVert();
|
var seg = new RcSegmentVert();
|
||||||
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
||||||
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
||||||
segmentVerts.Add(seg);
|
segmentVerts[n] = seg;
|
||||||
segmentRefs.Add(0L);
|
|
||||||
|
if (null != segmentRefs)
|
||||||
|
{
|
||||||
|
segmentRefs[n] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status |= DtStatus.DT_BUFFER_TOO_SMALL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
segmentCount = n;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -472,8 +472,9 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
{
|
{
|
||||||
if (m_polys != null)
|
if (m_polys != null)
|
||||||
{
|
{
|
||||||
var segmentVerts = new List<RcSegmentVert>();
|
const int MAX_SEGS = DtDetour.DT_VERTS_PER_POLYGON * 4;
|
||||||
var segmentRefs = new List<long>();
|
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS];
|
||||||
|
Span<long> refs = stackalloc long[MAX_SEGS];
|
||||||
|
|
||||||
for (int i = 0; i < m_polys.Count; i++)
|
for (int i = 0; i < m_polys.Count; i++)
|
||||||
{
|
{
|
||||||
|
@ -491,18 +492,20 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
dd.DepthMask(true);
|
dd.DepthMask(true);
|
||||||
if (_sample.GetNavMeshQuery() != null)
|
if (_sample.GetNavMeshQuery() != null)
|
||||||
{
|
{
|
||||||
|
int nsegs = 0;
|
||||||
var result = _sample
|
var result = _sample
|
||||||
.GetNavMeshQuery()
|
.GetNavMeshQuery()
|
||||||
.GetPolyWallSegments(m_polys[i], false, m_filter, ref segmentVerts, ref segmentRefs);
|
.GetPolyWallSegments(m_polys[i], m_filter, segs, refs, ref nsegs, MAX_SEGS);
|
||||||
|
|
||||||
if (result.Succeeded())
|
if (result.Succeeded())
|
||||||
{
|
{
|
||||||
dd.Begin(LINES, 2.0f);
|
dd.Begin(LINES, 2.0f);
|
||||||
for (int j = 0; j < segmentVerts.Count; ++j)
|
for (int j = 0; j < nsegs; ++j)
|
||||||
{
|
{
|
||||||
RcSegmentVert s = segmentVerts[j];
|
ref RcSegmentVert s = ref segs[j];
|
||||||
var v0 = s.vmin;
|
var v0 = s.vmin;
|
||||||
var s3 = s.vmax;
|
var s3 = s.vmax;
|
||||||
|
|
||||||
// Skip too distant segments.
|
// Skip too distant segments.
|
||||||
var distSqr = DtUtils.DistancePtSegSqr2D(m_spos, v0, s3, out var tseg);
|
var distSqr = DtUtils.DistancePtSegSqr2D(m_spos, v0, s3, out var tseg);
|
||||||
if (distSqr > RcMath.Sqr(m_neighbourhoodRadius))
|
if (distSqr > RcMath.Sqr(m_neighbourhoodRadius))
|
||||||
|
@ -515,8 +518,9 @@ public class TestNavmeshSampleTool : ISampleTool
|
||||||
RcVec3f norm = new RcVec3f(delta.Z, 0, -delta.X);
|
RcVec3f norm = new RcVec3f(delta.Z, 0, -delta.X);
|
||||||
norm = RcVec3f.Normalize(norm);
|
norm = RcVec3f.Normalize(norm);
|
||||||
RcVec3f p1 = RcVec.Mad(p0, norm, agentRadius * 0.5f);
|
RcVec3f p1 = RcVec.Mad(p0, norm, agentRadius * 0.5f);
|
||||||
|
|
||||||
// Skip backfacing segments.
|
// Skip backfacing segments.
|
||||||
if (segmentRefs[j] != 0)
|
if (refs[j] != 0)
|
||||||
{
|
{
|
||||||
int col = DuRGBA(255, 255, 255, 32);
|
int col = DuRGBA(255, 255, 255, 32);
|
||||||
dd.Vertex(s.vmin.X, s.vmin.Y + agentClimb, s.vmin.Z, col);
|
dd.Vertex(s.vmin.X, s.vmin.Y + agentClimb, s.vmin.Z, col);
|
||||||
|
|
|
@ -17,13 +17,13 @@ freely, subject to the following restrictions:
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using DotRecast.Core;
|
using DotRecast.Core;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace DotRecast.Detour.Test;
|
namespace DotRecast.Detour.Test;
|
||||||
|
|
||||||
|
|
||||||
public class GetPolyWallSegmentsTest : AbstractDetourTest
|
public class GetPolyWallSegmentsTest : AbstractDetourTest
|
||||||
{
|
{
|
||||||
private static readonly RcSegmentVert[][] VERTICES =
|
private static readonly RcSegmentVert[][] VERTICES =
|
||||||
|
@ -83,28 +83,30 @@ public class GetPolyWallSegmentsTest : AbstractDetourTest
|
||||||
[Test]
|
[Test]
|
||||||
public void TestFindDistanceToWall()
|
public void TestFindDistanceToWall()
|
||||||
{
|
{
|
||||||
var segmentVerts = new List<RcSegmentVert>();
|
const int MAX_SEGS = DtDetour.DT_VERTS_PER_POLYGON * 4;
|
||||||
var segmentRefs = new List<long>();
|
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS];
|
||||||
|
Span<long> refs = stackalloc long[MAX_SEGS];
|
||||||
|
int nsegs = 0;
|
||||||
|
|
||||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||||
for (int i = 0; i < startRefs.Length; i++)
|
for (int i = 0; i < startRefs.Length; i++)
|
||||||
{
|
{
|
||||||
var result = query.GetPolyWallSegments(startRefs[i], true, filter, ref segmentVerts, ref segmentRefs);
|
var result = query.GetPolyWallSegments(startRefs[i], filter, segs, refs, ref nsegs, MAX_SEGS);
|
||||||
Assert.That(segmentVerts.Count, Is.EqualTo(VERTICES[i].Length));
|
Assert.That(nsegs, Is.EqualTo(VERTICES[i].Length));
|
||||||
Assert.That(segmentRefs.Count, Is.EqualTo(REFS[i].Length));
|
Assert.That(nsegs, Is.EqualTo(REFS[i].Length));
|
||||||
for (int v = 0; v < VERTICES[i].Length / 6; v++)
|
for (int v = 0; v < VERTICES[i].Length / 6; v++)
|
||||||
{
|
{
|
||||||
Assert.That(segmentVerts[v].vmin.X, Is.EqualTo(VERTICES[i][v].vmin.X).Within(0.001f));
|
Assert.That(segs[v].vmin.X, Is.EqualTo(VERTICES[i][v].vmin.X).Within(0.001f));
|
||||||
Assert.That(segmentVerts[v].vmin.Y, Is.EqualTo(VERTICES[i][v].vmin.Y).Within(0.001f));
|
Assert.That(segs[v].vmin.Y, Is.EqualTo(VERTICES[i][v].vmin.Y).Within(0.001f));
|
||||||
Assert.That(segmentVerts[v].vmin.Z, Is.EqualTo(VERTICES[i][v].vmin.Z).Within(0.001f));
|
Assert.That(segs[v].vmin.Z, Is.EqualTo(VERTICES[i][v].vmin.Z).Within(0.001f));
|
||||||
Assert.That(segmentVerts[v].vmax.X, Is.EqualTo(VERTICES[i][v].vmax.X).Within(0.001f));
|
Assert.That(segs[v].vmax.X, Is.EqualTo(VERTICES[i][v].vmax.X).Within(0.001f));
|
||||||
Assert.That(segmentVerts[v].vmax.Y, Is.EqualTo(VERTICES[i][v].vmax.Y).Within(0.001f));
|
Assert.That(segs[v].vmax.Y, Is.EqualTo(VERTICES[i][v].vmax.Y).Within(0.001f));
|
||||||
Assert.That(segmentVerts[v].vmax.Z, Is.EqualTo(VERTICES[i][v].vmax.Z).Within(0.001f));
|
Assert.That(segs[v].vmax.Z, Is.EqualTo(VERTICES[i][v].vmax.Z).Within(0.001f));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int v = 0; v < REFS[i].Length; v++)
|
for (int v = 0; v < REFS[i].Length; v++)
|
||||||
{
|
{
|
||||||
Assert.That(segmentRefs[v], Is.EqualTo(REFS[i][v]));
|
Assert.That(refs[v], Is.EqualTo(REFS[i][v]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue