Recast: move polygon surface area calculation to librecast

Let recast compute this instead of detour. We need this before the detour navmesh is getting build as we have to determine whether a polygon is too small before that, and flag it as such.
This commit is contained in:
Kawe Mazidjatari 2024-08-30 15:43:21 +02:00
parent 05b6e23a75
commit 041d02cd65
8 changed files with 48 additions and 36 deletions

View File

@ -1267,8 +1267,9 @@ unsigned char* Editor_TileMesh::buildTileMesh(const int tx, const int ty, const
params.verts = m_pmesh->verts;
params.vertCount = m_pmesh->nverts;
params.polys = m_pmesh->polys;
params.polyAreas = m_pmesh->areas;
params.polyFlags = m_pmesh->flags;
params.polyAreas = m_pmesh->areas;
params.surfAreas = m_pmesh->surfa;
params.polyCount = m_pmesh->npolys;
params.nvp = m_pmesh->nvp;
params.cellResolution = m_polyCellRes;

View File

@ -85,9 +85,6 @@ static const unsigned short DT_FIRST_USABLE_POLY_GROUP = 2;
/// are even on the same (or connected) poly island before trying to compute a path).
static const int DT_MIN_POLY_GROUP_COUNT = 3;
/// The cached poly surface area quantization factor.
static const float DT_POLY_AREA_QUANT_FACTOR = 0.01f;
/// The maximum number of traversal tables per navmesh that will be used for static pathing.
static const int DT_MAX_TRAVERSE_TABLES = 5;
@ -268,13 +265,6 @@ struct dtPoly
inline unsigned char getType() const { return areaAndtype >> 6; }
};
/// Calculates the surface area of the polygon.
/// @param[in] poly The polygon.
/// @param[in] verts The polygon vertices.
/// @return The total surface are of the polygon.
float dtCalcPolySurfaceArea(const dtPoly* poly, const float* verts);
unsigned short dtQuantPolySurfaceArea(const float area);
/// Defines the location of detail sub-mesh data within a dtMeshTile.
struct dtPolyDetail
{

View File

@ -36,6 +36,7 @@ struct dtNavMeshCreateParams
const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp]
const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount]
const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount]
const unsigned short* surfAreas; ///< The surface area amount for each polygon. [Size: #polyCount]
int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1]
int nvp; ///< Maximum number of vertices per polygon. [Limit: >= 3]
int cellResolution; ///< The resolution of the diamond cell grid [Limit: >= 1]

View File

@ -1868,28 +1868,6 @@ unsigned char dtQuantLinkDistance(const float distance)
return (unsigned char)(rdMathRoundf(distance * DT_TRAVERSE_DIST_QUANT_FACTOR));
}
float dtCalcPolySurfaceArea(const dtPoly* poly, const float* verts)
{
float polyArea = 0.0f;
// Only run if we have more than 2 verts since poly's with 2 verts
// (off-mesh connections) don't have any surface area.
for (int i = 2; i < poly->vertCount; ++i)
{
const float* va = &verts[poly->verts[0]*3];
const float* vb = &verts[poly->verts[i]*3];
const float* vc = &verts[poly->verts[i-1]*3];
polyArea += rdTriArea2D(va,vb,vc);
}
return polyArea;
}
unsigned short dtQuantPolySurfaceArea(const float area)
{
return (unsigned short)rdMathRoundf(area * DT_POLY_AREA_QUANT_FACTOR);
}
float dtCalcOffMeshRefYaw(const float* spos, const float* epos)
{
const float dx = epos[0]-spos[0];

View File

@ -960,10 +960,11 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
for (int i = 0; i < params->polyCount; ++i)
{
dtPoly* p = &navPolys[i];
p->vertCount = 0;
p->flags = params->polyFlags[i];
p->vertCount = 0;
p->setArea(params->polyAreas[i]);
p->setType(DT_POLYTYPE_GROUND);
p->surfaceArea = params->surfAreas[i];
for (int j = 0; j < nvp; ++j)
{
if (src[j] == MESH_NULL_IDX) break;
@ -992,8 +993,6 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
p->vertCount++;
}
rdVscale(p->center, p->center, 1 / (float)(p->vertCount));
p->surfaceArea = dtQuantPolySurfaceArea(dtCalcPolySurfaceArea(p,navVerts));
src += nvp*2;
}

View File

@ -457,6 +457,7 @@ struct rcPolyMesh
unsigned short* regs; ///< The region id assigned to each polygon. [Length: #maxpolys]
unsigned short* flags; ///< The user defined flags for each polygon. [Length: #maxpolys]
unsigned char* areas; ///< The area id assigned to each polygon. [Length: #maxpolys]
unsigned short* surfa; ///< The surface area amount for each polygon. [Length: #maxpolys]
int nverts; ///< The number of vertices.
int npolys; ///< The number of polygons.
int maxpolys; ///< The number of allocated polygons.
@ -633,6 +634,10 @@ static const unsigned char RC_NULL_AREA = 0;
/// recognized by some steps in the build process.
static const unsigned char RC_WALKABLE_AREA = 63;
/// The cached polygon surface area quantization factor.
/// @see rcPolyMesh::surfa
static const float RC_POLY_SURFAREA_QUANT_FACTOR = 0.01f;
/// The value returned by #rcGetCon if the specified direction is not connected
/// to another span. (Has no neighbor.)
static const int RC_NOT_CONNECTED = 0x3f;

View File

@ -225,6 +225,7 @@ rcPolyMesh::rcPolyMesh()
, regs()
, flags()
, areas()
, surfa()
, nverts()
, npolys()
, maxpolys()
@ -245,6 +246,7 @@ rcPolyMesh::~rcPolyMesh()
rdFree(regs);
rdFree(flags);
rdFree(areas);
rdFree(surfa);
}
rcPolyMeshDetail* rcAllocPolyMeshDetail()

View File

@ -1110,6 +1110,12 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.areas' (%d).", maxTris);
return false;
}
mesh.surfa = (unsigned short*)rdAlloc(sizeof(unsigned short)*maxTris, RD_ALLOC_PERM);
if (!mesh.surfa)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.surfa' (%d).", maxTris);
return false;
}
mesh.nverts = 0;
mesh.npolys = 0;
@ -1355,6 +1361,36 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
}
}
// Calculate polygon surface area's.
for (int i = 0; i < mesh.npolys; i++)
{
const unsigned short* p = &mesh.polys[i*2*nvp];
unsigned short vi[3];
float fv[3][2];
float polyArea = 0.0f;
for (int j = 2; j < nvp; ++j)
{
if (p[j] == RC_MESH_NULL_IDX)
break;
vi[0] = p[0];
vi[1] = p[j];
vi[2] = p[j-1];
for (int k = 0; k < 3; k++)
{
const unsigned short* v = &mesh.verts[vi[k]*3];
fv[k][0] = mesh.bmin[0] + v[0]*mesh.cs;
fv[k][1] = mesh.bmin[1] + v[1]*mesh.cs;
}
polyArea += rdTriArea2D(fv[0], fv[1], fv[2]);
}
mesh.surfa[i] = (unsigned short)rdMathRoundf(polyArea*RC_POLY_SURFAREA_QUANT_FACTOR);
}
// Just allocate the mesh flags array. The user is responsible to fill it.
mesh.flags = (unsigned short*)rdAlloc(sizeof(unsigned short)*mesh.npolys, RD_ALLOC_PERM);
if (!mesh.flags)