Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have noticed that BoundingFrustum.Intersects() is a rather slow check in XNA. I am doing only 256 checks per frame and it eats up arround 50-60% of availible time when running at 60fps. This is kind of crazy. I would like to know if anyone else has experienced these types of performance problems with the BoundingFrustum class in XNA? Does anyone suggest I make my own boundingfrustum class/struct?

(One pitfall, when using the BoundingFrustum class, is declaring a new instance of it every frame... for some reason it is a class and not a struct. I am not doing this.)

share|improve this question
    
Can you include the relevant parts of your code? Frustum checks can be more expensive than people sometimes think, especially with XNA's horrible floating point performance on the Xbox 360, but 256 checks should barely be notable. –  user744 Dec 14 '10 at 17:44
    
Trust me, my code is fine. The intersection test has been implemented with accuracy in mind, with performance being optional. –  Mike Dec 15 '10 at 3:08
    
-1. It's hard to help when you won't share the necessary details of what you're doing. –  user744 Dec 15 '10 at 10:16
2  
What more is there to share? Mike is correct in that BoundingFrustum.Intersects() is not as fast as it could be. This can easily be confirmed by Reflector. –  arriu Dec 15 '10 at 17:36
add comment

1 Answer

up vote 2 down vote accepted

It seemed a little strange to me so I made a little app to test how much time it took. It appears that the time the intersects method takes varies by where the axis aligned bounding boxes are positioned. This makes sense because more checks are needed in some cases to verify that an intersection is not occurring.

I imagine you are running this code on the Xbox 360 since you have a large performance impact. Using Reflector it is easy to see that the method was not coded with speed in mind. The function is riddled with floating point operations and function calls. The compact .Net framework does not inline any function calls and combined with the horrible floating point performance I can see why so much time is used up by the intersects function.

I did some research and came across this article: http://zach.in.tu-clausthal.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html

There are various faster methods for frustum culling you could implement to speed things up. Here is a reasonably accurate intersects implementation which is about 7 to 10 times faster. (note: it does give a few false positives, see the "Geometric Approach - Testing Boxes" section of the article above)

public static class FrustumHelper
{
        public static Vector3 GetNegativeVertex(this BoundingBox aabb, 
                                                ref Vector3 normal)
        {
            Vector3 p = aabb.Max;
            if (normal.X >= 0)
                p.X = aabb.Min.X;
            if (normal.Y >= 0)
                p.Y = aabb.Min.Y;
            if (normal.Z >= 0)
                p.Z = aabb.Min.Z;

            return p;
        }

        public static void FastIntersects(this BoundingFrustum boundingfrustum, 
                                          ref BoundingBox aabb, 
                                          out bool intersects)
        {
            intersects = false;

            Plane plane; Vector3 normal, p;

            plane = boundingfrustum.Bottom;
            normal = plane.Normal;
            normal.X = -normal.X; 
            normal.Y = -normal.Y; 
            normal.Z = -normal.Z;
            p = aabb.GetPositiveVertex(ref normal);
            if (-plane.D + normal.X * p.X + normal.Y * p.Y + normal.Z * p.Z < 0)
                return;

            plane = boundingfrustum.Far;
            normal = plane.Normal;
            normal.X = -normal.X;
            normal.Y = -normal.Y;
            normal.Z = -normal.Z;
            p = aabb.GetPositiveVertex(ref normal);
            if (-plane.D + normal.X * p.X + normal.Y * p.Y + normal.Z * p.Z < 0)
                return;

            plane = boundingfrustum.Left;
            normal = plane.Normal;
            normal.X = -normal.X;
            normal.Y = -normal.Y;
            normal.Z = -normal.Z;
            p = aabb.GetPositiveVertex(ref normal);
            if (-plane.D + normal.X * p.X + normal.Y * p.Y + normal.Z * p.Z < 0)
                return;

            plane = boundingfrustum.Near;
            normal = plane.Normal;
            normal.X = -normal.X;
            normal.Y = -normal.Y;
            normal.Z = -normal.Z;
            p = aabb.GetPositiveVertex(ref normal);
            if (-plane.D + normal.X * p.X + normal.Y * p.Y + normal.Z * p.Z < 0)
                return;

            plane = boundingfrustum.Right;
            normal = plane.Normal;
            normal.X = -normal.X;
            normal.Y = -normal.Y;
            normal.Z = -normal.Z;
            p = aabb.GetPositiveVertex(ref normal);
            if (-plane.D + normal.X * p.X + normal.Y * p.Y + normal.Z * p.Z < 0)
                return;

            plane = boundingfrustum.Top;
            normal = plane.Normal;
            normal.X = -normal.X;
            normal.Y = -normal.Y;
            normal.Z = -normal.Z;
            p = aabb.GetPositiveVertex(ref normal);
            if (-plane.D + normal.X * p.X + normal.Y * p.Y + normal.Z * p.Z < 0)
                return;

            intersects = true;
        }
}
share|improve this answer
    
presumably even faster if you do all that normals work when you set the frustum instead of each intersection test –  Will Jan 25 '11 at 6:33
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.