Culling your scene to the View Frustum. |
Something that causes Frustration and an occasional Tantrum.
|
You could write code to reject those polygons yourself - but that would be pretty pointless because it would probably take as long - if not longer - than OpenGL takes.
The optimal solution is to do a coarse level cull in your application - rejecting entire objects that lie completely off the screen - and let OpenGL do the fine-grained cull at the level of individual polygons. This approach will greatly speed up most OpenGL applications.
This paper describes one efficient method for attacking this problem.
There is also a need to cull objects that are closer than the plane of the screen (including objects that are behind the user's head). Hence, the cull operation actually works in a truncated pyramid. The correct mathematical term for such a solid is a 'Frustum' (frequently mis-spelled Frustrum or Fustrum for some reason).
Everything that's completely inside the 'view frustum' needs to be drawn - everything that's completely outside can certainly be thrown away - anything that crosses the frustum is...erm... something we'll let OpenGL worry about at the polygon level - so we'll need to draw those objects also.
Since we don't want to duplicate the work of OpenGL at the vertex level, we'll want to test an entire object in one go - without looking at each vertex in turn. The way to do that is to 'summarise' the extent of the object using either a sphere or cubeoid that just encloses all of the objects' vertices. This is called a 'bounding volume'.
Personally, I prefer to use a bounding sphere - but opinions vary on this point.
So, the problem boils down to "How do I tell if an arbitary sphere is either inside or crossing the six planes of the frustum?" - Fortunately, there is a really easy way to do that.
A*x + B*y + C*z + D = 0...that plane equation calculation can be done one-time whenever the view frustum is set up.
Note that for an arbitary point (px,py,pz), the distance to the plane is:
d = A*px + B*py + C*pz + D...so for each vertex of your bounding volume, you can measure the distance to each of those planes.
For a sphere: Just toss the center point of the sphere into the equation above - and if the (signed) distance places the center point more than 'radius' units outside any of the planes then you can cull the object.
That was easy!
Only if the super-sphere straddles the frustum do you need to go and test all of those smaller objects.
To generalize this, you might want a hierarchy of spheres- containing-spheres - how deep and how 'wide' that tree needs to be depends on your application.
If do you use a heirarchical bounding volume scheme - then you can do more: You can (for example) flag *which* planes you were entirely 'inside' of and not re-test them for lesser objects.
Still, for each sphere, you may need to do as many as six sphere-center-to-plane distance calculations.
...Or do you?
If you have a relatively 'normal' symmetrical view frustum, there are some simplifications that save a lot of CPU time in calculating those six distances. Notice that: