# Strange rotation sympton, aabb extents (with video)

## Recommended Posts

cozzie    5029

Hi,

I have a strange problem with calculating my AABB extents, min and max.

For testing I places 2 small cubes in my scene, which constantly take over the AABB's min and max vertices as a world position.

This perfectly illustrates the sympton.

Only with 90, 180, 270 or 360 degrees rotation the extents match the real min and max points of the rotating object.

Here's the video:

Below are the related code parts.

This is what I do:

- calculate the AABB initally with untransformed, not rotated verticies

- the 8 corners are stored in a 'base' vertex array

- every frame where the object is moved or rotated, I transform the 8 base vertices with the new matrix

- then I find the min/ max extents to use for AABB culling

Can someone help me out?

// initial creation of the AABB

void CreateAABB(TVERTEX *pVtxArray, DWORD pStart, DWORD pNr, BOUNDINGBOX *pBox)
{
// MIN and MAX vertices
pBox->min.x = pVtxArray[pStart].position.x;
pBox->min.y = pVtxArray[pStart].position.y;
pBox->min.z = pVtxArray[pStart].position.z;

pBox->max.x = pVtxArray[pStart].position.x;
pBox->max.y = pVtxArray[pStart].position.y;
pBox->max.z = pVtxArray[pStart].position.z;

for(DWORD vc=pStart;vc<pStart+pNr;++vc)
{
if(pVtxArray[vc].position.x < pBox->min.x) pBox->min.x = pVtxArray[vc].position.x;
if(pVtxArray[vc].position.x > pBox->max.x) pBox->max.x = pVtxArray[vc].position.x;

if(pVtxArray[vc].position.y < pBox->min.y) pBox->min.y = pVtxArray[vc].position.y;
if(pVtxArray[vc].position.y > pBox->max.y) pBox->max.y = pVtxArray[vc].position.y;

if(pVtxArray[vc].position.z < pBox->min.z) pBox->min.z = pVtxArray[vc].position.z;
if(pVtxArray[vc].position.z > pBox->max.z) pBox->max.z = pVtxArray[vc].position.z;
}

// FULL 8 vertices of the AABB
pBox->boxArrayBase[0].x = pBox->min.x;
pBox->boxArrayBase[0].y = pBox->min.y;
pBox->boxArrayBase[0].z = pBox->min.z;

pBox->boxArrayBase[1].x = pBox->max.x;
pBox->boxArrayBase[1].y = pBox->max.y;
pBox->boxArrayBase[1].z = pBox->max.z;

pBox->boxArrayBase[2].x = pBox->max.x;
pBox->boxArrayBase[2].y = pBox->max.y;
pBox->boxArrayBase[2].z = pBox->min.z;

pBox->boxArrayBase[3].x = pBox->min.x;
pBox->boxArrayBase[3].y = pBox->max.y;
pBox->boxArrayBase[3].z = pBox->min.z;

pBox->boxArrayBase[4].x = pBox->min.x;
pBox->boxArrayBase[4].y = pBox->min.y;
pBox->boxArrayBase[4].z = pBox->max.z;

pBox->boxArrayBase[5].x = pBox->max.x;
pBox->boxArrayBase[5].y = pBox->min.y;
pBox->boxArrayBase[5].z = pBox->max.z;

pBox->boxArrayBase[6].x = pBox->max.x;
pBox->boxArrayBase[6].y = pBox->min.y;
pBox->boxArrayBase[6].z = pBox->min.z;

pBox->boxArrayBase[7].x = pBox->min.x;
pBox->boxArrayBase[7].y = pBox->max.y;
pBox->boxArrayBase[7].z = pBox->max.z;

for(int i=0;i<8;++i) pBox->boxArray[i] = pBox->boxArrayBase[i];
pBox->created = true;
}

// updating the AABB

