Jump to content
  • Advertisement
Sign in to follow this  
kevlur

Frustum culling problem

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

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 this post


Link to post
Share on other sites
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.

Share this post


Link to post
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 this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!