OOBB Creation/Intersection

Started by
22 comments, last by oliii 15 years, 10 months ago
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?
Advertisement
Have you tried this one? It's in C# but logic should be pretty similar to C/C++.

Link
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.
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 = D3DXVECTOR3(m_vObjectBounds.GetX(), m_vObjectBounds.GetY(), m_vObjectBounds.GetZ());	// Rotate the vInput based off the matrix and store in vOutput	for(int i = 0; i < 8; ++i)		D3DXVec3TransformCoord(&vOutput, &vInput, &rotation);	// Covert to Vector	for(int i = 0; i < 8; ++i)		m_vObjectBounds = Vector(vOutput.x, vOutput.y, vOutput.z);	// Find the new min/max	D3DXVECTOR3 min = vOutput[0];	D3DXVECTOR3 max = vOutput[0];	for(int i = 0; i < 8; ++i)	{		if(vOutput.x < min.x)			min.x = vOutput.x;		else if(vOutput.x > max.x)			max.x = vOutput.x;		if(vOutput.y < min.y)			min.y = vOutput.y;		else if(vOutput.y > max.y)			max.y = vOutput.y;		if(vOutput.z < min.z)			min.z = vOutput.z;		else if(vOutput.z > max.z)			max.z = vOutput.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?
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.

Everything is better with Metal.

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.
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).
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 aabbcorners[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 = cor + (corners - cor) * orientation;}// the aabb of the obbvector aabbmin = obb[0];vector aabbmax = obb[0];for(int i = 1; i < 8; i ++){    if(obb.x < aabbmin.x)         aabbmin.x = obb.x;     else if(obb.x > aabbmax.x)         aabbmax.x = obb.x;     if(obb.y < aabbmin.y)         aabbmin.x = obb.y;     else if(obb.y > aabbmax.y)         aabbmax.y = obb.y;     if(obb.z < aabbmin.z)         aabbmin.z = obb.z;     else if(obb.z > aabbmax.z)         aabbmax.z = obb.z; }

Everything is better with Metal.

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?
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);

Everything is better with Metal.

This topic is closed to new replies.

Advertisement