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

123 lines
7 KiB
Markdown

Chapter 68\
Quake's Lighting Model {#Heading1}
-----------------------
### A Radically Different Approach to Lighting Polygons {#Heading2}
It was during my senior year in college that I discovered computer
games. Not Wizardry, or Choplifter, or Ultima, because none of those
existed yet—the game that hooked me was the original Star Trek game, in
which you navigated from one 8x8 quadrant to another in search of
starbases, occasionally firing phasers or photon torpedoes. This was
less exciting than it sounds; after each move, the current quadrant had
to be reprinted from scratch, along with the current stats—and the
output device was a 10 cps printball console. A typical game took over
an hour, during which nothing particularly stimulating ever happened
(Klingons appeared periodically, but they politely waited for your next
move before attacking, and your photon torpedoes never missed, so the
outcome was never in doubt), but none of that mattered; nothing could
detract from the sheer thrill of being in a computer-simulated universe.
Then the college got a PDP-11 with four CRT terminals, and suddenly Star
Trek could redraw in a second instead of a minute. Better yet, I found
the source code for the Star Trek program in the recesses of the new
system, the first time I'd ever seen any real-world code other than my
own, and excitedly dove into it. One evening, as I was looking through
the code, a really cute girl at the next terminal asked me for help
getting a program to run. After I had helped her, eager to get to know
her better, I said, "Want to see something? This is the actual source
for the Star Trek game!" and proceeded to page through the code,
describing each subroutine. We got to talking, and eventually I worked
up the nerve to ask her out. She said sure, and we ended up having a
good time, although things soon fell apart because of her two or three
other boyfriends (I never did get an exact count). The interesting
thing, though, was her response when I finally got around to asking her
out. She said, "It's about time!" When I asked what she meant, she said,
"I've been trying to get you to ask me out all evening—but it took you
forever! You didn't actually think I was interested in that Star Trek
program, did you?"
Actually, yes, I had thought that, because *I* was interested in it. One
thing I learned from that experience, and have had reinforced countless
times since, is that we—you, me, anyone who programs because they love
it, who would do it for free if necessary—are a breed apart. We're
different, and luckily so; while everyone else is worrying about
downsizing, we're in one of the hottest industries in the world. And, so
far as I can see, the biggest reason we're in such a good situation
isn't intelligence, or hard work, or education, although those help;
it's that we actually *like* this stuff.
It's important to keep it that way. I've seen far too many people start
to treat programming like a job, forgetting the joy of doing it, and
burn out. So keep an eye on how you feel about the programming you're
doing, and if it's getting stale, it's time to learn something new;
there's plenty of interesting programming of all sorts to be done.
Follow your interests—and don't forget to have fun!
### The Lighting Conundrum {#Heading3}
I spent about two years working with John Carmack on Quake's 3-D
graphics engine. John faced several fundamental design issues while
architecting Quake. I've written in earlier chapters about some of those
issues, including eliminating non-visible polygons quickly via a
precalculated potentially visible set (PVS), and improving performance
by inserting potentially visible polygons into a global edge list and
scanning out only the nearest polygon at each pixel.
In this chapter, I'm going to talk about another, equally crucial design
issue: how we developed our lighting approach for the part of the Quake
engine that draws the world itself, the static walls and floors and
ceilings. Monsters and players are drawn using completely different
rendering code, with speed the overriding factor. A primary goal for the
world, on the other hand, was to be as precise as possible, getting
everything right so that polygons, textures, and sophisticated lighting
would be pegged in place, with no visible shifting or distortion under
all viewing conditions, for maximum player immersion—all with good
performance, of course. As I'll discuss, the twin goals of performance
and rock-solid, complex lighting proved to be difficult to achieve with
traditional lighting approaches; ultimately, a dramatically different
approach was required.
### Gouraud Shading {#Heading4}
The traditional way to do realistic lighting in polygon pipelines is
Gouraud shading (also known as *smooth shading*). Gouraud shading
involves generating a lighting value at each polygon vertex by applying
all relevant world lighting, linearly interpolating between lighting
values down the edges of the polygon, and then linearly interpolating
between the edges of the polygon across each span. If texture mapping is
desired (and all polygons are texture mapped in Quake), then at each
pixel in each span, the pixel's corresponding texture map location
(texel) is determined, and the interpolated lighting is applied to the
texel to generate a final, lit pixel. Texels are generally taken from a
32x32 or 64x64 texture that's tiled repeatedly across the polygon, for
several reasons: performance (a 64x64 texture sits nicely in the 486 or
Pentium cache), database size, and less artwork.
The interpolated lighting can consist of either a color intensity value
or three separate red, green, and blue values. RGB lighting produces
more sophisticated results, such as colored lights, but is slower and
best suited to RGB modes. Games like Quake that are targeted at
palettized 256-color modes generally use intensity lighting; each pixel
is lit by looking up the pixel color in a table, using the texel color
and the lighting intensity as the look-up indices.
Gouraud shading allows for decent lighting effects with a relatively
small amount of calculation and a compact data set that's a simple
extension of the basic polygon model. However, there are several
important drawbacks to Gouraud shading, as well.
#### Problems with Gouraud Shading {#Heading5}
The quality of Gouraud shading depends heavily on the average size of
the polygons being drawn. Linear interpolation is used, so highlights
can only occur at vertices, and color gradients are monotonic across the
face of each polygon. This can make for bland lighting effects if
polygons are large, and makes it difficult to do spotlights and other
detailed or dramatic lighting effects. After John brought the initial,
primitive Quake engine up using Gouraud shading for lighting, the first
thing he tried to improve lighting quality was adding a single vertex
and creating new polygons wherever a spotlight was directly overhead a
polygon, with the new vertex added directly underneath the light, as
shown in Figure 68.1. This produced fairly attractive highlights, but
simultaneously made evident several problems.