29. OpenGL Bounding Sphere Collision (Version 2.0)
Introduction
Collision detection is a fundamental part of any game or simulation. Without it, you wouldn’t know when two objects interact or collide, such as when a player hits a wall or picks up an item. One simple and efficient way to detect collisions in OpenGL is by using **bounding spheres**.
A bounding sphere is a spherical boundary that surrounds an object. By calculating the distance between the centers of two bounding spheres and comparing it to the sum of their radii, we can determine if a collision has occurred.
In this tutorial, we’ll learn how to implement bounding sphere collision detection, visualize the collision response with color changes, and allow real-time object movement using keyboard controls.
Understanding Bounding Spheres
A bounding sphere is defined by:
- The center of the sphere (x, y, z coordinates).
- The radius, which determines the size of the sphere.
The collision detection works as follows:
1. Calculate the distance between the centers of two spheres.
2. Compare this distance to the sum of their radii.
3. If the distance is less than or equal to the sum of the radii, a collision is occurring.
Calculating Distance Between Two Points
The formula to calculate the distance between two points in 3D space is:
This formula is the foundation of our collision detection logic.
Collision Detection Logic
We’ll use the above formula to calculate the distance between two spheres. Then, we compare it with the sum of their radii:
void collision(void) { d = sqrt(((p1x - p2x) * (p1x - p2x)) + ((p1y - p2y) * (p1y - p2y)) + ((p1z - p2z) * (p1z - p2z))); }
If a collision occurs, the distance between the two centers will satisfy:
Visualizing the Collision
To make collisions visible, we’ll change the color of the spheres:
- Red: Collision detected.
- Blue: No collision.
Here’s how we define the color logic:
void pointz(void) { glPushMatrix(); if (d <= p2radius + p1radius) { glColor3f(1, 0, 0); // Red for collision } else { glColor3f(0, 0, 1); // Blue for no collision } glBegin(GL_POINTS); glVertex3f(p1x, p1y, p1z); // Draw point 1 glEnd(); glPopMatrix(); glPushMatrix(); glColor3f(0, 1, 0); // Green for point 2 glBegin(GL_POINTS); glVertex3f(p2x, p2y, p2z); // Draw point 2 glEnd(); glPopMatrix(); }
Adding Movement Controls
To test the collision detection, we’ll allow the user to move the spheres using keyboard input:
void keyboard(unsigned char key, int x, int y) { // Move sphere 1 if (key == 'q') { p1z -= 0.1; } if (key == 'z') { p1z += 0.1; } if (key == 'w') { p1y += 0.1; } if (key == 's') { p1y -= 0.1; } if (key == 'a') { p1x -= 0.1; } if (key == 'd') { p1x += 0.1; } // Move sphere 2 if (key == 'i') { p2y += 0.1; } if (key == 'k') { p2y -= 0.1; } if (key == 'j') { p2x -= 0.1; } if (key == 'l') { p2x += 0.1; } // Exit program if (key == 27) { exit(0); } // ESC key }
Tutorial Code
Here’s the complete implementation of the bounding sphere collision detection:
#include <GL/gl.h> #include <GL/glut.h> #include <cmath> // Variables for positions, radius, and distance GLfloat d; GLfloat p1x = 0.0, p1y = 0.0, p1z = 0.0; // Point 1 position GLfloat p2x = 2.0, p2y = 0.0, p2z = 0.0; // Point 2 position const GLfloat p1radius = 1.0; const GLfloat p2radius = 0.5; // Calculate the distance between two points void collision(void) { d = sqrt(((p1x - p2x) * (p1x - p2x)) + ((p1y - p2y) * (p1y - p2y)) + ((p1z - p2z) * (p1z - p2z))); } // Render the points and their collision status void pointz(void) { glPushMatrix(); if (d <= p2radius + p1radius) { glColor3f(1, 0, 0); // Collision (red) } else { glColor3f(0, 0, 1); // No collision (blue) } glBegin(GL_POINTS); glVertex3f(p1x, p1y, p1z); // Point 1 glEnd(); glPopMatrix(); glPushMatrix(); glColor3f(0, 1, 0); // Point 2 (green) glBegin(GL_POINTS); glVertex3f(p2x, p2y, p2z); glEnd(); glPopMatrix(); } // Display callback void display(void) { glClearColor(0.0, 0.0, 0.0, 1.0); // Black background glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glPointSize(5); // Set point size collision(); // Check for collisions pointz(); // Render points glutSwapBuffers(); } // Reshape callback void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); glMatrixMode(GL_MODELVIEW); } // Main function int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow("Bounding Sphere Collision"); glutDisplayFunc(display); glutIdleFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); // Handle keyboard input glutMainLoop(); return 0; }
If you have any questions, feel free to email me at swiftless@gmail.com. Happy coding!
how come i had to #define p1radius 1
#define p2radius 0
const p1radius = 1 etc…
would not work
HI…
I am new to the whole idea of cording…..
But your tutes are helping a lot in OPENgl…. would be great if you can add video tutes too…
Thanks alot….
hello there. ive been using ur collision code but somehow it only works properly when the other sphere is at x:0 , z:0. here is my collision code, i dont see anything wrong with it!
bool collide::collision(float x1, float z1, float radius1, float x2, float z2, float radius2)
{
distance = sqrt(((x1 – x2) * (x1 – x2)) + ((z1 – z2) * (z1 – z2)));
if (distance < (radius1 + radius2))
{
cout << distance << endl;
return true;
}
else
{
return false;
}
}
WONDERFUL TUTORIAL!!! – THANK YOU.
I’m new to OpenGL, and your bounding sphere collision is *exactly* what I googled, and found here, and employed in my own project,…and it worked flawlessly with minimal effort on my end.
Bravo to you and all the hard work you’ve done in getting these tutorials up as_they_are.
Thank you.
Thank you.
Thank you.
-kropcke
Hey dude,
i appreciate your effort, but nevertheless, after reading through the tutorial i have to say, it’s trivial … who should consider it a problem to test 2 points via a radius for collision.
for me, this is another of those, wannabe explanatory tutorials that mislead searches for the real meat.
Hi Lemonade,
Of course it’s trivial, but it is a widely used form of collision in both 2D and 3D and for someone who has never used collision algorithms before, this one is easy for them to pick up. I really don’t see where the misleading comes from, the title says exactly what the tutorial covers. What were you searching for that lead to any confusion?
Thanks,
Swiftless
It’s almost impossible to read this code when the ad next to the line numbers makes it only 3 characters per line..
Hi Josh,
I’ve had a couple of reports of this since the new theme has kicked in, I’ll be either removing the ads on the pages messing up, or making them WordPress friendly shortly.
Sorry for any inconvenience.
Swiftless
Can you make a tutorial on AABB collision detection ?
Hi Dorekofu_87,
If I get a chance, I will see what I can do 🙂
Cheers,
Swiftless
distance between two points…simple but powerful!!!!
how do wuould i approximate say asphere to a cube correctly?
Hey Hotcoffee Bennett,
When you say approximate, what do you mean exactly?
If you want to find a sphere that covers an entire cube, the radius of the sphere should be the distance between the centre of the cube and one of the edges.
Cheers,
Swiftless
Pictures would make this even better
Hi Philip, I hope I understood you good, but what you want to know, is how to know where you are looking at some point of the rendering? are you using glLookAt ? if yes, then from the 4th to the 6th value are the LookAt X,Y,Z respectively, if not, then you are using glRotatef -> in this case I don’t really know how to apply, I guess doing some Sin/Cos will be enough, they way to “shoot” in straight line, can be done by using some geometry -> something like Ray Tracing, the definition of a Ray is; r(t) = o + td, where “o” is the origin (your actual position) and t is the direction you are looking at, “d” is the direction vector (where you are looking at), and t is the scalar, t means how many times is multiplied the direction, for example your origin is 0,0,0 and d is 1,0,0, that means that you are looking at the x axis and the ray distance at x is 1, but if t is 2, then you are looking at x=2, if t<0 that means the point is behind the ray, "d" should be normalized, so "t" we can say is a distance unit, which shows how far is the point from the origin 😉
The easiest collision detection is doing ray-sphere and ray-triangle , I think ray-plane is easy too, but I have code it yet (in my life)
@Donald: sorry man, I have some troubles with my thesis, and I will need more time, before we can start the video-youtube-thing, I hope all is fine hehe! 😉
Hi Donald
How do you determine which direction is away from the camera or which way it is looking
Hi Phillip,
That sounds like a great start, a sphere-plane intersection would work, but you only really need a ray-plane intersection for this. The ray being a vector that shoots from the camera, in the direction the camera is facing.
You’re plane should not need bounds, as it should only be generated as soon as you hit the sphere, and should only last for as long as it takes to calculate the next position to move to.
Cheers,
Swiftless
Hello
I have managed to do a sphere(camera) plane(wall) test, but the trouble is the plane is infinate, it detects when i hit the wall and when i try to go around it. How can i set bounds to the plane (wall) without making the wall axis alligned.
Hi Phillip,
For this kind of interaction, you are going to have to do a bit more maths. Given we know the centre of the sphere, the size of the radius, and the point on the surface where the collision occurs, you are going to have to calculate the surface normal for this point on the sphere.
Using the surface normal, you can calculate the angle between the direction your object is moving, and the surface normal of the sphere, and with that angle you can then determine if you want to stop or ‘slide’ to another position.
Cheers,
Swiftless
Using the bounding sphere equation, when i detect the collsion i set the camera position to the last position but all this does is bounce off the object and is very jerky. How can i hit the object and slide around or stop dead if your square to the object.
Ooops, rewrote it wrong was supposed to be:
distance = sqrt(((heroX – Object[i].Xpos) * (heroX – Object[i].Xpos)) + ((heroY – Object[i].Ypos) * (heroY – Object[i].Ypos))
+ ((heroZ – Object[i].Zpos) * (heroZ – Object[i].Zpos)));
Thanks,
I was trying to pass object details into the array and then push the array values into the equation.
distance = sqrt(((hero – Object[i].Xpos) * (hero – Object[i].Xpos)) + ((hero – Object[i].Ypos) * (hero – Object[i].Ypos))
+ ((hero – Object[i].Zpos) * (hero – Object[i].Zpos)));
It didn’t seem to work. I will try the true/false boolean, hopefully i will make this work one way or another.
Hi,
I was wondering, how would you go about adapting bounding sphere collision system for multiple objects. Cant wrap my head around it, how to keep track of multiple objects without hardcoding them all in.
Any ideas?
Hi E_Nuclear,
I have had this question asked to me before via email, and this is the response I gave:
To have it go over a group of objects, try something like this:
// First change the collision method to return true or false, and to accept 3 parameters, the two objects, and the radius of the bounding sphere
bool collision (object a, object b, float radius) {
float d = sqrt(((a.x – b.x) * (a.x – b.x)) + ((a.y – b.y) * (a.y – b.y)) + ((a.z – b.z) * (a.z – b.z)));
if (d <= radius) {
return true;
}
return false;
}
// And then, you will need to call it (probably in a loop is easiest)
for (int i = 0; i < objects; i++) {
for (int j = 0; j < objects; j++) {
if (collision(object[i], object[j], 5.0f)) {
// Do collision code
}
}
}
This assumes you have one list of objects, each with an x, y and z position. And it also assumes that you want to check if any object has collided with any other object.
Hope this helps,
Swiftless
Hi once again,
Isn’t that bothers me, but is actually a number 2 (Two) in E2A instead of Z 😛 It really wouldn’t bother me at all just because Eza sounds like a girl’s name 😛 and beside that, if you want I can make the vids for you 🙂 if you have a logo and so on, it can be like a cooler vid, I’m a lil’ into postproduction so if you would like just let me know, you got my mail, so just write to me 😉
Hi D,
I got an idea, what about if you do like a video (recording) of how the code looks in action? you know it doesn’t have to be in your site the flash file (uploading it at youtube, for bandwidth consume avoidance of course 🙂 )
Hi E2A (Sorry),
Believe it or not, I was thinking of video versions of the tutorials just last night.
I’m going to see if I have time for this after I finish rewriting most of the tutorials, but I can definitely fit in videos of the end result of the code.
Thanks for the suggestion,
Swiftless