Recast: fix BVTree calculations and rendering (XZY -> XYZ)

Should've been converted to the source engine coordinate system as well, but we missed this as then rendering thereof was 'fixed' incorrectly causing incorrect bounding volumes to appear correctly. Fixed the renderer and the calculation; the AI now never gets stuck in-game regardless whether 256 or 512 sized tiles are used.
This commit is contained in:
Kawe Mazidjatari 2024-08-21 14:40:33 +02:00
parent 5aff50f8cf
commit 8fce111502
3 changed files with 64 additions and 59 deletions

View File

@ -205,9 +205,8 @@ void CAI_Utility::DrawNavMeshBVTree(
continue;
const float flCellSize = 1.0f / pTile->header->bvQuantFactor;
const fltx4 xTileAABB = LoadGatherSIMD(pTile->header->bmin[0], pTile->header->bmin[1], pTile->header->bmin[2], 0.0f);
const fltx4 xCellSize = LoadGatherSIMD(flCellSize, flCellSize, flCellSize, 0.0f);
const float* tileBmin = pTile->header->bmin;
const float* tileBmax = pTile->header->bmax;
for (int j = 0, nc = pTile->header->bvNodeCount; j < nc; ++j)
{
@ -219,11 +218,15 @@ void CAI_Utility::DrawNavMeshBVTree(
vTransforms.xmm[1] = LoadGatherSIMD(0.0f, 1.0f, 0.0f, 0.0f);
vTransforms.xmm[2] = LoadGatherSIMD(0.0f, 0.0f, 1.0f, 0.0f);
// Formula: tile->header->bm##[axis]+node->bm##[axis]*cs;
const fltx4 xMins = MaddSIMD(LoadGatherSIMD(pNode->bmin[0], pNode->bmin[1], pNode->bmin[2], 0.0f), xCellSize, xTileAABB);
const fltx4 xMaxs = MaddSIMD(LoadGatherSIMD(pNode->bmax[0], pNode->bmax[1], pNode->bmax[2], 0.0f), xCellSize, xTileAABB);
const Vector3D mins(tileBmax[0]-pNode->bmax[0]*flCellSize,
tileBmin[1]+pNode->bmin[1]*flCellSize,
tileBmin[2]+pNode->bmin[2]*flCellSize);
v_RenderBox(vTransforms.mat, *reinterpret_cast<const Vector3D*>(&xMins), *reinterpret_cast<const Vector3D*>(&xMaxs),
const Vector3D maxs(tileBmax[0]-pNode->bmin[0]*flCellSize,
tileBmin[1]+pNode->bmax[1]*flCellSize,
tileBmin[2]+pNode->bmax[2]*flCellSize);
v_RenderBox(vTransforms.mat, mins, maxs,
Color(188, 188, 188, 255), bDepthBuffer);
}
}

View File

@ -524,10 +524,11 @@ static void drawMeshTileBVTree(duDebugDraw* dd, const dtMeshTile* tile, const fl
const dtBVNode* n = &tile->bvTree[i];
if (n->i < 0) // Leaf indices are positive.
continue;
duAppendBoxWire(dd, tile->header->bmin[0] + n->bmin[0]*cs,
duAppendBoxWire(dd,
tile->header->bmax[0] - n->bmax[0]*cs,
tile->header->bmin[1] + n->bmin[1]*cs,
tile->header->bmin[2] + n->bmin[2]*cs,
tile->header->bmin[0] + n->bmax[0]*cs,
tile->header->bmax[0] - n->bmin[0]*cs,
tile->header->bmin[1] + n->bmax[1]*cs,
tile->header->bmin[2] + n->bmax[2]*cs,
duRGBA(255,255,255,128));

View File

@ -164,6 +164,15 @@ static void subdivide(BVItem* items, int nitems, int imin, int imax, int& curNod
}
}
static const unsigned short DT_MESH_NULL_IDX = 0xffff;
static int countPolyVerts(const unsigned short* p, const int nvp) // todo(amos): deduplicate
{
for (int i = 0; i < nvp; ++i)
if (p[i] == DT_MESH_NULL_IDX)
return i;
return nvp;
}
static int createBVTree(dtNavMeshCreateParams* params, dtBVNode* nodes, int /*nnodes*/)
{
// Build tree
@ -173,59 +182,60 @@ static int createBVTree(dtNavMeshCreateParams* params, dtBVNode* nodes, int /*nn
{
BVItem& it = items[i];
it.i = i;
float polyVerts[DT_VERTS_PER_POLYGON*3];
const float* targetVert;
int vertCount;
// Calc polygon bounds. Use detail meshes if available.
if (params->detailMeshes)
{
int vb = (int)params->detailMeshes[i*4+0];
int ndv = (int)params->detailMeshes[i*4+1];
float bmin[3];
float bmax[3];
const int vb = (int)params->detailMeshes[i*4+0];
vertCount = (int)params->detailMeshes[i*4+1];
const float* dv = &params->detailVerts[vb*3];
rdVcopy(bmin, dv);
rdVcopy(bmax, dv);
for (int j = 1; j < ndv; j++)
{
rdVmin(bmin, &dv[j * 3]);
rdVmax(bmax, &dv[j * 3]);
}
// BV-tree uses cs for all dimensions
it.bmin[0] = (unsigned short)rdClamp((int)((bmin[0] - params->bmin[0])*quantFactor), 0, 0xffff);
it.bmin[1] = (unsigned short)rdClamp((int)((bmin[1] - params->bmin[1])*quantFactor), 0, 0xffff);
it.bmin[2] = (unsigned short)rdClamp((int)((bmin[2] - params->bmin[2])*quantFactor), 0, 0xffff);
it.bmax[0] = (unsigned short)rdClamp((int)((bmax[0] - params->bmin[0])*quantFactor), 0, 0xffff);
it.bmax[1] = (unsigned short)rdClamp((int)((bmax[1] - params->bmin[1])*quantFactor), 0, 0xffff);
it.bmax[2] = (unsigned short)rdClamp((int)((bmax[2] - params->bmin[2])*quantFactor), 0, 0xffff);
targetVert = &params->detailVerts[vb*3];
}
else
{
const unsigned short* p = &params->polys[i*params->nvp * 2];
it.bmin[0] = it.bmax[0] = params->verts[p[0] * 3 + 0];
it.bmin[1] = it.bmax[1] = params->verts[p[0] * 3 + 1];
it.bmin[2] = it.bmax[2] = params->verts[p[0] * 3 + 2];
const int nvp = params->nvp;
for (int j = 1; j < params->nvp; ++j)
const unsigned short* p = &params->polys[i*nvp * 2];
vertCount = countPolyVerts(p, nvp);
for (int j = 0; j < vertCount; ++j)
{
if (p[j] == MESH_NULL_IDX) break;
unsigned short x = params->verts[p[j] * 3 + 0];
unsigned short y = params->verts[p[j] * 3 + 1];
unsigned short z = params->verts[p[j] * 3 + 2];
const unsigned short* polyVert = &params->verts[p[j] * 3];
float* flPolyVert = &polyVerts[j * 3];
if (x < it.bmin[0]) it.bmin[0] = x;
if (y < it.bmin[1]) it.bmin[1] = y;
if (z < it.bmin[2]) it.bmin[2] = z;
if (x > it.bmax[0]) it.bmax[0] = x;
if (y > it.bmax[1]) it.bmax[1] = y;
if (z > it.bmax[2]) it.bmax[2] = z;
flPolyVert[0] = params->bmin[0]+polyVert[0]*params->cs;
flPolyVert[1] = params->bmin[1]+polyVert[1]*params->cs;
flPolyVert[2] = params->bmin[2]+polyVert[2]*params->ch;
}
// Remap z
it.bmin[2] = (unsigned short)rdMathFloorf((float)it.bmin[2] * params->ch / params->cs);
it.bmax[2] = (unsigned short)rdMathCeilf((float)it.bmax[2] * params->ch / params->cs);
targetVert = polyVerts;
}
float bmin[3];
float bmax[3];
rdVcopy(bmin, targetVert);
rdVcopy(bmax, targetVert);
for (int j = 1; j < vertCount; j++)
{
rdVmin(bmin, &targetVert[j * 3]);
rdVmax(bmax, &targetVert[j * 3]);
}
// BV-tree uses cs for all dimensions
it.bmin[0] = (unsigned short)rdClamp((int)((params->bmax[0] - bmax[0])*quantFactor), 0, 0xffff);
it.bmin[1] = (unsigned short)rdClamp((int)((bmin[1] - params->bmin[1])*quantFactor), 0, 0xffff);
it.bmin[2] = (unsigned short)rdClamp((int)((bmin[2] - params->bmin[2])*quantFactor), 0, 0xffff);
it.bmax[0] = (unsigned short)rdClamp((int)((params->bmax[0] - bmin[0])*quantFactor), 0, 0xffff);
it.bmax[1] = (unsigned short)rdClamp((int)((bmax[1] - params->bmin[1])*quantFactor), 0, 0xffff);
it.bmax[2] = (unsigned short)rdClamp((int)((bmax[2] - params->bmin[2])*quantFactor), 0, 0xffff);
}
int curNode = 0;
@ -561,15 +571,6 @@ bool dtCreateTraverseTableData(const dtTraverseTableCreateParams* params)
return true;
}
static const unsigned short DT_MESH_NULL_IDX = 0xffff;
static int countPolyVerts(const unsigned short* p, const int nvp) // todo(amos): deduplicate
{
for (int i = 0; i < nvp; ++i)
if (p[i] == DT_MESH_NULL_IDX)
return i;
return nvp;
}
struct CellItem
{
float pos[3];