bool UpdateAABB(BOUNDINGBOX *pBox)
{
if(!pBox->created) return false;

//	8 AABB corners need to be transformed by the latest world matrix
//	now find the 2 extents

pBox->min.x = pBox->boxArray[0].x;
pBox->min.y = pBox->boxArray[0].y;
pBox->min.z = pBox->boxArray[0].z;

pBox->max.x = pBox->boxArray[0].x;
pBox->max.y = pBox->boxArray[0].y;
pBox->max.z = pBox->boxArray[0].z;

for(int vc=0;vc<8;++vc)
{
if(pBox->boxArray[vc].x < pBox->min.x) pBox->min.x = pBox->boxArray[vc].x;
if(pBox->boxArray[vc].x > pBox->max.x) pBox->max.x = pBox->boxArray[vc].x;

if(pBox->boxArray[vc].y < pBox->min.y) pBox->min.y = pBox->boxArray[vc].y;
if(pBox->boxArray[vc].y > pBox->max.y) pBox->max.y = pBox->boxArray[vc].y;

if(pBox->boxArray[vc].z < pBox->min.z) pBox->min.z = pBox->boxArray[vc].z;
if(pBox->boxArray[vc].z > pBox->max.z) pBox->max.z = pBox->boxArray[vc].z;
}
return true;
}

// update the world matrix

bool CD3dmeshInst::UpdateWorldMatrix()
{
if(!mDynamic) return false;
if(!mIsMoved && !mIsRotated && !mIsScaled) return false;

if(mIsMoved)
{
D3DXMatrixIdentity(&mMatTranslate);
D3DXMatrixTranslation(&mMatTranslate, mWorldPos.x, mWorldPos.y, mWorldPos.z);
}
if(mIsRotated)
{
D3DXMatrixIdentity(&mMatRotateX);
D3DXMatrixIdentity(&mMatRotateY);
D3DXMatrixIdentity(&mMatRotateZ);
}
if(mScale)
{
D3DXMatrixIdentity(&mMatScale);
D3DXMatrixScaling(&mMatScale, mScale, mScale, mScale);
}

mMatWorld = (D3DXMATRIXA16)(mMatScale*mMatRotateX*mMatRotateY*mMatRotateZ*mMatTranslate);

D3DXMatrixInverse(&mMatWorldInv, NULL, &mMatWorld);
D3DXMatrixTranspose(&mMatWorldInvTransp, &mMatWorldInv);
return true;
}

// update the bounding volume based on new world matrix

bool CD3dmeshInst::UpdateBVWorldSpace()
{
// WORLD MATRIX should be already updated

if(!mDynamic) return false;

// FULL mesh
if(mIsMoved || mIsRotated || mIsScaled)			// TO BE SPECIFIED LATER
{

for(int i=0;i<8;++i) D3DXVec3TransformCoord(&mBoundingBox.boxArray[i], &mBoundingBox.boxArrayBase[i], &mMatWorld);

if(!UpdateAABB(&mBoundingBox)) return false;

}
return true;
}



Rotation, translation etc. of the mesh all work fine, I use the same updated mMatWorld matrix for rendering the mesh through my shaders without problems. Maybe something wrong with updating/ transforming the boundingbox corners/ extents? radians and degrees?

Help );

##### Share on other sites
RobTheBloke    2553

Video looks correct for a local AABB to world space AABB conversion, and the code looks correct. If you draw lines to define the AABB, you'll quickly that it matches the min/max extents just fine. I suspect your confusion is because you have created a world space AABB, but were expecting to see an OBB rather than the AABB you're getting back.

##### Share on other sites
cozzie    5029

Hi rob.

Don't know if I understand you correct. I try to update the world space AABB when a object is rotated or moved, to achieve that the min/ max extents of the bounding box stay the same relative to the object itself. Maybe that's an OBB then :)

I understand what you mean that the extents you see in the demo/ video are the extents which will count for any rotation (sort of max. independent of rotation).

Do you know how I can achieve that the extents are matched with the rotation?

I thought I would do that by transforming the 8 corners from local space into worldspace, using the World Matrix where I both applied transformation (pos) and rotations, which should bring me to new world space 8 corners (including rotation). Or am i overseeing something?

##### Share on other sites
cozzie    5029

