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)); }
// Intersect sphere s0 moving in direction d over time interval t0 <= t <= t1, against // a stationary sphere s1. If found intersecting, return time t of collision public static bool TestMovingSphereSphere(Sphere s0, LVector3 d, LFloat t0, LFloat t1, Sphere s1, out LFloat t) { // Compute sphere bounding motion of s0 during time interval from t0 to t1 Sphere b = new Sphere();//TODO 移除掉new LFloat mid = (t0 + t1) * LFloat.half; b.c = s0.c + d * mid; b.r = (mid - t0) * d.magnitude + s0.r; t = LFloat.zero; // If bounding sphere not overlapping s1, then no collision in this interval if (!TestSphereSphere(b, s1)) { return(false); } // Cannot rule collision out: recurse for more accurate testing. To terminate the // recursion, collision is assumed when time interval becomes sufficiently small if (t1 - t0 < LFloat.INTERVAL_EPSI_LON) { t = t0; return(true); } // Recursively test first half of interval; return collision if detected if (TestMovingSphereSphere(s0, d, t0, mid, s1, out t)) { return(true); } // Recursively test second half of interval return(TestMovingSphereSphere(s0, d, mid, t1, s1, out t)); }