101 lines
5.8 KiB
Markdown
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.
|