Code cleanup and small optimizations in RecastFilter.cpp rcFilterLedgeSpans (https://github.com/recastnavigation/recastnavigation/pull/672)

- 3e94c3b6fc

* 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

Revise Comment
This commit is contained in:
ikpil 2024-01-01 14:10:57 +09:00 committed by Ikpil
parent 2d36b5f639
commit 9d01b5243f
1 changed files with 49 additions and 38 deletions

View File

@ -84,70 +84,79 @@ namespace DotRecast.Recast
/// A span is a ledge if: <tt>RcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt> /// A span is a ledge if: <tt>RcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
/// ///
/// @see rcHeightfield, rcConfig /// @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); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_FILTER_BORDER);
int w = solid.width; int xSize = heightfield.width;
int h = solid.height; int zSize = heightfield.height;
// Mark border spans. // 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. // Skip non walkable spans.
if (s.area == RC_NULL_AREA) if (span.area == RC_NULL_AREA)
{
continue; continue;
}
int bot = (s.smax); int bot = (span.smax);
int top = s.next != null ? s.next.smin : SPAN_MAX_HEIGHT; int top = span.next != null ? span.next.smin : SPAN_MAX_HEIGHT;
// Find neighbours minimum height. // Find neighbours minimum height.
int minh = SPAN_MAX_HEIGHT; int minNeighborHeight = SPAN_MAX_HEIGHT;
// Min and max height of accessible neighbours. // Min and max height of accessible neighbours.
int asmin = s.smax; int accessibleNeighborMinHeight = span.smax;
int asmax = s.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 dx = x + GetDirOffsetX(direction);
int dy = y + GetDirOffsetY(dir); int dz = z + GetDirOffsetY(direction);
// Skip neighbours which are out of bounds. // 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); minNeighborHeight = (-walkableClimb - 1);
continue; break;
} }
// From minus infinity to the first span. // From minus infinity to the first span.
RcSpan ns = solid.spans[dx + dy * w]; RcSpan neighborSpan = heightfield.spans[dx + dz * xSize];
int nbot = -walkableClimb; int neighborTop = neighborSpan != null ? neighborSpan.smin : SPAN_MAX_HEIGHT;
int ntop = ns != null ? ns.smin : SPAN_MAX_HEIGHT;
// Skip neightbour if the gap between the spans is too small. // 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) - bot >= walkableHeight)
minh = Math.Min(minh, nbot - bot); {
minNeighborHeight = (-walkableClimb - 1);
break;
}
// Rest of the spans. // 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; int neighborBot = neighborSpan.smax;
ntop = ns.next != null ? ns.next.smin : SPAN_MAX_HEIGHT; neighborTop = neighborSpan.next != null ? neighborSpan.next.smin : SPAN_MAX_HEIGHT;
// Skip neightbour if the gap between the spans is too small. // 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. // Find min/max accessible neighbour height.
if (MathF.Abs(nbot - bot) <= walkableClimb) if (MathF.Abs(accessibleNeighbourHeight) <= walkableClimb)
{ {
if (nbot < asmin) if (neighborBot < accessibleNeighborMinHeight) accessibleNeighborMinHeight = neighborBot;
asmin = nbot; if (neighborBot > accessibleNeighborMaxHeight) accessibleNeighborMaxHeight = neighborBot;
if (nbot > asmax) }
asmax = nbot; else if (accessibleNeighbourHeight < -walkableClimb)
{
break;
} }
} }
} }
@ -155,14 +164,16 @@ namespace DotRecast.Recast
// The current span is close to a ledge if the drop to any // The current span is close to a ledge if the drop to any
// neighbour span is less than the walkableClimb. // neighbour span is less than the walkableClimb.
if (minh < -walkableClimb) if (minNeighborHeight < -walkableClimb)
s.area = RC_NULL_AREA; {
span.area = RC_NULL_AREA;
}
// If the difference between all neighbours is too large, // If the difference between all neighbours is too large,
// we are at steep slope, mark the span as ledge. // 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;
} }
} }
} }