นี่คือโค้ด Line vs AABB ที่ฉันใช้:
namespace {
//Helper function for Line/AABB test. Tests collision on a single dimension
//Param: Start of line, Direction/length of line,
// Min value of AABB on plane, Max value of AABB on plane
// Enter and Exit "timestamps" of intersection (OUT)
//Return: True if there is overlap between Line and AABB, False otherwise
//Note: Enter and Exit are used for calculations and are only updated in case of intersection
bool Line_AABB_1d(float start, float dir, float min, float max, float& enter, float& exit)
{
//If the line segment is more of a point, just check if it's within the segment
if(fabs(dir) < 1.0E-8)
return (start >= min && start <= max);
//Find if the lines overlap
float ooDir = 1.0f / dir;
float t0 = (min - start) * ooDir;
float t1 = (max - start) * ooDir;
//Make sure t0 is the "first" of the intersections
if(t0 > t1)
Math::Swap(t0, t1);
//Check if intervals are disjoint
if(t0 > exit || t1 < enter)
return false;
//Reduce interval based on intersection
if(t0 > enter)
enter = t0;
if(t1 < exit)
exit = t1;
return true;
}
}
//Check collision between a line segment and an AABB
//Param: Start point of line segement, End point of line segment,
// One corner of AABB, opposite corner of AABB,
// Location where line hits the AABB (OUT)
//Return: True if a collision occurs, False otherwise
//Note: If no collision occurs, OUT param is not reassigned and is not considered useable
bool CollisionDetection::Line_AABB(const Vector3D& s, const Vector3D& e, const Vector3D& min, const Vector3D& max, Vector3D& hitPoint)
{
float enter = 0.0f;
float exit = 1.0f;
Vector3D dir = e - s;
//Check each dimension of Line/AABB for intersection
if(!Line_AABB_1d(s.x, dir.x, min.x, max.x, enter, exit))
return false;
if(!Line_AABB_1d(s.y, dir.y, min.y, max.y, enter, exit))
return false;
if(!Line_AABB_1d(s.z, dir.z, min.z, max.z, enter, exit))
return false;
//If there is intersection on all dimensions, report that point
hitPoint = s + dir * enter;
return true;
}