// Intersect AABBs ‘a’ and ‘b’ moving with constant velocities va and vb. // On intersection, return time of first and last contact in tfirst and tlast public static bool IntersectMovingAABBAABB(AABB a, AABB b, LVector3 va, LVector3 vb, out LFloat tfirst, out LFloat tlast) { // Exit early if ‘a’ and ‘b’ initially overlapping if (TestAABBAABB(a, b)) { tfirst = tlast = LFloat.zero; return(true); } // Use relative velocity; effectively treating 'a' as stationary LVector3 v = vb - va; // Initialize times of first and last contact tfirst = LFloat.zero; tlast = LFloat.one; // For each axis, determine times of first and last contact, if any for (int i = 0; i < 3; i++) { if (v[i] < LFloat.zero) { if (b.max[i] < a.min[i]) { return(false); // Nonintersecting and moving apart } if (a.max[i] < b.min[i]) { tfirst = Max((a.max[i] - b.min[i]) / v[i], tfirst); } if (b.max[i] > a.min[i]) { tlast = Min((a.min[i] - b.max[i]) / v[i], tlast); } } if (v [i] > LFloat.zero) { if (b.min[i] > a.max[i]) { return(false); // Nonintersecting and moving apart } if (b.max[i] < a.min[i]) { tfirst = Max((a.min[i] - b.max[i]) / v[i], tfirst); } if (a.max[i] > b.min[i]) { tlast = Min((a.max[i] - b.min[i]) / v[i], tlast); } } // No overlap possible if time of first contact occurs after time of last contact if (tfirst > tlast) { return(false); } } return(true); }
public static bool IntersectMovingSphereAABB(Sphere s, LVector3 d, AABB b, out LFloat t) { // Compute the AABB resulting from expanding b by sphere radius r AABB e = b; int _val = s.r._val; e.min._x -= _val; e.min._y -= _val; e.min._z -= _val; e.max._x += _val; e.max._y += _val; e.max._z += _val; // Intersect ray against expanded AABB e. Exit with no intersection if ray // misses e, else get intersection point p and time t as result LVector3 p; if (!IntersectRayAABB(s.c, d, e, out t, out p) || t > LFloat.one) { return(false); } // Compute which min and max faces of b the intersection point p lies // outside of. Note, u and v cannot have the same bits set and // they must have at least one bit set amongst them int u = 0, v = 0; if (p.x < b.min.x) { u |= 1; } if (p.x > b.max.x) { v |= 1; } if (p.y < b.min.y) { u |= 2; } if (p.y > b.max.y) { v |= 2; } if (p.z < b.min.z) { u |= 4; } if (p.z > b.max.z) { v |= 4; } // ‘Or’ all set bits together into a bit mask (note: here u + v == u | v) int m = u + v; // Define line segment [c, c+d] specified by the sphere movement Segment seg = new Segment(s.c, s.c + d); // If all 3 bits set (m == 7) then p is in a vertex region if (m == 7) { // Must now intersect segment [c, c+d] against the capsules of the three // edges meeting at the vertex and return the best time, if one or more hit LFloat tmin = LFloat.FLT_MAX; if (IntersectSegmentCapsule(seg, Corner(b, v), Corner(b, v ^ 1), s.r, out t)) { tmin = Min(t, tmin); } if (IntersectSegmentCapsule(seg, Corner(b, v), Corner(b, v ^ 2), s.r, out t)) { tmin = Min(t, tmin); } if (IntersectSegmentCapsule(seg, Corner(b, v), Corner(b, v ^ 4), s.r, out t)) { tmin = Min(t, tmin); } if (tmin == LFloat.FLT_MAX) { return(false); // No intersection } t = tmin; return(true); // Intersection at time t == tmin } // If only one bit set in m, then p is in a face region if ((m & (m - 1)) == 0) { // Do nothing. Time t from intersection with // expanded box is correct intersection time return(true); } // p is in an edge region. Intersect against the capsule at the edge return(IntersectSegmentCapsule(seg, Corner(b, u ^ 7), Corner(b, v), s.r, out t)); }