126 lines
7.3 KiB
Markdown
126 lines
7.3 KiB
Markdown
#### 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.
|