Recast: rcFilterLedgeSpans optimizations and improvements

Merge recastnavigation/recastnavigation#672

Actually improves the filtering of ledge spans as they are now a lot firmer against their limits, this is also beneficial for traverse link generation as we get more accurate ledge spans to work with (making the offsetting math do its job better since it assumes accurate ledge spans).

There was a report further down this pull request that pathing results differed after this change, along with a new one at https://github.com/recastnavigation/recastnavigation/issues/729. I was however not able to replicate it, nor did any behavior change in-game on a navmesh generated on kings canyon.
This commit is contained in:
Kawe Mazidjatari 2024-08-22 19:17:29 +02:00
parent de5fb7cbef
commit ec056e277e

View File

@ -98,39 +98,43 @@ void rcFilterLedgeSpans(rcContext* context, const int walkableHeight, const int
// Skip neighbours which are out of bounds. // Skip neighbours which are out of bounds.
if (dx < 0 || dy < 0 || dx >= xSize || dy >= ySize) if (dx < 0 || dy < 0 || dx >= xSize || dy >= ySize)
{ {
minNeighborHeight = rdMin(minNeighborHeight, -walkableClimb - bot); minNeighborHeight = (-walkableClimb - 1);
continue; break;
} }
// From minus infinity to the first span. // From minus infinity to the first span.
const rcSpan* neighborSpan = heightfield.spans[dx + dy * xSize]; const rcSpan* neighborSpan = heightfield.spans[dx + dy * xSize];
int neighborBot = -walkableClimb;
int neighborTop = neighborSpan ? (int)neighborSpan->smin : MAX_HEIGHT; int neighborTop = neighborSpan ? (int)neighborSpan->smin : MAX_HEIGHT;
// Skip neighbour if the gap between the spans is too small. // Skip neighbour if the gap between the spans is too small.
if (rdMin(top, neighborTop) - rdMax(bot, neighborBot) > walkableHeight) if (rdMin(top, neighborTop) - bot >= walkableHeight)
{ {
minNeighborHeight = rdMin(minNeighborHeight, neighborBot - bot); minNeighborHeight = (-walkableClimb - 1);
break;
} }
// Rest of the spans. // Rest of the spans.
for (neighborSpan = heightfield.spans[dx + dy * xSize]; neighborSpan; neighborSpan = neighborSpan->next) for (neighborSpan = heightfield.spans[dx + dy * xSize]; neighborSpan; neighborSpan = neighborSpan->next)
{ {
neighborBot = (int)neighborSpan->smax; const int neighborBot = (int)neighborSpan->smax;
neighborTop = neighborSpan->next ? (int)neighborSpan->next->smin : MAX_HEIGHT; neighborTop = neighborSpan->next ? (int)neighborSpan->next->smin : MAX_HEIGHT;
// Skip neighbour if the gap between the spans is too small. // Skip neighbour if the gap between the spans is too small.
if (rdMin(top, neighborTop) - rdMax(bot, neighborBot) > walkableHeight) if (rdMin(top, neighborTop) - rdMax(bot, neighborBot) >= walkableHeight)
{ {
minNeighborHeight = rdMin(minNeighborHeight, neighborBot - bot); const int accessibleNeighbourHeight = neighborBot - bot;
minNeighborHeight = rdMin(minNeighborHeight, accessibleNeighbourHeight);
// Find min/max accessible neighbour height. // Find min/max accessible neighbour height.
if (rdAbs(neighborBot - bot) <= walkableClimb) if (rdAbs(accessibleNeighbourHeight) <= walkableClimb)
{ {
if (neighborBot < accessibleNeighborMinHeight) accessibleNeighborMinHeight = neighborBot; if (neighborBot < accessibleNeighborMinHeight) accessibleNeighborMinHeight = neighborBot;
if (neighborBot > accessibleNeighborMaxHeight) accessibleNeighborMaxHeight = neighborBot; if (neighborBot > accessibleNeighborMaxHeight) accessibleNeighborMaxHeight = neighborBot;
} }
else if (accessibleNeighbourHeight < -walkableClimb)
{
break;
}
} }
} }
} }