Changed to limit neighbor search to a maximum count and use array for memory efficiency in `DtCrowd.AddNeighbour()`

This commit is contained in:
ikpil 2024-07-07 14:58:38 +09:00
parent 76e5ade4d1
commit 9ebaa3fc65
4 changed files with 63 additions and 17 deletions

View File

@ -24,6 +24,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Changed `new float[]` to `stackalloc float[]` in `DtConvexConvexIntersections.Intersect()` - Changed `new float[]` to `stackalloc float[]` in `DtConvexConvexIntersections.Intersect()`
- Changed agents management from list to dictionary in `DtCrowd` - Changed agents management from list to dictionary in `DtCrowd`
- Changed to efficiently stack nearby DtCrowdAgents in `DtCrowd.GetNeighbours()` - Changed to efficiently stack nearby DtCrowdAgents in `DtCrowd.GetNeighbours()`
- Changed to limit neighbor search to a maximum count and use array for memory efficiency in `DtCrowd.AddNeighbour()`
### Removed ### Removed
- Removed RcMeshDetails.VdistSq2(float[], float[]) - Removed RcMeshDetails.VdistSq2(float[], float[])

View File

@ -20,7 +20,7 @@ freely, subject to the following restrictions:
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Diagnostics;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Core.Collections; using DotRecast.Core.Collections;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;
@ -258,6 +258,7 @@ namespace DotRecast.Detour.Crowd
ag.topologyOptTime = 0; ag.topologyOptTime = 0;
ag.targetReplanTime = 0; ag.targetReplanTime = 0;
ag.nneis = 0;
ag.dvel = RcVec3f.Zero; ag.dvel = RcVec3f.Zero;
ag.nvel = RcVec3f.Zero; ag.nvel = RcVec3f.Zero;
@ -897,14 +898,56 @@ namespace DotRecast.Detour.Crowd
} }
// Query neighbour agents // Query neighbour agents
GetNeighbours(ag.npos, ag.option.height, ag.option.collisionQueryRange, ag, ref ag.neis, _grid); ag.nneis = GetNeighbours(ag.npos, ag.option.height, ag.option.collisionQueryRange, ag, ag.neis, DtCrowdConst.DT_CROWDAGENT_MAX_NEIGHBOURS, _grid);
} }
} }
public static int AddNeighbour(DtCrowdAgent idx, float dist, Span<DtCrowdNeighbour> neis, int nneis, int maxNeis)
private int GetNeighbours(RcVec3f pos, float height, float range, DtCrowdAgent skip, ref List<DtCrowdNeighbour> result, DtProximityGrid grid)
{ {
result.Clear(); // Insert neighbour based on the distance.
int nei = 0;
if (0 == nneis)
{
nei = nneis;
}
else if (dist >= neis[nneis - 1].dist)
{
if (nneis >= maxNeis)
return nneis;
nei = nneis;
}
else
{
int i;
for (i = 0; i < nneis; ++i)
{
if (dist <= neis[i].dist)
{
break;
}
}
int tgt = i + 1;
int n = Math.Min(nneis - i, maxNeis - tgt);
Debug.Assert(tgt + n <= maxNeis);
if (n > 0)
{
RcSpans.Move(neis, i, tgt, n);
}
nei = i;
}
neis[nei] = new DtCrowdNeighbour(idx, dist);
return Math.Min(nneis + 1, maxNeis);
}
private int GetNeighbours(RcVec3f pos, float height, float range, DtCrowdAgent skip, DtCrowdNeighbour[] result, int maxResult, DtProximityGrid grid)
{
int n = 0;
const int MAX_NEIS = 32; const int MAX_NEIS = 32;
Span<int> ids = stackalloc int[MAX_NEIS]; Span<int> ids = stackalloc int[MAX_NEIS];
@ -934,11 +977,10 @@ namespace DotRecast.Detour.Crowd
continue; continue;
} }
result.Add(new DtCrowdNeighbour(ag, distSqr)); n = AddNeighbour(ag, distSqr, result, n, maxResult);
} }
result.Sort((o1, o2) => o1.dist.CompareTo(o2.dist)); return n;
return result.Count;
} }
private void FindCorners(IList<DtCrowdAgent> agents, DtCrowdAgentDebugInfo debug) private void FindCorners(IList<DtCrowdAgent> agents, DtCrowdAgentDebugInfo debug)
@ -1028,7 +1070,7 @@ namespace DotRecast.Detour.Crowd
ag.state = DtCrowdAgentState.DT_CROWDAGENT_STATE_OFFMESH; ag.state = DtCrowdAgentState.DT_CROWDAGENT_STATE_OFFMESH;
ag.ncorners = 0; ag.ncorners = 0;
ag.neis.Clear(); ag.nneis = 0;
continue; continue;
} }
else else
@ -1093,7 +1135,7 @@ namespace DotRecast.Detour.Crowd
float w = 0; float w = 0;
RcVec3f disp = new RcVec3f(); RcVec3f disp = new RcVec3f();
for (int j = 0; j < ag.neis.Count; ++j) for (int j = 0; j < ag.nneis; ++j)
{ {
DtCrowdAgent nei = ag.neis[j].agent; DtCrowdAgent nei = ag.neis[j].agent;
@ -1155,7 +1197,7 @@ namespace DotRecast.Detour.Crowd
_obstacleQuery.Reset(); _obstacleQuery.Reset();
// Add neighbours as obstacles. // Add neighbours as obstacles.
for (int j = 0; j < ag.neis.Count; ++j) for (int j = 0; j < ag.nneis; ++j)
{ {
DtCrowdAgent nei = ag.neis[j].agent; DtCrowdAgent nei = ag.neis[j].agent;
_obstacleQuery.AddCircle(nei.npos, nei.option.radius, nei.vel, nei.dvel); _obstacleQuery.AddCircle(nei.npos, nei.option.radius, nei.vel, nei.dvel);
@ -1243,7 +1285,7 @@ namespace DotRecast.Detour.Crowd
float w = 0; float w = 0;
for (int j = 0; j < ag.neis.Count; ++j) for (int j = 0; j < ag.nneis; ++j)
{ {
DtCrowdAgent nei = ag.neis[j].agent; DtCrowdAgent nei = ag.neis[j].agent;
long idx1 = nei.idx; long idx1 = nei.idx;

View File

@ -37,16 +37,19 @@ namespace DotRecast.Detour.Crowd
public bool partial; public bool partial;
/// The path corridor the agent is using. /// The path corridor the agent is using.
public DtPathCorridor corridor; public readonly DtPathCorridor corridor;
/// The local boundary data for the agent. /// The local boundary data for the agent.
public DtLocalBoundary boundary; public readonly DtLocalBoundary boundary;
/// Time since the agent's path corridor was optimized. /// Time since the agent's path corridor was optimized.
public float topologyOptTime; public float topologyOptTime;
/// The known neighbors of the agent. /// The known neighbors of the agent.
public List<DtCrowdNeighbour> neis = new List<DtCrowdNeighbour>(); public readonly DtCrowdNeighbour[] neis = new DtCrowdNeighbour[DtCrowdConst.DT_CROWDAGENT_MAX_NEIGHBOURS];
/// The number of neighbors.
public int nneis;
/// The desired speed. /// The desired speed.
public float desiredSpeed; public float desiredSpeed;

View File

@ -325,7 +325,7 @@ public class CrowdSampleTool : ISampleTool
2.0f); 2.0f);
dd.Begin(LINES, 2.0f); dd.Begin(LINES, 2.0f);
for (int j = 0; j < ag.neis.Count; ++j) for (int j = 0; j < ag.nneis; ++j)
{ {
DtCrowdAgent nei = ag.neis[j].agent; DtCrowdAgent nei = ag.neis[j].agent;
if (nei != null) if (nei != null)