/* It all boils down to this. Here is the portion of code that determines collision between a plane and a ray. Lets rexamin the equations of plane and ray: Plane: p * n = -d Where p == point on plane, n == unit normal to plane, d == signed distance to plane Ray: O + tD Where O == origin of ray, t == "time" traveled along ray, D == Direction vector of the ray If we replace 'p' with the equation of ray we get: (O + tD) * n = -d And with a little algerbra for a final answer we get: t = -((n * O) + d) / (n * D) If we treat our ray like a parametric line, we know that when 't' is between 0.0f and 1.0f, then there is a collision with the ray, otherwise, the ray does not collide */ bool CPlane::intersect(const CRay &ray) { // Calculate the denominator // **NOTE** Our ray's direction vector is always normalized, so we must // multiply by the ray's length so we correctly check collision against // the desired portion of the ray float denominator = mNormal * ray.getDir() * ray.getLength(); // If the denominator is greater than or equal to 0.0f, the ray intersects on the backside of // the plane or is collinear to the plane // **NOTE** The "backside" of a plane is defined to be the side of the plane the // plane's normal points away from if(denominator >= 0.0f) return false; // Calculate the numerator float numerator = -((mNormal * ray.getOrigin()) + mDist); // Calculate 't' float t = numerator / denominator; // This return statement reads like: // // if(t < 0.0f || t > 1.0f) // return false; // else // return true; // // We use this shorter notation because it gets rid of the if statement. Branching // is usually a speed hit on x86 architecture which Windows 2000 and XP run on. return (t >= 0.0f && t <= 1.0f); }
/* So lets quickly digest how this algorithm works. First we assume that the origin of the ray is inside of the AABB. If this is true, then we know that the ray MUST collide with AABB because it is contained inside of the AABB. If the origin is not inside of the AABB, then we check to see if the direction the ray is heading is away from the AABB. If it is, then it must NOT collide. Lastly, if the origin is outside of the AABB, and the ray is heading towards the AABB, we use the length of the ray and test to see if there is an intersection. */ bool CAxisAlgnBB::intersect(const CRay &ray) { // Compute the ray delta CVector rayDelta = ray.getDir() * ray.getLength(); // First we check to see if the origin of the ray is // inside the AABB. If it is, the ray intersects the AABB so // we'll return true. We start by assuming the ray origin is // inside the AABB bool inside = true; // This stores the distance from either the min or max (x,y,z) to the ray's // origin (x,y,z) respectively, divided by the length of the ray. The largest // value has the delta time of a possible intersection. float xt, yt, zt; // Test the X component of the ray's origin to see if we are inside or not if(ray.getOrigin().x < mMin.x) { xt = mMin.x - ray.getOrigin().x; if(xt > rayDelta.x) // If the ray is moving away from the AABB, there is no intersection return false; xt /= rayDelta.x; inside = false; } else if(ray.getOrigin().x > mMax.x) { xt = mMax.x - ray.getOrigin().x; if(xt < rayDelta.x) // If the ray is moving away from the AABB, there is no intersection return false; xt /= rayDelta.x; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the x component of the ray // origin is in between, the AABB's left and right side (which reside in the yz plane), // we know we don't have to test those sides so we set this to a negative value. xt = -1.0f; } // Test the X component of the ray's origin to see if we are inside or not if(ray.getOrigin().y < mMin.y) { yt = mMin.y - ray.getOrigin().y; if(yt > rayDelta.y) // If the ray is moving away from the AABB, there is no intersection return false; yt /= rayDelta.y; inside = false; } else if(ray.getOrigin().y > mMax.y) { yt = mMax.y - ray.getOrigin().y; if(yt < rayDelta.y) // If the ray is moving away from the AABB, there is no intersection return false; yt /= rayDelta.y; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the y component of the ray // origin is in between, the AABB's top and bottom side (which reside in the xz plane), // we know we don't have to test those sides so we set this to a negative value. yt = -1.0f; } if(ray.getOrigin().z < mMin.z) { zt = mMin.z - ray.getOrigin().z; if(zt > rayDelta.z) // If the ray is moving away from the AABB, there is no intersection return false; zt /= rayDelta.z; inside = false; } else if(ray.getOrigin().z > mMax.z) { zt = mMax.z - ray.getOrigin().z; if(zt < rayDelta.z) // If the ray is moving away from the AABB, there is no intersection return false; zt /= rayDelta.z; inside = false; } else { // Later on we use the "xt", "yt", and "zt" variables to determine which plane (either // xy, xz, or yz) we may collide with. Since the z component of the ray // origin is in between, the AABB's front and back side (which reside in the xy plane), // we know we don't have to test those sides so we set this to a negative value. zt = -1.0f; } // If the origin inside the AABB if(inside) return true; // The ray intersects the AABB // Otherwise we have some checking to do... // We want to test the AABB planes with largest value out of xt, yt, and zt. So // first we determine which value is the largest. float t = xt; if(yt > t) t = yt; if(zt > t) t = zt; // **NOTE** Normally comparing two floating point numbers won't necessarily work, however, // since we set to explicitly to equal either xt, yt, or zt above, the equality test // will pass if(t == xt) // If the ray intersects with the AABB's YZ plane { // Compute intersection values float y = ray.getOrigin().y + rayDelta.y * t; float z = ray.getOrigin().z + rayDelta.z * t; // Test to see if collision takes place within the bounds of the AABB if(y < mMin.y || y > mMax.y) return false; else if(z < mMin.z || z > mMax.z) return false; } else if(t == yt) // Intersects with the XZ plane { // Compute intersection values float x = ray.getOrigin().x + rayDelta.x * t; float z = ray.getOrigin().z + rayDelta.z * t; // Test to see if collision takes place within the bounds of the AABB if(x < mMin.x || x > mMax.x) return false; else if(z < mMin.z || z > mMax.z) return false; } else // Intersects with the XY plane { assert(t == zt); // Compute intersection values float x = ray.getOrigin().x + rayDelta.x * t; float y = ray.getOrigin().y + rayDelta.y * t; // Test to see if collision takes place within the bounds of the AABB if(x < mMin.x || x > mMax.x) return false; else if(y < mMin.y || y > mMax.y) return false; } // The ray intersects the AABB return true; }