Submitted by
Gard on Sat, 2003-11-08 03:22.
Polygon Count Reduction
By David Hyde, Mad Dog and Richard Neff
Contents
(Click on a heading to quickly scroll down the page)
Introduction
The purpose of this tutorial is to describe several simple
techniques you can use in your Quake2 maps to reduce the number of
polygons seen by the game engine, thereby increasing the performance of
your map and improving gameplay. None of the techniques described here
are difficult to implement, and will usually not result in any
undesirable tradeoffs, i.e. reduced visual quality. This tutorial does not
discuss hint brushes, which, like the techniques discussed here, are
often used to influence the way qbsp3 partitions brushes. Proper use of
hint brushes is a difficult technique to master, and, unlike the methods
discussed here, generally requires a trial-and-error approach to
achieve the desired results. NOTE: Don't even think about using hint
brushes unless you are able to run "gl_showtris 1" (see below). It's
just about impossible to know how to use hint brushes to block off areas
when you don't know what the engine can/cannot see from a view. For
more information on the use of hint brushes, see Steven Boswell's
excellent article, qbsp3, qvis3, and map-making.
The authors assume that the reader has some experience at
creating maps for Quake2. This is not meant to be a primer on map
editing, and we assume that the reader has prior knowledge of why
reducing polygon counts is important. For basic information on creating
Quake2 maps and map-related issues, read through the Tutorials, Entity Properties, and FAQ sections at Rust.
Back To Table Of Contents
Example maps
This tutorial is accompanied by an example map that demonstrates
most of the techniques mentioned here. To get the most out of this
tutorial you should print this document and refer to it as you navigate
through the rooms in the examples. The example map is available here.
Two files are included - a standard .map file that you can import into
most Quake2 editors, and a compiled bsp. Unzip tricks.zip to your
quake2\baseq2\maps directory. To see the results achieved by the methods
used in the examples, you should run the map with r_speeds 1 and, if available to you, gl_showtris 1. Either start the map with a command line similar to:
\quake2\quake2.exe +set r_speeds 1 +set gl_showtris 1 +map tricks
or start Quake2, bring up the console(press the '~' key), and type:
r_speeds 1;gl_showtris 1;map tricks
NOTE: All of the example maps are very simple, and so the
polygon counts are reasonably low with or without the methods described
in this tutorial. Likewise, the reductions in polygon counts achieved by
the methods described here are not very significant in the context of
the examples. However, these methods will produce significant performance increases when used together in a large, detailed map.
GL_Showtris draws white lines around all of the polygons in view
of the game engine. This allows you to see how your brushes are broken
up in a level, and also shows you what polygons the engine sees that you
might have thought were sufficiently isolated that they would not be in
view. If you have a 3dfx card, you will first need to download the Mesa OpenGL drivers from Phil Frisbie's Programming Page.
These drivers will allow you to use the Default OpenGL video mode with
your 3dfx card, which in turn allows you to use gl_showtris. Framerates
will be only slightly slower than with the normal 3dfx setting.

