4.2 KiB
| title | author | date | isbn | publisher | category | chapter | pages |
|---|---|---|---|---|---|---|---|
| Michael Abrash's Graphics Programming Black Book, Special Edition | Michael Abrash | 1997-07-01 | 1576101746 | The Coriolis Group | Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development | 67 | 1239-1241 |
Implementation Notes
Finally, a few notes on Listing 67.1. First, you'll notice that although we clip all polygons to the view frustum in worldspace, we nonetheless later clamp them to valid screen coordinates before adding them to the edge list. This catches any cases where arithmetic imprecision results in clipped polygon vertices that are a bit outside the frustum. I've only found such imprecision to be significant at very small z distances, so clamping would probably be unnecessary if there were a near clip plane, and might not even be needed in Listing 67.1, because of the slight nudge inward that we give the frustum planes, as described in Chapter 65. However, my experience has consistently been that relying on worldspace or viewspace clipping to produce valid screen coordinates 100 percent of the time leads to sporadic and hard-to-debug errors.
There is no separate routine to clear the background in Listing 67.1. Instead, a special background surface at an effectively infinite distance is added, so whenever no polygons are active the background color is drawn. If desired, it's a simple matter to flag the background surface and draw the background specially. For example, the background could be drawn as a starfield or a cloudy sky.
The edge-processing code in Listing 67.1 is fully capable of handling concave polygons as easily as convex polygons, and can handle an arbitrary number of vertices per polygon, as well. One change is needed for the latter case: Storage for the maximum number of vertices per polygon must be allocated in the polygon structures. In a fully polished implementation, vertices would be linked together or pointed to, and would be dynamically allocated from a vertex pool, so each polygon wouldn't have to contain enough space for the maximum possible number of vertices.
Each surface has a field named state, which is incremented when a
leading edge for that surface is encountered, and decremented when a
trailing edge is reached. A surface is activated by a leading edge only
if state increments to 1, and is deactivated by a trailing edge only
if state decrements to 0. This is another guard against arithmetic
problems, in this case quantization during the conversion of vertex
coordinates from floating point to fixed point. Due to this conversion,
it is possible, although rare, for a polygon that is viewed nearly
edge-on to have a trailing edge that occurs slightly before the
corresponding leading edge, and the span-generation code will behave
badly if it tries to emit a span for a surface that hasn't yet started.
It would help performance if this sort of fix-up could be eliminated by
careful arithmetic, but I haven't yet found a way to do so for
1/z-sorted spans.
Lastly, as discussed in Chapter 66, Listing 67.1 uses the gradients for
1/z with respect to changes in screen x and y to calculate 1/z for
active surfaces each time a leading edge needs to be sorted into the
surface stack. The natural origin for gradient calculations is the
center of the screen, which is (x,y) coordinate (0,0) in viewspace.
However, when the gradients are calculated in AddPolygonEdges(), the
origin value is calculated at the upper-left corner of the screen. This
is done so that screen x and y coordinates can be used directly to
calculate 1/z, with no need to adjust the coordinates to be relative to
the center of the screen. Also, the screen gradients grow more extreme
as a polygon is viewed closer to edge-on. In order to keep the gradient
calculations from becoming meaningless or generating errors, a small
epsilon is applied to backface culling, so that polygons that are very
nearly edge-on are culled. This calculation would be more accurate if it
were based directly on the viewing angle, rather than on the dot product
of a viewing ray to the polygon with the polygon normal, but that would
require a square root, and in my experience the epsilon used in Listing
67.1 works fine.