bool BasicPrimitiveTests::IntersectingRayAgainstAABB(const Ray & ray, const AABB & aabb, float & rtn_t) { /* Main Idea: -> Uses slab representation for box. -> Finds intersection of ray/segment with each slab. Then compares intersection times for overlap in all slabs. -> Keep track of: -> A: The farthest of all entries into a slab -> B: The closest of all exits out of a slab. -> If A > B at anytime, exit with no intersection. Intersecting slabs: -> Intersect slabs by inserting ray equation into plane equations for slab. -> Solve for t -> Must handle case when ray parallel to slab separately. -> To avoid division by zero. Can test for intersection without calculating intersection point: -> Choose coordinate system where box is axis aligned and centered at origin: AABB: -> Translate segment and AABB to origin. OBB: -> Transform Segment to OBB space, then translate both segment and OBB to origin. -> Do separating axis test with 6 axes: -> Three principle axes. -> Three cross products of box face normals and segment direction vector. */ rtn_t = 0.0f; float tmax = FLT_MAX; Eigen::Vector3f aabb_min = aabb.GetCenter() - aabb.GetExtents(); Eigen::Vector3f aabb_max = aabb.GetCenter() + aabb.GetExtents(); for (int i = 0; i < 3; ++i) { if (abs(ray.GetDirection()[i]) < EPSILON) { //Ray is parallel to slab. Not hit if origin not within slab. if (ray.GetOrigin()[i] < aabb_min[i] || ray.GetOrigin()[i] > aabb_max[i]) { return false; } } else { float one_over_direction = 1.0f / ray.GetDirection()[i]; float t1 = (aabb_min[i] - ray.GetOrigin()[i]) * one_over_direction; float t2 = (aabb_max[i] - ray.GetOrigin()[i]) * one_over_direction; if (t1 > t2) Swap(t1, t2); if (t1 > rtn_t) rtn_t = t1; if (t2 > tmax) tmax = t2; if (rtn_t > tmax) return false; } } return true; }
int BasicPrimitiveTests::IntersectingSegmentAgainstAABB(const LineSegment & segment, const AABB & aabb, float & rtn_t1, float & rtn_t2) { rtn_t1 = 0.0f; rtn_t2 = FLT_MAX; Eigen::Vector3f aabb_min = aabb.GetCenter() - aabb.GetExtents(); Eigen::Vector3f aabb_max = aabb.GetCenter() + aabb.GetExtents(); Eigen::Vector3f segment_direction = segment.GetPointB() - segment.GetPointA(); for (int i = 0; i < 3; ++i) { if (abs(segment_direction[i]) < EPSILON) { //Ray is parallel to slab. Not hit if origin not within slab. if (segment.GetPointA()[i] < aabb_min[i] || segment.GetPointA()[i] > aabb_max[i]) { return 0; } } else { float one_over_direction = 1.0f / segment_direction[i]; float t1 = (aabb_min[i] - segment.GetPointA()[i]) * one_over_direction; float t2 = (aabb_max[i] - segment.GetPointA()[i]) * one_over_direction; if (t1 > 1.0f && t2 > 1.0f) { return 0; } if (t1 > t2) Swap(t1, t2); if (t1 > rtn_t1) rtn_t1 = t1; if (t2 > rtn_t2) rtn_t2 = t2; if (rtn_t1 > rtn_t2) return 0; } } if (rtn_t1 >= 0.0f && rtn_t1 <= 1.0f) { if (rtn_t2 >= 0.0f && rtn_t2 <= 1.0f) { return 2; } else { return 1; } } else { Swap(rtn_t1, rtn_t2); if (rtn_t1 >= 0.0f && rtn_t1 <= 1.0f) { return 1; } return 0; } }
void OBB::Create(const AABB& aabb, const Matrix4x4& mat) { // Note: must be coherent with Rotate() aabb.GetCenter(mCenter); aabb.GetExtents(mExtents); // Here we have the same as OBB::Rotate(mat) where the obb is (mCenter, mExtents, Identity). // So following what's done in Rotate: // - x-form the center mCenter *= mat; // - combine rotation with identity, i.e. just use given matrix mRot = mat; }