Microsoft DirectX 8.1 (C++) |
This sample illustrates how to cull objects whose object bounding box (OBB) does not intersect the viewing frustum. By not passing these objects to Microsoft® Direct3D®, you save the time that would be spent by Direct3D transforming and lighting these objects, which will never be visible. The time saved could be significant if there are many such objects or if the objects contain many vertices.
More elaborate and efficient culling can be done by creating hierarchies of objects, with bounding boxes around groups of objects, so that not every object's OBB has to be compared to the view frustum.
It is more efficient to do this OBB/frustum intersection calculation in your own code than to use Direct3D to transform the OBB and check the resulting clip flags.
You can adapt the culling routines in this sample meet the needs of programs that you write.
Source: (SDK root)\Samples\Multimedia\Direct3D\Cull
Executable: (SDK root)\Samples\Multimedia\Direct3D\Bin
When you run this program, you'll see a scene with teapots rendered into two viewports. The right viewport uses the view frustum that the code will cull against. The left viewport has an independent camera, and shows the right viewport's frustum as a visible object, so you can see where culling should occur. Fifty teapots are randomly placed in the scene and they are rendered along with their semitransparent OBBs.
The teapots are colored as follows to indicate their cull status.
Color | Description | Cull status |
---|---|---|
Dark green | The object was quickly determined to be inside the frustum. | CS_INSIDE |
Light green | The object was determined after some work to be inside the frustum. | CS_INSIDE_SLOW |
Dark red | The object was quickly determined to be outside the frustum. | CS_OUTSIDE |
Light red | The object was determined after some work to be outside the frustum | CS_OUTSIDE_SLOW |
You should see only green teapots in the right window. Note that most teapots are either dark green or dark red, indicating that the slower tests are not needed for the majority of cases.
To move the camera for the right viewport, click on the right side of the window, then use the camera keys listed below to move around.
To move the camera for the left viewport, click on the left side of the window, then use the camera keys listed below to move around.
You can also rotate the teapots to set up particular relationships against the view frustum. You cannot move the teapots, but you can get the same effect by moving the frustum instead.
The following table lists the keys that are implemented. You can use menu commands for the same controls.
Key | Action |
---|---|
F1 | Shows help or available commands |
F2 | Prompts the user to select a new rendering device or display mode |
ALT+ENTER | Toggles between full-screen and windowed modes |
ESC | Exits the application |
W, S, ARROW KEYS | Moves the camera |
Q, E, A, Z | Rotates the camera |
Y, U, H, J | Rotates the teapots |
N | Moves the left camera to match the right camera |
M | Moves the right camera to its original position |
The OBB/viewport intersection algorithm used by this program is:
The distinction between CS_INSIDE and CS_INSIDE_SLOW, and between CS_OUTSIDE and CS_OUTSIDE_SLOW, is provided here only for educational purposes. In a shipping application, you probably would combine the cull states into just CS_INSIDE and CS_OUTSIDE, because usually you need to know only whether the OBB is inside or outside the frustum.
The culling code shown here is written in a straightforward way for readability. It is not optimized for performance. Additional optimizations can be made, especially if the bounding box is a regular box (for example, the front and back faces are parallel). This algorithm could be generalized to work for arbitrary convex bounding hulls to allow tighter fitting against the underlying models.
This sample uses common DirectX code that consists of programming elements such as helper functions. This code is shared with other samples in the DirectX SDK. You can find the common headers and source code in (SDK root)\Samples\Multimedia\Common.