127 lines
No EOL
7.3 KiB
Markdown
127 lines
No EOL
7.3 KiB
Markdown
---
|
|
title: Michael Abrash's Graphics Programming Black Book, Special Edition
|
|
author: Michael Abrash
|
|
date: '1997-07-01'
|
|
isbn: '1576101746'
|
|
publisher: The Coriolis Group
|
|
category: 'Web and Software Development: Game Development,Web and Software Development:
|
|
Graphics and Multimedia Development'
|
|
chapter: '70'
|
|
pages: 1279-1281
|
|
---
|
|
|
|
### Passages: The Last-Minute Change that Didn't Happen {#Heading4}
|
|
|
|
Earlier, I mentioned that we almost changed 3-D engines again in the
|
|
last month of Quake's development. Here's what happened: One of the
|
|
alternatives to the PVS is the use of *portals*, where the focus is on
|
|
the places where polygons don't exist along leaf faces, rather than the
|
|
more usual focus on the polygons themselves. These "empty" places are
|
|
themselves polygons, called portals, that describe all the places that
|
|
visibility can pass from one leaf to another. Portals are used by the
|
|
PVS generator to determine visibility, and are used in other 3-D engines
|
|
as the primary mechanism for determining leaf or sector visibility. For
|
|
example, portals can be projected to screenspace, then used as a 2-D
|
|
clipping region to restrict drawing of more distant polygons to only
|
|
those that are visible through the portal. Or, as in Quake's
|
|
preprocessor, visibility boundary planes can be constructed from one
|
|
portal to the next, and 3-D clipping to those planes can be used to
|
|
determine visible polygons or leaves. Used either way, portals can
|
|
support more changeable worlds than the PVS, because, unlike the PVS,
|
|
the portals themselves can easily be changed on the fly.
|
|
|
|
The problem with portal-based visibility is that it tends to perform at
|
|
its worst in complex scenes, which can have many, many portals. Since
|
|
those are the most expensive scenes to draw, as well, portals tend to
|
|
worsen the worst case. However, late in Quake's development, John
|
|
realized that the approach of storing portals themselves in the world
|
|
database could readily be improved upon. (To be clear, Quake wasn't
|
|
using portals at that point, and didn't end up using them.) Since the
|
|
aforementioned sets of 3-D visibility clipping planes *between*
|
|
portals—which he named *passages*—were what actually got used for
|
|
visibility, if he stored those, instead of generating them dynamically
|
|
from the portals, he would be able to do visibility much faster than
|
|
with standard portals. This would give a significantly tighter polygon
|
|
set than the PVS, because it would be based on visibility through the
|
|
passages from the viewpoint, rather than the PVS's approach of
|
|
visibility from anywhere in the leaf, and that would be a considerable
|
|
help, because the level designers were running right up against
|
|
performance limits, partly because of the PVS's relatively loose polygon
|
|
set. John immediately decided that passages-based visibility was a
|
|
sufficiently superior approach that if it worked out, he would switch
|
|
Quake to it, even at that late stage, and within a weekend, he had
|
|
implemented it and had it working—only to find that, like portals, it
|
|
improved best cases but worsened worst cases, and overall wasn't a win
|
|
for Quake. In truth, given how close we were to shipping, John was as
|
|
much thankful as disappointed that passages didn't work out, but the
|
|
possibilities were too great for us not to have taken a shot at it.
|
|
|
|
So why even bother mentioning this? Partly to show that not every
|
|
interesting idea pans out; I tend to discuss those that *did* pan out,
|
|
and it's instructive to point out that many ideas don't. That doesn't
|
|
mean you shouldn't try promising ideas, though. First, some do pan out,
|
|
and you'll never know which unless you try. Second, an idea that doesn't
|
|
work out in one case can still be filed away for another case. It's
|
|
quite likely that passages will be useful in a different context in a
|
|
future engine.
|
|
|
|
The more approaches you try, the larger your toolkit and the broader
|
|
your understanding will be when you tackle your next project.
|
|
|
|
### Drawing the World {#Heading5}
|
|
|
|
Everything described so far is a preprocessing step. When Quake is
|
|
actually running, the world is drawn as follows: First, the PVS for the
|
|
view leaf is decompressed, and each leaf flagged as visible is marked as
|
|
being in the current frame's PVS. (The marking is done by storing the
|
|
current frame's number in the leaf; this avoids having to clear the PVS
|
|
marking each frame.) All the parent nodes of each leaf in the PVS are
|
|
also marked; this information could have been stored as additional PVS
|
|
flags, but to save space is bubbled up the BSP from each visible leaf.
|
|
|
|
After the PVS is marked, the BSP is walked front-to-back. At each node,
|
|
the bounding box of the node's subspace is clipped against the view
|
|
frustum; if the bounding box is fully clipped, then that node and all
|
|
its children are ignored. Likewise, if the node is not in the PVS for
|
|
the current viewpoint leaf, the node and all its children are ignored.
|
|
If the bounding box is partially clipped or not clipped at all, that
|
|
information is passed to the children so that any unnecessary clip tests
|
|
can be avoided. The children in front of the node are then processed
|
|
recursively. When a leaf is reached, polygons that touch that leaf are
|
|
marked as potentially drawable. When recursion in front of a node is
|
|
finished, all polygons on the front side of the node that are marked as
|
|
potentially drawable are added to the edge list, and then the children
|
|
on the back side of that node are similarly processed recursively.
|
|
|
|
The edge list is a special, intermediate step between polygons and
|
|
drawing. Each polygon is clipped, transformed, and projected, and its
|
|
non-horizontal edges are added to a global list of potentially drawable
|
|
edges. After all the potentially drawable edges in the world have been
|
|
added, the global edge list is scanned out all at once, and all the
|
|
visible spans (the nearest spans, as determined by sorting on BSP-walk
|
|
order) in the world are emitted into span lists linked off the
|
|
respective surface descriptors (for now, you can think of a surface as
|
|
being the same as a polygon). Taken together, these spans cover every
|
|
pixel on the screen once and only once, resulting in zero overdraw;
|
|
surfaces that are completely hidden by nearer surfaces generate no spans
|
|
at all. The spans are then drawn; all the spans for one surface are
|
|
drawn, and then all the spans for the next, so that there's texture
|
|
coherency between spans, which is very helpful for processor cache
|
|
coherency, and also to reduce setup overhead.
|
|
|
|
The primary purpose of the edge list is to make Quake's performance as
|
|
level—that is, as consistent—as possible. Compared to simply drawing all
|
|
potentially drawable polygons front-to-back, the edge list certainly
|
|
slows down the best case, that is, when there's no overdraw. However, by
|
|
eliminating overdraw, the worst case is helped considerably; in Quake,
|
|
there's a ratio of perhaps 4:1 between worst and best case drawing time,
|
|
versus the 10:1 or more that can happen with straight polygon drawing.
|
|
Leveling is very important, because cases where a game slows down to the
|
|
point of being unplayable dictate game and level design, and the fewer
|
|
constraints placed on design, the better.
|
|
|
|
> 
|
|
> A corollary is that best case performance can be seductively misleading;
|
|
> it's a great feeling to see a scene running at 30 or even 60 frames per
|
|
> second, but if the bulk of the game runs at 15 fps, those best cases are
|
|
> just going to make the rest of the game look worse. |