Here's a static image where I rotated the object 30 degrees on the Y-axis.

Showing the AABB extents, this means that's is culled quite a bit later then going out of the frustum (which I try to get more accurate).

It's a bit confusing because I understand that the extents are correct when I want rotation independence.

Here's the same situation, where the object is not rotated/ Y rot = 0

Edited by cozzie

##### Share on other sites
RobTheBloke    2553

Don't know if I understand you correct. I try to update the world space AABB when a object is rotated or moved, to achieve that the min/ max extents of the bounding box stay the same relative to the object itself. Maybe that's an OBB then

Yup, that's an OBB.

There is a simple way of doing this, although for some reason, most people overcomplicate things. To construct an OBB from an AABB + transform, do this:

// just because it explains how I think about the world....
struct Matrix
{
Vec3 x;
Vec3 y;
Vec3 z;
Vec3 w;
};

const Vec3 minBound; //< AABB Points in local space (w == 1)
const Vec3 maxBound;
const Matrix worldTransform; //< of your mesh

// compute the extents. Note this is a vector quantity, not a Point! (w == 0)
Vec3 extents = maxBound - minBound;

// and OBB is just a matrix in effect.
Matrix OBB;

// transform minBound into world space.
OBB.w = minBound * worldTransform;

// scale transform axes by extents.
OBB.x = worldTransform.x * extents.x;
OBB.y = worldTransform.y * extents.y;
OBB.z = worldTransform.z * extents.z;

// Ok. At this point, you can test this worked by drawing a single unit length cube ([0,0,0] to [1,1,1]) using
// OBB as the transform. It should match your local space OBB exactly. If not, you've got a bug
// (or my tired eyes have got the maths wrong)

// Storing an OBB like this is however useless for most people.

// So, invert the OBB....
OBB = invert(OBB);

// now, given some world space point:
Vec3 P;

// transform it by the matrix
Vec3 P1 = P * OBB;

// is it inside the OBB?
if( P1.x <= 1.0f && P1.x >= 0 && P1.y <= 1.0f && P1.y >= 0 && P1.z <= 1.0f && P1.z >= 0 )
{
// inside the unit lengthed cube, therefore it's inside the OBB
}

ray intersections and the like, can simply be performed against a unit lengthed cube ([0,0,0] to [1,1,1]), by transforming the Ray/Frustum/Whatever into the local space of the box. You could modify the code to center the OBB on the center of the AABB (and test against the cube [-0.5,-0.5,-0.5] to [0.5,0.5,0.5]), but that will just come down to personal preference. Some people prefer having a Min/Max bound along with the transform, but I can't see the point in that personally.... (well, i suppose it would reduce the data required to just the same data that you're already storing, the local space AABB bounds + the world matrix)

Edited by RobTheBloke

##### Share on other sites
cozzie    5029

Thanks Rob. As soon as I understand it, it'll solve my problem :)

Just kidding.

I'm trying to understand it, and tried to write it out step by step.

What I do now, initially:

1 - find min and max vertices(bounds?) in local space, no rotation etc.

2 - define 8 corners based on local space min and max vertices (save in 'base array')

updating:

3 - update worldmatrix of the mesh

4 - transform the 8 base vertices (corners) with world matrix of the mesh.

Now the 8 corners are in world space. Is this where I have then created an OBB?

5 - from these 8 corners find min and max, so I have updated min/max vertices (bounds?)

From min and max vertices I find the center en size vertices

6 - I check with the frustum planes using center and size vertices

So now I'm probably back to checking an AABB against frustum plains, or not? (where in step 5 I had an OBB)

If the above assumptions are correct, then my change should probably be after step 4.

If it possible that I keep using the checking P and N vertex with the frustum planes, where P/N vertices are following the planes normal direction?

If so, my change would be in step 5, in creating the correct min and max vertices of the OBB.

Sorry for the maybe simple questions, I'm really trying to understand.

##### Share on other sites
RobTheBloke    2553

