Skip to content

Commit

Permalink
Fix dynamic mesh bounds calculation #77
Browse files Browse the repository at this point in the history
  • Loading branch information
ikpil committed Sep 20, 2024
1 parent e9a0584 commit 2d0e2f8
Show file tree
Hide file tree
Showing 14 changed files with 98 additions and 40 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Fixed
- Fix raycast shortcuts ([@Sarofc](https://github.com/Sarofc)) [#72](https://github.com/ikpil/DotRecast/issues/72)
- Fix dynamic mesh bounds calculation ([@ppiastucki](https://github.com/ppiastucki)) [#77](https://github.com/ikpil/DotRecast/issues/77)
- issuer : [@OhJeongrok](https://github.com/OhJeongrok)

### Changed
- Changed data structure of 'neis' from List<byte> to byte[] for optimized memory usage and improved access speed in `DtLayerMonotoneRegion`
Expand Down
12 changes: 6 additions & 6 deletions DotRecast.sln
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,18 @@ Global
{FFE40BBF-843B-41FA-8504-F4ABD166762E} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{38933A87-4568-40A5-A3DA-E2445E8C2B99} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{C19E4BFA-63A0-4815-9815-869A9DC52DBC} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{88754FE2-A05A-4D4D-A81A-90418AD32362} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{554CB5BD-D58A-4856-BFE1-666A62C9BEA3} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{FA7EF26A-BA47-43FD-86F8-0A33CFDF643F} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{F9C5B52E-C01D-4514-94E9-B1A6895352E2} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{53AF87DA-37F8-4504-B623-B2113F4438CA} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{67C68B34-118A-439C-88E1-D6D1ED78DC59} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{17E4F2F0-FC27-416E-9CB6-9F2CAAC49C9D} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{7BAA69B2-EDC7-4603-B16F-BC7B24353F81} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{DEB16B90-CCD4-497E-A2E9-4CC66FD7EF47} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{3CAA7306-088E-4373-A406-99755CC2B605} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{023E1E6A-4895-4573-89AE-3D5D8E0B39C8} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{DF987948-8C23-4337-AF83-D87D6407518D} = {8ED75CF7-A3D6-423D-8499-9316DD413DAD}
{88754FE2-A05A-4D4D-A81A-90418AD32362} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{554CB5BD-D58A-4856-BFE1-666A62C9BEA3} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{F9C5B52E-C01D-4514-94E9-B1A6895352E2} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{67C68B34-118A-439C-88E1-D6D1ED78DC59} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{7BAA69B2-EDC7-4603-B16F-BC7B24353F81} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{3CAA7306-088E-4373-A406-99755CC2B605} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{10395C8F-DFBD-4263-8A20-EA3500A6E55A} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
{D1EFC625-D095-4208-98A2-112B73CB40B0} = {A7CB8D8B-70DA-4567-8316-0659FCAE1C73}
EndGlobalSection
Expand Down
18 changes: 12 additions & 6 deletions src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ private bool Rebuild(ICollection<DtDynamicTile> tiles)
{
foreach (var tile in tiles)
Rebuild(tile);

return UpdateNavMesh();
}

Expand All @@ -188,17 +188,17 @@ private ICollection<DtDynamicTile> GetTiles(float[] bounds)
return _tiles.Values;
}

int minx = (int)MathF.Floor((bounds[0] - navMeshParams.orig.X) / navMeshParams.tileWidth);
int minz = (int)MathF.Floor((bounds[2] - navMeshParams.orig.Z) / navMeshParams.tileHeight);
int maxx = (int)MathF.Floor((bounds[3] - navMeshParams.orig.X) / navMeshParams.tileWidth);
int maxz = (int)MathF.Floor((bounds[5] - navMeshParams.orig.Z) / navMeshParams.tileHeight);
int minx = (int)MathF.Floor((bounds[0] - navMeshParams.orig.X) / navMeshParams.tileWidth) - 1;
int minz = (int)MathF.Floor((bounds[2] - navMeshParams.orig.Z) / navMeshParams.tileHeight) - 1;
int maxx = (int)MathF.Floor((bounds[3] - navMeshParams.orig.X) / navMeshParams.tileWidth) + 1;
int maxz = (int)MathF.Floor((bounds[5] - navMeshParams.orig.Z) / navMeshParams.tileHeight) + 1;
List<DtDynamicTile> tiles = new List<DtDynamicTile>();
for (int z = minz; z <= maxz; ++z)
{
for (int x = minx; x <= maxx; ++x)
{
DtDynamicTile tile = GetTileAt(x, z);
if (tile != null)
if (tile != null && IntersectsXZ(tile, bounds))
{
tiles.Add(tile);
}
Expand All @@ -208,6 +208,12 @@ private ICollection<DtDynamicTile> GetTiles(float[] bounds)
return tiles;
}

private bool IntersectsXZ(DtDynamicTile tile, float[] bounds)
{
return tile.voxelTile.boundsMin.X <= bounds[3] && tile.voxelTile.boundsMax.X >= bounds[0] &&
tile.voxelTile.boundsMin.Z <= bounds[5] && tile.voxelTile.boundsMax.Z >= bounds[2];
}

private List<DtDynamicTile> GetTilesByCollider(long cid)
{
return _tiles.Values.Where(t => t.ContainsCollider(cid)).ToList();
Expand Down
20 changes: 11 additions & 9 deletions src/DotRecast.Detour.Dynamic/Io/DtVoxelFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public RcConfig GetConfig(DtVoxelTile tile, RcAreaModification walkbableAreaMod,
walkbableAreaMod, buildMeshDetail);
}

public static DtVoxelFile From(RcConfig config, List<RcBuilderResult> results)
public static DtVoxelFile From(RcConfig config, IList<RcBuilderResult> results)
{
DtVoxelFile f = new DtVoxelFile();
f.version = 1;
Expand Down Expand Up @@ -109,13 +109,14 @@ public static DtVoxelFile From(RcConfig config, List<RcBuilderResult> results)
};
foreach (RcBuilderResult r in results)
{
float pad = r.SolidHeightfiled.borderSize * r.SolidHeightfiled.cs;
f.tiles.Add(new DtVoxelTile(r.TileX, r.TileZ, r.SolidHeightfiled));
f.bounds[0] = Math.Min(f.bounds[0], r.SolidHeightfiled.bmin.X);
f.bounds[0] = Math.Min(f.bounds[0], r.SolidHeightfiled.bmin.X + pad);
f.bounds[1] = Math.Min(f.bounds[1], r.SolidHeightfiled.bmin.Y);
f.bounds[2] = Math.Min(f.bounds[2], r.SolidHeightfiled.bmin.Z);
f.bounds[3] = Math.Max(f.bounds[3], r.SolidHeightfiled.bmax.X);
f.bounds[2] = Math.Min(f.bounds[2], r.SolidHeightfiled.bmin.Z + pad);
f.bounds[3] = Math.Max(f.bounds[3], r.SolidHeightfiled.bmax.X - pad);
f.bounds[4] = Math.Max(f.bounds[4], r.SolidHeightfiled.bmax.Y);
f.bounds[5] = Math.Max(f.bounds[5], r.SolidHeightfiled.bmax.Z);
f.bounds[5] = Math.Max(f.bounds[5], r.SolidHeightfiled.bmax.Z - pad);
}

return f;
Expand Down Expand Up @@ -155,12 +156,13 @@ public static DtVoxelFile From(DtDynamicNavMesh mesh)
{
RcHeightfield heightfield = vt.Heightfield();
f.tiles.Add(new DtVoxelTile(vt.tileX, vt.tileZ, heightfield));
f.bounds[0] = Math.Min(f.bounds[0], vt.boundsMin.X);
float pad = vt.borderSize * vt.cellSize;
f.bounds[0] = Math.Min(f.bounds[0], vt.boundsMin.X + pad);
f.bounds[1] = Math.Min(f.bounds[1], vt.boundsMin.Y);
f.bounds[2] = Math.Min(f.bounds[2], vt.boundsMin.Z);
f.bounds[3] = Math.Max(f.bounds[3], vt.boundsMax.X);
f.bounds[2] = Math.Min(f.bounds[2], vt.boundsMin.Z + pad);
f.bounds[3] = Math.Max(f.bounds[3], vt.boundsMax.X - pad);
f.bounds[4] = Math.Max(f.bounds[4], vt.boundsMax.Y);
f.bounds[5] = Math.Max(f.bounds[5], vt.boundsMax.Z);
f.bounds[5] = Math.Max(f.bounds[5], vt.boundsMax.Z - pad);
}

return f;
Expand Down
9 changes: 8 additions & 1 deletion src/DotRecast.Recast.Demo/DemoSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class DemoSample
private DtNavMesh _navMesh;
private DtNavMeshQuery _navMeshQuery;
private readonly RcNavMeshBuildSettings _settings;
private RcConfig _cfg;
private IList<RcBuilderResult> _recastResults;
private bool _changed;

Expand All @@ -56,6 +57,11 @@ public DemoInputGeomProvider GetInputGeom()
return _geom;
}

public RcConfig GetRecastConfig()
{
return _cfg;
}

public IList<RcBuilderResult> GetRecastResults()
{
return _recastResults;
Expand Down Expand Up @@ -86,9 +92,10 @@ public void SetChanged(bool changed)
_changed = changed;
}

public void Update(DemoInputGeomProvider geom, IList<RcBuilderResult> recastResults, DtNavMesh navMesh)
public void Update(DemoInputGeomProvider geom, RcConfig cfg, IList<RcBuilderResult> recastResults, DtNavMesh navMesh)
{
_geom = geom;
_cfg = cfg;
_recastResults = recastResults;
_navMesh = navMesh;
SetQuery(navMesh);
Expand Down
6 changes: 3 additions & 3 deletions src/DotRecast.Recast.Demo/RecastDemo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ private void LoadNavMesh(FileStream file, string filename)

if (null != mesh)
{
_sample.Update(_sample.GetInputGeom(), ImmutableArray<RcBuilderResult>.Empty, mesh);
_sample.Update(_sample.GetInputGeom(), _sample.GetRecastConfig(), ImmutableArray<RcBuilderResult>.Empty, mesh);
_toolsetView.SetEnabled(true);
}
}
Expand Down Expand Up @@ -684,7 +684,7 @@ private void OnGeomLoadBegan(GeomLoadBeganEvent args)
{
var geom = LoadInputMesh(args.FilePath);

_sample.Update(geom, ImmutableArray<RcBuilderResult>.Empty, null);
_sample.Update(geom, null, ImmutableArray<RcBuilderResult>.Empty, null);
}

private void OnNavMeshBuildBegan(NavMeshBuildBeganEvent args)
Expand Down Expand Up @@ -719,7 +719,7 @@ private void OnNavMeshBuildBegan(NavMeshBuildBeganEvent args)
return;
}

_sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh);
_sample.Update(_sample.GetInputGeom(), buildResult.Cfg, buildResult.RecastBuilderResults, buildResult.NavMesh);
_sample.SetChanged(false);
settingsView.SetBuildTime((RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond);
//settingsUI.SetBuildTelemetry(buildResult.Item1.Select(x => x.GetTelemetry()).ToList());
Expand Down
24 changes: 21 additions & 3 deletions src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 3. This notice may not be removed or altered from any source distribution.
using DotRecast.Core.Collections;
using DotRecast.Core.Numerics;
using DotRecast.Detour.Dynamic;
using DotRecast.Detour.Dynamic.Io;
using DotRecast.Recast.Toolset;
using DotRecast.Recast.Toolset.Tools;
using DotRecast.Recast.Demo.Draw;
Expand Down Expand Up @@ -117,8 +118,16 @@ public void Layout()
if (mode == RcDynamicUpdateToolMode.BUILD)
{
const string loadVoxelPopupStrId = "Load Voxels Popup";

bool isLoadVoxelPopup = true;
if (_sample.GetRecastResults() != null && _sample.GetRecastConfig() != null)
{
if (ImGui.Button("Import Voxels"))
{
Copy();
}
}

if (ImGui.Button("Load Voxels..."))
{
ImGui.OpenPopup(loadVoxelPopupStrId);
Expand Down Expand Up @@ -410,7 +419,7 @@ public void HandleUpdate(float dt)
{
buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond;
var dynaMesh = _tool.GetDynamicNavMesh();
_sample.Update(null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
_sample.Update(null, null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
_sample.SetChanged(false);
}
}
Expand All @@ -420,6 +429,15 @@ public void HandleUpdate(float dt)
}
}

private void Copy()
{
if (_sample.GetRecastResults() != null && _sample.GetRecastConfig() != null)
{
var dynaMesh = _tool.Copy(_sample.GetRecastConfig(), _sample.GetRecastResults());
UpdateFrom(dynaMesh.config);
BuildDynaMesh();
}
}

private void Load(string filename)
{
Expand Down Expand Up @@ -457,7 +475,7 @@ private void BuildDynaMesh()
}

buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond;
_sample.Update(null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
_sample.Update(null, null, dynaMesh.RecastResults(), dynaMesh.NavMesh());
}

private void UpdateTo(DtDynamicNavMeshConfig config)
Expand Down
2 changes: 1 addition & 1 deletion src/DotRecast.Recast.Demo/Tools/ObstacleSampleTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void Layout()
var buildResult = _tool.Build(geom, settings, RcByteOrder.LITTLE_ENDIAN, true);
if (buildResult.Success)
{
_sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh);
_sample.Update(_sample.GetInputGeom(), buildResult.Cfg, buildResult.RecastBuilderResults, buildResult.NavMesh);
}
}

Expand Down
14 changes: 13 additions & 1 deletion src/DotRecast.Recast.Toolset/Builder/NavMeshBuildResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace DotRecast.Recast.Toolset.Builder
public class NavMeshBuildResult
{
public readonly bool Success;
public readonly RcConfig Cfg;
public readonly IList<RcBuilderResult> RecastBuilderResults;
public readonly DtNavMesh NavMesh;

Expand All @@ -17,11 +18,22 @@ public NavMeshBuildResult()
NavMesh = null;
}

public NavMeshBuildResult(IList<RcBuilderResult> recastBuilderResults, DtNavMesh navMesh)
// for solo
public NavMeshBuildResult(RcConfig cfg, IList<RcBuilderResult> recastBuilderResults, DtNavMesh navMesh)
{
Success = true;
Cfg = cfg;
RecastBuilderResults = recastBuilderResults;
NavMesh = navMesh;
}

// for tiles
public NavMeshBuildResult(RcConfig cfg, IList<RcBuilderResult> recastBuilderResults)
{
Success = true;
Cfg = cfg;
RecastBuilderResults = recastBuilderResults;
NavMesh = null;
}
}
}
2 changes: 1 addition & 1 deletion src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public NavMeshBuildResult Build(DemoInputGeomProvider geom,
}

var navMesh = BuildNavMesh(meshData, vertsPerPoly);
return new NavMeshBuildResult(RcImmutableArray.Create(rcResult), navMesh);
return new NavMeshBuildResult(cfg, RcImmutableArray.Create(rcResult), navMesh);
}

private DtNavMesh BuildNavMesh(DtMeshData meshData, int vertsPerPoly)
Expand Down
11 changes: 6 additions & 5 deletions src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public NavMeshBuildResult Build(IInputGeomProvider geom,
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans,
bool keepInterResults, bool buildAll)
{
List<RcBuilderResult> results = BuildRecastResult(
NavMeshBuildResult result = BuildRecastResult(
geom,
tileSize,
partitionType,
Expand All @@ -72,12 +72,12 @@ public NavMeshBuildResult Build(IInputGeomProvider geom,
keepInterResults, buildAll
);

var tileMeshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, results);
var tileMeshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result.RecastBuilderResults);
var tileNavMesh = BuildNavMesh(geom, tileMeshData, cellSize, tileSize, vertsPerPoly);
return new NavMeshBuildResult(results, tileNavMesh);
return new NavMeshBuildResult(result.Cfg, result.RecastBuilderResults, tileNavMesh);
}

public List<RcBuilderResult> BuildRecastResult(IInputGeomProvider geom,
public NavMeshBuildResult BuildRecastResult(IInputGeomProvider geom,
int tileSize,
RcPartition partitionType,
float cellSize, float cellHeight,
Expand All @@ -102,7 +102,8 @@ public List<RcBuilderResult> BuildRecastResult(IInputGeomProvider geom,
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RcBuilder rcBuilder = new RcBuilder();
return rcBuilder.BuildTiles(geom, cfg, keepInterResults, buildAll, Environment.ProcessorCount + 1, Task.Factory);
var results = rcBuilder.BuildTiles(geom, cfg, keepInterResults, buildAll, Environment.ProcessorCount + 1, Task.Factory);
return new NavMeshBuildResult(cfg, results);
}

public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List<DtMeshData> meshData, float cellSize, int tileSize, int vertsPerPoly)
Expand Down
2 changes: 1 addition & 1 deletion src/DotRecast.Recast.Toolset/RcNavMeshBuildSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class RcNavMeshBuildSettings
public bool tiled = false;
public int tileSize = 32;

public bool keepInterResults = false;
public bool keepInterResults = true; // full memory
public bool buildAll = true;
}
}
14 changes: 12 additions & 2 deletions src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ public RcGizmo AddShape(RcDynamicColliderShape colliderShape, RcVec3f p)
return colliderWithGizmo;
}