Screenshot from a level you're probably familiar with, with gl_showtris turned on.
R_Speeds displays several numbers of interest to map authors. The
format of this report is dependent on what type of rendering you are
using. With software rendering, r_speeds will display something like:
33 ms 250/220/30
poly 0 surf
The first number indicates the time, in milliseconds, required for one
game cycle. Your framerate in frames/sec is 1000 divided by this number.
The second number indicates how many polygons are in view, the third
number shows how many polygons are drawn, and the fourth entry is the
number of polygons in view but not drawn. For our purposes, the second number (polygons in view) is what we are trying to reduce.
With 3D accelerators, the r_speeds display will look something like:
250 wpoly 450 epoly 3 tex 2 lmaps
"wpoly" is the number of world polygons in view and "epoly" is the
number of entity polygons. Although you also need to monitor "epoly",
this tutorial concentrates on the wpolyentry.
Back To Table Of Contents
The Tricks
Awareness of qbsp3's default cutsThe
original id-supplied qbsp3 (and most other qbsp3's) initially divides
your map into 1024x1024x8192 sections. This procedure can produce
unwanted brush cuts unless you arrange your map to minimize these
effects. Steven Boswell has produced a version of qbsp3 which does
not divide your map up in this way (available
here),
but this can often produce "Subdivide face: didn't split the polygon"
errors. In the first room of the example map, the inside face of the
wall to the player's left is at x=-16. This causes qbsp3 to break the 4
adjoining surfaces (floor, ceiling, and adjacent walls) along the line
x=0.
Any brush which intersects a line at x or y equal to a multiple of 1024 will be divided in this way.
(Since the sections used are 8192 units tall, and the maximum extents
of a map are +/-4096 units in any direction, you don't have to worry
about these cuts on the z axis.) The solution here is obvious: move the
entire room (or only this one wall) 16 units in the +x direction, and
these cuts are no longer made (Actually they are made, but no longer
result in additional polygons). Of course if your room is larger than
1024 units in either the x or y direction, at least one of these cuts
will still be made. However, you can minimize the effects of these cuts
by careful arrangement of your brushes. For example, if you have a crate
with one face at x=1022, move it over 2 units so that this face is at
x=1024. This method can very easily decrease your polygon count by 50 or
more in a room with many details.
Back To Table Of Contents
Alternative uses of func_wall
The second set of examples shows a room with 6 columns that span from
floor to ceiling. The intersection of the columns with the horizontal
floor and ceiling surfaces causes the horizontal faces to be broken up
more than they would be if the columns were not present. In the next
room, these columns are made into a func_wall. Since entities (including
func_walls) do not influence the way qbsp3 breaks up your world
brushes, the floor and ceiling are partitioned as they would be if the
columns were not present at all.
There are several limitations to using this method:
- The lighting quality of your func_wall will usually not be as good
(though it is hard to see a difference in the example). Extra effort
would usually be required to correct this.
- Entities do not block light or, put another way, cast
shadows. You can see this effect in the screenshots from the example map
below.
- You cannot have more than 256 total models in any one map, and
each func_wall counts against the total. If you exceed this limitation,
you will get a game-crashing Index Overflow error. For more information
on this subject, see this tutorial. You can include multiple non-contiguous brushes in the same func_wall (as has been done in the example), but:
- You should never allow a func_wall to span across areas that
are not seen by the engine at the same time. For example, it might be
tempting to include many brushes throughout your map into the same
func_wall, like on opposite sides of an areaportal, to prevent Index
Overflow errors. However, this practice will at a minimum cause visual
errors in your func_walls.
- You should never make a wall/floor/ceiling which "touches" the void an entity; otherwise, your map will leak!

Normal brushes used for columns

Columns are a func_wall. Note the lack of shadows.
Back To Table Of Contents
Embedded light fixtures
It's very easy to slap several of the 16x16 light fixture
textures against your ceiling, walls, or floors to light a room.
However, the 4 edges adjacent to the lit surface are visible, and will
be divided up into 2 polygons each. You can embed your light fixtures in
your ceiling/walls/floor such that the sides of the fixture aren't
visible. This method generally results in a decrease of 8
polygons/fixture. Of course, this method is quite a bit more trouble, as
you will also have to divide your ceiling/walls/floor up carefully. For
best results, you could place the fixtures such that the edges are all
at multiples of the texture dimensions, as well as making sure they line
up with each other. This not only allows you to forego texture
alignment hassles, but will also produce fewer brush cuts than if your
fixtures are placed at random locations.
This method is
applicable to other textures, of course. For example, "exit" signs, etc.
and texture blending can use this method to decrease the number of
brush cuts.
If you want the edges of the fixtures visible, such that it is
apparent that the fixtures stand out from the mounting surface, consider
moving the fixtures 1 unit from the surface such that the two brushes
don't touch. (This technique is described below). This method will not be as effective as embedding the fixtures, but willproduce a lower polygon count than placing the fixtures flush against your ceiling/walls/floor.
Back To Table Of Contents
Doughnut hallway
The doughnut hallway is the only method presented here that
significantly alters the appearance of your map. If you have adjacent
rooms connected by a short hallway, but don't want to separate the rooms
with a door and func_areaportal, the doughnut hallway is ideal for
blocking visibility from one room to the next. This method was used
extensively in Quake1, since it lacked func_areaportals to block vis
from one room to another. It's popularly known as the "Donut Trick", and
is as viable a technique for Quake2 as it was for Quake1.
The key to the success of the doughnut hallway is to size the
vis-blocking wall such that the player (and the engine) cannot see from
one hallway entrance to the opposite side of the wall. This wall should
extend from the floor to the ceiling, and both the floor and ceiling of
the hallway must be constructed with solid non-transparent textures.
Naturally, making this wall an entity in whole or in part would defeat
efforts at blocking polygons from view.

Doughnut hallway
A similar result can be achieved in a large open space if a huge
monolithic structure is placed so it blocks the view from one side of
the area to the other. Naturally this would require experimentation to
get just right for each specific open area where you might want to use
this method. Of course you may only make things worse if your
vis-blocking structure is not quite so monolithic, and its own polys
added to the mix outnumbers the polys that it blocks.
Back To Table Of Contents
Brush subtraction is evil
Well, OK, not really. But brush subtraction (or carving, hollowing, CSG
subtraction) is generally the most abused feature of any map editor.
The time savings you achieve with brush subtraction are very often more
than offset by the time required to fix brush subtraction errors. At
best what you're liable to get is a mess that is painful to look at and
read in your editor. The example map shows a set of 3 arched doorways
constructed with brush subtraction. In this case, small roundoff errors
have resulted in several very noticeable gaps between brushes, and
higher than necessary polygon counts. In the next room, the identical
arched doorways have been created by manual placement of the brushes
that form the arches. NOTE: Even if your editor does not have
roundoff problems and you very carefully perform the subtraction
operation with the cutting brush aligned to the grid and do everything
else correctly, this example shows an obvious problem with using brush
subtraction with a non-square cutting brush on a large wall - say you've
constructed your arches, but then decide you want to move one arch over
by 4 units - good luck. Well, take the opportunity then to pat yourself
on the back for all the time you saved performing brush subtraction in
the first place, because you're going to be using that time now.
If you insist on using brush subtraction for some odd masochistic reason for this type of operation, you will do much less damage in this case by isolating the area that is affected to the smallest possible one.
In this example, the cylindrical top of the arch is subtracted from
the smallest possible cube. The result of this operation is then copied
to the other arch locations. This results in much simpler (and more
importantly much easier to edit) brushes.
Back To Table Of Contents
Gaps between brushes
Brushes will always be split where they intersect other brushes.
To get rid of this effect, you can move small objects away from the
other brush by 1 unit so that they do not touch. If this trick is used
with discretion this small gap will not be visible to the player. This
technique is typically best used in areas where the player isn't going
to notice differences in shadowing -- such as the ceiling or on the
upper edges of walls. You can also use this technique on non-breakable
windows to lower your polygon count (it won't help to use this method on
breakable windows -- since they are entities they will not break up the
window frame anyway). The lighting will be fine, but you should use
this method with discretion if the player can get very close to the
window - the gap will almost always be visible from close range. Floors
are typically the worst place to try to implement this feature (as shown
below), unless they're in a very well lit area with offsetting lights
where shadows won't be dramatic.

The
crate in this example is 1 unit from the floor. Notice that the
resulting shadows give the crate the appearance of being suspended
several units above the floor.
In the example map, the roof of the test room is open to the sky
with many criss-crossing roof beams. These beams result in the faces
making up the walls of the room being broken up much more than they
would be if the beams were not present. In the following room, these
beams have been shortened by 2 units such that neither end touches a
wall. Even in this relatively simple room, this method results in a
polygon reduction of about 30. The lighting in this room is such that
the gap is not visible at all, so there is no visual problem in this
case.

Beams touch the wall. Notice how the wall is split up by qbsp3

Ends of beams are 1 unit away from wall
NOTE: This method should never be used on brushes that
would otherwise block visibility from one area to another. For example,
creating 1-unit gaps at the tops and bottoms of vis-blocking walls is a
pretty silly thing to do.
Back To Table Of Contents
Detail brushes
You have probably seen warnings that the use of detail brushes will result in higher r_speeds. While sometimes
true, the only way to know for certain whether the use of detail
brushes will increase, decrease, or have no effect on r_speeds is to
test it and measure the results. Detail brushes are usually recommended
as a method for speeding up a lengthy vis, since they are not included
in vis calculations. Qbsp3 will not use the planes of detail brushes to split your map, so sometimes the use of detail brushes will decrease the number of polygons in your map - this is what we want.
Detail brushes can generally safely be used on any object which does
little or nothing to block visibility. If restricted to small objects
which don't block the view of other objects, the use of detail brushes usually does not cause an increase in r_speeds. And in fact, in the 3rd roof beam example detail brushes actually improve r_speeds since the planes of the beams are no longer used to split up the map.

Beams
are detail brushes. Contrast this screenshot with those above. Note
that the planes of the beams are no longer selected as bsp splitters.
NOTE: Detail brushes are designed to be used on brushes that do not block the player's view. You should never make a wall/floor/ceiling which "touches" the void a detail brush; otherwise, your map will leak!
Back To Table Of Contents
Mitered corners
Some may think this method is generally best reserved for times when
you are truly desperate to lower your polygon counts. While the return
on your investment is usually small, and can be quite a bit of trouble
(particularly if your editor does not support vertex manipulation - a
glaring omission), in general this can be a good technique on general
principles. In the example map, one room contains two open-ended
concrete boxes that are constructed from normal cube brushes. The next
room shows these same concrete boxes constructed with mitered brushes.
This technique will generally result in lower polygon counts in any
location where the outside corner of the intersection of two brushes is visible.

Exploded view of mitered box
Back To Table Of Contents
Let the textures do the work
This is primarily intended for all of you engineers and architects and
wannabe's out there - you know who we're talking about. It may be very
tempting to try to mimic a real environment with brushes as much as
possible, down to the smallest details. However, this practice will very
often produce a completely beautiful, but unplayable map. If
architectural details aren't critical to gameplay, consider simplifying
your level by simulating details with textures. If a stock-Q2
texture does not exist that will accomplish what you want, make your
own! There are several excellent tools available for creating custom
textures (Wally, for example).

"Correct" Wide-flange beams

Beams simulated with custom texture
Here's a sobering thought for those wishing to include custom
textures (or sounds, models or custom anything for that matter) with
multiplayer maps: An online server will seldom run such a map, for the
simple reason that it is unlikely that all players connecting to that
server will have the necessary files themselves. Other players who make
their own maps as you do will have the Quake2 textures extracted for
compiling purposes, and they may be loath to "pollute" their textures
directory with new ones which will only make selecting textures for
their own maps confusing. Additionally, if such a map has to be run from
a custom "game" directory, it would be even more unlikely an online
server would run it, unless your map is part of a mod which the server
is running. Keep in mind also that it is not possible to run 2 "game"
directories simultaneously, so maps run from custom directories cannot
be used with bots. Custom files are probably best suited to
single-player maps.
Back To Table Of Contents
3 Sides rather than 4
This one will seem obvious after you try it. If you have four-sided
brushes in a spot where the player cannot get to the far side, use a
3-sided brush instead. Depending on the architecture of your map, this
simple change can result in a significant decrease in your polygon
count. In the example map, two barred windows are placed in the two test
rooms. In the first room, the bars are regular square brushes; in the
second room, triangular brushes are used with the point of the triangle
facing away from the player. Even up close it is hard to tell that these
brushes aren't 4-sided, but the peak polygon count drops by more than
50 with this simple change. This method will likely produce similar
results with jail cells and any type of grate.
Back To Table Of Contents
Transparent vs. opaque water
Transparent water is cool, but of course does nothing to block
visibility. If you have water brushes in a high-poly area of your map,
consider turning off the TRANS33 or TRANS66 flags, which will make the
water opaque (or use a non-transparent water texture). The water is
still transparent on the inside, but will act like a normal solid brush
from the outside and block visibility. Yeah, you say, "but I like my
transparent water." Before you dismiss this idea entirely check out the
example map with r_speeds turned on (or the screenshots below, taken
from another map) and note the difference.

Transparent water. Notice that the engine sees the bottom of the pool.

Opaque water
Back To Table Of Contents
No draw = No polys
This may be the most obvious one of all (so why was it the last method
we thought of?). Environment (or sky) textures do not contribute towards
the polygon count. You can replace brushes that do little to contribute
to the look of a room with sky brushes to lower your polygon count. In
the example map, a small section of the ceiling has been replaced with a
sky brush, resulting in lowering the world polygon count by 4. Of
course, the more complex your ceiling is, the greater will be the
savings realized. Taken to its logical conclusion, here's a screenshot
from our ultimate deathmatch map:

Not much to look at, but check out the r_speeds! Yeah, OK, it's a dumb idea. Shut up.
NOTE: This method is best used on brushes which do not face other
parts of a map. If a sky brush is located between two map areas, the
player may sometimes see through the brushes of another area and into
that area. These visual errors are sometimes hard to fix. For more
information on the "sky bug", see the FAQ at Rust.
Back To Table Of Contents
Fast framerates for large, detailed areas
Ha! Made you look! Sorry, but there's only so much you can do to make
your map play well. Large areas with a lot of detail just don't work
with Quake2.
Back To Table Of Contents
Putting it all together
The following screenshots show the results of using several of the
techniques described here in a single room. Your own results will vary,
of course, but it should be apparent by now that by making prudent,
well-thought-out changes to your map you may be able to significantly
improve it's performance.

a. Room has southwest corner at -16,-16
b. Roof beams intersect walls
c. Light fixtures flush against walls
d. Hideous, evil brush subtraction used in floor

a. Room has southwest corner at 0, 0
b. Roof beams are detail brushes and do not touch walls
c. Light fixtures embedded in walls
d. Manually placed triangular brushes for the cylindrical part of holes in floor
The authors consider this tutorial a work in progress, and are
always open to new ideas which should be included here. If you find a
technique not outlined here that works, by all means contact us and clue
us in!
Partial Transparency
Entity Properties