Recast: vastly improve reliability of land-side off-mesh link tile query

Instead of a box query, just take the position in the tile grid the land-side off-mesh vert is on. This vastly improves the query reliability for off-mesh links with a larger radius to the point it never fails if it is in a valid location. The box query isn't needed here as the off-mesh vert has to be on a tile, else the polygon box query will fail (unless its bounding box does happen to overlap with the point, but in this case the off-mesh connection is placed improperly causing the only factor to have its link established being luck).
This commit is contained in:
Kawe Mazidjatari 2024-09-19 15:44:23 +02:00
parent 2ed18dc6e0
commit 4a9bfbe79a
2 changed files with 34 additions and 48 deletions

View File

@ -1002,7 +1002,7 @@ private:
public:
/// Returns neighbour tile based on side.
/// Returns tile based on position.
int getTilesAt(const int x, const int y,
dtMeshTile** tiles, const int maxTiles) const;

View File

@ -602,6 +602,12 @@ dtStatus dtNavMesh::connectOffMeshLinks(const dtTileRef tileRef)
const unsigned char traverseType = con->getTraverseType();
const bool invertVertLookup = con->getVertLookupOrder();
#if DT_NAVMESH_SET_VERSION >= 7
// NOTE: need to remove the vert lookup inversion flag from here as the
// engine uses this value directly to index into the activity array.
con->setTraverseType(traverseType, 0);
#endif
// Start end-point is always connect back to off-mesh connection.
const unsigned short basePolyIdx = (unsigned short)decodePolyIdPoly(basePolyRef);
dtPoly* basePoly = &tile->polys[basePolyIdx];
@ -623,70 +629,50 @@ dtStatus dtNavMesh::connectOffMeshLinks(const dtTileRef tileRef)
rdVadd(bmax, &con->pos[3], halfExtents);
// Find tiles the query touches.
int minx, miny, maxx, maxy;
calcTileLoc(bmin, &minx, &miny);
calcTileLoc(bmax, &maxx, &maxy);
int tx, ty;
calcTileLoc(&con->pos[3], &tx, &ty);
static const int MAX_NEIS = 32;
dtMeshTile* neis[MAX_NEIS];
const int nneis = getTilesAt(tx, ty, neis, MAX_NEIS);
const unsigned char side = rdClassifyPointOutsideBounds(&con->pos[3], header->bmin, header->bmax);
const unsigned char oppositeSide = (side == 0xff) ? 0xff : (unsigned char)rdOppositeTile(side);
#if DT_NAVMESH_SET_VERSION >= 7
// NOTE: need to remove the vert lookup inversion flag from here as the
// engine uses this value directly to index into the activity array.
con->setTraverseType(traverseType, 0);
#endif
bool breakOut = false;
for (int y = miny; y <= maxy; ++y)
for (int j = 0; j < nneis; ++j)
{
for (int x = minx; x <= maxx; ++x)
{
const int nneis = getTilesAt(x, y, neis, MAX_NEIS);
for (int j = 0; j < nneis; ++j)
{
dtMeshTile* neiTile = neis[j];
dtMeshTile* neiTile = neis[j];
// Find polygon to connect to.
const dtPolyRef landPolyRef = clampOffMeshVertToPoly(con, tile, neiTile, false);
// Find polygon to connect to.
const dtPolyRef landPolyRef = clampOffMeshVertToPoly(con, tile, neiTile, false);
if (!landPolyRef)
continue;
if (!landPolyRef)
continue;
// Link off-mesh connection to target poly.
if (!connectOffMeshLink(tile, conPoly, landPolyRef, oppositeSide, 1, DT_NULL_TRAVERSE_TYPE, 0))
return DT_FAILURE | DT_OUT_OF_MEMORY;
// Link off-mesh connection to target poly.
if (!connectOffMeshLink(tile, conPoly, landPolyRef, oppositeSide, 1, DT_NULL_TRAVERSE_TYPE, 0))
return DT_FAILURE | DT_OUT_OF_MEMORY;
// Link target poly to off-mesh connection.
// Link target poly to off-mesh connection.
#if DT_NAVMESH_SET_VERSION < 7
if (con->flags & DT_OFFMESH_CON_BIDIR)
if (con->flags & DT_OFFMESH_CON_BIDIR)
#endif
{
const unsigned int landPolyIdx = decodePolyIdPoly(landPolyRef);
dtPoly* landPoly = &neiTile->polys[landPolyIdx];
{
const unsigned int landPolyIdx = decodePolyIdPoly(landPolyRef);
dtPoly* landPoly = &neiTile->polys[landPolyIdx];
if (!connectOffMeshLink(neiTile, landPoly, conPolyRef, side, 0xff, traverseType,
invertVertLookup ? DT_OFFMESH_CON_TRAVERSE_ON_POLY : DT_OFFMESH_CON_TRAVERSE_ON_VERT))
return DT_FAILURE | DT_OUT_OF_MEMORY;
}
#if DT_NAVMESH_SET_VERSION >= 7
// Off-mesh link is fully linked, mark it.
conPoly->flags |= DT_POLYFLAGS_JUMP_LINKED;
#endif
// All links have been established, break out entirely.
breakOut = true;
break;
}
if (breakOut)
break;
if (!connectOffMeshLink(neiTile, landPoly, conPolyRef, side, 0xff, traverseType,
invertVertLookup ? DT_OFFMESH_CON_TRAVERSE_ON_POLY : DT_OFFMESH_CON_TRAVERSE_ON_VERT))
return DT_FAILURE | DT_OUT_OF_MEMORY;
}
if (breakOut)
break;
#if DT_NAVMESH_SET_VERSION >= 7
// Off-mesh link is fully linked, mark it.
conPoly->flags |= DT_POLYFLAGS_JUMP_LINKED;
#endif
// All links have been established, break out entirely.
break;
}
}