Sign in to follow this  

OOBB Creation/Intersection

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

I have been trying to read about object oriented bounding boxes and I honestly can not find much on them. Can anyone show me or point me to a place where I can learn how to create and test oobb intersections?

Share this post


Link to post
Share on other sites
The reason you're having trouble finding references may be that you're using the wrong search term (the more frequently used term is 'OBB', or 'oriented bounding box').

There are many references on the topic available online - just try searching for 'OBB' (plus whatever other topics you're interested in, e.g. 'intersection') and you should get plenty of hits.

Share this post


Link to post
Share on other sites
I have been working on this and can not figure out why my rotation is not working. The box rotates just fine, however, the translation is wrong. I am using a Vector class and am switching it over a D3DXVECTOR3. I declare a min/max/objectbounds[8] in my header file. I create my obb like so


void COBB::SetupCollisionBox(float fX, float fY, float fZ, float fWidth, float fHeight, float fDepth)
{
m_Min = Vector3D(fX, fY, fZ);
m_Max = Vector3D(fX + fWidth, fY + fHeight, fZ + fDepth);

m_vObjectBounds[0] = Vector(m_Min.GetX(), m_Min.GetY(), m_Min.GetZ());
m_vObjectBounds[1] = Vector(m_Max.GetX(), m_Min.GetY(), m_Min.GetZ());
m_vObjectBounds[2] = Vector(m_Min.GetX(), m_Max.GetY(), m_Min.GetZ());
m_vObjectBounds[3] = Vector(m_Max.GetX(), m_Max.GetY(), m_Min.GetZ());
m_vObjectBounds[4] = Vector(m_Min.GetX(), m_Min.GetY(), m_Max.GetZ());
m_vObjectBounds[5] = Vector(m_Max.GetX(), m_Min.GetY(), m_Max.GetZ());
m_vObjectBounds[6] = Vector(m_Min.GetX(), m_Max.GetY(), m_Max.GetZ());
m_vObjectBounds[7] = Vector(m_Max.GetX(), m_Max.GetY(), m_Max.GetZ());
}


Here is how I do my rotation. Only the translation seems to be off, however, I can not figure out why.


// Convert to D3DXVECTOR3
D3DXVECTOR3 vInput[8];
D3DXVECTOR3 vOutput[8];

for(int i = 0; i < 8; ++i)
vInput[i] = D3DXVECTOR3(m_vObjectBounds[i].GetX(), m_vObjectBounds[i].GetY(), m_vObjectBounds[i].GetZ());

// Rotate the vInput based off the matrix and store in vOutput
for(int i = 0; i < 8; ++i)
D3DXVec3TransformCoord(&vOutput[i], &vInput[i], &rotation);

// Covert to Vector
for(int i = 0; i < 8; ++i)
m_vObjectBounds[i] = Vector(vOutput[i].x, vOutput[i].y, vOutput[i].z);


// Find the new min/max
D3DXVECTOR3 min = vOutput[0];
D3DXVECTOR3 max = vOutput[0];

for(int i = 0; i < 8; ++i)
{
if(vOutput[i].x < min.x)
min.x = vOutput[i].x;
else if(vOutput[i].x > max.x)
max.x = vOutput[i].x;

if(vOutput[i].y < min.y)
min.y = vOutput[i].y;
else if(vOutput[i].y > max.y)
max.y = vOutput[i].y;

if(vOutput[i].z < min.z)
min.z = vOutput[i].z;
else if(vOutput[i].z > max.z)
max.z = vOutput[i].z;

}

// Recreate Min/Max
m_Min = Vector(min.x, min.y, min.z);
m_Max = Vector(max.x, max.y, max.z);


I can tell that it is off on the translation by a visual representation (that I almost think is perfectly correct, however, with out collision testing I could be wrong).

Which leads me to my last question, I can not tell how to test two OBB's colliding with each other using this method. Does anyone know how I can tell if the are?

Share this post


Link to post
Share on other sites
where is the translation performed? I can only see rotation.

Are you sure your rotation is corect? Your box will rotate around the origin, not the centre of the box.

Share this post


Link to post
Share on other sites
I had this problem too, with little help from anybody in this forum. The secret is finding other OBB's position in this OBB's local space by projecting other OBB's center point first into this OBB's X axis, then onto this OBB's Y axis.

In other words, expressing center point of 2nd OBB in the local coordinate system of 1st OBB (here I call 1st OBB "this OBB" and 2nd OBB "other OBB").

Calculating other OBB's new center point using this OBB as frame of reference:

OtherOBBDistanceVector = OtherOBBPosition - ThisOBBPosition

OtherOBBLocalPosition.X = OtherOBBDistanceVector Dot ThisOBBXAxis
OtherOBBLocalPosition.Y = OtherOBBDistanceVector Dot ThisOBBYAxis

Calculating other OBB's new axes using this OBB as a frame of reference:

OtherOBBLocalXAxis.X = ThisOBBXAxis Dot OtherOBBXAxis
OtherOBBLocalXAxis.Y = ThisOBBYAxis Dot OtherOBBXAxis

OtherOBBLocalYAxis.X = -OtherOBBLocalXAxis.Y
OtherOBBLocalYAxis.Y = OtherOBBLocalXAxis.X

We only need to calculate one of the axis, second axis is just perpendicular. Also note that I am implementing this test in 2D, but as far as transforming into local space goes, it's the same for the Z axis.

Here's a complete C# program I wrote to test all of the above concepts:
www.hitman2d.com/downloads/misc/obb.zip

Also note that when you cross 1st OBB's edges with 2nd OBB's edges to find more potential separating axes (applicable only to a 3D test which I don't do), sometimes the result is a near null vector when the edges are near parallel. The errors in precision cause this. To prevent your collision from being detected incorrectly, you should add in a small epsilon value, which will cause the test to be conservative for parallel edges and will disappear for other cases.

Share this post


Link to post
Share on other sites
Quote:
Original post by oliii
where is the translation performed? I can only see rotation.

Are you sure your rotation is corect? Your box will rotate around the origin, not the centre of the box.


I never preform a transform. The way I tested this is because I set the position to 0, 0, 0 and it rotated just fine. However, when I moved the position to something else, the collision was was not where it was suppose to be. The origin/position is typically min, which is the (left, bottom, front).

Share this post


Link to post
Share on other sites
it's gonna rotate fine if you have no translation.

I seem to have replied to that problem a week ago :/

basically, it all depends where your centre of rotation is.



Vector cor = min; // min as the centre of rotation.
Vector corners[8];
Vector obb[8];

// the 8 corners of the aabb
corners[0] = vector(min.x, min.y, min.z);
corners[1] = vector(max.x, min.y, min.z);
corners[2] = vector(max.x, max.y, min.z);
corners[3] = vector(min.x, max.y, min.z);
corners[4] = vector(min.x, min.y, max.z);
corners[5] = vector(max.x, min.y, max.z);
corners[6] = vector(max.x, max.y, max.z);
corners[7] = vector(min.x, max.y, max.z);

// tansform into an obb.
for(int i = 0; i < 8; i ++)
{
obb[i] = cor + (corners[i] - cor) * orientation;
}

// the aabb of the obb
vector aabbmin = obb[0];
vector aabbmax = obb[0];
for(int i = 1; i < 8; i ++)
{
if(obb[i].x < aabbmin.x)
aabbmin.x = obb[i].x;
else if(obb[i].x > aabbmax.x)
aabbmax.x = obb[i].x;

if(obb[i].y < aabbmin.y)
aabbmin.x = obb[i].y;
else if(obb[i].y > aabbmax.y)
aabbmax.y = obb[i].y;

if(obb[i].z < aabbmin.z)
aabbmin.z = obb[i].z;
else if(obb[i].z > aabbmax.z)
aabbmax.z = obb[i].z;
}

Share this post


Link to post
Share on other sites
Ah, I had no idea it was basically the way you do an AABB Rotation but saving the objectbounds. I thought it was more complicated based off of the way I was reading the collision. It seems like every time I read about OBB collision that I see them using "extents". Is this necessary?

Share this post


Link to post
Share on other sites
depends what you need them for. as far as I'm concerned, an obb is better described as a centre position, three directional vector (or a orthonormal matrix, same thing), and extents (or the half-size of the box) along those three vectors. That works great for collision detection.

However, the mental leap of using the 8 corners and building an AABB around them is easier than using the gemetrical properties of an obb.

for example, if you describe an obb as [centre, dir[3], halfsize[3]], then the AABB would be :


float rx = fabs(dir[0].x * halfsize[0]) + fabs(dir[1].x * halfsize[1]) + fabs(dir[2].x * halfsize[2]);
float ry = fabs(dir[0].y * halfsize[0]) + fabs(dir[1].y * halfsize[1]) + fabs(dir[2].y * halfsize[2]);
float rz = fabs(dir[0].z * halfsize[0]) + fabs(dir[1].z * halfsize[1]) + fabs(dir[2].z * halfsize[2]);

min = centre - vector(rx, ry, rz);
max = centre + vector(rx, ry, rz);

Share this post


Link to post
Share on other sites
Maybe I read your reply wrong, however, the way you are describing it makes it seem like you are just building an AABB around an OBB and testing the collision like that. Doesn't that defeat the purpose of an OBB?

Also, given the case that I read your post wrong, how could I find the dir/half-size vectors if I only have the min/max and the array of corners stored in my class?

Share this post


Link to post
Share on other sites
if you want to do OOBB intersection, that's a whole new cattle of fish.


And yes, what the algos do is find the AABB (which can be useful, for fast culling and broad-phase CD).

to calculate the OOBB,


obb.centre = (max + min) * 0.5f;
obb.halfsize = (max - min) * 0.5f;


as for the directions, in your case, it's straight forward. As I said, the dir vectors form a orthonormal matrix (orientation matrix), and the dir vectors are all columns of your orientation matrix (or rows, but I think Direct3D uses column major matrices).


obb.dir[0] = Vector(orientation.m11, orientation.m21, orientation.m31);
obb.dir[1] = Vector(orientation.m12, orientation.m22, orientation.m32);
obb.dir[2] = Vector(orientation.m13, orientation.m23, orientation.m33);


if you have the corners, it's easy. The directions are basically the direction of edges that are made up from corners. The half-size is the 1/2 length of the edges, and the centre pos is the middle point between two diagonally opposed corners.

I use a vector to store the halfsize here, instead of an array of three floats, but in effect, it's the same thing. In C++, you will often see vector class overloading the operator[] to take advantage of that, and the vector class looking like...


class Vector
{
union
{
float coords[3];
struct
{
float x, y, z;
};
};


float operator[](int i) const { return coords[i]; }
float& operator[](int i) { return coords[i]; }

//.....
};


now, for collison detection between OBB, you should use the SAT test. It's very easy, very fast, and very robust.

Share this post


Link to post
Share on other sites
Quote:
Original post by Hurp
What is the SAT test? I have heard of that before, however, I can not find anything on it.
The term to search for is 'separating axis test'.

Share this post


Link to post
Share on other sites
Hello, I have continued to work on this and while I think I am very close, I still get in accurate collision. My first problem I would think is with my directions. My directions (In DirectX) should be the following right?

m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._12, m_mOrientation._13);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._22, m_mOrientation._22, m_mOrientation._23);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._33, m_mOrientation._32, m_mOrientation._33);

I have tested both row major and column major with the below code (very similar to what oliii has shown in the past. Does anyone see a problem with it? The min of my box is the position.


bool COBB::CheckCollisionWithOBB(COBB *incBox)
{
if(!AxisOverlap(this->m_vDirections[0], this, incBox)) return true;
if(!AxisOverlap(this->m_vDirections[1], this, incBox)) return true;
if(!AxisOverlap(this->m_vDirections[2], this, incBox)) return true;

if(!AxisOverlap(incBox->m_vDirections[0], this, incBox)) return true;
if(!AxisOverlap(incBox->m_vDirections[0], this, incBox)) return true;
if(!AxisOverlap(incBox->m_vDirections[0], this, incBox)) return true;

D3DXVECTOR3 BoxOnePosition = D3DXVECTOR3(GetMin().m_fX, GetMin().m_fY, GetMin().m_fZ);
D3DXVECTOR3 BoxTwoPosition = D3DXVECTOR3(incBox->GetMin().m_fX, incBox->GetMin().m_fY, incBox->GetMin().m_fZ);

D3DXVECTOR3 Test1, Test2, Test3, Test4, Test5, Test6, Test7, Test8, Test9;
D3DXVec3Cross(&Test1, &this->m_vDirections[0], &incBox->m_vDirections[0]);
D3DXVec3Cross(&Test2, &this->m_vDirections[0], &incBox->m_vDirections[1]);
D3DXVec3Cross(&Test3, &this->m_vDirections[0], &incBox->m_vDirections[2]);

D3DXVec3Cross(&Test4, &this->m_vDirections[1], &incBox->m_vDirections[0]);
D3DXVec3Cross(&Test5, &this->m_vDirections[1], &incBox->m_vDirections[1]);
D3DXVec3Cross(&Test6, &this->m_vDirections[1], &incBox->m_vDirections[2]);

D3DXVec3Cross(&Test7, &this->m_vDirections[2], &incBox->m_vDirections[0]);
D3DXVec3Cross(&Test8, &this->m_vDirections[2], &incBox->m_vDirections[1]);
D3DXVec3Cross(&Test9, &this->m_vDirections[2], &incBox->m_vDirections[2]);

if(!AxisOverlap(Test1, this, incBox)) return true;
if(!AxisOverlap(Test2, this, incBox)) return true;
if(!AxisOverlap(Test3, this, incBox)) return true;
if(!AxisOverlap(Test4, this, incBox)) return true;
if(!AxisOverlap(Test5, this, incBox)) return true;
if(!AxisOverlap(Test6, this, incBox)) return true;
if(!AxisOverlap(Test7, this, incBox)) return true;
if(!AxisOverlap(Test8, this, incBox)) return true;
if(!AxisOverlap(Test9, this, incBox)) return true;

return false;
}

bool COBB::ExtentsOverlap(float min1, float max1, float min2, float max2)
{
return !(min1 > max2 || min2 > max1);
}

void COBB::ComputeBoxExtents(D3DXVECTOR3 Axis, COBB *box, float &min, float &max)
{
D3DXVECTOR3 BoxPosition = D3DXVECTOR3(box->GetMin().m_fX, box->GetMin().m_fY, box->GetMin().m_fZ);

Vector halfsize = (GetMax() - GetMin()) * 0.5f;

float p = D3DXVec3Dot(&BoxPosition, &Axis);
float r0 = fabs(D3DXVec3Dot(&box->m_vDirections[0], &Axis)) * halfsize.m_fX;
float r1 = fabs(D3DXVec3Dot(&box->m_vDirections[1], &Axis)) * halfsize.m_fY;
float r2 = fabs(D3DXVec3Dot(&box->m_vDirections[2], &Axis)) * halfsize.m_fZ;

float r = r0 + r1 + r2;

min = p-r;
max = p+r;
}

bool COBB::AxisOverlap(D3DXVECTOR3 Axis, COBB *box1, COBB *box2)
{
float min1, max1;
float min2, max2;

ComputeBoxExtents(Axis, box1, min1, max1);
ComputeBoxExtents(Axis, box2, min2, max2);

return ExtentsOverlap(min1, max1, min2, max2);
}

Share this post


Link to post
Share on other sites
I didn't look at the rest of the code, but it looks like you have a couple of errors here:
m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._12, m_mOrientation._13);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._21, m_mOrientation._22, m_mOrientation._23);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._31, m_mOrientation._32, m_mOrientation._33);

