65 lines
3.9 KiB
Markdown
65 lines
3.9 KiB
Markdown
#### Implementation Notes {#Heading9}
|
|
|
|
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.
|