crowd performance

This commit is contained in:
ikpil 2023-05-04 00:29:08 +09:00
parent cd39cbbd36
commit d3d966cccc
3 changed files with 53 additions and 82 deletions

View File

@ -869,7 +869,7 @@ namespace DotRecast.Detour.Crowd
{ {
Vector3f p = ag.npos; Vector3f p = ag.npos;
float r = ag.option.radius; float r = ag.option.radius;
m_grid.addItem(ag, p.x - r, p.z - r, p.x + r, p.z + r); m_grid.AddItem(ag, p.x - r, p.z - r, p.x + r, p.z + r);
} }
_telemetry.stop("buildProximityGrid"); _telemetry.stop("buildProximityGrid");
@ -901,12 +901,12 @@ namespace DotRecast.Detour.Crowd
_telemetry.stop("buildNeighbours"); _telemetry.stop("buildNeighbours");
} }
private List<CrowdNeighbour> getNeighbours(Vector3f pos, float height, float range, CrowdAgent skip, ProximityGrid grid) private List<CrowdNeighbour> getNeighbours(Vector3f pos, float height, float range, CrowdAgent skip, ProximityGrid grid)
{ {
List<CrowdNeighbour> result = new List<CrowdNeighbour>(); List<CrowdNeighbour> result = new List<CrowdNeighbour>();
HashSet<CrowdAgent> proxAgents = grid.queryItems(pos.x - range, pos.z - range, pos.x + range, pos.z + range); HashSet<CrowdAgent> proxAgents = grid.QueryItems(pos.x - range, pos.z - range, pos.x + range, pos.z + range);
foreach (CrowdAgent ag in proxAgents) foreach (CrowdAgent ag in proxAgents)
{ {
if (ag == skip) if (ag == skip)
@ -1392,4 +1392,4 @@ namespace DotRecast.Detour.Crowd
} }
}; };
} }
} }

View File

