Skip to content

Commit

Permalink
[Upstream] Code cleanup and small optimizations in RecastFilter.cpp r…
Browse files Browse the repository at this point in the history
…cFilterLedgeSpans (ikpil/DotRecast#29)

- recastnavigation/recastnavigation@3e94c3b

* Code cleanup and minor refactor in RecastFilter.cpp rcFilterLedgeSpans

Because span.smax is always > 0, bot > 0 as well, and (-walkableClimb - bot) is always < -walkableClimb. Furthermore, as long as minNeighborHeight < -walkableClimb' at least once, there is no need to continue the traversal.

* Code cleanup and minor refactor in RecastFilter.cpp rcFilterLedgeSpans

Because span.smax is always > 0, bot > 0 as well, and (-walkableClimb - bot) is always < -walkableClimb. Furthermore, as long as minNeighborHeight < -walkableClimb' at least once, there is no need to continue the traversal.

* Update RecastFilter.cpp
  • Loading branch information
ikpil committed Jan 2, 2024
1 parent 327e6ed commit 72a7d50
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 56 deletions.
2 changes: 1 addition & 1 deletion Runtime/DotRecast.Core/Numerics/RcVec2f.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public struct RcVec2f
public float X;
public float Y;

public static RcVec2f Zero { get; } = new RcVec2f { X = 0, Y = 0 };
public static readonly RcVec2f Zero = new RcVec2f { X = 0, Y = 0 };

public RcVec2f(float x, float y)
{
Expand Down
10 changes: 5 additions & 5 deletions Runtime/DotRecast.Core/Numerics/RcVec3f.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ public struct RcVec3f
public float Y;
public float Z;

public static RcVec3f Zero { get; } = new RcVec3f(0.0f, 0.0f, 0.0f);
public static RcVec3f One { get; } = new RcVec3f(1.0f);
public static RcVec3f UnitX { get; } = new RcVec3f(1.0f, 0.0f, 0.0f);
public static RcVec3f UnitY { get; } = new RcVec3f(0.0f, 1.0f, 0.0f);
public static RcVec3f UnitZ { get; } = new RcVec3f(0.0f, 0.0f, 1.0f);
public static readonly RcVec3f Zero = new RcVec3f(0.0f, 0.0f, 0.0f);
public static readonly RcVec3f One = new RcVec3f(1.0f);
public static readonly RcVec3f UnitX = new RcVec3f(1.0f, 0.0f, 0.0f);
public static readonly RcVec3f UnitY = new RcVec3f(0.0f, 1.0f, 0.0f);
public static readonly RcVec3f UnitZ = new RcVec3f(0.0f, 0.0f, 1.0f);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RcVec3f(float x, float y, float z)
Expand Down
2 changes: 1 addition & 1 deletion Runtime/DotRecast.Detour.Extras/Jumplink/JumpLinkType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class JumpLinkType
public static readonly JumpLinkType EDGE_CLIMB_DOWN = new JumpLinkType(EDGE_CLIMB_DOWN_BIT);
public static readonly JumpLinkType EDGE_JUMP_OVER = new JumpLinkType(EDGE_JUMP_OVER_BIT);

public int Bit { get; }
public readonly int Bit;

private JumpLinkType(int bit)
{
Expand Down
4 changes: 2 additions & 2 deletions Runtime/DotRecast.Detour/DtNavMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class DtNavMesh

/** A version number used to detect compatibility of navigation tile states. */
public const int DT_NAVMESH_STATE_VERSION = 1;

public const int DT_SALT_BITS = 16;
public const int DT_TILE_BITS = 28;
public const int DT_POLY_BITS = 20;
Expand Down Expand Up @@ -284,7 +284,7 @@ public DtStatus GetTileAndPolyByRef(long refs, out DtMeshTile tile, out DtPoly p
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
}

if (m_tiles[it].salt != salt || m_tiles[it].data.header == null)
if (m_tiles[it].salt != salt || m_tiles[it].data == null || m_tiles[it].data.header == null)
{
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
}
Expand Down
4 changes: 2 additions & 2 deletions Runtime/DotRecast.Recast.Toolset/Tools/RcCrowdToolMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public class RcCrowdToolMode
TOGGLE_POLYS
);

public int Idx { get; }
public string Label { get; }
public readonly int Idx;
public readonly string Label;

private RcCrowdToolMode(int idx, string label)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class RcDynamicUpdateToolMode
BUILD, COLLIDERS, RAYCAST
);

public int Idx { get; }
public string Label { get; }
public readonly int Idx;
public readonly string Label;

private RcDynamicUpdateToolMode(int idx, string label)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public class RcTestNavmeshToolMode
);


public int Idx { get; }
public string Label { get; }
public readonly int Idx;
public readonly string Label;

