# Object Collisions?

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 07/09/2012 at 15:12, xxxxxxxx wrote:

There are basically three levels to Collision Detection:

1. Bounding Box
2. Polygon-Polygon Bounding Box
3. Ray-Triangle Intersection

Each of these represents a more accurate collision detection.

All you need for 1. is to GetRad() and GetMp() for the two objects to be tested.  Note that GetMp() returns the bounding box in LOCAL space.  You need to convert that to GLOBAL space like so to do the AABB collision test:

``````
// Global-space Bounding-Box Center Point
Vector bbCenter = obj->GetMp() * obj->GetUpMg();
// Bounding-Box extents in X/Y/Z
// Bounding-Box minimum extents
Vector bbMin = bbCenter - bbBounds;
// Bounding-Box maximum extents
Vector bbMax = bbCenter + bbBounds;
``````

These give you an AABB and not an OBB (I think).

This is now very simple. Given world object A and another object B you can test for a collision simply by doing a number of checks e.g.

• If the max x position of A is less than the min x position of B they do not collide
• If the min x position of A is greater than the max x position of B they do not collide
• and the same goes for y and z

If none of the checks find that no collision occurred then obviously a collision did occur. This does make sense - read it slowly :)

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 07/09/2012 at 16:57, xxxxxxxx wrote:

Hi Robert,

I'm not understanding your BB code. It's returning zeros (local coords. based on the object's matrix..not the the world?) no matter where the object is in the world.

``````    BaseObject *player = doc->SearchObject("player");             //The object to work on
Vector playerPos = player->GetMg().off;                       //The player object's global position

Vector playerbbCenter = player->GetMp() * player->GetUpMg();  //The BB Global or local position?
GePrint(RealToString(playerbbCenter.x));                      //<---- Always prints zero
GePrint(RealToString(playerbbCenter.y));                      //<---- Always prints zero
GePrint(RealToString(playerbbCenter.z));                      //<---- Always prints zero
``````

With playerbbCenter always returning (0,0,0) I don't understand how that is useful?

-ScottA

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 07/09/2012 at 18:14, xxxxxxxx wrote:

Try using player->GetMp() * player->GetMg();

Also, if you have a hierarchy of objects or are looking at a Null/HyperNURBS/Generator as parent of the object(s) then that might explain why you always get (0,0,0).  You will need to traverse the hierarchy of objects to get the BB radius and BB center.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 07/09/2012 at 19:02, xxxxxxxx wrote:

Hurray!
I think I got it now Robert.
I didn't use the GetMp() function. But this seems to be working properly.

``````//This creates AABB collision checking between two objects
//Similar to the results from the xpresso collision node

BaseObject *player = doc->SearchObject("player");               //One of the objects to check for collisions
if(!player) return FALSE;
Vector playerPos = player->GetMg().off;                         //The object's global position
Vector playerbbCenter = playerPos;                              //The bounding box's position
Vector playerbbBounds = player->GetRad();                       //Bounding-Box extents in X/Y/Z
Vector playerbbMin = playerbbCenter - playerbbBounds;           //Bounding-Box minimum extents
Vector playerbbMax = playerbbCenter + playerbbBounds;           //Bounding-Box maximum extents

BaseObject *enemy = doc->SearchObject("enemy");                 //The other object to check for collisions
if(!enemy) return FALSE;
Vector enemyPos = enemy->GetMg().off;                           //The object's global position
Vector enemybbCenter = enemyPos;                                //The bounding box's position
Vector enemybbBounds = enemy->GetRad();                         //Bounding-Box extents in X/Y/Z
Vector enemybbMin = enemybbCenter - enemybbBounds;              //Bounding-Box minimum extents
Vector enemybbMax = enemybbCenter + enemybbBounds;              //Bounding-Box maximum extents

LONG collision = 1;                   //The Collision value will be set to true before we check the two objects for collisions

if(playerbbMax.x < enemybbMin.x)      //If the player's positive X bounds is less than the enemy's negative X bounds
{ collision = 0; }                    //We don't have a collison
if(playerbbMin.x > enemybbMax.x)      //If the player's negative X bounds is more than the enemy's positive X bounds
{ collision = 0; }                    //We don't have a collison

if(playerbbMax.y < enemybbMin.y)      //If the player's positive Y bounds is less than the enemy's negative Y bounds
{ collision = 0;  }                   //We don't have a collison
if(playerbbMin.y > enemybbMax.y)      //If the player's negative Y bounds is more than the enemy's positive Y bounds
{ collision = 0; }                    //We don't have a collison

if(playerbbMax.z < enemybbMin.z)      //If the player's positive Z bounds is less than the enemy's negative Z bounds
{ collision = 0; }                    //We don't have a collison
if(playerbbMin.z > enemybbMax.z)      //If the player's negative Z bounds is more than the enemy's positive Z bounds
{ collision = 0; }                    //We don't have a collison

GePrint(LongToString(collision));
``````

I will try out you suggestion with GetMp(). But I don't seem to need it.

Thanks a ton Robert.
-ScottA

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 03:50, xxxxxxxx wrote:

Collision Node probably uses internal GeColliderEngine.

If you want results from "Collision" output then use DoPolyPairs() then "Polygon Index 1" is GetId1() and "Polygon Index 2" GetId2().

If you want results from "Distance" output then use DoDistance() or DoTolerance() then "Point 1" is GetP1() and "Point 2" is GetP2().

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 07:48, xxxxxxxx wrote:

Originally posted by xxxxxxxx

Collision Node probably uses internal GeColliderEngine.

The code I have now is working exactly like the collision node. So I'm just curious why you would you think that Remo?

I have almost no experience at all with the GeColliderEngine. So what you're saying is making no sense to me yet. But I would like to learn more about it. So I am going to try and learn how to use it today.
Can you offer any kind of code tips or something to help me get started with it?

We have a sphere collision example and an AABB collision example in this thread so far.
I would love it if we can post more of these collision examples in this thread. They are very useful.

-ScottA
BTW: Thanks for the link. That book looks like a very good collision book based on the errata.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 09:43, xxxxxxxx wrote:

Hey Robert,

I was playing with this a bit the other day and I think you need to add/subtract the Rad() before multiplying by the global matrix (note that the bounding box is also in local space, so combine first, then multiply the results by the global matrix to get the whole thing into global space)...

``````

Vector bbCenter = obj->GetMp();   // Local-space Bounding-Box Center Point
Vector bbBounds = obj->GetRad();  // Local-space Bounding-Box extents in X/Y/Z
Vector bbMin = (bbCenter - bbBounds) * obj->GetMg(); // Bounding-Box minimum extents (positioned and oriented in global-space)
Vector bbMax = (bbCenter + bbBounds) * obj->GetMg(); // Bounding-Box maximum extents (positioned and oriented in global-space)

// NOTE: multiplying by the global matrix (rotations) can negate some of the min/max values, so re-normalize...
MinMax mm;
mm.Init(bbMin1);
bbMin1 = mm.GetMin();
bbMax1 = mm.GetMax();

``````

EDIT: Actually, the above code doesn't work and I kinda know why, but need to figure out the fix.
EDIT2: OK, the above addition (using a MinMax class) to re-normalize fixes it.

Scott,

You should not be using the 'position' of the objects (the player->GetMg().off), since that does not account for the 'midpoint' of the object, that you need for doing the spherical/bounding-box test.  Note that the object's position may be at 0/0/0, but the actual mesh may be offset by any amount from there (and thus the middle of the mesh would also be offset).

Using code similar to the above will account for this, as well as any rotations / scaling of the objects, which you're also not accounting for with the code you have.

Cheers.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 10:44, xxxxxxxx wrote:

Here you go - just add some objects to scene and pass it doc->GetFirstObject() and it'll tell you if that object collides with any other object in the scene (using crude bounding box test only)...

``````
void BBoxTest(BaseObject *op)
{
if( op )
{
Vector bbCenter = op->GetMp();   // Local-space Bounding-Box Center Point
Vector bbBounds = op->GetRad();  // Local-space Bounding-Box extents in X/Y/Z
Vector bbMin1 = (bbCenter - bbBounds) * op->GetMgn(); // Bounding-Box minimum extents (positioned and oriented in global-space)
Vector bbMax1 = (bbCenter + bbBounds) * op->GetMgn(); // Bounding-Box maximum extents (positioned and oriented in global-space)
MinMax mm;
mm.Init(bbMin1);
bbMin1 = mm.GetMin();
bbMax1 = mm.GetMax();
//      GePrint(op->GetName()+" bbMin1: "+utVecToString(bbMin1)+" bbMax1: "+utVecToString(bbMax1));

BaseObject *op2 = op->GetNext();
while( op2 )
{
Vector bbMin2 = (op2->GetMp() - op2->GetRad()) * op2->GetMgn(); // Bounding-Box minimum extents (positioned and oriented in global-space)
Vector bbMax2 = (op2->GetMp() + op2->GetRad()) * op2->GetMgn(); // Bounding-Box maximum extents (positioned and oriented in global-space)
mm.Init(bbMin2);
bbMin2 = mm.GetMin();
bbMax2 = mm.GetMax();
//            GePrint(op2->GetName()+" bbMin2: "+utVecToString(bbMin2)+" bbMax2: "+utVecToString(bbMax2));

Bool xlap, ylap, zlap;
if( bbMin2.x <= bbMax1.x && bbMax2.x >= bbMin1.x )    xlap = true;
else                                                  xlap = false;
if( bbMin2.y <= bbMax1.y && bbMax2.y >= bbMin1.y )    ylap = true;
else                                                  ylap = false;
if( bbMin2.z <= bbMax1.z && bbMax2.z >= bbMin1.z )    zlap = true;
else                                                  zlap = false;
String slap = op->GetName()+" / " + op2->GetName();
slap += " xlap: ";
slap += xlap ? "true" : "false";
slap += " ylap: ";
slap += ylap ? "true" : "false";
slap += " zlap: ";
slap += zlap ? "true" : "false";
slap += " BBox Collision: ";
slap += (xlap && ylap && zlap) ? "true" : "false";
GePrint(slap);
op2 = op2->GetNext();
}
}
}
``````

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 11:24, xxxxxxxx wrote:

Thanks Giblet.

Using your custom method. The collisions between two non-rotated objects works good.
But I'm not getting proper collisions when the objects are rotated.
-Create two cubes
-Put the second cube above the first cube close...but not quite colliding

The only time I'm getting collisions is when I rotate either object in -B or +P

-ScottA

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 16:13, xxxxxxxx wrote:

Yeah, I see that it's still not working.. and I know why, I'm just trying to come up with the best solution...

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 16:26, xxxxxxxx wrote:

The problem with multiplying the global matrix after you get the minima and maxima bounds is that it is now an OBB.  The vector returned by GetRad() is simply a distance vector (relative) and is already aligned globally.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 08/09/2012 at 23:18, xxxxxxxx wrote:

OBB?  (I'm not familiar with the term)

GetRad() returns a 'local-space' distance (radius) vector on each axis.  In other words, imagine a playing-cards pack, with a GetRad() vector of 20/40/10... if you rotate the object 90deg on the Y axis, the x and z axis swap, so you'd (effectively) have 10/40/20 in global-space, which is quite different - implying that you do indeed need to modify the GetRad() value by the global-space matrix.

The problem with doing that (erm, what I was doing above) is that you are effectively only rotating 2 pseudo-points - two actual points of the bounding box (ie. top/right/rear and bottom/left/front), but there are 6 others that make up that box, that aren't correctly accounted for.

I think the solution would be to (temporarily) actually generate all 8 points, rotate them (apply the global matrix), then feed all 8 back into the MinMax class to reduce it back to the bbMin and bbMax vectors.

Of course I could be going down the wrong path - there may be some other solution, which I'd love to hear.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 09/09/2012 at 08:23, xxxxxxxx wrote:

As mentioned, there may be other ways of doing this, but this now seems to work...

``````
void BBoxTest(BaseObject *op)
{
if( op )
{
Vector bbMin1 = op->GetMp() - op->GetRad(); // Bounding-Box minimum extents (Local-space)
Vector bbMax1 = op->GetMp() + op->GetRad(); // Bounding-Box maximum extents (Local-space)
Matrix opgm = op->GetMgn();

// Generate (8) points of bounding box in Global-space and generate new min/max vectors
MinMax mm;

// bottom
mm.Init(bbMin1 * opgm);

// top

bbMin1 = mm.GetMin();
bbMax1 = mm.GetMax();
//        GePrint(op->GetName()+" bbMin1: "+utVecToString(bbMin1)+" bbMax1: "+utVecToString(bbMax1));

BaseObject *op2 = op->GetNext();
while( op2 )
{
Vector bbMin2 = op2->GetMp() - op2->GetRad(); // Bounding-Box minimum extents (Local-space)
Vector bbMax2 = op2->GetMp() + op2->GetRad(); // Bounding-Box maximum extents (Local-space)
opgm = op2->GetMgn();

// Generate (8) points of bounding box in Global-space and generate new min/max vectors
// bottom
mm.Init(bbMin2 * opgm);

// top

bbMin2 = mm.GetMin();
bbMax2 = mm.GetMax();
//            GePrint(op2->GetName()+" bbMin2: "+utVecToString(bbMin2)+" bbMax2: "+utVecToString(bbMax2));

Bool xlap, ylap, zlap;
if( bbMin2.x < bbMax1.x && bbMax2.x > bbMin1.x )    xlap = true;    else xlap = false;
if( bbMin2.y < bbMax1.y && bbMax2.y > bbMin1.y )    ylap = true;    else ylap = false;
if( bbMin2.z < bbMax1.z && bbMax2.z > bbMin1.z )    zlap = true;    else zlap = false;
String slap = op->GetName()+" / " + op2->GetName();
slap += " xlap: ";                slap += xlap ? "true" : "false";
slap += " ylap: ";                slap += ylap ? "true" : "false";
slap += " zlap: ";                slap += zlap ? "true" : "false";
slap += " BBox Collision: ";    slap += (xlap && ylap && zlap) ? "true" : "false";
GePrint(slap);
op2 = op2->GetNext();
}
}
}
``````

EDIT: replaced it with a slightly tidier version.
EDIT 9/11/12: Fixed a bug where I had too many mm.Init() calls

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 10/09/2012 at 05:54, xxxxxxxx wrote:

Well here helper class that help to use GeColliderEngine.
GeColliderHelper.h

Just look at GeColliderHelperTest() function.

It will calculate distance between two first object in the document.
It will also do collision detection and return ids of two first colliding polygons.

By the way why do you use MinMax and not proper AABBox class ?

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 10/09/2012 at 06:18, xxxxxxxx wrote:

Originally posted by xxxxxxxx

...By the way why do you use MinMax and not proper AABBox class ?

Hi Remo,

I didn't look at any example code or the GeColliderEngine stuff - he said he was interested in knowing how to do the simple Bounding Box test, so I took it on as an academic exercise (ie. just to see how I would do it).  I'm not sure what a "proper AABBox class" is or where to find one, since I didn't look anything up.  The MinMax class served the purpose I needed.

As mentioned, I'm sure that there are other (perhaps even well-defined) methods of doing it (that even uses acronyms like OBB and AABB that help describe the method), but I just worked from scratch, so I'm unfamiliar with those terms :).

Cheers.

EDIT: Just so I don't look like a complete dolt, I just looked around and determined that 'AABB' likely stands for "Axis Aligned Bounding Boxes", which probably describes what I did.  I'm also guessing that 'OBB' probably means "Oriented Bounding Boxes" (?).

EDIT 2: Ok, it looks like what I'm technically doing is creating a OBB as the source for an AABB, as in the first few pages from here.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 11/09/2012 at 05:49, xxxxxxxx wrote:

Yes, your acronyms are correct. :)

This is why I was a bit scared of multiplying the bounds by the global matrix.  They should stay in their proper orientation and just have their positions represented in global space - but I had to convince myself that they weren't being 'transformed' in any unexpected way.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 11/09/2012 at 06:03, xxxxxxxx wrote:

Gotcha :).

If you created a polygonal box object using those 8 transformed points I came up with, you'd end up with something similar to the yellow cube on the left-side of the "Figure 4" image on page 2 of that article I linked.  I then use that (yellow, OBB box) cube to determine the new MinMax (blue, AABB box) extents. Obviously, that's more 'slop' than the right-side of that image, but you don't have to find and transform all the points of the mesh - just the 8 points of the bounding cube.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 11/09/2012 at 10:55, xxxxxxxx wrote:

As usual, I got bored :) ...

``````
class AABBox
{
private:
Vector    m_bbMin;
Vector    m_bbMax;
Bool    m_init;
void GetAABBox(BaseObject *op, Vector *pMin, Vector *pMax);

public:
Vector GetMin(void)                        { return m_bbMin; }
Vector GetMax(void)                        { return m_bbMax; }
void Init(BaseObject *op);
Bool CollidesWith(BaseObject *op);
AABBox(BaseObject *op);
AABBox(void) {    m_init = false; }
~AABBox(void) {}
};

AABBox::AABBox(BaseObject *op)
{
this->Init(op);
}

void AABBox::GetAABBox(BaseObject *op, Vector *pMin, Vector *pMax)
{
Matrix opgm = op->GetMgn();
MinMax mm;

//--------------------------------------------------------------------------------------------
// With this implementation, if the BaseObject being passed in is an instance of a PointObject,
// then the OBB will be built from the actual Global-space points... this take longer if there
// are more than 8 points, but gives a tighter fitting AABBox
//--------------------------------------------------------------------------------------------
if( op->IsInstanceOf(Opoint) )
{
const Vector *pPoints = ToPoint(op)->GetPointR();
LONG i, numPoints = ToPoint(op)->GetPointCount();
mm.Init();
for(i=0; i<numPoints; i++)
{
pPoints++;
}
}
else
{
//--------------------------------------------------------------------------------------------
// ...otherwise, generate an 8 point OBB from the Global-space extent vectors
//--------------------------------------------------------------------------------------------
*pMin = op->GetMp() - op->GetRad(); // Bounding-Box minimum extents (Local-space)
*pMax = op->GetMp() + op->GetRad(); // Bounding-Box maximum extents (Local-space)

// bottom
mm.Init(*pMin * opgm);

// top
}

// convert to AABBox (described by min/max extent vectors)
*pMin = mm.GetMin();
*pMax = mm.GetMax();

//    GePrint(op->GetName()+" bbMin: "+utVecToString(*pMin)+" bbMax: "+utVecToString(*pMax));
}

void AABBox::Init(BaseObject *op)
{
m_init = false;
if( !op )    return;

this->GetAABBox(op, &m_bbMin, &m_bbMax);

m_init = true;
}

Bool AABBox::CollidesWith(BaseObject *op)
{
if( !m_init )    return false;

Vector bbMin; // Bounding-Box minimum extents
Vector bbMax; // Bounding-Box maximum extents

this->GetAABBox(op, &bbMin, &bbMax);

Bool xlap, ylap, zlap;
if( bbMin.x < m_bbMax.x && bbMax.x > m_bbMin.x )    xlap = true;    else xlap = false;
if( bbMin.y < m_bbMax.y && bbMax.y > m_bbMin.y )    ylap = true;    else ylap = false;
if( bbMin.z < m_bbMax.z && bbMax.z > m_bbMin.z )    zlap = true;    else zlap = false;

String slap = op->GetName();
slap += " xlap: ";                slap += xlap ? "true" : "false";
slap += " ylap: ";                slap += ylap ? "true" : "false";
slap += " zlap: ";                slap += zlap ? "true" : "false";
slap += " BBox Collision: ";    slap += (xlap && ylap && zlap) ? "true" : "false";
GePrint(slap);

return (xlap && ylap && zlap);
}

void BBoxTest(BaseObject *op)
{
if( op )
{
AABBox aabb(op);

BaseObject *op2 = op->GetNext();
LONG collisions = 0;
while( op2 )
{
collisions += aabb.CollidesWith(op2);
op2 = op2->GetNext();
}
}
}
``````

Cheers.

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/09/2012 at 07:35, xxxxxxxx wrote:

Sorry for not posting back guys.
My mother had a serious health issue this past weekend and I've been basically living at the hospital for the past few days.

@Giblet.
Thank you very much for not giving up on this and doing all the work you did on it.
The collision class you made looks like it will be very good.
I'm not really able to focus my mind on programming with my mother's health so bad. So it might be a while before I get back to it.

I did test it out like this:

``````    BaseObject *player = doc->GetFirstObject();             //The first object in the OM
if(!player) return FALSE;
BBoxTest(player);
``````

And it looks like it works good.

But your class has a some other methods in it (init(),CollidesWith()) that I need to figure out how and when to call.
I'll take a look at better look at when my mind is in better shape.

Thanks a ton for all the work you've done on this.
-ScottA

• THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/09/2012 at 14:33, xxxxxxxx wrote:

No problem.. there's an updated version of it at the bottom of this thread.