Visibility optimization

From Valve Developer Community
Revision as of 03:35, 1 September 2008 by TomEdwards (talk | contribs) (draft)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Controlling what is being drawn in the first place is the best way of optimising a map. Unfortunately, literally checking whether every object (or surface) can be seen by the camera swiftly becomes more expensive than rendering the objects in the first place, so we have to use a compromise.


Source’s compromise is the Binary Space Partition model, the work of John Carmack which it inherits from Quake. This splits the world into visleaves (with VBSP), which abstract line-of-sight calculations (performed by VVIS) to volumes of space instead of precise locations and, in the process, allow those calculations to occur when the map is compiled instead of on the fly.

Visleaves in a corridor. In reality they would be flush against the walls and each other.

The image to the left shows how leaves might be created in a u-turn corridor. There is no line of sight between leaf one and three, and therefore when the camera is one the contents of the other are not drawn. But we encounter a limitation of this system when we consider leaf two: the contents of all three leaves are drawn when the camera is within it, even though we may be staring straight at a wall!

In a lot of cases it’s more expensive to fix this problem than it is to go ahead and draw the scene, but there are also tools to clip the corridors properly if needed that we’ll look at later.

Tip.png Tip: Leaves are split by world brushes, but also every 1024 units, regardless of brush geometry, in order to split large areas into chunks. Hammer highlights the grid every 1024 units to help you account for this.

Inspecting leaves

Hammer view
The Orange Box version of Hammer has a new function to view the current map’s leaves in the 3D view (Map > Load Portal File). This displays leaf edges that touch other edges as thick blue lines. It’s a fantastic learning tool: if you compile your map without VIS or RAD (then re-load its portal file to refresh the display) you can very quickly see changes to the leaves.
Tip.png Tip: For even more clarity use auto visigroups to remove objects from your map that don’t block visibility – i.e. everything but “World Geometry”.
Note.png Note: Ep1 users will need to use glview instead.
An in-game console command that draws the leaf that the camera is currently in as a red outline.
Shows what is being drawn through walls. You will be able to see leaves popping in and out of view with this enabled.

Reducing VVIS time

  • Stick to the grid as much as you can. Brush sizes that are powers of two are also good.
  • When creating a map with very large open spaces, calculating visibility between all of the leaves can take a long time. A VERY long time. Valve introduced func_viscluster with the Orange Box to alleviate this (Ep1 users will just have to suffer, unfortunately).


Both area draw at the same time. This can be fixed with a hint.

Unfortunately, leaves don’t always work out so well as they did in our first example. Consider the alternate leaf layout for our earlier example on the left (in practice the leaves would be configured as per the first image, but for the sake of the argument...). In this example the leaves can all see each other, leading to the whole area being drawn at once for no good reason. This is where hints come in.

A hint is a brush face textured with tools\toolshint (other faces should be covered with tools\toolsskip), which tells VBSP to split any leaves it intersects along its plane. In our example, we would place a hint where the grey line indicates, so that it slices one and three to the same sizes that they were in our first example.

Unfortunately it isn’t possible to merge leaves together, so after giving the compiler our hint we are left with three (number) leaves where we only used to have one. There’s nothing that can be done about this; luckily it isn’t a huge problem.

Detail brushes

As was mentioned above, leaves are moulded around world brushes. But what if you don’t want a brush to do that? If you have a brush that can be seen around at all times (e.g. a statue plinth, a small freestanding wall) there’s no point in creating lots of extra leaves around it.

The answer is func_detail, an internal entity which tells the compilers to ignore the brush when calculating visibility without otherwise affecting its behaviour.


Grey areas indicate good areaportal locations. Remember that in practice the larger leaves would be split into 1024x1024 squares.

There is one final limitation with leaves, which can be seen in the image to the left. All of the leaves can see each other, and this time there is very little that hint brushes can achieve.

Note.png Note: It is possible to use hints to reduce visibility in this situation, but only with a ridiculous number of them at very precise angles. If you can’t see across a room for hint brushes, then you should be using an areaportal instead!

In this situation we should create areaportals at the mouth of each opening. These make the engine perform the per-object line of sight testing that John Carmack created the BSP/visleaf system to avoid – but with that system behind it, and with the calculations restricted to when the camera looks through the areaportal, performance can be gained if it blocks enough objects from view.

Areaportals can cause problems if you place them incorrectly, so be sure to read about them carefully.