Sign in to follow this  

Cube-Cube collision detection

This topic is 2291 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

Hi.

Im currently writing an FPS. I allready have a working level and collisions between the player and the floor/walls work fine. I Test the players collision box with the floors/walls collision boxes using this simple logic.

[code]
boolean valueInRange(float value, float min, float max)
{ return (value >= min) && (value <= max); }

boolean rectOverlap(Rect A, Rect B)
{
boolean xOverlap = valueInRange(A.x, B.x, B.x + B.width) ||
valueInRange(B.x, A.x, A.x + A.width);

boolean yOverlap = valueInRange(A.y, B.y, B.y + B.height) ||
valueInRange(B.y, A.y, A.y + A.height);

boolean zOverlap = valueInRange(A.z, B.z, B.z + B.depth) ||
valueInRange(B.z, A.z, A.z + A.depth);

return xOverlap && yOverlap && zOverlap;
}
[/code]

But that obviously doesnt work if i need to test the players collision box against a rotated collision box like for example a ramp.

I can calculate the coordinates of the 8 corners of the rotated colision box in world space but how would i determine if it intersects with the players colision box. Its a givin that the players collision box will never be rotated for incase that helps.

Any help appreciated. Thnx in Advance!

Share this post


Link to post
Share on other sites
Hi,

[quote name='Wilhelm van Huyssteen' timestamp='1311070045' post='4837300']
Hi.

Im currently writing an FPS. I allready have a working level and collisions between the player and the floor/walls work fine. I Test the players collision box with the floors/walls collision boxes using this simple logic.

[code]
boolean valueInRange(float value, float min, float max)
{ return (value >= min) && (value <= max); }

boolean rectOverlap(Rect A, Rect B)
{
boolean xOverlap = valueInRange(A.x, B.x, B.x + B.width) ||
valueInRange(B.x, A.x, A.x + A.width);

boolean yOverlap = valueInRange(A.y, B.y, B.y + B.height) ||
valueInRange(B.y, A.y, A.y + A.height);

boolean zOverlap = valueInRange(A.z, B.z, B.z + B.depth) ||
valueInRange(B.z, A.z, A.z + A.depth);

return xOverlap && yOverlap && zOverlap;
}
[/code]

But that obviously doesnt work if i need to test the players collision box against a rotated collision box like for example a ramp.

I can calculate the coordinates of the 8 corners of the rotated colision box in world space but how would i determine if it intersects with the players colision box. Its a givin that the players collision box will never be rotated for incase that helps.

Any help appreciated. Thnx in Advance!
[/quote]

I'm not sure why it matters if the players box would be rotated?

I use code similar to this code
[code]
boolean rectCol(Rect A, Rect B) //rectangle collision because overlap is such a long word ;)
{
bool xCol = (A.bbMin.x <= B.bbMax.x) && (A.bbMax.x >= B.bbMin.x);
bool yCol = (A.bbMin.y <= B.bbMax.y) && (A.bbMax.y >= B.bbMin.y);
bool zCol = (A.bbMin.z <= B.bbMax.z) && (A.bbMax.z >= B.bbMin.z);
return xCol && yCol && zCol;
}
[/code]

Of course this is not live code, it was whipped up just to demonstrate the simplicity of such code. Also if the language supports it pass addresses around as they are obviously smaller than passing whole complex objects! hope this helps there!

Ramp collision should be implemented with the same bounding box collision, but then you would need to find the collision point within the box to test if the "player" is colliding with the ramp

Share this post


Link to post
Share on other sites
Hi!

Ok, so, the rotated box you're talking about is called "OBB" (oriented bounding box). I don't have an AABB to OBB function handy at the moment, since I've never used it, but that's the keyword you're looking for anyway.

Now, a small comment regarding your code... You could put all those checks in one line. Basically, something like:

[code]

return (valueInRange(A.x, B.x, B.x + B.width) ||
valueInRange(B.x, A.x, A.x + A.width)) &&
(valueInRange(A.y, B.y, B.y + B.height) ||
valueInRange(B.y, A.y, A.y + A.height)) &&
(valueInRange(A.z, B.z, B.z + B.depth) ||
valueInRange(B.z, A.z, A.z + A.depth));
[/code]

It will be faster, since there will be lots of early outs, instead of having to create 3 bools, calculate all of them and then check them.
If you could, however, try using Lewis's version, it has less checks than the whole valueInRange thing.
And it could be done even faster by doing:

[code]
return (A.bbMin.x <= B.bbMax.x) &&
(A.bbMax.x >= B.bbMin.x) &&
(A.bbMin.y <= B.bbMax.y) &&
(A.bbMax.y >= B.bbMin.y) &&
(A.bbMin.z <= B.bbMax.z) &&
(A.bbMax.z >= B.bbMin.z);

[/code]

Share this post


Link to post
Share on other sites
Hello

Maybe there's a more specific algorithm for arbitrary boxes (oriented bounding boxes, OBB), but I know that the [url="http://en.wikipedia.org/wiki/Separating_axis_theorem"]SAT[/url] (separating axis theorem) method could solve this problem, it works on arbitrary convex polytopes (2D and 3D) so it works for simple boxes too.

Share this post


Link to post
Share on other sites
Hi, I'm sure if the compiler did not optimize code for us we would have to inline the code like that but can anyone confirm or deny that the compiler does this? I'm sure C++ is smart enough to do basic var stacking and loop unrolling where needed... Hopefully anyway :rolleyes:(this is my hopeful face)

[quote name='godplusplus' timestamp='1314874053' post='4856225']
Now, a small comment regarding your code... You could put all those checks in one line. Basically, something like:

[code]

return (valueInRange(A.x, B.x, B.x + B.width) ||
valueInRange(B.x, A.x, A.x + A.width)) &&
(valueInRange(A.y, B.y, B.y + B.height) ||
valueInRange(B.y, A.y, A.y + A.height)) &&
(valueInRange(A.z, B.z, B.z + B.depth) ||
valueInRange(B.z, A.z, A.z + A.depth));
[/code]

It will be faster, since there will be lots of early outs, instead of having to create 3 bools, calculate all of them and then check them.
If you could, however, try using Lewis's version, it has less checks than the whole valueInRange thing.
And it could be done even faster by doing:

[code]
return (A.bbMin.x <= B.bbMax.x) &&
(A.bbMax.x >= B.bbMin.x) &&
(A.bbMin.y <= B.bbMax.y) &&
(A.bbMax.y >= B.bbMin.y) &&
(A.bbMin.z <= B.bbMax.z) &&
(A.bbMax.z >= B.bbMin.z);

[/code]
[/quote]
I am also quite sure you need extra brackets and to change some of the && to || ala
[code]
return ((A.bbMin.x <= B.bbMax.x) || (A.bbMax.x >= B.bbMin.x)) && ((A.bbMin.y <= B.bbMax.y) || (A.bbMax.y >= B.bbMin.y)) && ((A.bbMin.z <= B.bbMax.z) || (A.bbMax.z >= B.bbMin.z));
[/code]
voilla this now works as expected when I test it :P(oh the cheek of me)
by the way i'm not poking fun I'm just in a very good mood :D

Share this post


Link to post
Share on other sites
There is a much neater way to tell if two AABBs overlap.

Firstly, start using a vector library to help with adding, subtracting and so forth; it will lead to less bugs and make your code more readable.

If you define an AABB by two vectors, one being its centre and the other its half-extents (half the length, width and height), then you can tell if two AABBs overlap by doing this:

[code]D = |centreB-centreA| – (halfExtentsA+halfExtentsB)

binary overlap = D.x < 0 && D.y < 0;[/code]


Where |a| = abs(a).

However, if you want OBB vs OBB, its a much more difficult test. I would use a sphere or a capsule to represent the player instead of a box - the tests for those primitive are much easier :)

Cheers, Paul.

Share this post


Link to post
Share on other sites

This topic is 2291 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this