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 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 DtNavMeshQuery.GetPolyWallSegments() to use Span<T> for enhanced performance, memory efficiency.
|
||||
|
||||
### Removed
|
||||
- Nothing
|
||||
|
|
|
@ -18,6 +18,7 @@ freely, subject to the following restrictions:
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
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)
|
||||
{
|
||||
const int MAX_SEGS_PER_POLY = DtDetour.DT_VERTS_PER_POLYGON * 3;
|
||||
|
||||
if (startRef == 0)
|
||||
{
|
||||
Reset();
|
||||
|
@ -104,18 +107,17 @@ namespace DotRecast.Detour.Crowd
|
|||
{
|
||||
// Secondly, store all polygon edges.
|
||||
m_segs.Clear();
|
||||
|
||||
var segmentVerts = new List<RcSegmentVert>();
|
||||
var segmentRefs = new List<long>();
|
||||
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS_PER_POLY];
|
||||
int nsegs = 0;
|
||||
|
||||
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())
|
||||
{
|
||||
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 s3 = s.vmax;
|
||||
|
||||
|
|
|
@ -3138,11 +3138,11 @@ namespace DotRecast.Detour
|
|||
/// @param[out] segmentCount The number of segments returned.
|
||||
/// @param[in] maxSegments The maximum number of segments the result arrays can hold.
|
||||
/// @returns The status flags for the query.
|
||||
public DtStatus GetPolyWallSegments(long refs, bool storePortals, IDtQueryFilter filter,
|
||||
ref List<RcSegmentVert> segmentVerts, ref List<long> segmentRefs)
|
||||
public DtStatus GetPolyWallSegments(long refs, IDtQueryFilter filter,
|
||||
Span<RcSegmentVert> segmentVerts, Span<long> segmentRefs, ref int segmentCount,
|
||||
int maxSegments)
|
||||
{
|
||||
segmentVerts.Clear();
|
||||
segmentRefs.Clear();
|
||||
segmentCount = 0;
|
||||
|
||||
DtStatus status = m_nav.GetTileAndPolyByRef(refs, out var tile, out var poly);
|
||||
if (status.Failed())
|
||||
|
@ -3160,6 +3160,8 @@ namespace DotRecast.Detour
|
|||
Span<DtSegInterval> ints = stackalloc DtSegInterval[MAX_INTERVAL];
|
||||
int nints;
|
||||
|
||||
bool storePortals = segmentRefs != null;
|
||||
|
||||
status = DtStatus.DT_SUCCESS;
|
||||
|
||||
for (int i = 0, j = poly.vertCount - 1; i < poly.vertCount; j = i++)
|
||||
|
@ -3205,16 +3207,26 @@ namespace DotRecast.Detour
|
|||
continue;
|
||||
}
|
||||
|
||||
int ivj = poly.verts[j] * 3;
|
||||
int ivi = poly.verts[i] * 3;
|
||||
var seg = new RcSegmentVert();
|
||||
seg.vmin = RcVec.Create(tile.data.verts, ivj);
|
||||
seg.vmax = RcVec.Create(tile.data.verts, ivi);
|
||||
// RcArrays.Copy(tile.data.verts, ivj, seg, 0, 3);
|
||||
// RcArrays.Copy(tile.data.verts, ivi, seg, 3, 3);
|
||||
segmentVerts.Add(seg);
|
||||
segmentRefs.Add(neiRef);
|
||||
n++;
|
||||
if (n < maxSegments)
|
||||
{
|
||||
int ivj = poly.verts[j] * 3;
|
||||
int ivi = poly.verts[i] * 3;
|
||||
var seg = new RcSegmentVert();
|
||||
seg.vmin = RcVec.Create(tile.data.verts, ivj);
|
||||
seg.vmax = RcVec.Create(tile.data.verts, ivi);
|
||||
segmentVerts[n] = seg;
|
||||
if (null != segmentRefs)
|
||||
{
|
||||
segmentRefs[n] = neiRef;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DtStatus.DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3232,12 +3244,25 @@ namespace DotRecast.Detour
|
|||
{
|
||||
float tmin = ints[k].tmin / 255.0f;
|
||||
float tmax = ints[k].tmax / 255.0f;
|
||||
var seg = new RcSegmentVert();
|
||||
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
||||
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
||||
segmentVerts.Add(seg);
|
||||
segmentRefs.Add(ints[k].refs);
|
||||
n++;
|
||||
|
||||
if (n < maxSegments)
|
||||
{
|
||||
var seg = new RcSegmentVert();
|
||||
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
||||
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
||||
segmentVerts[n] = seg;
|
||||
|
||||
if (null != segmentRefs)
|
||||
{
|
||||
segmentRefs[n] = ints[k].refs;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DtStatus.DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
|
||||
// Wall segment.
|
||||
|
@ -3247,16 +3272,31 @@ namespace DotRecast.Detour
|
|||
{
|
||||
float tmin = imin / 255.0f;
|
||||
float tmax = imax / 255.0f;
|
||||
var seg = new RcSegmentVert();
|
||||
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
||||
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
||||
segmentVerts.Add(seg);
|
||||
segmentRefs.Add(0L);
|
||||
n++;
|
||||
|
||||
if (n < maxSegments)
|
||||
{
|
||||
var seg = new RcSegmentVert();
|
||||
seg.vmin = RcVec.Lerp(tile.data.verts, vj, vi, tmin);
|
||||
seg.vmax = RcVec.Lerp(tile.data.verts, vj, vi, tmax);
|
||||
segmentVerts[n] = seg;
|
||||
|
||||
if (null != segmentRefs)
|
||||
{
|
||||
segmentRefs[n] = 0;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DtStatus.DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
segmentCount = n;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -472,8 +472,9 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
{
|
||||
if (m_polys != null)
|
||||
{
|
||||
var segmentVerts = new List<RcSegmentVert>();
|
||||
var segmentRefs = new List<long>();
|
||||
const int MAX_SEGS = DtDetour.DT_VERTS_PER_POLYGON * 4;
|
||||
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS];
|
||||
Span<long> refs = stackalloc long[MAX_SEGS];
|
||||
|
||||
for (int i = 0; i < m_polys.Count; i++)
|
||||
{
|
||||
|
@ -491,18 +492,20 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
dd.DepthMask(true);
|
||||
if (_sample.GetNavMeshQuery() != null)
|
||||
{
|
||||
int nsegs = 0;
|
||||
var result = _sample
|
||||
.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())
|
||||
{
|
||||
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 s3 = s.vmax;
|
||||
|
||||
// Skip too distant segments.
|
||||
var distSqr = DtUtils.DistancePtSegSqr2D(m_spos, v0, s3, out var tseg);
|
||||
if (distSqr > RcMath.Sqr(m_neighbourhoodRadius))
|
||||
|
@ -515,8 +518,9 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
RcVec3f norm = new RcVec3f(delta.Z, 0, -delta.X);
|
||||
norm = RcVec3f.Normalize(norm);
|
||||
RcVec3f p1 = RcVec.Mad(p0, norm, agentRadius * 0.5f);
|
||||
|
||||
// Skip backfacing segments.
|
||||
if (segmentRefs[j] != 0)
|
||||
if (refs[j] != 0)
|
||||
{
|
||||
int col = DuRGBA(255, 255, 255, 32);
|
||||
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.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DotRecast.Core;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace DotRecast.Detour.Test;
|
||||
|
||||
|
||||
public class GetPolyWallSegmentsTest : AbstractDetourTest
|
||||
{
|
||||
private static readonly RcSegmentVert[][] VERTICES =
|
||||
|
@ -83,28 +83,30 @@ public class GetPolyWallSegmentsTest : AbstractDetourTest
|
|||
[Test]
|
||||
public void TestFindDistanceToWall()
|
||||
{
|
||||
var segmentVerts = new List<RcSegmentVert>();
|
||||
var segmentRefs = new List<long>();
|
||||
const int MAX_SEGS = DtDetour.DT_VERTS_PER_POLYGON * 4;
|
||||
Span<RcSegmentVert> segs = stackalloc RcSegmentVert[MAX_SEGS];
|
||||
Span<long> refs = stackalloc long[MAX_SEGS];
|
||||
int nsegs = 0;
|
||||
|
||||
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
||||
for (int i = 0; i < startRefs.Length; i++)
|
||||
{
|
||||
var result = query.GetPolyWallSegments(startRefs[i], true, filter, ref segmentVerts, ref segmentRefs);
|
||||
Assert.That(segmentVerts.Count, Is.EqualTo(VERTICES[i].Length));
|
||||
Assert.That(segmentRefs.Count, Is.EqualTo(REFS[i].Length));
|
||||
var result = query.GetPolyWallSegments(startRefs[i], filter, segs, refs, ref nsegs, MAX_SEGS);
|
||||
Assert.That(nsegs, Is.EqualTo(VERTICES[i].Length));
|
||||
Assert.That(nsegs, Is.EqualTo(REFS[i].Length));
|
||||
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(segmentVerts[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(segmentVerts[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(segmentVerts[v].vmax.Z, Is.EqualTo(VERTICES[i][v].vmax.Z).Within(0.001f));
|
||||
Assert.That(segs[v].vmin.X, Is.EqualTo(VERTICES[i][v].vmin.X).Within(0.001f));
|
||||
Assert.That(segs[v].vmin.Y, Is.EqualTo(VERTICES[i][v].vmin.Y).Within(0.001f));
|
||||
Assert.That(segs[v].vmin.Z, Is.EqualTo(VERTICES[i][v].vmin.Z).Within(0.001f));
|
||||
Assert.That(segs[v].vmax.X, Is.EqualTo(VERTICES[i][v].vmax.X).Within(0.001f));
|
||||
Assert.That(segs[v].vmax.Y, Is.EqualTo(VERTICES[i][v].vmax.Y).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++)
|
||||
{
|
||||
Assert.That(segmentRefs[v], Is.EqualTo(REFS[i][v]));
|
||||
Assert.That(refs[v], Is.EqualTo(REFS[i][v]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue