THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 13/09/2012 at 06:20, xxxxxxxx wrote:
Hey guys,
I created a AABBox class for another thread, but expanded it to allow you to add additional objects (cumulative bounding box). It's in C++, but you're welcome to use/convert it if it's any use...
//==================================================================================
// AABBox Class - An implementation of an "Axis Aligned Bounding Box" class
//
// This implementation actually builds a OBB (Oriented Bounding Box) to use as the
// source for generating the AABB.
//
// As implemented, if the object is an instance of a PointObject, it uses the
// (Global-space) points of the object as the OBB.
//
// If it's not a PointObject, it generates a BBox (8-point cube) out of the min/max
// extents of the object (again in Global-space) to use as the OBB.
//
// The class also has provisions for generating a bounding box for a combination of
// multiple objects, as well as a simple collision-detection routine.
//==================================================================================
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; }
Bool CollidesWith(BaseObject *op);
void AddObject(BaseObject *op);
void Init(BaseObject *op = NULL);
AABBox(BaseObject *op);
AABBox(void) { m_init = false; }
~AABBox(void) {}
};
AABBox::AABBox(BaseObject *op)
{
this->Init(op);
}
void AABBox::Init(BaseObject *op)
{
m_init = false;
m_bbMin = Vector();
m_bbMax = Vector();
if( !op ) return;
this->GetAABBox(op, &m_bbMin, &m_bbMax);
m_init = true;
}
void AABBox::AddObject(BaseObject *op)
{
if( !op ) return;
if( !m_init )
{
this->Init(op);
}
else
{
// first store the old values...
MinMax mm;
mm.Init(m_bbMin);
mm.AddPoint(m_bbMax);
// then add new object...
this->GetAABBox(op, &m_bbMin, &m_bbMax);
mm.AddPoint(m_bbMin);
mm.AddPoint(m_bbMax);
// and determine new extents...
m_bbMin = mm.GetMin();
m_bbMax = mm.GetMax();
}
}
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 this is too slow, you can
// get rid of this top part and just always do 8 points, below.
//
// to see the difference in using the actual points and the 8 point box, see the image on the
// second page of this article: http://www.gamasutra.com/view/feature/3426/when_two_hearts_collide_.php
//--------------------------------------------------------------------------------------------
if( op->IsInstanceOf(Opoint) )
{
const Vector *pPoints = ToPoint(op)->GetPointR();
LONG i, numPoints = ToPoint(op)->GetPointCount();
mm.Init();
for(i=0; i<numPoints; i++)
{
mm.AddPoint(*pPoints * opgm);
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);
mm.AddPoint(Vector(pMin->x, pMin->y, pMax->z) * opgm);
mm.AddPoint(Vector(pMax->x, pMin->y, pMax->z) * opgm);
mm.AddPoint(Vector(pMax->x, pMin->y, pMin->z) * opgm);
// top
mm.AddPoint(*pMax * opgm);
mm.AddPoint(Vector(pMax->x, pMax->y, pMin->z) * opgm);
mm.AddPoint(Vector(pMin->x, pMax->y, pMin->z) * opgm);
mm.AddPoint(Vector(pMin->x, pMax->y, pMax->z) * opgm);
}
// convert to AABBox (described by min/max extent vectors)
*pMin = mm.GetMin();
*pMax = mm.GetMax();
// GePrint(op->GetName()+" bbMin: "+utVecToString(*pMin)+" bbMax: "+utVecToString(*pMax));
}
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;
//==================================================================================
// output for testing purposes - delete or comment out it not needed
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);
}
//==================================================================================
// simple testing routine... builds AABBox from first object in scene (actually,
// whatever object you pass to it), then tests for collisions with all other
// (root level) objects below it in scene (but doesn't really do anything with
// the results)
//==================================================================================
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();
}
}
}
//==================================================================================
// simple testing routine to recursively walk the heirarchy, adding each object to
// the AABBox, to generate a single / cumulative bounding box.
//==================================================================================
void AccumulateBBox(AABBox *aabb, BaseObject *op)
{
if( !aabb ) return;
while(op)
{
aabb->AddObject(op);
AccumulateBBox(aabb, op->GetDown());
op = op->GetNext();
}
}
...I didn't include any code to call the bottom two test routines, but it should be pretty straight-forward. Note that you can also get the min/max vectors from the AABBox (which would be in Global-space).
Cheers.