Share this post


Link to post
Share on other sites
jyk: What was wrong with that code?

oliii: Here is basically all of my code. The Rotation/Creation/Translation all work "correctly".

.h

#pragma once

class COBB : public CCollisionInterface
{
private:
Vector3 m_vMin;
Vector3 m_vMax;
Vector3 m_vObjectBounds[8];
D3DXMATRIX m_mOrientation;

Vector3 m_vMove;

bool ExtentsOverlap(float min1, float max1, float min2, float max2);
void ComputeBoxExtents(D3DXVECTOR3 Axis, COBB *box, float &min, float &max);
bool AxisOverlap(D3DXVECTOR3 Axis, COBB *box1, COBB *box2);

public:
COBB();
~COBB();
D3DXVECTOR3 m_vDirections[3];
void SetupCollisionBox(float fX, float fY, float fZ, float fWidth, float fHeight, float fDepth);

bool CheckCollisionWithOBB(COBB *incBox);

void Translate(float fX, float fY, float fZ);

void Rotate(float fX, float fY, float fZ);

COBB *GetCollisionBox() { return this; }
Vector3 *GetObjectBounds() { return m_vObjectBounds; }
Vector3 GetMax() { return m_vMax; }
Vector3 GetMin() { return m_vMin; }

};

#endif


