77 lines
4.4 KiB
Markdown
77 lines
4.4 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](67-04.html) [Table of Contents](index.html) [Next](68-01.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
#### 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.
|
||
|
||
------------------------ --------------------------------- --------------------
|
||
[Previous](67-04.html) [Table of Contents](index.html) [Next](68-01.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|