138 lines
7.9 KiB
Markdown
138 lines
7.9 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](70-05.html) [Table of Contents](index.html) [Next](70-07.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
#### The Subdivision Rasterizer {#Heading12}
|
||
|
||
This rasterizer, which we call the *subdivision rasterizer*, first draws
|
||
all the vertices in the model. Then it takes each front-facing triangle,
|
||
and determines if it has a side that’s at least two pixels long. If it
|
||
does, we split that side into two pieces at the pixel nearest to the
|
||
middle (using adds and shifts to average the endpoints of that side),
|
||
draw the vertex at the split point, and process each of the two split
|
||
triangles recursively, until we get down to triangles that have only
|
||
one-pixel sides and hence have nothing left to draw. This approach is
|
||
hideously slow and quite ugly (due to inaccuracies from integer
|
||
quantization) for 100-pixel triangles—but it’s very fast for, say,
|
||
five-pixel triangles, and is indistinguishable from more accurate
|
||
rasterization when a model is 25 or 50 feet away. Better yet, the
|
||
subdivider is ridiculously simple—a few dozen lines of code, far simpler
|
||
than the affine rasterizer—and was implemented in an evening,
|
||
immediately making the drawing of distant models about three times as
|
||
fast, a very good return for a bit of conceptual work. The affine
|
||
rasterizer got fairly close to the same performance with further
|
||
optimization—in the range of 10% to 50% slower—but that took weeks of
|
||
difficult programming.
|
||
|
||
We switch between the two rasterizers based on the model’s distance and
|
||
average triangle size, and in almost any scene, most models are far
|
||
enough away so subdivision rasterization is used. There are undoubtedly
|
||
faster ways yet to rasterize distant models adequately well, but the
|
||
subdivider was clearly a win, and is a good example of how thinking in a
|
||
radically different direction can pay off handsomely.
|
||
|
||
#### Sprites {#Heading13}
|
||
|
||
We had hoped to be able to eliminate sprites completely, making Quake
|
||
100% 3-D, but sprites—although sometimes very visibly 2-D—were used for
|
||
a few purposes, most noticeably the cores of explosions. As of CGDC last
|
||
year, explosions consisted of an exploding spray of particles (discussed
|
||
below), but there just wasn’t enough visual punch with that
|
||
representation; adding a series of sprites animating an explosion did
|
||
the trick. (In hindsight, we probably should have made the explosions
|
||
polygon models rather than sprites; it would have looked about as good,
|
||
and the few sprites we used didn’t justify the considerable amount of
|
||
code and programming time required to support them.) Drawing a sprite is
|
||
similar to drawing a normal polygon, complete with perspective
|
||
correction, although of course the inner loop must detect and skip over
|
||
transparent pixels, and must also perform z-buffering.
|
||
|
||
#### Particles {#Heading14}
|
||
|
||
The last drawing entity type is particles. Each particle is a
|
||
solid-colored rectangle, scaled by distance from the viewer and drawn
|
||
with z-buffering. There can be up to 2,000 particles in a scene, and
|
||
they are used for rocket trails, explosions, and the like. In one sense,
|
||
particles are very primitive technology, but they allow effects that
|
||
would be extremely difficult to do well with the other types of
|
||
entities, and they work well in tandem with other entities, as, for
|
||
example, providing a trail of fire behind a polygon-model lava ball that
|
||
flies into the air, or generating an expanding cloud around a sprite
|
||
explosion core.
|
||
|
||
### How We Spent Our Summer Vacation: After Shipping Quake {#Heading15}
|
||
|
||
Since shipping Quake in the summer of 1996, we’ve extended it in several
|
||
ways: We’ve worked with Rendition to port it to the Verite accelerator
|
||
chip, we’ve ported it to OpenGL, we’ve ported it to Win32, we’ve done
|
||
QuakeWorld, and we’ve added features for Quake 2. I’ll discuss each of
|
||
these briefly.
|
||
|
||
#### Verite Quake {#Heading16}
|
||
|
||
Verite Quake (VQuake) was the first hardware-accelerated version of
|
||
Quake. It looks extremely good, due to bilinear texture filtering, which
|
||
eliminates most pixel aliasing, and because it provides good performance
|
||
at higher resolutions such as 512x384 and 640x480. Implementing VQuake
|
||
proved to be an interesting task, for two reasons: The Verite chip’s
|
||
fill rate was marginal for Quake’s needs, and Verite contains a
|
||
programmable RISC chip, enabling more sophisticated processing than most
|
||
3-D accelerators. The need to squeeze as much performance as possible
|
||
out of Verite ruled out the use of a standard API such as Direct 3D or
|
||
OpenGL; instead, VQuake uses Rendition’s proprietary API, Speedy3D, with
|
||
the addition of some special calls and custom Verite code.
|
||
|
||
Interestingly, VQuake is very similar to software Quake; in order to
|
||
allow Verite to handle the high pixel processing loads of high-res,
|
||
VQuake uses an edge list and builds span lists on the CPU, just as in
|
||
software Quake, then Verite DMAs the span descriptors to onboard memory
|
||
and draws them. (This was only possible because Verite is fully
|
||
programmable; most accelerators wouldn’t be able to support this
|
||
architecture.) Similarly, the CPU builds lit, tiled surfaces in system
|
||
RAM, then Verite DMAs them to an onboard surface cache, from which they
|
||
are texture-mapped. In short, VQuake is very much like normal Quake,
|
||
except that the drawing of the spans is done by a specialized processor.
|
||
|
||
This approach works well, but some of the drawbacks of a surface cache
|
||
become more noticeable when hardware is involved. First, the DMAing is
|
||
an extra step that’s not necessary in software, slowing things down.
|
||
Second, onboard memory is a relatively limited resource (4 MB total),
|
||
and textures must be 16-bpp (because hardware can only do filtering in
|
||
RGB modes), thus eating up twice as much memory as the software
|
||
version’s 8-bpp textures—and memory becomes progressively scarcer at
|
||
higher resolutions, especially given the need for a z-buffer and two
|
||
16-bpp pages. (Note that using the edge list helps here, because it
|
||
filters out spans from polygons that are in the PVS but fully occluded,
|
||
reducing the number of surfaces that have to be downloaded.) Surface
|
||
caching in VQuake usually works just fine, but response when coming
|
||
around corners into complex scenes or when spinning can be more sluggish
|
||
than in software Quake.
|
||
|
||
An alternative to surface caching would have been to do two passes
|
||
across each span, one tiling the texture, and the other doing an alpha
|
||
blend using the light map as a texture, to light the texture (two-pass
|
||
alpha lighting). This approach produces exactly the same results as the
|
||
surface cache, without requiring downloading and caching of large
|
||
surfaces, and has the advantage of very level performance. However, this
|
||
approach requires at least twice the fill rate of the surface cache
|
||
approach, and Verite didn’t have enough fill rate for that at higher
|
||
resolutions. It’s also worth noting that two-pass alpha lighting doesn’t
|
||
have the same potential for procedural texturing that surface caching
|
||
does. In fact, given MMX and ever-faster CPUs, and the ability of the
|
||
CPU and the accelerator to process in parallel, it will become
|
||
increasingly tempting to use the CPU to build surfaces with procedural
|
||
texturing such as bump mapping, shimmers, and warps; this sort of
|
||
procedural texturing has the potential to give accelerated games highly
|
||
distinctive visuals. So the choice between surface caching and two-pass
|
||
alpha lighting for hardware accelerators depends on a game’s needs, and
|
||
it seems most likely that the two approaches will be mixed together,
|
||
with surface caching used for special surfaces, and two-pass alpha
|
||
lighting used for most drawing.
|
||
|
||
------------------------ --------------------------------- --------------------
|
||
[Previous](70-05.html) [Table of Contents](index.html) [Next](70-07.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|