.cpp

COBB::COBB()
{
m_unCollisionType = OBB;
D3DXMatrixIdentity(&m_mOrientation);
m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._12, m_mOrientation._13);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._22, m_mOrientation._22, m_mOrientation._23);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._33, m_mOrientation._32, m_mOrientation._33);
}

COBB::~COBB()
{

}

void COBB::SetupCollisionBox(float fX, float fY, float fZ, float fWidth, float fHeight, float fDepth)
{
m_vMin = Vector3(fX, fY, fZ);
m_vMax = Vector3(fX + fWidth, fY + fHeight, fZ + fDepth);

m_vObjectBounds[0] = Vector3D(m_vMin.GetX(), m_vMin.GetY(), m_vMin.GetZ()); // xyz
m_vObjectBounds[1] = Vector3D(m_vMax.GetX(), m_vMin.GetY(), m_vMin.GetZ()); // Xyz
m_vObjectBounds[2] = Vector3D(m_vMin.GetX(), m_vMax.GetY(), m_vMin.GetZ()); // xYz
m_vObjectBounds[3] = Vector3D(m_vMax.GetX(), m_vMax.GetY(), m_vMin.GetZ()); // XYz
m_vObjectBounds[4] = Vector3D(m_vMin.GetX(), m_vMin.GetY(), m_vMax.GetZ()); // xyZ
m_vObjectBounds[5] = Vector3D(m_vMax.GetX(), m_vMin.GetY(), m_vMax.GetZ()); // XyZ
m_vObjectBounds[6] = Vector3D(m_vMin.GetX(), m_vMax.GetY(), m_vMax.GetZ()); // xYZ
m_vObjectBounds[7] = Vector3D(m_vMax.GetX(), m_vMax.GetY(), m_vMax.GetZ()); // XYZ

}

bool COBB::CheckCollisionWithOBB(COBB *incBox)
{
if(!AxisOverlap(this->m_vDirections[0], this, incBox)) return true;
if(!AxisOverlap(this->m_vDirections[1], this, incBox)) return true;
if(!AxisOverlap(this->m_vDirections[2], this, incBox)) return true;

if(!AxisOverlap(incBox->m_vDirections[0], this, incBox)) return true;
if(!AxisOverlap(incBox->m_vDirections[0], this, incBox)) return true;
if(!AxisOverlap(incBox->m_vDirections[0], this, incBox)) return true;

D3DXVECTOR3 BoxOnePosition = D3DXVECTOR3(GetMin().m_fX, GetMin().m_fY, GetMin().m_fZ);
D3DXVECTOR3 BoxTwoPosition = D3DXVECTOR3(incBox->GetMin().m_fX, incBox->GetMin().m_fY, incBox->GetMin().m_fZ);

D3DXVECTOR3 Test1, Test2, Test3, Test4, Test5, Test6, Test7, Test8, Test9;
D3DXVec3Cross(&Test1, &this->m_vDirections[0], &incBox->m_vDirections[0]);
D3DXVec3Cross(&Test2, &this->m_vDirections[0], &incBox->m_vDirections[1]);
D3DXVec3Cross(&Test3, &this->m_vDirections[0], &incBox->m_vDirections[2]);

D3DXVec3Cross(&Test4, &this->m_vDirections[1], &incBox->m_vDirections[0]);
D3DXVec3Cross(&Test5, &this->m_vDirections[1], &incBox->m_vDirections[1]);
D3DXVec3Cross(&Test6, &this->m_vDirections[1], &incBox->m_vDirections[2]);

D3DXVec3Cross(&Test7, &this->m_vDirections[2], &incBox->m_vDirections[0]);
D3DXVec3Cross(&Test8, &this->m_vDirections[2], &incBox->m_vDirections[1]);
D3DXVec3Cross(&Test9, &this->m_vDirections[2], &incBox->m_vDirections[2]);

if(!AxisOverlap(Test1, this, incBox)) return true;
if(!AxisOverlap(Test2, this, incBox)) return true;
if(!AxisOverlap(Test3, this, incBox)) return true;
if(!AxisOverlap(Test4, this, incBox)) return true;
if(!AxisOverlap(Test5, this, incBox)) return true;
if(!AxisOverlap(Test6, this, incBox)) return true;
if(!AxisOverlap(Test7, this, incBox)) return true;
if(!AxisOverlap(Test8, this, incBox)) return true;
if(!AxisOverlap(Test9, this, incBox)) return true;

return false;
}

