Advertisement

Libraries that handle broadphase + narrowphase

Started by May 06, 2021 01:09 AM
2 comments, last by Programmer71 3 years, 9 months ago

I'm curious if anyone has had a chance to evaluate and compare various collision libraries. I'm not concerned with the library implementing physics, just collision.

Collision objects in my scenes are triangles and simple convex shapes. Moving objects are AABBs, spheres, or just rays. Shape sweeping is nice, and so is thread safety.

I'm using Bullet right now and while it works for everything I need, I wonder if something else is faster for the relative simplicity I need, and want to hear some opinions on other libraries before I go through the trouble of setting up another one.

namespace vml

{

namespace geo3d

{

namespace collisions

{

static int TriangleEllipsoidCollision( const glm::vec3 &pos,

const glm::vec3 &right,

const glm::vec3 &up,

const glm::vec3 &fwd,

const glm::vec3 &ellipsoidradius,

const glm::vec3 &p0, const glm::vec3 &p1, const glm::vec3 &p2,

const glm::vec3 &surfacenormal,

vml::geo3d::collisions::MTV &mtv)

{

// clean mtv

mtv.Distance = 0.0f;

mtv.Normal = glm::vec3(0, 0, 0);

mtv.ContactPoint = glm::vec3(0, 0, 0);

mtv.SurfaceNormal = glm::vec3(0, 0, 0);

mtv.HasContactPoints = false;

// extract rotation matrix

// we need only the rotational part

// thus the matrix is multiplied by the inverse

// scaling factors, also the matrix is

// scaled by the ellipsoid half sizes

float halfxradius = 0.5f * ellipsoidradius.x;

float halfyradius = 0.5f * ellipsoidradius.y;

float halfzradius = 0.5f * ellipsoidradius.z;

// scale parent matrix

float M00 = right.x * halfxradius;

float M01 = right.y * halfxradius;

float M02 = right.z * halfxradius;

float M10 = up.x * halfyradius;

float M11 = up.y * halfyradius;

float M12 = up.z * halfyradius;

float M20 = fwd.x * halfzradius;

float M21 = fwd.y * halfzradius;

float M22 = fwd.z * halfzradius;

// ellipsodi extremal points

// glm::vec3 qa = glm::vec3( M00 + mptr[12], M01 + mptr[13], M02 + mptr[14]);

// glm::vec3 qb = glm::vec3( M10 + mptr[12], M11 + mptr[13], M12 + mptr[14]);

// glm::vec3 qc = glm::vec3( M20 + mptr[12], M21 + mptr[13], M22 + mptr[14]);

// invert rotational matrix

// so the ellipsoid is noa a 1 radius sphere

float det = M00 * M11 * M22 - M00 * M21 * M12 +

M10 * M21 * M02 - M10 * M01 * M22 +

M20 * M01 * M12 - M20 * M11 * M02;

det = 1.0f / det;

float Invmm00 = (M11 * M22 - M21 * M12) * det;

float Invmm01 = (M20 * M12 - M10 * M22) * det;

float Invmm02 = (M10 * M21 - M20 * M11) * det;

float Invmm10 = (M21 * M02 - M01 * M22) * det;

float Invmm11 = (M00 * M22 - M20 * M02) * det;

float Invmm12 = (M20 * M01 - M00 * M21) * det;

float Invmm20 = (M01 * M12 - M02 * M11) * det;

float Invmm21 = (M10 * M02 - M00 * M12) * det;

float Invmm22 = (M00 * M11 - M10 * M01) * det;

// map triangle vertices to sphere space

glm::vec3 ta((p0.x - pos.x)*Invmm00 + (p0.y - pos.y)*Invmm01 + (p0.z - pos.z)*Invmm02,

(p0.x - pos.x)*Invmm10 + (p0.y - pos.y)*Invmm11 + (p0.z - pos.z)*Invmm12,

(p0.x - pos.x)*Invmm20 + (p0.y - pos.y)*Invmm21 + (p0.z - pos.z)*Invmm22);

glm::vec3 tb((p1.x - pos.x)*Invmm00 + (p1.y - pos.y)*Invmm01 + (p1.z - pos.z)*Invmm02,

(p1.x - pos.x)*Invmm10 + (p1.y - pos.y)*Invmm11 + (p1.z - pos.z)*Invmm12,

(p1.x - pos.x)*Invmm20 + (p1.y - pos.y)*Invmm21 + (p1.z - pos.z)*Invmm22);

glm::vec3 tc((p2.x - pos.x)*Invmm00 + (p2.y - pos.y)*Invmm01 + (p2.z - pos.z)*Invmm02,

(p2.x - pos.x)*Invmm10 + (p2.y - pos.y)*Invmm11 + (p2.z - pos.z)*Invmm12,

(p2.x - pos.x)*Invmm20 + (p2.y - pos.y)*Invmm21 + (p2.z - pos.z)*Invmm22);

// find the triangle closest point to 1 radius sphere

glm::vec3 contactpoint = vml::geo3d::distances::ClosestSpherePointToTriangle(glm::vec3(0, 0, 0), ta, tb, tc);

// unmap contact point

glm::vec3 unmappedcontactpoint(contactpoint.x*M00 + contactpoint.y*M10 + contactpoint.z*M20 + pos.x,

contactpoint.x*M01 + contactpoint.y*M11 + contactpoint.z*M21 + pos.y,

contactpoint.x*M02 + contactpoint.y*M12 + contactpoint.z*M22 + pos.z);

// check if there is intersection

float dist = contactpoint.x*contactpoint.x + contactpoint.y*contactpoint.y + contactpoint.z*contactpoint.z;

if (dist < 1+ vml::math::EPSILON)

{

if (dist > -vml::math::EPSILON && dist < vml::math::EPSILON)

return 0;

dist = 1.0f / sqrtf(dist);

glm::vec3 dir((contactpoint.x*M00 + contactpoint.y*M10 + contactpoint.z*M20)*(1-dist),

(contactpoint.x*M01 + contactpoint.y*M11 + contactpoint.z*M21)*(1-dist),

(contactpoint.x*M02 + contactpoint.y*M12 + contactpoint.z*M22)*(1-dist));

float magnitude = dir.x*dir.x + dir.y*dir.y + dir.z*dir.z;

if (magnitude > -vml::math::EPSILON && magnitude < vml::math::EPSILON)

return 0;

magnitude = sqrtf(magnitude);

dir.x /= magnitude;

dir.y /= magnitude;

dir.z /= magnitude;

mtv.Distance = magnitude * 1.01f;

mtv.Normal = dir; // pointing out of sphere center

mtv.SurfaceNormal = surfacenormal;

mtv.ContactPoint = unmappedcontactpoint;

mtv.HasContactPoints = true;

return 1;

}

return 0;

}

///////////////////////////////////////////

} //end of namespace boxes

} // end of geo3d namespace

} // end of vml namespace

