29. OpenGL Bounding Sphere Collision
not even be able to tell if there was a wall in front of you. So here
I am going to show you how to use bounding spheres.
Bounding spheres are like a sphere that radiates from your chosen point
and radiates to the distance in which you set as the radius of your
sphere.
A bigger sphere has a bigger radius. Therefore, objects can’t come as
close as with a smaller sphere.
Now first, we need to set some variables to be able to hold our points
locations and the size of their radii.
This will hold the distance between our objects
GLfloat d;
This will hold the x,y and z positions for our first point
GLfloat p1x;
GLfloat p1y;
GLfloat p1z;
This will hold the size of the radii for the 2 points
point 1 has a radius of 1, and point 2 has a radius of 0, there point 2
will act just like a point, while point 1 will act like a sphere
const p1radius = 1;
const p2radius = 0;
This will hold the x,y and z poisitions for our second point
GLfloat p2x;
GLfloat p2y;
GLfloat p2z;
Now for the guts of this tutorial, working out the collision
void collision (void) {
Our distance is worked out with this simple little formula.
d = sqrt(((p1x – p2x) * (p1x – p2x)) + ((p1y – p2y) * (p1y – p2y)) + ((p1z – p2z) * (p1z – p2z)));
}
Technically you could write it as:
d = sqrt(((p1x – p2x)^2) + ((p1y – p2y)^2) + ((p1z – p2z)^2));
But it is just a matter of preference.
Now to draw the points.
void pointz (void) {
glPushMatrix();
If the distance between the 2 points, is less than that of there radii
combined, then there is a collision
if (d <= p2radius + p1radius)
{
Set the color of our first point to red
glColor3f(1, 0, 0);
}
else
{
If not, then set it to blue
glColor3f(0, 0, 1);
}
Begin drawing the point
glBegin(GL_POINTS);
Draw it at its x,y and z position
glVertex3f(p1x, p1y, p1z);
glEnd();
glPopMatrix();
glPushMatrix();
Set the color of our first point to green
glColor3f(0, 1, 0);
Begin drawing the point
glBegin(GL_POINTS);
Draw it at its x,y and z position
glVertex3f(p2x, p2y, p2z);
glEnd();
glPopMatrix();
}
Now this is just to show you that it works, we are moving the points around
with the following keys.
void keyboard (unsigned char key, int x, int y) {
if (key==’q’) {
p1z = p1z – 0.1;
}
if (key==’z’) {
p1z = p1z + 0.1;
}
if (key==’w’) {
p1y = p1y + 0.1;
}
if (key==’s’) {
p1y = p1y – 0.1;
}
if (key==’a’) {
p1x = p1x – 0.1;
}
if (key==’d’) {
p1x = p1x + 0.1;
}
if (key==’i’) {
p2y = p2y + 0.1;
}
if (key==’k’) {
p2y = p2y – 0.1;
}
if (key==’j’) {
p2x = p2x – 0.1;
}
if (key==’l’) {
p2x = p2x + 0.1;
}
If you have any problems with this tutorial, please email me at swiftless@gmail.com
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. |
#include <GL/gl.h> #include <GL/glut.h> #include <math.h> GLfloat d; GLfloat p1x; const p1radius = 1; GLfloat p2x; void collision (void) { void pointz (void) { glPushMatrix(); void display (void) { void reshape (int w, int h) {
void keyboard (unsigned char key, int x, int y) { if (key==‘z’) { if (key==‘w’) { if (key==‘s’) { if (key==‘a’) { if (key==‘d’) { if (key==‘i’) { if (key==‘k’) { if (key==‘j’) { if (key==‘l’) { if (key==27) { //27 is the ascii code for the ESC key int main (int argc, char **argv) { |
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