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

101 lines
5.8 KiB
Markdown

#### Letting the Graphics Card Build the Textures {#Heading4}
One obvious solution is to have the accelerator card build the textures,
rather than having the CPU build and then download them. This eliminates
downloading completely, and lets the accelerator, which should be faster
at such things, do the texel manipulation. Whether this is actually
faster depends on whether the CPU or the accelerator is doing more of
the work overall, but it eliminates download time, which is a big help.
This approach retains the ability to composite other effects, such as
splatters and dents, onto surfaces, but by the same token retains the
high memory requirements and dynamic lighting performance impact of the
surface cache. It also requires that the 3-D API and accelerator being
used allow drawing into a texture, which is not universally true.
Neither do all APIs or accelerators allow applications enough control
over the texture heap so that an efficient surface cache can be
implemented, a point that favors non-caching approaches. (A similar
option that wasn't open to us due to time limitations is downloading
8-bpp surfaces and having the accelerator expand them to 16-bpp surfaces
as it stores them in texture memory. Better yet, some accelerators
support 8-bpp palettized hardware textures that are expanded to 16-bpp
on the fly during texturing.)
#### The Light Map as Alpha Texture {#Heading5}
Another appealing non-caching approach is doing unlit texture-mapping in
one pass, then lighting from the light map as a second pass, using the
light map as an alpha texture. In other words, the textured polygon is
drawn first, with no lighting, then the light map is textured on top of
the polygon, with the light map intensity used as an alpha value to
determine how brightly to light each texel. The hardware's
texture-mapping circuitry is used for both passes, so the lighting comes
out perspective-correct and consistent under all viewing conditions,
just as with the surface cache. The lighting polygons don't even have to
match the texture polygons, so they can represent dynamically changing
lighting.
Two-pass lighting not only looks good, but has no memory footprint other
than texture and light map storage, and provides level performance,
because it's not dependent on surface cache hit rate. The primary
downside to two-pass lighting is that it requires at least twice as much
performance from the accelerator as single-pass drawing. The current
crop of 3-D accelerators is not particularly fast, and few of them are
up to the task of doing two passes at high resolution, although that
will change soon. Another potential problem is that some accelerators
don't implement true alpha blending. Nonetheless, as accelerators get
better, I expect two-pass drawing (or three-or-more-pass, for adding
splatters and the like by overlaying sprite polygons) to be widely used.
I also expect Gouraud shading to be widely used; it's easy to use and
fast. Also, speedier CPUs and accelerators will enable much more
detailed geometry to be used, and the smaller that polygons become, the
better Gouraud shading looks compared to surface caching and two-pass
lighting.
The next graphics engine you'll see from id Software will be oriented
heavily toward hardware accelerators, and at this point it's a tossup
whether the engine will use surface caching, Gouraud shading, or
two-pass lighting.
### Drawing Triangle Models {#Heading6}
Most of the last group of chapters in this book discuss how Quake works.
If you look closely, though, you'll see that almost all of the
information is about drawing the world—the static walls, floors,
ceilings, and such. There are several reasons for this, in particular
that it's hard to get a world renderer working well, and that the world
is the base on which everything else is drawn. However, moving entities,
such as monsters, are essential to a useful game engine. Traditionally,
these have been done with sprites, but when we set out to build Quake,
we knew that it was time to move on to polygon-based models. (In the
case of Quake, the models are composed of triangles.) We didn't know
exactly how we were going to make the drawing of these models fast
enough, though, and went through quite a bit of experimentation and
learning in the process of doing so. For the rest of this chapter I'll
discuss some interesting aspects of our triangle-model architecture, and
present code for one useful approach for the rapid drawing of triangle
models.
#### Drawing Triangle Models Fast {#Heading7}
We would have liked one rendering model, and hence one graphics
pipeline, for all drawing in Quake; this would have simplified the code
and tools, and would have made it much easier to focus our optimization
efforts. However, when we tried adding polygon models to Quake's global
edge table, edge processing slowed down unacceptably. This isn't that
surprising, because the edge table was designed to handle 200 to 300
large polygons, not the 2,000 to 3,000 tiny triangles that a dozen
triangle models in a scene can add. Restructuring the edge list to use
trees rather than linked lists would have helped with the larger data
sets, but the basic problem is that the edge table requires a
considerable amount of overhead per edge per scan line, and triangle
models have too few pixels per edge to justify that overhead. Also, the
much larger edge table generated by adding triangle models doesn't fit
well in the CPU cache.
Consequently, we implemented a separate drawing pipeline for triangle
models, as shown in Figure 69.1. Unlike the world pipeline, the
triangle-model pipeline is in most respects a traditional one, with a
few exceptions, noted below. The entire world is drawn first, and then
the triangle models are drawn, using z-buffering for proper visibility.
For each triangle model, all vertices are transformed and projected
first, and then each triangle is drawn separately.