# Frustum culling problem

This topic is 4991 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi all, I've tried to implement frustum culling, but im having problem with the far plane of the frustum. As explained in http://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf and on the website www.toymaker.info im doing like this(using C++ and Direct3D):

struct TFrustumPlane             /*Struct that define a frustum plane*/
{
D3DXVECTOR3 m_normal;
float m_distance;

inline void Normalise()
{
float denom = 1 / sqrt((m_normal.x*m_normal.x) + (m_normal.y*m_normal.y) + (m_normal.z*m_normal.z));
m_normal.x = m_normal.x * denom;
m_normal.y = m_normal.y * denom;
m_normal.z = m_normal.z * denom;
m_distance = m_distance * denom;
}

inline float DistanceToPoint(D3DXVECTOR3 &v)
{
return D3DXVec3Dot(&m_normal, &v) + m_distance;
}

};

TFrustumPlane m_frustumPlanes[6];   /* the 6 frustum planes */

void ExtractPlanes(void)            /* Function that extract the 6 planes */
{                                   /* and store each of them in          */
D3DXMATRIXA16 matComb;      /* a TFrustumPlane                    */

D3DXMatrixMultiply(&matComb, &viewMatrix, &projectionMatrix);

// Left clipping plane
m_frustumPlanes[0].m_normal.x = matComb._14 + matComb._11;
m_frustumPlanes[0].m_normal.y = matComb._24 + matComb._21;
m_frustumPlanes[0].m_normal.z = matComb._34 + matComb._31;
m_frustumPlanes[0].m_distance = matComb._44 + matComb._41;

// Right clipping plane
m_frustumPlanes[1].m_normal.x = matComb._14 - matComb._11;
m_frustumPlanes[1].m_normal.y = matComb._24 - matComb._21;
m_frustumPlanes[1].m_normal.z = matComb._34 - matComb._31;
m_frustumPlanes[1].m_distance = matComb._44 - matComb._41;

// Top clipping plane
m_frustumPlanes[2].m_normal.x = matComb._14 - matComb._12;
m_frustumPlanes[2].m_normal.y = matComb._24 - matComb._22;
m_frustumPlanes[2].m_normal.z = matComb._34 - matComb._32;
m_frustumPlanes[2].m_distance = matComb._44 - matComb._42;

// Bottom clipping plane
m_frustumPlanes[3].m_normal.x = matComb._14 + matComb._12;
m_frustumPlanes[3].m_normal.y = matComb._24 + matComb._22;
m_frustumPlanes[3].m_normal.z = matComb._34 + matComb._32;
m_frustumPlanes[3].m_distance = matComb._44 + matComb._42;

// Near clipping plane
m_frustumPlanes[4].m_normal.x = matComb._13;
m_frustumPlanes[4].m_normal.y = matComb._23;
m_frustumPlanes[4].m_normal.z = matComb._33;
m_frustumPlanes[4].m_distance = matComb._43;

// Far clipping plane
m_frustumPlanes[5].m_normal.x = matComb._14 - matComb._13;
m_frustumPlanes[5].m_normal.y = matComb._24 - matComb._23;
m_frustumPlanes[5].m_normal.z = matComb._34 - matComb._33;
m_frustumPlanes[5].m_distance = matComb._44 - matComb._43;

m_frustumPlanes[0].Normalise();
m_frustumPlanes[1].Normalise();
m_frustumPlanes[2].Normalise();
m_frustumPlanes[3].Normalise();
m_frustumPlanes[4].Normalise();
m_frustumPlanes[5].Normalise();
}