bool COBB::ExtentsOverlap(float min1, float max1, float min2, float max2)
{
return !(min1 > max2 || min2 > max1);
}

void COBB::ComputeBoxExtents(D3DXVECTOR3 Axis, COBB *box, float &min, float &max)
{
D3DXVECTOR3 BoxPosition = D3DXVECTOR3(box->GetMin().m_fX, box->GetMin().m_fY, box->GetMin().m_fZ);

Vector3 halfsize = (GetMax() - GetMin()) * 0.5f;

float p = D3DXVec3Dot(&BoxPosition, &Axis);
float r0 = fabs(D3DXVec3Dot(&box->m_vDirections[0], &Axis)) * halfsize.m_fX;
float r1 = fabs(D3DXVec3Dot(&box->m_vDirections[1], &Axis)) * halfsize.m_fY;
float r2 = fabs(D3DXVec3Dot(&box->m_vDirections[2], &Axis)) * halfsize.m_fZ;

float r = r0 + r1 + r2;

min = p-r;
max = p+r;
}

bool COBB::AxisOverlap(D3DXVECTOR3 Axis, COBB *box1, COBB *box2)
{
float min1, max1;
float min2, max2;

ComputeBoxExtents(Axis, box1, min1, max1);
ComputeBoxExtents(Axis, box2, min2, max2);

return ExtentsOverlap(min1, max1, min2, max2);
}

void COBB::Translate(float fX, float fY, float fZ)
{
m_vMax += Vector3D(fX, fY, fZ);
m_vMin += Vector3D(fX, fY, fZ);

m_vMove += Vector3D(fX, fY, fZ);

for(unsigned int i = 0; i < 8; ++i)
m_vObjectBounds[i] += Vector3D(fX, fY, fZ);


}

void COBB::Rotate(float fX, float fY, float fZ)
{
D3DXMATRIX mRotation;
D3DXMatrixRotationYawPitchRoll(&mRotation, fY, fX, fZ);
m_mOrientation = mRotation;
m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._12, m_mOrientation._13);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._22, m_mOrientation._22, m_mOrientation._23);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._33, m_mOrientation._32, m_mOrientation._33);

//m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._21, m_mOrientation._31);
//m_vDirections[1] = D3DXVECTOR3(m_mOrientation._12, m_mOrientation._22, m_mOrientation._32);
//m_vDirections[2] = D3DXVECTOR3(m_mOrientation._13, m_mOrientation._23, m_mOrientation._33);


D3DXVECTOR3 vInput[8];

D3DXVECTOR3 CoR = D3DXVECTOR3(m_vMin.GetX(), m_vMin.GetY(), m_vMin.GetZ()); // centre of rotation?

for(int i = 0; i < 8; i ++)
{
vInput[i] = D3DXVECTOR3(m_vObjectBounds[i].GetX(), m_vObjectBounds[i].GetY(), m_vObjectBounds[i].GetZ());
vInput[i] -= CoR;

D3DXVec3TransformCoord(&vInput[i], &vInput[i], &mRotation);
vInput[i] = vInput[i] + CoR;
m_vObjectBounds[i] = Vector3D(vInput[i].x, vInput[i].y, vInput[i].z);;
}

//m_vMin = m_vMax = corner[0];
m_vMin = Vector3(vInput[0].x, vInput[0].y, vInput[0].z);
m_vMax = m_vMin;

for(int i = 1; i < 8; i ++)
{
if(vInput[i].x < m_vMin.GetX())
m_vMin.SetX(vInput[i].x);
else if(vInput[i].x > m_vMax.GetX())
m_vMax.SetX(vInput[i].x);


if(vInput[i].y < m_vMin.GetY())
m_vMin.SetY(vInput[i].y);
else if(vInput[i].y > m_vMax.GetY())
m_vMax.SetY(vInput[i].y);

if(vInput[i].z < m_vMin.GetZ())
m_vMin.SetZ(vInput[i].z);
else if(vInput[i].z > m_vMax.GetZ())
m_vMax.SetZ(vInput[i].z);
}

}

Share this post


Link to post
Share on other sites
your matrix axes are wrong...

either this

m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._21, m_mOrientation._31);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._12, m_mOrientation._22, m_mOrientation._32);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._13, m_mOrientation._23, m_mOrientation._33);


or this


m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._12, m_mOrientation._13);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._21, m_mOrientation._22, m_mOrientation._23);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._31, m_mOrientation._32, m_mOrientation._33);


try this for the compute box extents



void COBB::ComputeBoxExtents(D3DXVECTOR3 Axis, COBB *box, float &min, float &max)
{
D3DXVECTOR3 BoxPosition = D3DXVECTOR3(box->GetMin().m_fX, box->GetMin().m_fY, box->GetMin().m_fZ);

Vector3 halfsize = (GetMax() - GetMin()) * 0.5f;
Vector3 centre = (GetMax() + GetMin()) * 0.5f;

float p = D3DXVec3Dot(¢re, &Axis);

float r0 = fabs(D3DXVec3Dot(&box->m_vDirections[0], &Axis)) * halfsize.m_fX;
float r1 = fabs(D3DXVec3Dot(&box->m_vDirections[1], &Axis)) * halfsize.m_fY;
float r2 = fabs(D3DXVec3Dot(&box->m_vDirections[2], &Axis)) * halfsize.m_fZ;

float r = r0 + r1 + r2;

min = p-r;
max = p+r;
}


but really, you're obb is just wrong... it should be a centre position, an halfsize vector, and three directional vectors. Using min-max will just add too many complications.

Share this post


Link to post
Share on other sites
your matrix axes are wrong...

either this

m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._21, m_mOrientation._31);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._12, m_mOrientation._22, m_mOrientation._32);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._13, m_mOrientation._23, m_mOrientation._33);


or this


m_vDirections[0] = D3DXVECTOR3(m_mOrientation._11, m_mOrientation._12, m_mOrientation._13);
m_vDirections[1] = D3DXVECTOR3(m_mOrientation._21, m_mOrientation._22, m_mOrientation._23);
m_vDirections[2] = D3DXVECTOR3(m_mOrientation._31, m_mOrientation._32, m_mOrientation._33);


try this for the compute box extents



void COBB::ComputeBoxExtents(D3DXVECTOR3 Axis, COBB *box, float &min, float &max)
{
D3DXVECTOR3 BoxPosition = D3DXVECTOR3(box->GetMin().m_fX, box->GetMin().m_fY, box->GetMin().m_fZ);

Vector3 halfsize = (GetMax() - GetMin()) * 0.5f;
Vector3 centre = (GetMax() + GetMin()) * 0.5f;

float p = D3DXVec3Dot(¢re, &Axis);

float r0 = fabs(D3DXVec3Dot(&box->m_vDirections[0], &Axis)) * halfsize.m_fX;
float r1 = fabs(D3DXVec3Dot(&box->m_vDirections[1], &Axis)) * halfsize.m_fY;
float r2 = fabs(D3DXVec3Dot(&box->m_vDirections[2], &Axis)) * halfsize.m_fZ;

float r = r0 + r1 + r2;

min = p-r;
max = p+r;
}


but really, you're obb is just wrong... it should be a centre position, an halfsize vector, and three directional vectors. Using min-max will just add too many complications. I really cant understand how you transform works at all. The min-max are just there in object space. When you object moves in the world, the aabb then becomes on obb like this one :


#pragma once

class COBB : public CCollisionInterface
{
public:
COBB(const Vector& min, const Vector max);
~COBB();

bool CheckCollisionWithOBB(COBB *incBox);

void SetOrientation(float fX, float fY, float fZ);
void SetOrientation(float pitch, float yaw, float roll);

COBB *GetCollisionBox() { return this; }
Vector3 *GetObjectBounds() { return m_vObjectBounds; }

private:
bool ExtentsOverlap(float min1, float max1, float min2, float max2);
void ComputeBoxExtents(const Vector3& Axis, float &min, float &max);
bool AxisOverlap(D3DXVECTOR3 Axis, COBB *box1, COBB *box2);
void ComputeBounds();
void ComputeCentre();

Vector3 m_vDirections[3];
Vector3 m_vCentre;
Vector3 m_vHalfSize;
Vector3 m_vObjectBounds[8];

Vector3 m_vOffset;
Vector3 m_vPosition;
};





COBB::COBB(const Vector3& min, const Vector3& max)
{
m_vDirections[0] = Vector3(1, 0, 0);
m_vDirections[1] = Vector3(0, 1, 0);
m_vDirections[2] = Vector3(0, 0, 1);
m_vHalfSize = (max - min) * 0.5f;
m_vOffset = (max + min) * 0.5f;
m_vPosition = Vector3(0, 0, 0);

ComputeCentre();
ComputeBounds();
}

void COBB::ComputeCentre()
{
m_vCentre = m_vPosition;
m_vCentre += m_vDirections[0] * m_vOffset.m_fX;
m_vCentre += m_vDirections[1] * m_vOffset.m_fY;
m_vCentre += m_vDirections[2] * m_vOffset.m_fZ;
}

void COBB::ComputeBounds()
{
static const Vector3 s_corners[8] =
{
Vector3(-1, -1, -1),
Vector3(-1, -1, 1),
Vector3( 1, -1, 1),
Vector3( 1, -1, -1),
Vector3(-1, 1, -1),
Vector3(-1, 1, 1),
Vector3( 1, 1, 1),
Vector3( 1, 1, -1),
};

for(int i = 0; i < 8; i ++)
{
m_vObjectBounds[i] = m_vCentre;
m_vObjectBounds[i] += m_vDirections[0] * m_vHalfSize.m_fX * s_corners[i].m_fX;
m_vObjectBounds[i] += m_vDirections[1] * m_vHalfSize.m_fY * s_corners[i].m_fY;
m_vObjectBounds[i] += m_vDirections[2] * m_vHalfSize.m_fZ * s_corners[i].m_fZ;
}
}

void COBB::SetPosition(float fX, float fY, float fZ)
{
m_vPosition = Vector3(fX, fY, fZ);
ComputeCentre();
ComputeBounds();
}

void COBB::SetOrientation(float pitch, float yaw, float roll)
{
D3DXMATRIX mRotation;
D3DXMatrixRotationYawPitchRoll(&mRotation, yaw, pitch, roll);

m_vDirections[0] = Vector3(mRotation._11, mRotation._21, mRotation._31);
m_vDirections[1] = Vector3(mRotation._12, mRotation._22, mRotation._32);
m_vDirections[2] = Vector3(mRotation._13, mRotation._23, mRotation._33);

ComputeCentre();
ComputeBounds();
}

void COBB::ComputeBoxExtents(const Vector3& Axis, float &min, float &max)
{
float p = Axis.DotProduct(m_vCentre);
float r0 = fabs(Axis.DotProduct(m_vDirections[0]) * m_vHalfSize.m_fX;
float r1 = fabs(Axis.DotProduct(m_vDirections[1]) * m_vHalfSize.m_fY;
float r2 = fabs(Axis.DotProduct(m_vDirections[2]) * m_vHalfSize.m_fZ;
float r = r0 + r1 + r2;
min = p-r;
max = p+r;
}

bool COBB::AxisOverlap(const Vector3& Axis, COBB *box1, COBB *box2)
{
float axis_length_squared = Axis.DotProduct(Axis);

// check for degenerate axes. skip the test.
if(axis_length_squared < 1.0E-6f)
return true;

float min1, max1;
float min2, max2;

box1->ComputeBoxExtents(Axis, min1, max1);
box2->ComputeBoxExtents(Axis, min2, max2);

return ExtentsOverlap(min1, max1, min2, max2);
}

Share this post


Link to post
Share on other sites
During my OBB Creation, could I use the min as the as the position? Setting the position to just 0, 0, 0 doesn't seem right to me (well, with the way I am doing it). The way my translate works is it just takes the current position, then adds the incoming position. So if I am at (1, 1, 1) and I send it (2, 2, 3) the new position is (3, 3, 3). With that being said, do you see anything noticable wrong with this code?


void COBB::SetupCollisionBox(float fX, float fY, float fZ, float fWidth, float fHeight, float fDepth)
{
Vector vMin = Vector(fX, fY, fZ);
Vector vMax = Vector(fX + fWidth, fY + fHeight, fZ + fDepth);

m_vDirections[0] = Vector(1, 0, 0);
m_vDirections[1] = Vector(0, 1, 0);
m_vDirections[2] = Vector(0, 0, 1);
m_vHalfSize = (vMax - vMin) * 0.5f;
m_vOffset = (vMax + vMin) * 0.5f;
m_vPosition = vMin;//Vector(0, 0, 0);

ComputeCentre();
ComputeBounds();
}
void COBB::ComputeCentre()
{
m_vCentre = m_vPosition;
m_vCentre += m_vDirections[0] * m_vOffset.m_fX;
m_vCentre += m_vDirections[1] * m_vOffset.m_fY;
m_vCentre += m_vDirections[2] * m_vOffset.m_fZ;
}

void COBB::ComputeBounds()
{
static const Vector s_corners[8] =
{
Vector(-1, -1, -1),
Vector(-1, -1, 1),
Vector( 1, -1, 1),
Vector( 1, -1, -1),
Vector(-1, 1, -1),
Vector(-1, 1, 1),
Vector( 1, 1, 1),
Vector( 1, 1, -1),
};

for(int i = 0; i < 8; i ++)
{
m_vObjectBounds[i] = m_vCentre;
m_vObjectBounds[i] += m_vDirections[0] * m_vHalfSize.m_fX * s_corners[i].m_fX;
m_vObjectBounds[i] += m_vDirections[1] * m_vHalfSize.m_fY * s_corners[i].m_fY;
m_vObjectBounds[i] += m_vDirections[2] * m_vHalfSize.m_fZ * s_corners[i].m_fZ;
}
}


bool COBB::CheckCollisionWithOBB(COBB *incBox)
{
D3DXVECTOR3 thisDirection[3] =
{
D3DXVECTOR3(m_vDirections[0].GetX(), m_vDirections[0].GetY(), m_vDirections[0].GetZ()),
D3DXVECTOR3(m_vDirections[1].GetX(), m_vDirections[1].GetY(), m_vDirections[1].GetZ()),
D3DXVECTOR3(m_vDirections[2].GetX(), m_vDirections[2].GetY(), m_vDirections[2].GetZ()),
};

D3DXVECTOR3 incDirection[3] =
{
D3DXVECTOR3(incBox->m_vDirections[0].GetX(), incBox->m_vDirections[0].GetY(), incBox->m_vDirections[0].GetZ()),
D3DXVECTOR3(incBox->m_vDirections[1].GetX(), incBox->m_vDirections[1].GetY(), incBox->m_vDirections[1].GetZ()),
D3DXVECTOR3(incBox->m_vDirections[2].GetX(), incBox->m_vDirections[2].GetY(), incBox->m_vDirections[2].GetZ()),
};

if(!AxisOverlap(thisDirection[0], this, incBox)) return true;
if(!AxisOverlap(thisDirection[1], this, incBox)) return true;
if(!AxisOverlap(thisDirection[2], this, incBox)) return true;

if(!AxisOverlap(incDirection[0], this, incBox)) return true;
if(!AxisOverlap(incDirection[0], this, incBox)) return true;
if(!AxisOverlap(incDirection[0], this, incBox)) return true;

D3DXVECTOR3 BoxOnePosition = D3DXVECTOR3(GetPosition().m_fX, GetPosition().m_fY, GetPosition().m_fZ);
D3DXVECTOR3 BoxTwoPosition = D3DXVECTOR3(incBox->GetPosition().m_fX, incBox->GetPosition().m_fY, incBox->GetPosition().m_fZ);

D3DXVECTOR3 Test1, Test2, Test3, Test4, Test5, Test6, Test7, Test8, Test9;
D3DXVec3Cross(&Test1, &thisDirection[0], &incDirection[0]);
D3DXVec3Cross(&Test2, &thisDirection[0], &incDirection[1]);
D3DXVec3Cross(&Test3, &thisDirection[0], &incDirection[2]);

D3DXVec3Cross(&Test4, &thisDirection[1], &incDirection[0]);
D3DXVec3Cross(&Test5, &thisDirection[1], &incDirection[1]);
D3DXVec3Cross(&Test6, &thisDirection[1], &incDirection[2]);

D3DXVec3Cross(&Test7, &thisDirection[2], &incDirection[0]);
D3DXVec3Cross(&Test8, &thisDirection[2], &incDirection[1]);
D3DXVec3Cross(&Test9, &thisDirection[2], &incDirection[2]);

if(!AxisOverlap(Test1, this, incBox)) return true;
if(!AxisOverlap(Test2, this, incBox)) return true;
if(!AxisOverlap(Test3, this, incBox)) return true;
if(!AxisOverlap(Test4, this, incBox)) return true;
if(!AxisOverlap(Test5, this, incBox)) return true;
if(!AxisOverlap(Test6, this, incBox)) return true;
if(!AxisOverlap(Test7, this, incBox)) return true;
if(!AxisOverlap(Test8, this, incBox)) return true;
if(!AxisOverlap(Test9, this, incBox)) return true;

return false;
}

bool COBB::ExtentsOverlap(float min1, float max1, float min2, float max2)
{
return !(min1 > max2 || min2 > max1);
}

void COBB::ComputeBoxExtents(D3DXVECTOR3 Axis, COBB *box, float &min, float &max)
{
D3DXVECTOR3 vCentre(m_vCentre.GetX(), m_vCentre.GetY(), m_vCentre.GetZ());
D3DXVECTOR3 incDirection[3] =
{
D3DXVECTOR3(box->m_vDirections[0].GetX(), box->m_vDirections[0].GetY(), box->m_vDirections[0].GetZ()),
D3DXVECTOR3(box->m_vDirections[1].GetX(), box->m_vDirections[1].GetY(), box->m_vDirections[1].GetZ()),
D3DXVECTOR3(box->m_vDirections[2].GetX(), box->m_vDirections[2].GetY(), box->m_vDirections[2].GetZ()),
};

float p = D3DXVec3Dot(&vCentre, &Axis);
float r0 = fabs(D3DXVec3Dot(&incDirection[0], &Axis)) * m_vHalfSize.m_fX;
float r1 = fabs(D3DXVec3Dot(&incDirection[1], &Axis)) * m_vHalfSize.m_fY;
float r2 = fabs(D3DXVec3Dot(&incDirection[2], &Axis)) * m_vHalfSize.m_fZ;

float r = r0 + r1 + r2;

min = p-r;
max = p+r;
}

bool COBB::AxisOverlap(D3DXVECTOR3 Axis, COBB *box1, COBB *box2)
{
float min1, max1;
float min2, max2;

ComputeBoxExtents(Axis, box1, min1, max1);
ComputeBoxExtents(Axis, box2, min2, max2);

return ExtentsOverlap(min1, max1, min2, max2);
}

void COBB::Translate(float fX, float fY, float fZ)
{
m_vPosition += Vector(fX, fY, fZ);
ComputeCentre();
ComputeBounds();
}

void COBB::Rotate(float fX, float fY, float fZ)
{
D3DXMATRIX mRotation;
D3DXMatrixRotationYawPitchRoll(&mRotation, fY, fX, fZ);

m_vDirections[0] = Vector(mRotation._11, mRotation._12, mRotation._13);
m_vDirections[1] = Vector(mRotation._21, mRotation._22, mRotation._23);
m_vDirections[2] = Vector(mRotation._31, mRotation._32, mRotation._33);


ComputeCentre();
ComputeBounds();
}

Share this post


Link to post
Share on other sites
it's all a matter of where your centre of rotation is, so in your case :



Vector vMin = Vector(fX, fY, fZ);
Vector vMax = Vector(fX + fWidth, fY + fHeight, fZ + fDepth);
m_vDirections[0] = Vector(1, 0, 0);
m_vDirections[1] = Vector(0, 1, 0);
m_vDirections[2] = Vector(0, 0, 1);
m_vHalfSize = (vMax - vMin) * 0.5f; // half size of the box
m_vPosition = vMin;//Vector(0, 0, 0); // centre of rotation in object space
m_vOffset = (vMax + vMin) * 0.5f - (m_vPosition); // offset of the box centre to the centre of rotation in object space.

Share this post


Link to post
Share on other sites

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