allow toggling convex hull simplification at run-time in order to expected convex hull creation work

This commit is contained in:
Irlan 2018-05-12 21:56:11 -03:00
parent df304a5bb8
commit 569a555bde
2 changed files with 108 additions and 112 deletions

View File

@ -44,7 +44,9 @@ struct b3QHull : public b3Hull
// Create a convex hull from an array of points. // Create a convex hull from an array of points.
// If the creation has failed then this convex hull is not modified. // If the creation has failed then this convex hull is not modified.
void Set(const b3Vec3* points, u32 count); // Use the flag simplify to tell the convex hull creation code to simplify the convex hull after
// construction.
void Set(const b3Vec3* points, u32 count, bool simplify = true);
// Set this hull as a cylinder located at the origin. // Set this hull as a cylinder located at the origin.
void SetAsCylinder(float32 radius = 1.0f, float32 height = 1.0f); void SetAsCylinder(float32 radius = 1.0f, float32 height = 1.0f);

View File

@ -21,10 +21,6 @@
#define B3_NULL_HULL_FEATURE 0xFF #define B3_NULL_HULL_FEATURE 0xFF
// Enables or disables convex hull simplification.
// This can speed up collision detection and stability significantly.
#define B3_SIMPLIFY_HULL 1
// Used to map pointers to indices // Used to map pointers to indices
// If more performance is required then a use hash-map // If more performance is required then a use hash-map
template<class T, u32 N> template<class T, u32 N>
@ -142,13 +138,13 @@ static b3Vec3 b3ComputeCentroid(b3QHull* hull)
return centroid; return centroid;
} }
void b3QHull::Set(const b3Vec3* points, u32 count) void b3QHull::Set(const b3Vec3* points, u32 count, bool simplify)
{ {
B3_ASSERT(count >= 4); B3_ASSERT(count >= 4);
// Copy points into local buffer, perform welding. // Copy points into local buffer, perform welding.
u32 psCount = 0; u32 psCount = 0;
b3Vec3* ps = (b3Vec3*) b3Alloc(count * sizeof(b3Vec3)); b3Vec3* ps = (b3Vec3*)b3Alloc(count * sizeof(b3Vec3));
for (u32 i = 0; i < count; ++i) for (u32 i = 0; i < count; ++i)
{ {
b3Vec3 p = points[i]; b3Vec3 p = points[i];
@ -176,131 +172,129 @@ void b3QHull::Set(const b3Vec3* points, u32 count)
b3Free(ps); b3Free(ps);
return; return;
} }
// Create a convex hull. // Create a convex hull.
qhHull hull;
#if B3_SIMPLIFY_HULL == 1 if (simplify == true)
qhHull primary;
primary.Construct(ps, psCount);
b3Free(ps);
// Simplify the constructed hull.
// Put the origin inside the hull.
b3Vec3 s;
s.SetZero();
for (qhVertex* v = primary.GetVertexList().head; v; v = v->next)
{ {
s += v->position; qhHull primary;
} primary.Construct(ps, psCount);
s /= float32(primary.GetVertexList().count); b3Free(ps);
primary.Translate(-s); // Simplify the constructed hull.
// Build the dual hull // Put the origin inside the hull.
u32 dvCount = 0; b3Vec3 s;
qhFace** dfs = (qhFace**)b3Alloc(primary.GetFaceList().count * sizeof(qhFace*)); s.SetZero();
b3Vec3* dvs = (b3Vec3*)b3Alloc(primary.GetFaceList().count * sizeof(b3Vec3)); for (qhVertex* v = primary.GetVertexList().head; v; v = v->next)
for (qhFace* f = primary.GetFaceList().head; f; f = f->next)
{
b3Plane plane = f->plane;
B3_ASSERT(plane.offset > 0.0f);
b3Vec3 v = plane.normal / plane.offset;
b3Vec3 vn = plane.normal;
bool unique = true;
for (u32 j = 0; j < dvCount; ++j)
{ {
qhFace*& df = dfs[j]; s += v->position;
b3Vec3& dv = dvs[j]; }
b3Vec3 dvn = b3Normalize(dv); s /= float32(primary.GetVertexList().count);
// ~45 degrees primary.Translate(-s);
const float32 kTol = 0.7f;
// Build the dual hull
if (b3Dot(vn, dvn) > kTol) u32 dvCount = 0;
qhFace** dfs = (qhFace**)b3Alloc(primary.GetFaceList().count * sizeof(qhFace*));
b3Vec3* dvs = (b3Vec3*)b3Alloc(primary.GetFaceList().count * sizeof(b3Vec3));
for (qhFace* f = primary.GetFaceList().head; f; f = f->next)
{
b3Plane plane = f->plane;
B3_ASSERT(plane.offset > 0.0f);
b3Vec3 v = plane.normal / plane.offset;
b3Vec3 vn = plane.normal;
bool unique = true;
for (u32 j = 0; j < dvCount; ++j)
{ {
if (f->area > df->area) qhFace*& df = dfs[j];
b3Vec3& dv = dvs[j];
b3Vec3 dvn = b3Normalize(dv);
// ~45 degrees
const float32 kTol = 0.7f;
if (b3Dot(vn, dvn) > kTol)
{ {
df = f; if (f->area > df->area)
dv = v; {
df = f;
dv = v;
}
unique = false;
break;
} }
unique = false;
break;
} }
}
if (unique) if (unique)
{
dfs[dvCount] = f;
dvs[dvCount] = v;
++dvCount;
}
}
b3Free(dfs);
if (dvCount < 4)
{
b3Free(dvs);
return;
}
qhHull dual;
dual.Construct(dvs, dvCount);
b3Free(dvs);
// Recover the simplified hull in primary space.
u32 pvCount = 0;
b3Vec3* pvs = (b3Vec3*)b3Alloc(dual.GetFaceList().count * sizeof(b3Vec3));
for (qhFace* f = dual.GetFaceList().head; f; f = f->next)
{
b3Plane plane = f->plane;
B3_ASSERT(plane.offset > 0.0f);
b3Vec3 v = plane.normal / plane.offset;
bool unique = true;
for (u32 j = 0; j < pvCount; ++j)
{
if (b3DistanceSquared(v, pvs[j]) <= B3_LINEAR_SLOP * B3_LINEAR_SLOP)
{ {
unique = false; dfs[dvCount] = f;
break; dvs[dvCount] = v;
++dvCount;
} }
} }
if (unique) b3Free(dfs);
if (dvCount < 4)
{ {
pvs[pvCount++] = v; b3Free(dvs);
return;
} }
}
if (pvCount < 4) qhHull dual;
{ dual.Construct(dvs, dvCount);
b3Free(dvs);
// Recover the simplified hull in primary space.
u32 pvCount = 0;
b3Vec3* pvs = (b3Vec3*)b3Alloc(dual.GetFaceList().count * sizeof(b3Vec3));
for (qhFace* f = dual.GetFaceList().head; f; f = f->next)
{
b3Plane plane = f->plane;
B3_ASSERT(plane.offset > 0.0f);
b3Vec3 v = plane.normal / plane.offset;
bool unique = true;
for (u32 j = 0; j < pvCount; ++j)
{
if (b3DistanceSquared(v, pvs[j]) <= B3_LINEAR_SLOP * B3_LINEAR_SLOP)
{
unique = false;
break;
}
}
if (unique)
{
pvs[pvCount++] = v;
}
}
if (pvCount < 4)
{
b3Free(pvs);
return;
}
hull.Construct(pvs, pvCount);
b3Free(pvs); b3Free(pvs);
return;
// Translate the hull back to the origin
hull.Translate(s);
}
else
{
hull.Construct(ps, psCount);
b3Free(ps);
} }
qhHull hull;
hull.Construct(pvs, pvCount);
b3Free(pvs);
// Translate the hull back to the origin
hull.Translate(s);
#else
qhHull hull;
hull.Construct(ps, psCount);
b3Free(ps);
#endif
if (hull.GetVertexList().count > B3_MAX_HULL_VERTICES) if (hull.GetVertexList().count > B3_MAX_HULL_VERTICES)
{ {
// Vertex excess // Vertex excess
@ -464,7 +458,7 @@ void b3QHull::SetAsCylinder(float32 radius, float32 height)
} }
// Set // Set
Set(vs, count); Set(vs, count, false);
} }
void b3QHull::SetAsCone(float32 radius, float32 height) void b3QHull::SetAsCone(float32 radius, float32 height)
@ -499,5 +493,5 @@ void b3QHull::SetAsCone(float32 radius, float32 height)
vs[count++].Set(0.0f, height, 0.0f); vs[count++].Set(0.0f, height, 0.0f);
// Set // Set
Set(vs, count); Set(vs, count, false);
} }