Recast: add option to ignore input triangle winding order

The mesh data from the game's BVH4 tree does not appear to have a fixed triangle winding order, making it nearly impossible to generate correct navmeshes while using the decoded BVH4 data. Fixing the sign enables us to generate the navmesh over the game's collision data properly rather than using the render mesh. This change does not appear to have a negative effect on the generated NavMesh.
This commit is contained in:
Kawe Mazidjatari 2024-10-25 11:04:27 +02:00
parent ed9cd80034
commit 0940ad3ce6
5 changed files with 14 additions and 12 deletions

View File

@ -238,7 +238,7 @@ bool Editor_SoloMesh::handleBuild()
// If your input data is multiple meshes, you can transform them here, calculate
// the are type for each of the meshes and rasterize them.
memset(m_triareas, 0, ntris*sizeof(unsigned char));
rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas);
rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas, true);
if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, m_triareas, ntris, *m_solid, m_cfg.walkableClimb))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not rasterize triangles.");

View File

@ -298,7 +298,7 @@ int Editor_TempObstacles::rasterizeTileLayers(
memset(rc.triareas, 0, ntris*sizeof(unsigned char));
rcMarkWalkableTriangles(m_ctx, tcfg.walkableSlopeAngle,
verts, nverts, tris, ntris, rc.triareas);
verts, nverts, tris, ntris, rc.triareas, false);
if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, rc.triareas, ntris, *rc.solid, tcfg.walkableClimb))
return 0;
@ -319,7 +319,7 @@ int Editor_TempObstacles::rasterizeTileLayers(
memset(rc.triareas, 0, ntris * sizeof(unsigned char));
rcMarkWalkableTriangles(m_ctx, tcfg.walkableSlopeAngle,
verts, nverts, tris, ntris, rc.triareas);
verts, nverts, tris, ntris, rc.triareas, true);
if (!rcRasterizeTriangles(m_ctx, verts, nverts, tris, rc.triareas, ntris, *rc.solid, tcfg.walkableClimb))
return 0;

View File

@ -1051,7 +1051,7 @@ unsigned char* Editor_TileMesh::buildTileMesh(const int tx, const int ty, const
memset(m_triareas, 0, nctris*sizeof(unsigned char));
rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle,
verts, nverts, ctris, nctris, m_triareas);
verts, nverts, ctris, nctris, m_triareas, false);
if (!rcRasterizeTriangles(m_ctx, verts, nverts, ctris, m_triareas, nctris, *m_solid, m_cfg.walkableClimb))
return 0;
@ -1075,7 +1075,7 @@ unsigned char* Editor_TileMesh::buildTileMesh(const int tx, const int ty, const
memset(m_triareas, 0, nctris * sizeof(unsigned char));
rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle,
verts, nverts, ctris, nctris, m_triareas);
verts, nverts, ctris, nctris, m_triareas, true);
if (!rcRasterizeTriangles(m_ctx, verts, nverts, ctris, m_triareas, nctris, *m_solid, m_cfg.walkableClimb))
return 0;

View File

@ -677,7 +677,7 @@ void rcCalcGridSize(const float* minBounds, const float* maxBounds, float cellSi
/// @param[in] minBounds The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
/// @param[in] maxBounds The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
/// @param[in] cellSize The xy-plane cell size to use for the field. [Limit: > 0] [Units: wu]
/// @param[in] cellHeight The y-axis cell size to use for field. [Limit: > 0] [Units: wu]
/// @param[in] cellHeight The z-axis cell size to use for field. [Limit: > 0] [Units: wu]
/// @returns True if the operation completed successfully.
bool rcCreateHeightfield(rcContext* context, rcHeightfield& heightfield, int sizeX, int sizeZ,
const float* minBounds, const float* maxBounds,
@ -702,8 +702,9 @@ bool rcCreateHeightfield(rcContext* context, rcHeightfield& heightfield, int siz
/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
/// @param[in] numTris The number of triangles.
/// @param[out] triAreaIDs The triangle area ids. [Length: >= @p nt]
/// @param[in] ignoreWindingOrder Whether to ignore the winding order of the triangle.
void rcMarkWalkableTriangles(rcContext* context, float walkableSlopeAngle, const float* verts, int numVerts,
const int* tris, int numTris, unsigned char* triAreaIDs);
const int* tris, int numTris, unsigned char* triAreaIDs, const bool ignoreWindingOrder);
/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA.
///
@ -723,8 +724,9 @@ void rcMarkWalkableTriangles(rcContext* context, float walkableSlopeAngle, const
/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
/// @param[in] numTris The number of triangles.
/// @param[out] triAreaIDs The triangle area ids. [Length: >= @p nt]
/// @param[in] ignoreWindingOrder Whether to ignore the winding order of the triangle.
void rcClearUnwalkableTriangles(rcContext* context, float walkableSlopeAngle, const float* verts, int numVerts,
const int* tris, int numTris, unsigned char* triAreaIDs);
const int* tris, int numTris, unsigned char* triAreaIDs, const bool ignoreWindingOrder);
/// Adds a span to the specified heightfield.
///

View File

@ -330,7 +330,7 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
void rcMarkWalkableTriangles(rcContext* context, const float walkableSlopeAngle,
const float* verts, const int numVerts,
const int* tris, const int numTris,
unsigned char* triAreaIDs)
unsigned char* triAreaIDs, const bool ignoreWindingOrder)
{
rdIgnoreUnused(context);
rdIgnoreUnused(numVerts);
@ -344,7 +344,7 @@ void rcMarkWalkableTriangles(rcContext* context, const float walkableSlopeAngle,
const int* tri = &tris[i * 3];
calcTriNormal(&verts[tri[0] * 3], &verts[tri[1] * 3], &verts[tri[2] * 3], norm);
// Check if the face is walkable.
if (norm[2] > walkableThr)
if ((ignoreWindingOrder ? rdMathFabsf(norm[2]) : norm[2]) > walkableThr)
{
triAreaIDs[i] = RC_WALKABLE_AREA;
}
@ -354,7 +354,7 @@ void rcMarkWalkableTriangles(rcContext* context, const float walkableSlopeAngle,
void rcClearUnwalkableTriangles(rcContext* context, const float walkableSlopeAngle,
const float* verts, int numVerts,
const int* tris, int numTris,
unsigned char* triAreaIDs)
unsigned char* triAreaIDs, const bool ignoreWindingOrder)
{
rdIgnoreUnused(context);
rdIgnoreUnused(numVerts);
@ -368,7 +368,7 @@ void rcClearUnwalkableTriangles(rcContext* context, const float walkableSlopeAng
const int* tri = &tris[i * 3];
calcTriNormal(&verts[tri[0] * 3], &verts[tri[1] * 3], &verts[tri[2] * 3], faceNormal);
// Check if the face is walkable.
if (faceNormal[2] <= walkableLimitZ)
if ((ignoreWindingOrder ? rdMathFabsf(faceNormal[2]) : faceNormal[2]) <= walkableLimitZ)
{
triAreaIDs[i] = RC_NULL_AREA;
}