You are creating an AABB. To create an OBB, do the same process for a box where the min bound is [0,0,0], and the max bound is [1,1,1]. Once created, this doesn't need to change. Using a matrix (centered at [0,0,0]), you can use scale to change the size, and simply rotate and translate to position and orient the box. Any other object you want to test against the OBB (such as a frustum) can be transformed into the local space of the AABB (the one between 0,0,0 and 1,1,1) by transforming it by the inverse of your OBB transform. You'd need to figure out how to transform a plane by a matrix (which handles the 6 planes of the frustum), or transform the frustum point and regenerate (which is less efficient), but either way it's not too complicated. At that point, if you have code for an AABB/Frustum test, it will work without modification. The advantage is that the frustum is now in the local space of the mesh data, which means any further testing you may need, it pretty trivial (without needing to transform the vertices for example)

If after step 4 you generated plane equations from those points, you would have an OBB (in world space), however that makes the frustum tests somewhat more complicated. The way i suggested doesn't need step 4 (since the points are always the same, as are the 6 planes of the box). I'd probably start with OBB/point, OBB/ray, before moving onto OBB/frustum to be honest - it'll be much easier to get your head around.

##### Share on other sites
EWClay    659
You can cull the OBB directly against the frustum without transforming anything.

If the box centre is c, the box axes are ax, ay, az, and the sizes on each axis are sx, sy, sz, then:

d = dot(c, plane)
s = abs(dot(ax, plane)) * sx + abs(dot(ay, plane)) * sy + abs(dot(az, plane)) * sz

If d > s not culled
If d < -s culled
Otherwise intersects.

##### Share on other sites
cozzie    5029

Thanks both. I think I'm getting it. For for being bit 'slow' on this subject.

I thought about it and come to the following approach:

Initial

- create 8 corners AABB from original vertices (untransformed, not rotated)

- find min, max, center and size vertices

Updating (after rotating/moving etc.)

- transform the 8 original (AABB) corners with world matrix (rotate/translate)

- update min, max, center and size vertices

Check OBB against frustum:

- go through all 6 planes

- d = dot(center, plane)

- s = abs(dot(ax, plane)) * size.x + abs(dot(ay, plane)) * size.y + abs(dot(az, plane)) * size.z

- if d > s inside frustum (stop checking if true for 1 plane)

- if d < -s outside frustum

There's one thing I'm not sure about yet, how do I get ax/ay/az, I assume I need to use my world matrix for this.

Which in this case is an endresult of the scale, rotation and translation matrices.

If I'm overseeing something, any comments are really appreciated.

##### Share on other sites
EWClay    659
The box centre is translated by the world matrix. The box size is the size in model coordinates and does not change. ax, ay and az come straight out of the world matrix. The bounding box vertices are not used in the method I described, nor are min and max.

##### Share on other sites
cozzie    5029
Ok, clear.
I can ignore updating min/max and corner vertices (unless used for other purposes). Initially I'll use them to find center and size.

For the ax, ay and yz I'll pick _m11, _m21, _m31, _m41 for x out the worldmatrix (2nd column for y, 3rd for z). Which includes both translation and rotation, bringing me to worldspace.

Now I fully understand i'll go implement it now and keep you posted.

##### Share on other sites
RobTheBloke    2553

You can cull the OBB directly against the frustum without transforming anything.

No you can't. By definition, the box has an orientation, and so that MUST be taken into account.

The box centre is translated by the world matrix. The box size is the size in model coordinates and does not change. ax, ay and az come straight out of the world matrix. The bounding box vertices are not used in the method I described, nor are min and max.

Your method is actually identical to mine (albeit with the origin in the middle of the box, rather than a corner). The big difference, is that you are employing a load of dot products to perform an inverse transformation on each plane equation / vector. This is exactly why I recommended performing the inverse transformation on the OBB matrix!! To make this as simple to understand as possible....  consider these two methods to inverse trnasform some points:

