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

77 lines
4.4 KiB
Markdown

Listing 60.1 isn't very long or complex, but it's somewhat more
complicated than it could be because it's structured to allow visual
display of the ongoing compilation process. That's because Listing 60.1
is actually just a part of a BSP compiler for Win32 that visually
depicts the progressive subdivision of space as the BSP tree is built.
(Note that Listing 60.1 might not compile as printed; I may have missed
copying some global variables that it uses.) The complete code is too
large to print here in its entirety, but it's on the CD-ROM in file
DDJBSP.ZIP.
### Optimizing the BSP Tree {#Heading7}
In the previous chapter, I promised that I'd discuss how to go about
deciding which wall to use as the splitter at each node in constructing
a BSP tree. That turns out to be a far more difficult problem than one
might think, but we can't ignore it, because the choice of splitter can
make a huge difference.
Consider, for example, a BSP in which the line or plane of the splitter
at the root node splits every single other surface in the world,
doubling the total number of surfaces to be dealt with. Contrast that
with a BSP built from the same surface set in which the initial splitter
doesn't split anything. Both trees provide a valid ordering, but one
tree is much larger than the other, with twice as many polygons after
the selection of just one node. Apply the same difference again to each
node, and the relative difference in size (and, correspondingly, in
traversal and rendering time) soon balloons astronomically. So we need
to do *something* to optimize the BSP tree—but what? Before we can try
to answer that, we need to know exactly what we'd like to optimize.
There are several possible optimization objectives in BSP compilation.
We might choose to balance the tree as evenly as possible, thereby
reducing the average depth to which the tree must be traversed.
Alternatively, we might try to approximately balance the area or volume
on either side of each splitter. That way we don't end up with huge
chunks of space in some tree branches and tiny slivers in others, and
the overall processing time will be more consistent. Or, we might choose
to select planes aligned with the major axes, because such planes can
help speed up our BSP traversal.
The BSP metric that seems most useful to me, however, is the number of
polygons that are split into two polygons in the course of building a
BSP tree. Fewer splits is better; the tree is smaller with fewer
polygons, and drawing will go faster with fewer polygons to draw, due to
per-polygon overhead. There's a problem with the fewest-splits metric,
though: There's no sure way to achieve it.
The obvious approach to minimizing polygon splits would be to try all
possible trees to find the best one. Unfortunately, the order of that
particular problem is N!, as I found to my dismay when I implemented
brute-force optimization in the first version of my BSP compiler. Take a
moment to calculate the number of operations for the 20-polygon set I
originally tried brute-force optimization on. I'll give you a hint:
There are 19 digits in 20!, and if each operation takes only one
microsecond, that's over 70,000 years (or, if you prefer, over 500,000
dog years). Now consider that a single game level might have 5,000 to
10,000 polygons; there aren't anywhere near enough dog years in the
lifetime of the universe to handle that. We're going to have to give up
on optimal compilation and come up with a decent heuristic approach, no
matter what optimization objective we select.
In Listing 60.1, I've applied the popular heuristic of choosing as the
splitter at each node the surface that splits the fewest of the other
surfaces that are being considered for that node. In other words, I
choose the wall that splits the fewest of the walls in the subspace it's
subdividing.
### BSP Optimization: an Undiscovered Country {#Heading8}
Although BSP trees have been around for at least 15 years now, they're
still only partially understood and are a ripe area for applied research
and general ingenuity. You might want to try your hand at inventing new
BSP optimization approaches; it's an interesting problem, and you might
strike paydirt. There are many things that BSP trees can't do well,
because it takes so long to build them—but what they do, they do
exceedingly well, so a better compilation approach that allowed BSP
trees to be used for more purposes would be valuable, indeed.