@ -20,44 +20,60 @@ freely, subject to the following restrictions:
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Linq; using System.Linq;
namespace DotRecast.Detour.Crowd namespace DotRecast.Detour.Crowd
{ {
public class ProximityGrid public class ProximityGrid
{ {
private readonly float m_cellSize; private readonly float _cellSize;
private readonly float m_invCellSize; private readonly float _invCellSize;
private readonly Dictionary<ItemKey, List<CrowdAgent>> items; private readonly Dictionary<long, List<CrowdAgent>> _items;
public ProximityGrid(float m_cellSize) public ProximityGrid(float cellSize)
{ {
this.m_cellSize = m_cellSize; _cellSize = cellSize;
m_invCellSize = 1.0f / m_cellSize; _invCellSize = 1.0f / cellSize;
items = new Dictionary<ItemKey, List<CrowdAgent>>(); _items = new Dictionary<long, List<CrowdAgent>>();
} }
void clear() public static long CombineKey(int x, int y)
{ {
items.Clear(); uint ux = (uint)x;
uint uy = (uint)y;
return ((long)ux << 32) | uy;
} }
public void addItem(CrowdAgent agent, float minx, float miny, float maxx, float maxy) public static void DecomposeKey(long key, out int x, out int y)
{ {
int iminx = (int)Math.Floor(minx * m_invCellSize); uint ux = (uint)(key >> 32);
int iminy = (int)Math.Floor(miny * m_invCellSize); uint uy = (uint)key;
int imaxx = (int)Math.Floor(maxx * m_invCellSize); x = (int)ux;
int imaxy = (int)Math.Floor(maxy * m_invCellSize); y = (int)uy;
}
void Clear()
{
_items.Clear();
}
public void AddItem(CrowdAgent agent, float minx, float miny, float maxx, float maxy)
{
int iminx = (int)Math.Floor(minx * _invCellSize);
int iminy = (int)Math.Floor(miny * _invCellSize);
int imaxx = (int)Math.Floor(maxx * _invCellSize);
int imaxy = (int)Math.Floor(maxy * _invCellSize);
for (int y = iminy; y <= imaxy; ++y) for (int y = iminy; y <= imaxy; ++y)
{ {
for (int x = iminx; x <= imaxx; ++x) for (int x = iminx; x <= imaxx; ++x)
{ {
ItemKey key = new ItemKey(x, y); long key = CombineKey(x, y);
if (!items.TryGetValue(key, out var ids)) if (!_items.TryGetValue(key, out var ids))
{ {
ids = new List<CrowdAgent>(); ids = new List<CrowdAgent>();
items.Add(key, ids); _items.Add(key, ids);
} }
ids.Add(agent); ids.Add(agent);
@ -65,20 +81,20 @@ namespace DotRecast.Detour.Crowd
} }
} }
public HashSet<CrowdAgent> queryItems(float minx, float miny, float maxx, float maxy) public HashSet<CrowdAgent> QueryItems(float minx, float miny, float maxx, float maxy)
{ {
int iminx = (int)Math.Floor(minx * m_invCellSize); int iminx = (int)Math.Floor(minx * _invCellSize);
int iminy = (int)Math.Floor(miny * m_invCellSize); int iminy = (int)Math.Floor(miny * _invCellSize);
int imaxx = (int)Math.Floor(maxx * m_invCellSize); int imaxx = (int)Math.Floor(maxx * _invCellSize);
int imaxy = (int)Math.Floor(maxy * m_invCellSize); int imaxy = (int)Math.Floor(maxy * _invCellSize);
HashSet<CrowdAgent> result = new HashSet<CrowdAgent>(); HashSet<CrowdAgent> result = new HashSet<CrowdAgent>();
for (int y = iminy; y <= imaxy; ++y) for (int y = iminy; y <= imaxy; ++y)
{ {
for (int x = iminx; x <= imaxx; ++x) for (int x = iminx; x <= imaxx; ++x)
{ {
ItemKey key = new ItemKey(x, y); long key = CombineKey(x, y);
if (items.TryGetValue(key, out var ids)) if (_items.TryGetValue(key, out var ids))
{ {
result.UnionWith(ids); result.UnionWith(ids);
} }
@ -88,59 +104,16 @@ namespace DotRecast.Detour.Crowd
return result; return result;
} }
public List<int[]> getItemCounts() public IEnumerable<(long, int)> GetItemCounts()
{ {
return items return _items
.Where(e => e.Value.Count > 0) .Where(e => e.Value.Count > 0)
.Select(e => new int[] { e.Key.x, e.Key.y, e.Value.Count }) .Select(e => (e.Key, e.Value.Count));
.ToList();
} }
public float getCellSize() public float GetCellSize()
{ {
return m_cellSize; return _cellSize;
} }
private class ItemKey
{
public readonly int x;
public readonly int y;
public ItemKey(int x, int y)
{
this.x = x;
this.y = y;
}
public override int GetHashCode()
{
int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
public override bool Equals(object? obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (GetType() != obj.GetType())
return false;
ItemKey other = (ItemKey)obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
};
} }
} }

View File

@ -408,12 +408,10 @@ public class CrowdTool : Tool
dd.begin(QUADS); dd.begin(QUADS);
ProximityGrid grid = crowd.getGrid(); ProximityGrid grid = crowd.getGrid();
float cs = grid.getCellSize(); float cs = grid.GetCellSize();
foreach (int[] ic in grid.getItemCounts()) foreach (var (combinedKey, count) in grid.GetItemCounts())
{ {
int x = ic[0]; ProximityGrid.DecomposeKey(combinedKey, out var x, out var y);
int y = ic[1];
int count = ic[2];
if (count != 0) if (count != 0)
{ {
int col = duRGBA(128, 0, 0, Math.Min(count * 40, 255)); int col = duRGBA(128, 0, 0, Math.Min(count * 40, 255));
@ -838,4 +836,4 @@ public class CrowdTool : Tool
{ {
return "Crowd"; return "Crowd";
} }
} }