public DtDynamicNavMesh Copy(RcConfig cfg, IList<RcBuilderResult> results)
{
var voxelFile = DtVoxelFile.From(cfg, results);
dynaMesh = new DtDynamicNavMesh(voxelFile);
dynaMesh.config.keepIntermediateResults = true;
colliderGizmos.Clear();

return dynaMesh;
}

public DtDynamicNavMesh Load(string filename, IRcCompressor compressor)
{
using var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
Expand Down Expand Up @@ -184,7 +194,7 @@ public RcGizmo CapsuleCollider(RcVec3f p, float walkableClimb)
(1f - 2 * (float)random.NextDouble())
);
a = RcVec3f.Normalize(a);

float len = 1f + (float)random.NextDouble() * 20f;
a.X *= len;
a.Y *= len;
Expand Down Expand Up @@ -235,7 +245,7 @@ public RcGizmo CompositeCollider(RcVec3f p, float walkableClimb)
RcVec3f baseUp = new RcVec3f(0, 1, 0);
RcVec3f forward = new RcVec3f((1f - 2 * (float)random.NextDouble()), 0, (1f - 2 * (float)random.NextDouble()));
forward = RcVec3f.Normalize(forward);

RcVec3f side = RcVec3f.Cross(forward, baseUp);
DtBoxCollider @base = new DtBoxCollider(baseCenter, Detour.Dynamic.Colliders.DtBoxCollider.GetHalfEdges(baseUp, forward, baseExtent),
SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD, walkableClimb);
Expand Down
2 changes: 1 addition & 1 deletion src/DotRecast.Recast.Toolset/Tools/RcObstacleTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public NavMeshBuildResult Build(IInputGeomProvider geom, RcNavMeshBuildSettings
_tc.BuildNavMeshTile(refs);
}

return new NavMeshBuildResult(RcImmutableArray<RcBuilderResult>.Empty, _tc.GetNavMesh());
return new NavMeshBuildResult(cfg, RcImmutableArray<RcBuilderResult>.Empty, _tc.GetNavMesh());
}

public void ClearAllTempObstacles()
Expand Down

0 comments on commit 2d0e2f8

Please sign in to comment.