private RcTestNavmeshToolMode(int idx, string label)
{
Expand Down
87 changes: 49 additions & 38 deletions Runtime/DotRecast.Recast/RcFilters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,85 +84,96 @@ public static void FilterLowHangingWalkableObstacles(RcTelemetry ctx, int walkab
/// A span is a ledge if: <tt>RcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
///
/// @see rcHeightfield, rcConfig
public static void FilterLedgeSpans(RcTelemetry ctx, int walkableHeight, int walkableClimb, RcHeightfield solid)
public static void FilterLedgeSpans(RcTelemetry ctx, int walkableHeight, int walkableClimb, RcHeightfield heightfield)
{
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_BORDER);

int w = solid.width;
int h = solid.height;
int xSize = heightfield.width;
int zSize = heightfield.height;

// Mark border spans.
for (int y = 0; y < h; ++y)
for (int z = 0; z < zSize; ++z)
{
for (int x = 0; x < w; ++x)
for (int x = 0; x < xSize; ++x)
{
for (RcSpan s = solid.spans[x + y * w]; s != null; s = s.next)
for (RcSpan span = heightfield.spans[x + z * xSize]; span != null; span = span.next)
{
// Skip non walkable spans.
if (s.area == RC_NULL_AREA)
if (span.area == RC_NULL_AREA)
{
continue;
}

int bot = (s.smax);
int top = s.next != null ? s.next.smin : SPAN_MAX_HEIGHT;
int bot = (span.smax);
int top = span.next != null ? span.next.smin : SPAN_MAX_HEIGHT;

// Find neighbours minimum height.
int minh = SPAN_MAX_HEIGHT;
int minNeighborHeight = SPAN_MAX_HEIGHT;

// Min and max height of accessible neighbours.
int asmin = s.smax;
int asmax = s.smax;
int accessibleNeighborMinHeight = span.smax;
int accessibleNeighborMaxHeight = span.smax;

for (int dir = 0; dir < 4; ++dir)
for (int direction = 0; direction < 4; ++direction)
{
int dx = x + GetDirOffsetX(dir);
int dy = y + GetDirOffsetY(dir);
int dx = x + GetDirOffsetX(direction);
int dz = z + GetDirOffsetY(direction);
// Skip neighbours which are out of bounds.
if (dx < 0 || dy < 0 || dx >= w || dy >= h)
if (dx < 0 || dz < 0 || dx >= xSize || dz >= zSize)
{
minh = Math.Min(minh, -walkableClimb - bot);
continue;
minNeighborHeight = (-walkableClimb - 1);
break;
}

// From minus infinity to the first span.
RcSpan ns = solid.spans[dx + dy * w];
int nbot = -walkableClimb;
int ntop = ns != null ? ns.smin : SPAN_MAX_HEIGHT;
RcSpan neighborSpan = heightfield.spans[dx + dz * xSize];
int neighborTop = neighborSpan != null ? neighborSpan.smin : SPAN_MAX_HEIGHT;

// Skip neightbour if the gap between the spans is too small.
if (Math.Min(top, ntop) - Math.Max(bot, nbot) > walkableHeight)
minh = Math.Min(minh, nbot - bot);
if (Math.Min(top, neighborTop) - bot >= walkableHeight)
{
minNeighborHeight = (-walkableClimb - 1);
break;
}

// Rest of the spans.
for (ns = solid.spans[dx + dy * w]; ns != null; ns = ns.next)
for (neighborSpan = heightfield.spans[dx + dz * xSize]; neighborSpan != null; neighborSpan = neighborSpan.next)
{
nbot = ns.smax;
ntop = ns.next != null ? ns.next.smin : SPAN_MAX_HEIGHT;
int neighborBot = neighborSpan.smax;
neighborTop = neighborSpan.next != null ? neighborSpan.next.smin : SPAN_MAX_HEIGHT;

// Skip neightbour if the gap between the spans is too small.
if (Math.Min(top, ntop) - Math.Max(bot, nbot) > walkableHeight)
if (Math.Min(top, neighborTop) - Math.Max(bot, neighborBot) >= walkableHeight)
{
minh = Math.Min(minh, nbot - bot);
int accessibleNeighbourHeight = neighborBot - bot;
minNeighborHeight = Math.Min(minNeighborHeight, accessibleNeighbourHeight);

// Find min/max accessible neighbour height.
if (MathF.Abs(nbot - bot) <= walkableClimb)
// Find min/max accessible neighbour height.
if (MathF.Abs(accessibleNeighbourHeight) <= walkableClimb)
{
if (neighborBot < accessibleNeighborMinHeight) accessibleNeighborMinHeight = neighborBot;
if (neighborBot > accessibleNeighborMaxHeight) accessibleNeighborMaxHeight = neighborBot;
}
else if (accessibleNeighbourHeight < -walkableClimb)
{
if (nbot < asmin)
asmin = nbot;
if (nbot > asmax)
asmax = nbot;
break;
}
}
}
}

// The current span is close to a ledge if the drop to any
// neighbour span is less than the walkableClimb.
if (minh < -walkableClimb)
s.area = RC_NULL_AREA;
if (minNeighborHeight < -walkableClimb)
{
span.area = RC_NULL_AREA;
}

// If the difference between all neighbours is too large,
// we are at steep slope, mark the span as ledge.
if ((asmax - asmin) > walkableClimb)
if ((accessibleNeighborMaxHeight - accessibleNeighborMinHeight) > walkableClimb)
{
s.area = RC_NULL_AREA;
span.area = RC_NULL_AREA;
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.ikpil.unirecast",
"displayName": "UniRecast",
"version": "0.0.5",
"version": "0.0.6",
"unity": "2019.3",
"description": "navigation mesh toolset for Unity3D using DotRecast",
"license": "MIT",
Expand All @@ -21,8 +21,7 @@
},
"repository": {
"url": "https://github.com/ikpil/UniRecast.git",
"type": "git",
"revision": "20bf43272e9a453cb080f2864185ee0396bf36e3"
"type": "git"
},
"samples": [
{
Expand Down

0 comments on commit 72a7d50

Please sign in to comment.