Jump to content
  • Advertisement
Sign in to follow this  
kosmon_x

Is this the simplest Sphere-AABB collision test?

This topic is 4771 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey all, After trying -numerous- possible solutions (most of which didn't work), I finally came up with this to detect a collision between a sphere and an axis aligned bounding box (AABB). The sphere is defined by a center and a radius, and the AABB is defined by a minimum and maxiumum point:
// First, compute the distance between the centers 
Vec3 SepAxis = Sphere.Center - AABB.Center;
float Dist = Vec3Length( SepAxis );

// then, find the unit vector that points from the box center to the sphere center
Vec3Normalize( SepAxis );

// divide each component of the unit vector by the maximum component, effectively "normalizing" the unit vector
if( SepAxis.x >= SepAxis.y && SepAxis.x >= SepAxis.z )
  SepAxis /= SepAxis.x;
else if( SepAxis.y >= SepAxis.x && SepAxis.y >= SepAxis.z )
  SepAxis /= SepAxis.y;
else
  SepAxis /= SepAxis.z;

// Now, find the effective radius of the box along the "normalized" unit vector pointing to the sphere
SepAxis.x *= Box.GetWidth() / 2.0f;
SepAxis.y *= Box.GetHeight() / 2.0f;
SepAxis.z *= Box.GetLength() / 2.0f;

// Finally, add the sphere radius to the box radius and compare to the distance
if( Dist <= (Sphere.Radius + Vec3Length( SepAxis ) )
  Collision true!
else
  Collision false
	





Where the box width is defined as Max.x - Min.x, height is Max.y - Min.y, and length is Max.z - Min.z. This seems to work with some preliminary testing. Is this the most efficient way to perform such a collision check? How does everyone else do it?

Share this post


Link to post
Share on other sites
Advertisement
I didn't really follow what you do but an easy way for non a continous test is to clamp the sphere center to the AABB boundaries. You get the closest point from AABB to sphere. From there it's rather easy to find if they collide or not.

Share this post


Link to post
Share on other sites
Hmm, looks reasonable enough. Can't say for sure wether it would work just from a quick read of it, but if it does, it does.

Here's my sphere-AABB test. It's a bit longer, but doesn't have any square roots or divides.

The idea behind it is to look at each of the 3 axes of the box individually to find the closest point on the box to the center of the sphere. Then it's just a distance check.

// Get the center of the sphere relative to the center of the box
Vec3 sphereCenterRelBox = Sphere.center - Box.center;
// Point on surface of box that is closest to the center of the sphere
Vec3 boxPoint;

// Check sphere center against box along the X axis alone.
// If the sphere is off past the left edge of the box,
// then the left edge is closest to the sphere.
// Similar if it's past the right edge. If it's between
// the left and right edges, then the sphere's own X
// is closest, because that makes the X distance 0,
// and you can't get much closer than that :)

if (sphereCenterRelBox.x < -Box.GetWidth()/2.0)
boxPoint.x = -Box.GetWidth()/2.0;
else if (sphereCenterRelBox.x > Box.GetWidth()/2.0)
boxPoint.x = Box.GetWidth()/2.0;
else
boxPoint.x = sphereCenterRelBox.x;

// ...same for Y axis
if (sphereCenterRelBox.y < -Box.GetHeight()/2.0)
boxPoint.y = -Box.GetHeight()/2.0;
else if (sphereCenterRelBox.y > Box.GetHeight()/2.0)
boxPoint.y = Box.GetHeight()/2.0;
else
boxPoint.y = sphereCenterRelBox.y;

// ... same for Z axis
if (sphereCenterRelBox.z < -Box.GetLength()/2.0)
boxPoint.z = -Box.GetLength()/2.0;
else if (sphereCenterRelBox.x > Box.GetLength()/2.0)
boxPoint.z = Box.GetLength()/2.0;
else
boxPoint.z = sphereCenterRelBox.z;

// Now we have the closest point on the box, so get the distance from
// that to the sphere center, and see if it's less than the radius

Vec3 dist = sphereCenterRelBox - boxPoint;

if (dist.x*dist.x + dist.y*dist.y + distz*dist.z < Sphere.radius*Sphere.radius)
return true;
else
return false;



EDIT: Dangit, b34r beat me to it and explained my whole function in one sentence...

Share this post


Link to post
Share on other sites
Quote:
Original post by b34r
I didn't really follow what you do but an easy way for non a continous test is to clamp the sphere center to the AABB boundaries. You get the closest point from AABB to sphere. From there it's rather easy to find if they collide or not.


seconded. Although this won't quite work if the sphere centre is inside the box. THen you have to do a special case, and find the cosest face to the sphere centre and use that.

simple code. Although it doesn't check if the sphere centre is inside teh box.


Vector ClosestPointOnAABB(Vector Point, CAABBox xBox)
{
Vector xClosestPoint;
xClosestPoint.x = (Point.x < xBox.Min.x)? xBox.Min.x : (Point.x > xBox.Max.x)? xBox.Max.x : Point.x;
xClosestPoint.y = (Point.y < xBox.Min.y)? xBox.Min.y : (Point.y > xBox.Max.y)? xBox.Max.y : Point.y;
xClosestPoint.z = (Point.z < xBox.Min.z)? xBox.Min.z : (Point.z > xBox.Max.z)? xBox.Max.z : Point.z;

return xClosestPoint;
}

bool Intersect(CSphere xSphere, CAABBox xBox, Vector& xNcoll, float& fDcoll)
{
if(xBox.Contains(xSphere.Centre))
{
// Do special code.
// here, for now don't do a collision, until the centre is
// outside teh box
fDcoll = 0.0f;
xNcoll = Vector(0, 0, 0);
return true;
}

// get closest point on box from sphere centre
Vector xClosest = ClosestPointOnAABB(xSphere.Centre, xBox);

// find the separation
Vector xDiff = xSphere.Centre - xClosest;

// check if points are far enough
float fDistSquared = xDiff.GetLengthSquared();

if (fDistSquared > xSphere.RadiusSquared())
{
return false;
}

float fDist = sqrt(fDistSquared);

// collision depth
fDcoll = xSphere.GetRadius() - fDist;

// normal of collision (going towards the sphere centre)
xNcoll = xDiff / fDist;

return true;
}


Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!