bool MFCollision_PlaneTriTest(const MFVector& plane, const MFVector& p0, const MFVector& p1, const MFVector& p2, MFVector *pIntersectionPoint) { float t0 = p0.DotH(plane); float t1 = p1.DotH(plane); float t2 = p2.DotH(plane); if(t0 <= 0.0f && t1 <= 0.0f && t2 <= 0) return false; if(t0 >= 0.0f && t1 >= 0.0f && t2 >= 0) return false; if(pIntersectionPoint) { // TODO: calculate point } return true; }
bool MFCollision_SpherePlaneTest(const MFVector& spherePos, float radius, const MFVector& plane, MFCollisionResult *pResult) { if(!pResult) { return spherePos.DotH(plane) < radius; } else { float d = spherePos.DotH(plane); pResult->bCollide = d < radius; if(pResult->bCollide) { pResult->depth = radius - d; pResult->normal = plane; pResult->intersectionPoint.Mad3(pResult->normal, -(d + pResult->depth*0.5f), spherePos); } return pResult->bCollide; } }
bool MFCollision_RaySlabTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& plane, float slabHalfWidth, MFRayIntersectionResult *pResult) { float a = plane.Dot3(rayDir); // if ray is parallel to plane if(a > -MFALMOST_ZERO && a < MFALMOST_ZERO) { // TODO: this is intentionally BROKEN // this is a near impossible case, and it adds a lot of junk to the function /* if(MFAbs(rayPos.DotH(plane)) <= slabHalfWidth) { if(pResult) { pResult->time = 0.0f; } return true; } */ return false; } // otherwise we can do the conventional test float inva = MFRcp(a); float t = -rayPos.DotH(plane); float t1 = (t + slabHalfWidth) * inva; float t2 = (t - slabHalfWidth) * inva; t = MFMin(t1, t2); t2 = MFMax(t1, t2); if(t > 1.0f || t2 < 0.0f) return false; if(pResult) { pResult->time = MFMax(t, 0.0f); pResult->surfaceNormal = a > 0.0f ? -plane : plane; } return true; }
bool MFCollision_SweepSphereTriTest(const MFVector &sweepSpherePos, const MFVector &sweepSphereVelocity, float sweepSphereRadius, const MFCollisionTriangle &tri, MFSweepSphereResult *pResult) { MFRayIntersectionResult result; // test the triangle surface if(!MFCollision_RaySlabTest(sweepSpherePos, sweepSphereVelocity, tri.plane, sweepSphereRadius, &result)) return false; MFVector intersection = sweepSpherePos + sweepSphereVelocity * result.time; // test if intersection is inside the triangle float dot0, dot1, dot2; dot0 = intersection.DotH(tri.edgePlanes[0]); // if(dot0 > sphereRadius) // return false; dot1 = intersection.DotH(tri.edgePlanes[1]); // if(dot1 > sphereRadius) // return false; dot2 = intersection.DotH(tri.edgePlanes[2]); // if(dot2 > sphereRadius) // return false; // test if intersection is inside the triangle face if(dot0 >= 0.0f && dot1 >= 0.0f && dot2 >= 0.0f) goto collision; // test the 3 edges if(dot0 < 0.0f) { if(MFCollision_RayCapsuleTest(sweepSpherePos, sweepSphereVelocity, tri.verts[0], tri.verts[1]-tri.verts[0], sweepSphereRadius, &result)) goto collision; } if(dot1 < 0.0f) { if(MFCollision_RayCapsuleTest(sweepSpherePos, sweepSphereVelocity, tri.verts[1], tri.verts[2]-tri.verts[1], sweepSphereRadius, &result)) goto collision; } if(dot2 < 0.0f) { if(MFCollision_RayCapsuleTest(sweepSpherePos, sweepSphereVelocity, tri.verts[2], tri.verts[0]-tri.verts[2], sweepSphereRadius, &result)) goto collision; } return false; collision: if(result.time == 0.0f) { // this is for double sided collision. float dot = sweepSpherePos.DotH(tri.plane); float amountResolve = sweepSphereRadius - MFAbs(dot); pResult->intersectionReaction = result.surfaceNormal * amountResolve; } else pResult->intersectionReaction = MFVector::zero; pResult->surfaceNormal = result.surfaceNormal; pResult->time = result.time; return true; }