WORD cullAABB(const D3DXVECTOR3 &aabbMin,   /* Test one AABB against the */
const D3DXVECTOR3 &aabbMax)   /* frustum                   */
{

bool intersect = FALSE;
WORD result=0;
D3DXVECTOR3 minExtreme,maxExtreme;

for (WORD i=0;i<5;i++)
{
if (m_frustumPlanes.m_normal.x >= 0)
{
minExtreme.x = aabbMin.x;
maxExtreme.x = aabbMax.x;
}
else
{
minExtreme.x = aabbMax.x;
maxExtreme.x = aabbMin.x;
}

if (m_frustumPlanes.m_normal.y >= 0)
{
minExtreme.y = aabbMin.y;
maxExtreme.y = aabbMax.y;
}
else
{
minExtreme.y = aabbMax.y;
maxExtreme.y = aabbMin.y;
}

if (m_frustumPlanes.m_normal.z >= 0)
{
minExtreme.z = aabbMin.z;
maxExtreme.z = aabbMax.z;
}
else
{
minExtreme.z = aabbMax.z;
maxExtreme.z = aabbMin.z;
}

if((m_frustumPlanes.DistanceToPoint(minExtreme) < 0) &&
(m_frustumPlanes.DistanceToPoint(maxExtreme) < 0))

return 0;
}

return 1;
}

void FrustumCulling(void)         /* Frustum culling :-) */
{

int i = 0;
D3DXVECTOR3 Min, Max;
int inside = 0;

ExtractPlanesD3D();

for(i = 0; i < NUMOBJ; i++)
{

OBJ.GetBoxMinMax(&Min, &Max);

inside = cullAABB(Min, Max);

if(inside)
OBJ.InsideFrustum = 1;
else
OBJ.InsideFrustum = 0;
}
}


This is the code i use and it works fine for all the clipping planes except for the far one; i know that it doesnt work with the far clipping plane cause ive put a rendered objects counter in the render() loop and even if i go far away from the objects (so far that they arent visible cause they are more far than the value i have set in D3DXMatrixPerspectiveFovLH for the far plane) and i look in direction of them, they are counted as rendered objects. For all the others 5 planes it works fine. Is there something wrong in the code where i extract the far plane normal and distance from the ViewProjection matrix? Is there something wrong in the function that test the AABB against a plane? Is there another way to get the far clipping plane normal and distance? Maybe extracting them from the others planes? What have i to do to know where is the problem? I am really stuck with this. I do appreciate whatever helps. Thanks in advance Kev

##### Share on other sites
Programming Role Playing Games with Directx and Programming a multiplayer first person shooter with directx.

##### Share on other sites
Your far plane normal is the same as the near plane, just backwards. So there's really no reason to calculate it. Just..

FarNormal.x = -NearNormal.x;
FarNormal.y = -NearNormal.y;
FarNormal.z = -NearNormal.z;

Actually, calculating both your near and far plane are pretty easy if you have a matrix for your camera's state. A camera state matrix would just be an inverted view matrix. In other words, if you use a matrix to rotate and move your camera, you can simply invert that to obtain your view matrix. You can then speed up calculations such as frustum planes by using the camera's matrix.

Do you know how matrices work? A 4x4 3D matrix is basically just 3 directions and a translation coordinate. Like a complex compass that points in 3 directions. So your near plane normal is just the forward direction in your camera matrix. The far plane normal is the same, but negative.

By using your camera's position, you can also cull objects against the frustum by using normals alone (you don't need plane distances). Here's the method I wrote to cull a single point with my setup:
BOOL Camera::Cull_Point(const Vector &p){	const Vector offset = p - GetCameraPosition();	FLOAT point_distance = CameraForward.Dot( offset );	if( point_distance < Setup.Display.Camera.Near	||  point_distance > Setup.Display.Camera.Far )		return TRUE;	if(	Frust_Left.Dot( offset ) < 0.0f	||	Frust_Right.Dot( offset ) < 0.0f	||	Frust_Top.Dot( offset ) < 0.0f	||	Frust_Bottom.Dot( offset ) < 0.0f )		return TRUE;	// It's visible	return FALSE;}

Frust_Left and such are just the frustum normals. Vector p is the position point to cull. CameraForward is just the forward direction pulled straight from the camera matrix. Let me know if you want me to add detail to something.

edit: Oops. Forgot to mention that Setup.Display.Camera.Near and Setup.Display.Camera.Far are just constant float values. The same values you use to calculate your projection matrix.

##### Share on other sites
Thanks very much for the info:)

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 9
• 31
• 16
• 11
• 10
• ### Forum Statistics

• Total Topics
634121
• Total Posts
3015613
×