abrash-black-book/68-02.md
2013-12-30 20:26:41 +11:00

135 lines
7.4 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

A primary problem with Gouraud shading is that it requires the vertices
used for world geometry to serve as lighting sample points as well, even
though there isn't necessarily a close relationship between lighting and
geometry. This artificial coupling often forces the subdivision of a
single polygon into several polygons purely for lighting reasons, as
with the spotlights mentioned above; these extra polygons increase the
world database size, and the extra transformations and projections that
they induce can harm performance considerably.
Similar problems occur with overlapping lights, and with shadows, where
additional polygons are required in order to approximate lighting detail
well. In particular, good shadow edges need small polygons, because
otherwise the gradient between light and dark gets spread across too
wide an area. Worse still, the rate of lighting change across a shadow
edge can vary considerably as a function of the geometry the edge
crosses; wider polygons stretch and diffuse the transition between light
and shadow. A related problem is that lighting discontinuities can be
very visible at t-junctions (although ultimately we had to add edges to
eliminate t-junctions anyway, because otherwise dropouts can occur along
polygon edges). These problems can be eased by adding extra edges, but
that increases the rasterization load.
![](images/68-01.jpg)\
**Figure 68.1**  *Adding an extra vertex directly beneath a light.*
#### Perspective Correctness {#Heading6}
Another problem is that Gouraud shading isn't perspective-correct. With
Gouraud shading, lighting varies linearly across the face of a polygon,
in equal increments per pixel—but unless the polygon is parallel to the
screen, the same sort of perspective correction is needed to step
lighting across the polygon properly as is required for texture mapping.
Lack of perspective correction is not as visibly wrong for lighting as
it is for texture mapping, because smooth lighting gradients can
tolerate considerably more warping than can the detailed bitmapped
images used in texture mapping, but it nonetheless shows up in several
ways.
First, the extent of the mismatch between Gouraud shading and
perspective lighting varies with the angle and orientation of the
polygon being lit. As a polygon turns to become more on-edge, for
example, the lighting warps more and therefore shifts relative to the
perspective-texture mapped texels it's shading, an effect I'll call
*viewing variance*. Lighting can similarly shift as a result of
clipping, for example if one or more polygon edges are completely
clipped; I'll refer to this as *clipping variance*.
These are fairly subtle effects; more pronounced is the *rotational
variance* that occurs when Gouraud shading any polygon with more than
three vertices. Consistent lighting for a polygon is fully defined by
three lighting values; taking four or more vertices and interpolating
between them, as Gouraud shading does, is basically a hack, and does not
reflect any consistent underlying model. If you view a Gouraud-shaded
quad head-on, then rotate it like a pinwheel, the lighting will shift as
the quad turns, as shown in Figure 68.2. The extent of the lighting
shift can be quite drastic, depending on how different the colors at the
vertices are.
It was rotational variance that finally brought the lighting issue to a
head for Quake. We'd look at the floors, which were Gouraud-shaded
quads; then we'd pivot, and the lighting would shimmy and shift,
especially where there were spotlights and shadows. Given the goal of
rendering the world as accurately and convincingly as possible, this was
unacceptable.
The obvious solution to rotational variance is to use only triangles,
but that brings with it a new set of problems. It takes twice as many
triangles as quads to describe the same scene, increasing the size of
the world database and requiring extra rasterization, at a performance
cost. Triangles still don't provide perspective lighting; their lighting
is rotationally invariant, but it's still wrong—just wrong in a more
consistant way. Gouraud-shaded triangles still result in odd lighting
patterns, and require lots of triangles to support shadowing and other
lighting detail. Finally, triangles don't solve clipping or viewing
variance.
![](images/68-02.jpg)\
**Figure 68.2**  *How Gouraud shading varies with polygon screen
orientation.*
Yet another problem is that while it may work well to add extra geometry
so that spotlights and shadows show up well, that's feasible only for
static lighting. Dynamic lighting—light cast by sources that move—has to
work with whatever geometry the world has to offer, because its needs
are constantly changing.
These issues led us to conclude that if we were going to use Gouraud
shading, we would have to build Quake levels from many small triangles,
with sufficiently finely detailed geometry so that complex lighting
could be supported and the inaccuracies of Gouraud shading wouldn't be
too noticeable. Unfortunately, that line of thinking brought us back to
the problem of a much larger world database and a much heavier
rasterization load (all the worse because Gouraud shading requires an
additional interpolant, slowing the inner rasterization loop), so that
not only would the world still be less than totally solid, because of
the limitations of Gouraud shading, but the engine would also be too
slow to support the complex worlds we had hoped for in Quake.
### The Quest for Alternative Lighting {#Heading7}
None of which is to say that Gouraud shading isn't useful in general.
Descent uses it to excellent effect, and in fact Quake uses Gouraud
shading for moving entities, because these consist of small triangles
and are always in motion, which helps hide the relatively small lighting
errors. However, Gouraud shading didn't seem capable of meeting our
design goals for rendering quality and speed for drawing the world as a
whole, so it was time to look for alternatives.
There are many alternative lighting approaches, most of them
higher-quality than Gouraud, starting with Phong shading, in which the
surface normal is interpolated across the polygon's surface, and going
all the way up to ray-tracing lighting techniques in which full
illumination calculations are performed for all direct and reflected
paths from each light source for each pixel. What all these approaches
have in common is that they're slower than Gouraud shading, too slow for
our purposes in Quake. For weeks, we kicked around and rejected various
possibilities and continued working with Gouraud shading for lack of a
better alternative—until the day John came into work and said, "You
know, I have an idea...."
#### Decoupling Lighting from Rasterization {#Heading8}
John's idea came to him while was looking at a wall that had been carved
into several pieces because of a spotlight, with an ugly lighting glitch
due to a t-junction. He thought to himself that if only there were some
way to treat it as one surface, it would look better and draw faster—and
then he realized that there was a way to do that.
The insight was to split lighting and rasterization into two separate
steps. In a normal Gouraud-based rasterizer, there's first an off-line
preprocessing step when the world database is built, during which
polygons are added to support additional lighting detail as needed, and
lighting values are calculated at the vertices of all polygons. At
runtime, the lighting values are modified if dynamic lighting is
required, and then the polygons are drawn with Gouraud shading.