Jump to content
  • Advertisement
Sign in to follow this  
RobMaddison

Frustum culling discrepancy

This topic is 2106 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 just noticed that my DIP calls is higher than it should be and it turns out I'm rendering things slightly outside my Frustum.  I'm using some code I found from the FlipCode website which checks each AABB corner against the frustum planes and I think there are some major flaws with it. 

 

It returns -1if all of the AABB corners are outside a plane - this is fine.

It returns 1 if all of the AABB corners are inside all planes - this is also fine.

It returns 0 if the AABB is 'partly inside', i.e. if at least one point is inside the frustum.  This, I found doesn't work with situations like the one I've attached in the image.  In the image, the bounding box is not in the frustum, but using this method, it will return that it's intersecting.  Corner B1 is inside the frustum plane P2 and Corner B2 is inside the frustum plane P1, but it should be outside.

 

Is there a better way of handling intersecting boxes?  Can't quite get my head around what checks I need to do

	// if all points are behind 1 specific plane, we are out
	// if we are in with all points, then we are fully in
	for(int p = 0; p < 6; ++p)
	{
		int iInCount = 8;
		int iPtIn = 1;		

		for(int i = 0; i < 8; ++i) 
		{			
			// test this point against the planes
			if(m_frustumPlanes[p].DistanceToPoint(corner[i]) < 0)
			{
				iPtIn = 0;
				--iInCount;
			}
		}	

		// were all the points outside of plane p?
		if(iInCount == 0)
			return(-1);		

		// check if they were all on the right side of the plane
		iTotalIn += iPtIn;
	}	

	// so if iTotalIn is 6, then all are inside the view
	if(iTotalIn == 6)
		return(1);	

	// we must be partly in then otherwise
	return(0);

Share this post


Link to post
Share on other sites
Advertisement

You have to add an extra check for whether ALL points are outside. In fact, this is the only thing you have to check.

 

Your example doesn't make much sense either. Do you mean that the AABB is larger than the frustum, and the frustum is inside the AABB? You could handle this by checking the frustum corners against the AABB planes - if all frustum points are inside the AABB, render the object.

 

Nope... that's not it either. Why don't you use bounding spheres instead? :D For AABB, it's not enough to check the corners - you'd have to treat the sides of the AABB and frustum as polygons, and check for polygon intersections to be able to tell if the AABB is "partly in".

Edited by tonemgub

Share this post


Link to post
Share on other sites
bool static extentSignedTest(const Vector4f& p, const Vector3f& center, const Vector3f& extent)
{
        return (dot(Vector3(p), center) + dot(abs(Vector3(p)), extent) < -p.w);
}
 
bool static isAABBInFrustum(const AABB& box, const Matrix44& frustumMatrix)
{                      
        const Vector4f  rowX                    = frustumMatrix.getRow(0);
        const Vector4f  rowY                    = frustumMatrix.getRow(1);
        const Vector4f  rowZ                    = frustumMatrix.getRow(2);
        const Vector4f  rowW                    = frustumMatrix.getRow(3);
       
        const Vector3f& center =  box.getCenter();
        const Vector3f& extent =  box.getExtents();
 
        // Left and right planes              
        if (extentSignedTest(rowW + rowX, center, extent))
                return false;
 
        if (extentSignedTest(rowW - rowX, center, extent))
                return false;
 
        // Bottom and top planes
        if (extentSignedTest(rowW + rowY, center, extent))
                return false;
 
        if (extentSignedTest(rowW - rowY, center, extent))
                return false;
       
        // Near and far planes
        if (extentSignedTest(rowW + rowZ, center, extent))
                return false;
 
        if (extentSignedTest(rowW - rowZ, center, extent))
                return false;
 
        return true;
}

Fast and simple but really tight object/world/view space bounding box frustum test. Simply calculate modelViewProjection matrix and send that and boundinBox(center, halfExtent).

 

For static objects you can calculate world space AABB and just send viewProj matrix.

 

There is also extension for even better accuracy which test if frustum corner points are inside of AABB. That should be quite easy to extend for my algorithm

http://www.iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm

 

 

Share this post


Link to post
Share on other sites

Guys, just as I was typing my reply to tonemgub when I saw the other replies and the sphere check idea sounds like a great alternative.  I can fit that in without too many changes.

 

This frustum code was something from my testbed engine from years ago, I'm glad I revisited it and not so glad I just pulled it from the web without checking it too much!

 

Thanks a lot for all the replies

Share this post


Link to post
Share on other sites

Nope... that's not it either. Why don't you use bounding spheres instead? biggrin.png For AABB, it's not enough to check the corners - you'd have to treat the sides of the AABB and frustum as polygons, and check for polygon intersections to be able to tell if the AABB is "partly in".

 

I didn't want to downvote you, but just to have it on paper for someone who stumbles over this thread: This is plain and simple wrong. You can eigther do it like L.Spiro did, or alternatively you can use the normal of the plane to determine the one corner point of the AABB that needs to be checked. All other points are definately on the same side of the plane (* if you treat the intersection case the same as being inside, which is OK if you just want to do frustum culling). Like this:

bool AABB::InsidePlane(const Plane& plane) const
{
    Vector3 vCenter = m_vCenter;
    const Vector3& vNormal = plane.GetNormal();

    if(vNormal.x >= 0.0f)  
        vCenter.x += m_vSize.x;
    else
        vCenter.x -= m_vSize.x;  

    if(vNormal.y >= 0.0f)  
        vCenter.y += m_vSize.y;
    else
        vCenter.y -= m_vSize.y;

    if(vNormal.z >= 0.0f)  
        vCenter.z += m_vSize.z;
    else
        vCenter.z -= m_vSize.z;

    float posDot = plane.Dot(vCenter);

    return posDot >= 0.0f;
}

Checking against all 6 box points is extremely slow in comparison, but converting the AABB and frustum planes to polygons is outright insane.

Edited by Juliean

Share this post


Link to post
Share on other sites

L. Spiro, how do you deal with situations where the AABB is not square?

The above code handles all cases of 3D AABB’s stored as I showed (mins and maxes for each axis provided). There is no restriction on the dimensions of the AABB.
I assume you got confused by the fact that there is only 1 member for the mins and 1 for the maxes. These are each 3D vectors, each holding an x, y, and z value.


L. Spiro Edited by L. Spiro

Share this post


Link to post
Share on other sites

L. Spiro, how do you deal with situations where the AABB is not square?

The above code handles all cases of 3D AABB’s stored as I showed (mins and maxes for each axis provided). There is no restriction on the dimensions of the AABB.I assume you got confused by the fact that there is only 1 member for the mins and 1 for the maxes. These are each 3D vectors, each holding an x, y, and z value.L. Spiro

No, my bounding boxes are stored in the exact same way. What I meant was, if you've got an AABB which is the shape of, say a deep pizza box (perhaps it's a terrain patch with relatively small height changes), the sphere would cover the extents of the box in the x and z directions, but in the y direction the sphere would extend downward far beyond the extents of the polygons - that said, it's possible that if the camera frustum is pointing downwards toward the terrain, parts of the terrain could be drawn that are nowhere near in the frustum.

Unless I've read it wrong?

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!