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

82 lines
4.7 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.

The amount of memory required for surface caching looked forbidding at
first. Surfaces are large relative to texture tiles, because every texel
of every surface is unique. Also, a surface can contain many texels
relative to the number of pixels actually drawn on the screen, because
due to perspective foreshortening, distant polygons have only a few
pixels relative to the surface size in texels. Surfaces associated with
partly hidden polygons must be fully built, even though only part of the
polygon is visible, and if polygons are drawn back to front with
overdraw, some polygons won't even be visible, but will still require
surface building and caching. What all this meant was that the surface
cache initially looked to be very large, on the order of several
megabytes, even at 320x200—too much for a game intended to run on an 8
MB machine.
#### Mipmapping To The Rescue {#Heading11}
Two factors combined to solve this problem. First, polygons are drawn
through an edge list with no overdraw, as I discussed a few chapters
back, so no surface is ever built unless at least part of it is visible.
Second, surfaces are built at four mipmap levels, depending on distance,
with each mipmap level having one-quarter as many texels as the
preceding level, as shown in Figure 68.4.
For those whose heads haven't been basted in 3-D technology for the past
several years, *mipmapping* is 3-D graphics jargon for a process that
normalizes the number of texels in a surface to be approximately equal
to the number of pixels, reducing calculation time for distant surfaces
containing only a few pixels. The mipmap level for a given surface is
selected to result in a texel:pixel ratio approximately between 1:1 and
1:2, so texels map roughly to pixels, and more distant surfaces are
correspondingly smaller. As a result, the number of surface texels
required to draw a scene at 320x200 is on the rough order of 64,000; the
number is actually somewhat higher, because of portions of surfaces that
are obscured and viewspace-tilted polygons, which have high
texel-to-pixel ratios along one axis, but not a whole lot higher. Thanks
to mipmapping and the edge list, 600K has proven to be plenty for the
surface cache at 320x200, even in the most complex scenes, and at
640x480, a little more than 1 MB suffices.
![](images/68-04.jpg)\
**Figure 68.4**  *How mipmapping reduces surface caching requirements.*
All mipmapped texture tiles are generated as a preprocessing step, and
loaded from disk at runtime. One interesting point is that a key to
making mipmapping look good turned out to be box-filtering down from one
level to the next by averaging four adjacent pixels, then using error
diffusion dithering to generate the mipmapped texels.
Also, mipmapping is done on a per-surface basis; the mipmap level for a
whole surface is selected based on the distance from the viewer of the
nearest vertex. This led us to limit surface size to a maximum of
256x256. Otherwise, surfaces such as floors would extend for thousands
of texels, all at the mipmap level of the nearest vertex, and would
require huge amounts of surface cache space while displaying a great
deal of aliasing in distant regions due to a high texel:pixel ratio.
#### Two Final Notes on Surface Caching {#Heading12}
Dynamic lighting has a significant impact on the performance of surface
caching, because whenever the lighting on a surface changes, the surface
has to be rebuilt. In the worst case, where the lighting changes on
every visible surface, the surface cache provides no benefit, and
rendering runs at the combined speed of surface building and texture
mapping. This worst-case slowdown is tolerable but certainly noticeable,
so it's best to design games that use surface caching so only some of
the surfaces change lighting at any one time. If necessary, you could
alternate surface relighting so that half of the surfaces change on even
frames, and half on odd frames, but large-scale, constant relighting is
not surface caching's strongest suit.
Finally, Quake barely begins to tap surface caching's potential. All
sorts of procedural texturing and post-processing effects are possible.
If a wall is shot, a sprite of pockmarks could be attached to the wall's
data structure, and the sprite could be drawn into the surface each time
the surface is rebuilt. The same could be done for splatters, or
graffiti, with translucency easily supported. These effects would then
be cached and drawn as part of the surface, so the performance cost
would be much less than effects done by on-screen overdraw every frame.
Basically, the surface is a handy repository for all sorts of effects,
because multiple techniques can be composited, because it caches the
results for reuse without rebuilding, and because the texels constructed
in a surface are automatically drawn in perspective.