I want to check a view frustum against the axis aligned bounding boxes of some objects, to check roughly whether those objects are in the field of view or not. Speed is not a big deal.
2 Answers
I figured out that building a world-space model of the view frustum and checking for bbox collisions with it was the wrong way to go about this.
A much simpler method is to go the opposite way and convert each vertex of a given bbox to screen-space, and if any vertex of the bbox is within the screen bounds then count that bbox as visible. I get the screen-space position by multiplying against the camera matrix and then accounting for perspective based on the field of view of the camera.Here's the code:
vertexMatrix = matrix([vertex.x,vertex.y,vertex.z,1])
productMatrix = (vertexMatrix * camMatrix)
pVectSS = vector(prodMatrix[0][0],prodMatrix[0][1],prodMatrix[0][2])
pointX = ((pVectSS.x/(-pVectSS.z))/tan(radians(hFOV/2)))/2.0+.5
pointY = ((pVectSS.y/(-pVectSS.z))/tan(radians(vFOV/2)))/2.0+.5
key:
camMatrix = camera inverse world-space matrix
pVectSS = position vector screen-space
hFOV = horizontal field of view
vFOV = vertical field of view

- 95
- 2
- 10
-
2There are several cases where the bb is within the frustum but its corners are not – Morgan Jun 26 '22 at 04:53
That will work. However, usually one would rather extract the frustum planes and calculate the distances to these. You said "speed is not a big deal", but eventually you may find that it is. After all, one does frustum culling to make things faster.
Multiplying a vertex with a matrix takes the equivalent of 4 dot products, therefore you need the equivalent of 32 dot products to check all 8 corners. Calculating the distance of a point to a plane takes a dot product and an addition, which is somewhat more efficient in the worst case and much more efficient in the average case (since you can often discard an object after clipping after one or two planes, and never more than three). There are a number of optimizations for clip planes that exploit temporary coherence, which I will not go into deeper detail.
Additionally, you can do some coarse culling beforehand by calculating the distance of the center point to a plane and check whether that is greater than the bounding box's radius. This will cull objects that are clearly "in" or "out" very cheaply. Or, alternatively, you could compare the dot product of your view vector to the cosine of your field of view value plus some "padding" (or alternatively, just see if it is positive) as a first ultra-coarse check. As you will remember, the dot product of two vectors tells you how much they point into the same direction. Something that has a negative dot product with your view vector certainly is something you can safely discard, because it's behind you.

- 67,688
- 20
- 135
- 185
-
I should have elaborated why speed is not a factor in this case; the script is used for pre-processing a 3d scene to decide which objects to export to a ray-trace renderer, so in the scheme of things its runtime speed isn't important, just implementation speed :). My answer was actually a bit wrong too, as there is an edge case where a large object is close to the camera and its verts are all outside the FOV, so I ended up just drawing screen-space bbox around the world-space one, which is a pretty bad hack, but good enough for now. – leohutson Mar 23 '11 at 00:24
-
For a raytracer, even only a handful of fragments here and there at boundaries may make a huge difference. You could consider drawing your scene using OpenGL (with fixed functionality if you want, since speed does not matter so much, and it's easy), and run an occlusion query for each object (supported by pretty much every graphics card since at least half a decade). No z-test, so transparent objects don't cull what's completely behind them, we're not interested in a pretty render anyway. All we want is a positive number in the query for any object that has as much as one fragment drawn. – Damon Mar 23 '11 at 08:26
-
Though another thing comes to mind: What about objects that are culled (regardless of the method) but needed anyway? When someone says "raytrace", the first thing that comes to mind are shiny things with reflections. An object can very well be visible in a reflective surface when it is far outside the viewing frustum. That may be not very noticeable in some situations, but will give very funny effects in others, especially with animation. If that can be a problem, you should rather not discard anything in the scene export. – Damon Mar 23 '11 at 08:30
-
Yeah, you're right, in this case it was necessary to cull objects because each object was in the region of 3 million poly's, plus all the reflections are very diffuse, so they aren't particularly affected by distant objects. The ray-tracer didn't want to cull objects itself since, like you say, reflective objects are usually affected by off-screen objects. – leohutson Mar 28 '11 at 04:20