This topic is now archived and is closed to further replies.

Reasons for "premature" culling?

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

Hello everyone. I have recently gotten culling to work for my meshes (see, I got it right), and in all my excitement I didn''t realize that my culling wasn''t working correctly (NOTE: I am using modified code from the "Cull" sample from the SDK). Imagine a scene with one model in the center and the interactive camera in looking straight at it: When the camera is, lets say, 10 units away, everything looks correctly. Now, lets say we tilt the camera up a bit. Now the mesh should still be in the frustum, but it isn''t being drawn. Next, lets say we move forward toward the object. Now that we are 5 (estimate) units away from the objects, it disappears again. Does anyone know a reason why this could happen so I can go back and recheck my code? I have tried rewriting several times, so I suspect that I''m not doing something correctly. If you want to see parts of my code, I will be happy to post it. Thanks.

Share this post

Link to post
Share on other sites
Ok, here it goes: I am culling (bounding) boxes, using modified code from the "Cull" example.

There are two main classes for my culling: CBoundingBox and CFrustum. CBoundingBox has two (relatively) short functions:

HRESULT CBoundingBox::Compute(PVOID pPointsFVF,
DWORD dwNumVerts,

if(FAILED( hr = D3DXComputeBoundingBox( pPointsFVF, dwNumVerts, dwFVF, &vecMin, &vecMax )))
return hr;

m_vecBoundsLocal[0] = D3DXVECTOR3( vecMin.x, vecMin.y, vecMin.z ); // xyz

m_vecBoundsLocal[1] = D3DXVECTOR3( vecMax.x, vecMin.y, vecMin.z ); // Xyz

m_vecBoundsLocal[2] = D3DXVECTOR3( vecMin.x, vecMax.y, vecMin.z ); // xYz

m_vecBoundsLocal[3] = D3DXVECTOR3( vecMax.x, vecMax.y, vecMin.z ); // XYz

m_vecBoundsLocal[4] = D3DXVECTOR3( vecMin.x, vecMin.y, vecMax.z ); // xyZ

m_vecBoundsLocal[5] = D3DXVECTOR3( vecMax.x, vecMin.y, vecMax.z ); // XyZ

m_vecBoundsLocal[6] = D3DXVECTOR3( vecMin.x, vecMax.y, vecMax.z ); // xYZ

m_vecBoundsLocal[7] = D3DXVECTOR3( vecMax.x, vecMax.y, vecMax.z ); // XYZ

return hr;


void CBoundingBox::Recompute(D3DXMATRIX matOrientation)
// Transform bounding box coords from local space to world space

for( int i = 0; i < 8; i++ )
D3DXVec3TransformCoord( &m_vecBoundsWorld[i], &m_vecBoundsLocal[i], &matOrientation );

// Determine planes of the bounding box

D3DXPlaneFromPoints( &m_planeBoundsWorld[0], &m_vecBoundsWorld[0],
&m_vecBoundsWorld[1], &m_vecBoundsWorld[2] ); // Near

D3DXPlaneFromPoints( &m_planeBoundsWorld[1], &m_vecBoundsWorld[6],
&m_vecBoundsWorld[7], &m_vecBoundsWorld[5] ); // Far

D3DXPlaneFromPoints( &m_planeBoundsWorld[2], &m_vecBoundsWorld[2],
&m_vecBoundsWorld[6], &m_vecBoundsWorld[4] ); // Left

D3DXPlaneFromPoints( &m_planeBoundsWorld[3], &m_vecBoundsWorld[7],
&m_vecBoundsWorld[3], &m_vecBoundsWorld[5] ); // Right

D3DXPlaneFromPoints( &m_planeBoundsWorld[4], &m_vecBoundsWorld[2],
&m_vecBoundsWorld[3], &m_vecBoundsWorld[6] ); // Top

D3DXPlaneFromPoints( &m_planeBoundsWorld[5], &m_vecBoundsWorld[1],
&m_vecBoundsWorld[0], &m_vecBoundsWorld[4] ); // Bottom


CBoundingBox::Compute() is called once during the creation of the object-to-be-culled:

VOID* pVertices;
if( FAILED( hr = m_pObjMesh->GetSysMemMesh()->LockVertexBuffer(D3DLOCK_READONLY, (BYTE**)&pVertices) ) )
return hr;

if( FAILED( hr = m_BoundingBox.Compute(pVertices,
return hr;


CBoundingBox::Recompute() is called once every frame.

CFrustum has one function to update the FOV:

void CFrustum::UpdateFrustum(D3DXMATRIX* pMatView, D3DXMATRIX* pMatProj)
D3DXMatrixMultiply( &mat, pMatView, pMatProj );
D3DXMatrixInverse( &mat, NULL, &mat );

vecFrustum[0] = D3DXVECTOR3(-1.0f, -1.0f, 0.0f); // xyz

vecFrustum[1] = D3DXVECTOR3( 1.0f, -1.0f, 0.0f); // Xyz

vecFrustum[2] = D3DXVECTOR3(-1.0f, 1.0f, 0.0f); // xYz

vecFrustum[3] = D3DXVECTOR3( 1.0f, 1.0f, 0.0f); // XYz

vecFrustum[4] = D3DXVECTOR3(-1.0f, -1.0f, 1.0f); // xyZ

vecFrustum[5] = D3DXVECTOR3( 1.0f, -1.0f, 1.0f); // XyZ

vecFrustum[6] = D3DXVECTOR3(-1.0f, 1.0f, 1.0f); // xYZ

vecFrustum[7] = D3DXVECTOR3( 1.0f, 1.0f, 1.0f); // XYZ

for( INT i = 0; i < 8; i++ )
D3DXVec3TransformCoord(&vecFrustum[i],&vecFrustum[i], &mat );

D3DXPlaneFromPoints( &planeFrustum[0], &vecFrustum[0],
&vecFrustum[1], &vecFrustum[2] ); // Near

D3DXPlaneFromPoints( &planeFrustum[1], &vecFrustum[6],
&vecFrustum[7], &vecFrustum[5] ); // Far

D3DXPlaneFromPoints( &planeFrustum[2], &vecFrustum[2],
&vecFrustum[6], &vecFrustum[4] ); // Left

D3DXPlaneFromPoints( &planeFrustum[3], &vecFrustum[7],
&vecFrustum[3], &vecFrustum[5] ); // Right

D3DXPlaneFromPoints( &planeFrustum[4], &vecFrustum[2],
&vecFrustum[3], &vecFrustum[6] ); // Top

D3DXPlaneFromPoints( &planeFrustum[5], &vecFrustum[1],
&vecFrustum[0], &vecFrustum[4] ); // Bottom


The objects rendering code looks like this:

HRESULT CObject::Render(CFrustum *pFrustum)

m_cullstate = CullObject(pFrustum, m_BoundingBox.GetLocalBoundingBoxCoords(),
return S_OK;
m_pObjMesh->Render(m_pd3dDevice, TRUE, TRUE);
return S_OK;
return S_OK;
m_pObjMesh->Render(m_pd3dDevice, TRUE, TRUE);
return S_OK;
return S_OK;
return E_FAIL;

return S_OK;

The CullObject() function is too long for me too here without getting yelled at, but it can be found in cull.cpp in the "cull" sample. This has probably been very vague, so I can elaborate if needed.

Share this post

Link to post
Share on other sites
Take a look at this site:

note: you will notice some negative signs in code that makes a frustum out of the matrix, you need to remove them to make it work

Combind that with Mark Morly''s code and you have a _working_ D3D Frustum

Share this post

Link to post
Share on other sites