Initial conversion to markdown
This commit is contained in:
parent
a96a114403
commit
5e10794a24
362 changed files with 67353 additions and 0 deletions
151
64-03.md
Normal file
151
64-03.md
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
------------------------ --------------------------------- --------------------
|
||||
[Previous](64-02.html) [Table of Contents](index.html) [Next](64-04.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
### The Beam Tree {#Heading8}
|
||||
|
||||
John’s original Quake design was to draw front-to-back, using a second
|
||||
BSP tree to keep track of what parts of the screen were already drawn
|
||||
and which were still empty and therefore drawable by the remaining
|
||||
polygons. Logically, you can think of this BSP tree as being a 2-D
|
||||
region describing solid and empty areas of the screen, as shown in
|
||||
Figure 64.4, but in fact it is a 3-D tree, of the sort known as a *beam
|
||||
tree.* A beam tree is a collection of 3-D wedges (beams), bounded by
|
||||
planes, projecting out from some center point, in this case the
|
||||
viewpoint, as shown in Figure 64.5.
|
||||
|
||||
In John’s design, the beam tree started out consisting of a single beam
|
||||
describing the frustum; everything outside that beam was marked solid
|
||||
(so nothing would draw there), and the inside of the beam was marked
|
||||
empty. As each new polygon was reached while walking the world BSP tree
|
||||
front-to-back, that polygon was converted to a beam by running planes
|
||||
from its edges through the viewpoint, and any part of the beam that
|
||||
intersected empty beams in the beam tree was considered drawable and
|
||||
added to the beam tree as a solid beam. This continued until either
|
||||
there were no more polygons or the beam tree became entirely solid. Once
|
||||
the beam tree was completed, the visible portions of the polygons that
|
||||
had contributed to the beam tree were drawn.
|
||||
|
||||
\
|
||||
**Figure 64.4** *Partitioning the screen into 2-D regions.*
|
||||
|
||||
\
|
||||
**Figure 64.5** *Beams as wedges projecting from the viewpoint to
|
||||
polygon edges.*
|
||||
|
||||
The advantage to working with a 3-D beam tree, rather than a 2-D region,
|
||||
is that determining which side of a beam plane a polygon vertex is on
|
||||
involves only checking the sign of the dot product of the ray to the
|
||||
vertex and the plane normal, because all beam planes run through the
|
||||
origin (the viewpoint). Also, because a beam plane is completely
|
||||
described by a single normal, generating a beam from a polygon edge
|
||||
requires only a cross-product of the edge and a ray from the edge to the
|
||||
viewpoint. Finally, bounding spheres of BSP nodes can be used to do the
|
||||
aforementioned bulk culling to the frustum.
|
||||
|
||||
The early-out feature of the beam tree—stopping when the beam tree
|
||||
becomes solid—seems appealing, because it appears to cap worst-case
|
||||
performance. Unfortunately, there are still scenes where it’s possible
|
||||
to see all the way to the sky or the back wall of the world, so in the
|
||||
worst case, all polygons in the frustum will still have to be tested
|
||||
against the beam tree. Similar problems can arise from tiny cracks due
|
||||
to numeric precision limitations. Beam-tree clipping is fairly
|
||||
time-consuming, and in scenes with long view distances, such as views
|
||||
across the top of a level, the total cost of beam processing slowed
|
||||
Quake’s frame rate to a crawl. So, in the end, the beam-tree approach
|
||||
proved to suffer from much the same malady as the painter’s algorithm:
|
||||
The worst case was much worse than the average case, and it didn’t scale
|
||||
well with increasing level complexity.
|
||||
|
||||
### 3-D Engine du Jour {#Heading9}
|
||||
|
||||
Once the beam tree was working, John relentlessly worked at speeding up
|
||||
the 3-D engine, always trying to improve the design, rather than
|
||||
tweaking the implementation. At least once a week, and often every day,
|
||||
he would walk into my office and say “Last night I couldn’t get to
|
||||
sleep, so I was thinking...” and I’d know that I was about to get my
|
||||
mind stretched yet again. John tried many ways to improve the beam tree,
|
||||
with some success, but more interesting was the profusion of wildly
|
||||
different approaches that he generated, some of which were merely
|
||||
discussed, others of which were implemented in overnight or weekend-long
|
||||
bursts of coding, in both cases ultimately discarded or further evolved
|
||||
when they turned out not to meet the design criteria well enough. Here
|
||||
are some of those approaches, presented in minimal detail in the hopes
|
||||
that, like Tom Wilson with the Paradise FIFO, your imagination will be
|
||||
sparked.
|
||||
|
||||
#### Subdividing Raycast {#Heading10}
|
||||
|
||||
Rays are cast in an 8x8 screen-pixel grid; this is a highly efficient
|
||||
operation because the first intersection with a surface can be found by
|
||||
simply clipping the ray into the BSP tree, starting at the viewpoint,
|
||||
until a solid leaf is reached. If adjacent rays don’t hit the same
|
||||
surface, then a ray is cast halfway between, and so on until all
|
||||
adjacent rays either hit the same surface or are on adjacent pixels;
|
||||
then the block around each ray is drawn from the polygon that was hit.
|
||||
This scales very well, being limited by the number of pixels, with no
|
||||
overdraw. The problem is dropouts; it’s quite possible for small
|
||||
polygons to fall between rays and vanish.
|
||||
|
||||
#### Vertex-Free Surfaces {#Heading11}
|
||||
|
||||
The world is represented by a set of surface planes. The polygons are
|
||||
implicit in the plane intersections, and are extracted from the planes
|
||||
as a final step before drawing. This makes for fast clipping and a very
|
||||
small data set (planes are far more compact than polygons), but it’s
|
||||
time-consuming to extract polygons from planes.
|
||||
|
||||
#### The Draw-Buffer {#Heading12}
|
||||
|
||||
Like a z-buffer, but with 1 bit per pixel, indicating whether the pixel
|
||||
has been drawn yet. This eliminates overdraw, but at the cost of an
|
||||
inner-loop buffer test, extra writes and cache misses, and, worst of
|
||||
all, considerable complexity. Variations include testing the draw-buffer
|
||||
a byte at a time and completely skipping fully-occluded bytes, or
|
||||
branching off each draw-buffer byte to one of 256 unrolled inner loops
|
||||
for drawing 0-8 pixels, in the process possibly taking advantage of the
|
||||
ability of the x86 to do the perspective floating-point divide in
|
||||
parallel while 8 pixels are processed.
|
||||
|
||||
#### Span-Based Drawing {#Heading13}
|
||||
|
||||
Polygons are rasterized into spans, which are added to a global span
|
||||
list and clipped against that list so that only the nearest span at each
|
||||
pixel remains. Little sorting is needed with front-to-back walking,
|
||||
because if there’s any overlap, the span already in the list is nearer.
|
||||
This eliminates overdraw, but at the cost of a lot of span arithmetic;
|
||||
also, every polygon still has to be turned into spans.
|
||||
|
||||
#### Portals {#Heading14}
|
||||
|
||||
The holes where polygons are missing on surfaces are tracked, because
|
||||
it’s only through such portals that line-of-sight can extend. Drawing
|
||||
goes front-to-back, and when a portal is encountered, polygons and
|
||||
portals behind it are clipped to its limits, until no polygons or
|
||||
portals remain visible. Applied recursively, this allows drawing only
|
||||
the visible portions of visible polygons, but at the cost of a
|
||||
considerable amount of portal clipping.
|
||||
|
||||
### Breakthrough! {#Heading15}
|
||||
|
||||
In the end, John decided that the beam tree was a sort of second-order
|
||||
structure, reflecting information already implicitly contained in the
|
||||
world BSP tree, so he tackled the problem of extracting visibility
|
||||
information directly from the world BSP tree. He spent a week on this,
|
||||
as a byproduct devising a perfect DOOM (2-D) visibility architecture,
|
||||
whereby a single, linear walk of a DOOM BSP tree produces zero-overdraw
|
||||
2-D visibility. Doing the same in 3-D turned out to be a much more
|
||||
complex problem, though, and by the end of the week John was frustrated
|
||||
by the increasing complexity and persistent glitches in the visibility
|
||||
code. Although the direct-BSP approach was getting closer to working, it
|
||||
was taking more and more tweaking, and a simple, clean design didn’t
|
||||
seem to be falling out. When I left work one Friday, John was preparing
|
||||
to try to get the direct-BSP approach working properly over the weekend.
|
||||
|
||||
------------------------ --------------------------------- --------------------
|
||||
[Previous](64-02.html) [Table of Contents](index.html) [Next](64-04.html)
|
||||
------------------------ --------------------------------- --------------------
|
||||
|
||||
* * * * *
|
||||
|
||||
Graphics Programming Black Book © 2001 Michael Abrash
|
||||
Loading…
Reference in a new issue