135 lines
7.4 KiB
Markdown
135 lines
7.4 KiB
Markdown
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.
|
||
|
||
\
|
||
**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.
|
||
|
||
\
|
||
**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.
|