🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Frustum culling problem

Started by
3 comments, last by sangmi 4 years, 6 months ago
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
Advertisement
I can advice some books that could help you with that:
Programming Role Playing Games with Directx and Programming a multiplayer first person shooter with directx.
Do you want to know how to make games?
http://howtomakeagam...n.blogspot.com/
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.
Thanks very much for the info:)

Don't you have to change this loop in cullAABB from

for (WORD i=0;i<5;i++)

to

for (WORD i=0;i<6;i++)

This topic is closed to new replies.

Advertisement