void inverseTransformPointsA(Matrix parent, std::vector<Vector3>& points)
{
for(uint32_t i =0; i< children.size(); ++i)
{
Vector3 p = points[i] - parent.w;
float px = dot( parent.x, p.x ) / dot( parent.x, parent.x );
float py = dot( parent.y, p.y ) / dot( parent.y, parent.y );
float pz = dot( parent.z, p.z ) / dot( parent.z, parent.z );
points[i] = Vector3( px, py, pz );
}
}
void inverseTransformPointsB(Matrix parent, std::vector<Vector3>& points)
{
Matrix inverse_parent = invert(parent);
for(uint32_t i =0; i< children.size(); ++i)
{
points[i] = inverse_parent.x * points[i].x;
points[i] += inverse_parent.y * points[i].y;
points[i] += inverse_parent.z * points[i].z;
points[i] += inverse_parent.w;
}
}


Of those two methods, the latter method can be computed with 3 mult + 3 add per vertex (when using SIMD). The first method requires a large number of dot products, which can't be vectorized easily (which should be apparent since it's computing x/y/z separately). It also requires a number of divisions, unless (as you have done) you say that scale is not allowed in your transformation matrix. Whilst there is _mm_dp_ps available in SSE4, it's not exactly quick (a single _mm_dp_ps instruction will take longer to execute than my entire inner loop). The latter method handles scaled objects without a problem.

##### Share on other sites
EWClay    659
I was trying to get away from the idea of transforming all the vertices. Transforming the planes into model space is a valid way to go. (Although it would lead to some questions over which parts can be pre-calculated in this case versus the unrotated case.)

As for the most efficient way of vectorising this, I think that's another discussion.

##### Share on other sites
cozzie    5029

Good to hear there are (at least) 2 approaches. Not sure though if I understand the one where I don't transform the vertices.

Trying to understand and use the other 'version' now first (and maybe later optimize/ beter vectorising).

Almost there but not the expected result unfortunately.

I checked/ debugged and see that the OBBcenter is correctly translated (center of the OBB).

Will dig into it to try to find what's wrong, as always, any advice is welcome

// checking OBB against frustum

int CD3dcam::OBBInFrustum(BOUNDINGBOX *pBoundingBox, D3DXMATRIX *pWorldMatrix)
{
float d, s;

for(int i=0;i<6;++i)
{
D3DXVECTOR3 planevector = D3DXVECTOR3(mFrustumPlane[i].a, mFrustumPlane[i].b, mFrustumPlane[i].c);

d = D3DXVec3Dot(&pBoundingBox->OBBcenter, &planevector);
s = abs	(D3DXVec3Dot(&D3DXVECTOR3(pWorldMatrix->_11, pWorldMatrix->_21, pWorldMatrix->_31), &planevector)) * pBoundingBox->OBBsize.x +
abs	(D3DXVec3Dot(&D3DXVECTOR3(pWorldMatrix->_12, pWorldMatrix->_22, pWorldMatrix->_32), &planevector)) * pBoundingBox->OBBsize.y +
abs	(D3DXVec3Dot(&D3DXVECTOR3(pWorldMatrix->_13, pWorldMatrix->_23, pWorldMatrix->_33), &planevector)) * pBoundingBox->OBBsize.z;

if(d > s) return INTERSECT;		// intersecting, early quit??
if(d < -s) return OUTSIDE;
}
return INSIDE;
}

// creating the AABB initially

