mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Recast: calculate 3D AABB box for rcCunkyTriMesh
The code originally did a 2D AABB, which has several negative effects. Its cheaper to calculate on load however the NavMesh results are less accurate as the boxes won't be subdivided on the Z axis during the build process. The second issue is that the raycast will query all overlapping triangles in a rectangle on a XY plane, for a detailed mesh, this could mean having to test over 1000 triangles for a simple ray cast accorss the geometry. A sample that collected 1000 triangles to test has been reduces to just 3 with this change. The build times have also been reduced by 50% (Kings Canyon NavMesh now builds in 32 minutes rather than 60+ minutes).
This commit is contained in:
parent
62f7b04f5a
commit
c71d7f52dc
@ -21,8 +21,8 @@
|
||||
|
||||
struct BoundsItem
|
||||
{
|
||||
float bmin[2];
|
||||
float bmax[2];
|
||||
float bmin[3];
|
||||
float bmax[3];
|
||||
int i;
|
||||
};
|
||||
|
||||
@ -48,30 +48,56 @@ static int compareItemY(const void* va, const void* vb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compareItemZ(const void* va, const void* vb)
|
||||
{
|
||||
const BoundsItem* a = (const BoundsItem*)va;
|
||||
const BoundsItem* b = (const BoundsItem*)vb;
|
||||
if (a->bmin[2] < b->bmin[2])
|
||||
return -1;
|
||||
if (a->bmin[2] > b->bmin[2])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void calcExtends(const BoundsItem* items, const int /*nitems*/,
|
||||
const int imin, const int imax,
|
||||
float* bmin, float* bmax)
|
||||
{
|
||||
bmin[0] = items[imin].bmin[0];
|
||||
bmin[1] = items[imin].bmin[1];
|
||||
bmin[2] = items[imin].bmin[2];
|
||||
|
||||
bmax[0] = items[imin].bmax[0];
|
||||
bmax[1] = items[imin].bmax[1];
|
||||
bmax[2] = items[imin].bmax[2];
|
||||
|
||||
for (int i = imin+1; i < imax; ++i)
|
||||
{
|
||||
const BoundsItem& it = items[i];
|
||||
if (it.bmin[0] < bmin[0]) bmin[0] = it.bmin[0];
|
||||
if (it.bmin[1] < bmin[1]) bmin[1] = it.bmin[1];
|
||||
if (it.bmin[2] < bmin[2]) bmin[2] = it.bmin[2];
|
||||
|
||||
if (it.bmax[0] > bmax[0]) bmax[0] = it.bmax[0];
|
||||
if (it.bmax[1] > bmax[1]) bmax[1] = it.bmax[1];
|
||||
if (it.bmax[2] > bmax[2]) bmax[2] = it.bmax[2];
|
||||
}
|
||||
}
|
||||
|
||||
inline int longestAxis(float x, float y)
|
||||
inline int longestAxis(float x, float y, float z)
|
||||
{
|
||||
return y > x ? 1 : 0;
|
||||
int axis = 0;
|
||||
float maxVal = x;
|
||||
if (y > maxVal)
|
||||
{
|
||||
axis = 1;
|
||||
maxVal = y;
|
||||
}
|
||||
if (z > maxVal)
|
||||
{
|
||||
axis = 2;
|
||||
}
|
||||
return axis;
|
||||
}
|
||||
|
||||
static void subdivide(BoundsItem* items, int nitems, int imin, int imax, int trisPerChunk,
|
||||
@ -110,8 +136,9 @@ static void subdivide(BoundsItem* items, int nitems, int imin, int imax, int tri
|
||||
// Split
|
||||
calcExtends(items, nitems, imin, imax, node.bmin, node.bmax);
|
||||
|
||||
int axis = longestAxis(node.bmax[0] - node.bmin[0],
|
||||
node.bmax[1] - node.bmin[1]);
|
||||
const int axis = longestAxis(node.bmax[0] - node.bmin[0],
|
||||
node.bmax[1] - node.bmin[1],
|
||||
node.bmax[2] - node.bmin[2]);
|
||||
|
||||
if (axis == 0)
|
||||
{
|
||||
@ -123,6 +150,11 @@ static void subdivide(BoundsItem* items, int nitems, int imin, int imax, int tri
|
||||
// Sort along y-axis
|
||||
qsort(items+imin, static_cast<size_t>(inum), sizeof(BoundsItem), compareItemY);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sort along z-axis
|
||||
qsort(items+imin, static_cast<size_t>(inum), sizeof(BoundsItem), compareItemZ);
|
||||
}
|
||||
|
||||
int isplit = imin+inum/2;
|
||||
|
||||
@ -162,17 +194,20 @@ bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris,
|
||||
const int* t = &tris[i*3];
|
||||
BoundsItem& it = items[i];
|
||||
it.i = i;
|
||||
// Calc triangle XY bounds.
|
||||
// Calc triangle XYZ bounds.
|
||||
it.bmin[0] = it.bmax[0] = verts[t[0]*3+0];
|
||||
it.bmin[1] = it.bmax[1] = verts[t[0]*3+1];
|
||||
it.bmin[2] = it.bmax[2] = verts[t[0]*3+2];
|
||||
for (int j = 1; j < 3; ++j)
|
||||
{
|
||||
const float* v = &verts[t[j]*3];
|
||||
if (v[0] < it.bmin[0]) it.bmin[0] = v[0];
|
||||
if (v[1] < it.bmin[1]) it.bmin[1] = v[1];
|
||||
if (v[2] < it.bmin[2]) it.bmin[2] = v[2];
|
||||
|
||||
if (v[0] > it.bmax[0]) it.bmax[0] = v[0];
|
||||
if (v[1] > it.bmax[1]) it.bmax[1] = v[1];
|
||||
if (v[2] > it.bmax[2]) it.bmax[2] = v[2];
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,18 +313,19 @@ int rcGetChunksOverlappingRect(const rcChunkyTriMesh * cm, float bmin[2], float
|
||||
|
||||
|
||||
|
||||
static bool checkOverlapSegment(const float p[2], const float q[2],
|
||||
const float bmin[2], const float bmax[2])
|
||||
static bool checkOverlapSegment(const float p[3], const float q[3],
|
||||
const float bmin[3], const float bmax[3])
|
||||
{
|
||||
float tmin = 0;
|
||||
float tmax = 1;
|
||||
float d[2];
|
||||
float d[3];
|
||||
d[0] = q[0] - p[0];
|
||||
d[1] = q[1] - p[1];
|
||||
d[2] = q[2] - p[2];
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (fabsf(d[i]) < RD_EPS)
|
||||
if (rdMathFabsf(d[i]) < RD_EPS)
|
||||
{
|
||||
// Ray is parallel to slab. No hit if origin not within slab
|
||||
if (p[i] < bmin[i] || p[i] > bmax[i])
|
||||
@ -310,8 +346,9 @@ static bool checkOverlapSegment(const float p[2], const float q[2],
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int rcGetChunksOverlappingSegment(const rcChunkyTriMesh* cm,
|
||||
float p[2], float q[2],
|
||||
float p[3], float q[3],
|
||||
int* ids, const int maxIds)
|
||||
{
|
||||
// Traverse tree
|
||||
|
@ -533,11 +533,13 @@ bool InputGeom::raycastMesh(const float* src, const float* dst, const unsigned i
|
||||
if (!traceWorld)
|
||||
return false;
|
||||
|
||||
float p[2], q[2];
|
||||
float p[3], q[3];
|
||||
p[0] = src[0] + (dst[0]-src[0]) * btmin;
|
||||
p[1] = src[1] + (dst[1]-src[1]) * btmin;
|
||||
p[2] = src[2] + (dst[2]-src[2]) * btmin;
|
||||
q[0] = src[0] + (dst[0]-src[0]) * btmax;
|
||||
q[1] = src[1] + (dst[1]-src[1]) * btmax;
|
||||
q[2] = src[2] + (dst[2]-src[2]) * btmax;
|
||||
|
||||
const int ncid = rcGetChunksOverlappingSegment(m_chunkyMesh, p, q, s_chunkIndices, MAX_CHUNK_INDICES);
|
||||
if (!ncid)
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
struct rcChunkyTriMeshNode
|
||||
{
|
||||
float bmin[2];
|
||||
float bmax[2];
|
||||
float bmin[3];
|
||||
float bmax[3];
|
||||
int i;
|
||||
int n;
|
||||
};
|
||||
@ -56,7 +56,7 @@ int rcGetChunksOverlappingRect(const rcChunkyTriMesh* cm, float bmin[2], float b
|
||||
int rcGetChunksOverlappingRect(const rcChunkyTriMesh* cm, float bmin[2], float bmax[2], int* ids, const int maxIds,int& currentCount,int& currentNode);
|
||||
|
||||
/// Returns the chunk indices which overlap the input segment.
|
||||
int rcGetChunksOverlappingSegment(const rcChunkyTriMesh* cm, float p[2], float q[2], int* ids, const int maxIds);
|
||||
int rcGetChunksOverlappingSegment(const rcChunkyTriMesh* cm, float p[3], float q[3], int* ids, const int maxIds);
|
||||
|
||||
|
||||
#endif // CHUNKYTRIMESH_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user