hope i pasted code well, I wen to your same route and like every route has its pro and cons, I am working an a game and I faced your vey same problem, even though in the future I plan to add a full fledged physics engine, for the moment I needed a simpler , cleand, and quicker soultion. I coded this ellipsoid - triangle collision detection code and coupled with a broad and narrow phase it works great. for the broad phase I already had an octree data structure, for the narrow phase, each octree node has a regular grid subdivision, for each model I look the octree node(s) it is located, then I trace how many cells it touches , all cells contatin collision triangles , for each triangle the function above is called, collection all mtv(s) . After this final step the minimum Mtv is found and it is evaluated in the collision response final step. It took a while to have the correct math working, us it wisely.

Advertisement

namespace vml

{

namespace geo3d

{

namespace distances

{

/////////////////////////////////////////////////////////////////////////////////////////

// Closest point on sphere to triabgle

static glm::vec3 ClosestSpherePointToTriangle(const glm::vec3 &p, const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c)

{

// Check if P in vertex region outside A

glm::vec3 ab = b - a;

glm::vec3 ac = c - a;

glm::vec3 ap = p - a;

float d1 = glm::dot(ab, ap);

float d2 = glm::dot(ac, ap);

// barycentric coordinates (1,0,0)

if (d1 < 0.0f && d2 < 0.0f) return a;

// Check if P in vertex region outside B

glm::vec3 bp = p - b;

float d3 = glm::dot(ab, bp);

float d4 = glm::dot(ac, bp);

// barycentric coordinates (0,1,0)

if (d3 > 0.0f && d4 < d3) return b;

// Check if P in edge region of AB, if so return projection of P onto AB

float vc = d1 * d4 - d3 * d2;

if (vc < 0.0f && d1 > 0.0f && d3 < 0.0f)

{

float v = d1 / (d1 - d3);

// barycentric coordinates (1-v,v,0)

return a + v * ab;

}

// Check if P in vertex region outside C

glm::vec3 cp = p - c;

float d5 = glm::dot(ab, cp);

float d6 = glm::dot(ac, cp);

// barycentric coordinates (0,0,1)

if (d6 > 0.0f && d5 < d6) return c;

// Check if P in edge region of AC, if so return projection of P onto AC

float vb = d5 * d2 - d1 * d6;

if (vb < 0.0f && d2 > 0.0f && d6 < 0.0f)

{

float w = d2 / (d2 - d6);

// barycentric coordinates (1-w,0,w)

return a + w * ac;

}

// Check if P in edge region of BC, if so return projection of P onto BC

float va = d3 * d6 - d5 * d4;

if (va < 0.0f && (d4 - d3) > 0.0f && (d5 - d6) > 0.0f)

{

float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));

// barycentric coordinates (0,1-w,w)

return b + w * (c - b);

}

// P inside face region. Compute Q through its barycentric coordinates (u,v,w)

float denom = 1.0f / (va + vb + vc);

float v = vb * denom;

float w = vc * denom;

// = u*a + v*b + w*c, u = va * denom = 1.0f - v - w

return a + ab * v + ac * w;

}

} //end of namespace boxes

} // end of geo3d namespace

} // end of vml namespace

Forgot the most important function

This topic is closed to new replies.

Advertisement