void CreateAABB(TVERTEX *pVtxArray, DWORD pStart, DWORD pNr, BOUNDINGBOX *pBox)
{
// MIN and MAX vertices - modelspace
pBox->AABBmin.x = pVtxArray[pStart].position.x;
pBox->AABBmin.y = pVtxArray[pStart].position.y;
pBox->AABBmin.z = pVtxArray[pStart].position.z;

pBox->AABBmax.x = pVtxArray[pStart].position.x;
pBox->AABBmax.y = pVtxArray[pStart].position.y;
pBox->AABBmax.z = pVtxArray[pStart].position.z;

for(DWORD vc=pStart;vc<pStart+pNr;++vc)
{
if(pVtxArray[vc].position.x < pBox->AABBmin.x) pBox->AABBmin.x = pVtxArray[vc].position.x;
if(pVtxArray[vc].position.x > pBox->AABBmax.x) pBox->AABBmax.x = pVtxArray[vc].position.x;

if(pVtxArray[vc].position.y < pBox->AABBmin.y) pBox->AABBmin.y = pVtxArray[vc].position.y;
if(pVtxArray[vc].position.y > pBox->AABBmax.y) pBox->AABBmax.y = pVtxArray[vc].position.y;

if(pVtxArray[vc].position.z < pBox->AABBmin.z) pBox->AABBmin.z = pVtxArray[vc].position.z;
if(pVtxArray[vc].position.z > pBox->AABBmax.z) pBox->AABBmax.z = pVtxArray[vc].position.z;
}

pBox->AABBsize.x = pBox->AABBmax.x - pBox->AABBmin.x;
pBox->AABBsize.y = pBox->AABBmax.y - pBox->AABBmin.y;
pBox->AABBsize.z = pBox->AABBmax.z - pBox->AABBmin.z;

pBox->AABBcenter = pBox->AABBmax - (pBox->AABBsize / 2.0f);

pBox->created = true;
}

D3DXVec3TransformCoord(&mBoundingBox.OBBcenter, &mBoundingBox.AABBcenter, &mMatWorld);
mBoundingBox.OBBsize = mBoundingBox.AABBsize; // ONLY UPDATE WITH SCALING



I also tried to use 'size.x / 2.0f' etc, but no effect.

Edited by cozzie

##### Share on other sites
cozzie    5029

Update;

I didn't normalize the axes from the world matrix, so just did that (before I can calculate the dot product with size).

Unfortunately not the expected result yet, culling happens to late (objects way out of the frustum and still not culled, till 'far away' from the objects).

What I have now:

int CD3dcam::OBBInFrustum(BOUNDINGBOX *pBoundingBox, D3DXMATRIX *pWorldMatrix)
{
float d, s;

for(int i=0;i<6;++i)
{
D3DXVECTOR3 planevector = D3DXVECTOR3(mFrustumPlane[i].a, mFrustumPlane[i].b, mFrustumPlane[i].c);

D3DXVECTOR3 ax, ay, az;
D3DXVec3Normalize(&ax, &D3DXVECTOR3(pWorldMatrix->_11, pWorldMatrix->_21, pWorldMatrix->_31));
D3DXVec3Normalize(&ay, &D3DXVECTOR3(pWorldMatrix->_12, pWorldMatrix->_22, pWorldMatrix->_32));
D3DXVec3Normalize(&az, &D3DXVECTOR3(pWorldMatrix->_13, pWorldMatrix->_23, pWorldMatrix->_33));

d = D3DXVec3Dot(&pBoundingBox->OBBcenter, &planevector);
s = abs	(D3DXVec3Dot(&ax, &planevector)) * pBoundingBox->OBBsize.x +
abs	(D3DXVec3Dot(&ay, &planevector)) * pBoundingBox->OBBsize.y +
abs	(D3DXVec3Dot(&az, &planevector)) * pBoundingBox->OBBsize.z;

if(d > s) return INTERSECT;		// intersecting, early quit??
if(d < -s) return OUTSIDE;
}
return INSIDE;
}



##### Share on other sites
EWClay    659
Dot of the centre with the plane should be D3DXPlaneDotCoord, I'm sure you were using that before. And don't return INTERSECT before the end because another plane could still reject it.

##### Share on other sites
cozzie    5029

Thanks, got it 'improved' I think.

Not sure though what's going wrong.

I've done some debugging, and when an object is expected to be culled (outside all 6 frustum planes), I get the following values for d and s:

plane 1: d = 25, s = 10

plane 2: d = -5.4, s = 11.6

plane 3: d = 5.44, s = 8.3

plane 4: d = 7.5, s = 12.5

plane 5: d = 16.5, s = 12.5

plane 6: d = 133, s = 12.5

For plane 1, 5 and 6 d > s, so it returns inside, where I expected all 6 to be d < -s.

