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.