int CD3dcam::OBBInFrustum(BOUNDINGBOX *pBoundingBox, D3DXMATRIX *pWorldMatrix)
{
float d, s;

for(int i=0;i<6;++i)
{
D3DXVECTOR3 planevector = D3DXVECTOR3(mFrustumPlane[i].a, mFrustumPlane[i].b, mFrustumPlane[i].c);

D3DXVECTOR3 ax = D3DXVECTOR3(pWorldMatrix->_11, pWorldMatrix->_21, pWorldMatrix->_31);
D3DXVECTOR3 ay = D3DXVECTOR3(pWorldMatrix->_12, pWorldMatrix->_22, pWorldMatrix->_32);
D3DXVECTOR3 az = D3DXVECTOR3(pWorldMatrix->_13, pWorldMatrix->_23, pWorldMatrix->_33);
D3DXVec3Normalize(&ax, &ax);
D3DXVec3Normalize(&ay, &ay);
D3DXVec3Normalize(&az, &az);

d = D3DXPlaneDotCoord(&mFrustumPlane[i], &pBoundingBox->OBBcenter);

s = abs	(D3DXVec3Dot(&ax, &planevector)) * pBoundingBox->OBBsize.x +
abs	(D3DXVec3Dot(&ay, &planevector)) * pBoundingBox->OBBsize.y +
abs	(D3DXVec3Dot(&az, &planevector)) * pBoundingBox->OBBsize.z;

if(d > s) return INSIDE;
if(d < -s) return OUTSIDE;
}
return INTERSECT;
}



##### Share on other sites
EWClay    659
Should be impossible to be outside all 6 planes. Just pick one and debug that. Centre dot plane should be zero if the box centre is exactly on the plane. Note that this is very similar to sphere culling, with s replacing the radius.

##### Share on other sites
cozzie    5029

Thanks, I'll debug some more to find out.

What I also was thinking about, is find the relation in the 'd > s' and 'd < -s' check, could I explain this as checking the nearest and farthest extents of the OBB?

(basically checking a point like you said, with sphere checking)

##### Share on other sites
cozzie    5029

Hi Ewclay,

Think I found something while debugging, when I use size /2 in the equation (so half size basically), it's now working correct for one plane.

I think I'm rejecting/ culling to early, after only one plane is processed.

If I take out if d > s RETURN INSIDE and only reject when d < -s I'm all good on the result (but possibly checking to much).

Any pointers I'd really appreciate.

Edited by cozzie

##### Share on other sites
EWClay    659
That sounds okay. The only time you would care about being fully inside is when using hierarchical culling, in which case you could skip any further culling under that node.

##### Share on other sites
cozzie    5029

Thanks, if I understand correct I now loop through all planes, till I find a plane where both extents of the OBB are outside a plane.

If so I return OUTSIDE. If all planes are processed and it's not fully outside, I return INTERSECT. Meaning that it could be either fully inside or partially inside/ intersecting with at least 1 plane.

To get this information I think I need to keep track of how many planes return inside based on d being > s.

If it's 6 in the end, the OBB is fully inside. Is this correct?

If so, I'll decide to implement it right away or later on when I'm introducing hierarchical culling (planned to do that not far from now).

##### Share on other sites
EWClay    659
You don't need to count them; any plane intersecting means the box is not fully inside.

##### Share on other sites
cozzie    5029

OK, then I'm not sure if I get it.

Original approach:

loop through planes

if d > s, return inside

if d < -s, return outside

if not returned after 6 planes

return intersect

When I do this, the result is only correct for 1 of the 6 planes (1st one processed). If I take out "if d > s return inside", the result is as aspected. But then I don't know if it's fully inside or intersecting (only returns outside or intersect at the end).

What I don't get is how I could then differ between inside or intersect (putting back if d > s return inside will stop checking the rest of the planes to early).

##### Share on other sites
EWClay    659
You just need to think through the logic of this.

If the box is fully outside any plane, no further planes need to be tested and you can return OUTSIDE immediately.

Any plane intersecting means the box is not fully inside, but you can't return INTERSECT until all the planes have been tested because one of them might still cull the box.

## Create an account

Register a new account