VIS optimization: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
Line 85: Line 85:
== Draw distance ==
== Draw distance ==


If you are dealing with a large open area without any cover at all then there isn't a lot you can do, save reducing the number of objects you're drawing, but employ [[env_fog_controller|fog]] to disguise a low [[draw distance]].
If you are dealing with a large open area without any cover at all then there isn't a lot you can do, save reducing the number of objects you're drawing, but employ [[env_fog_controller|fog]] to disguise a low [[draw distance]] by setting a 'far z_clip plane' further than the fog distance.


Draw distances can also be applied selectively to props, even prop_static, with the '''Start Fade Dist/Pixels''' and '''End Fade Dist/Pixels''' [[keyvalue]]s. As the names suggest, these values can represent either distance in units or pixels on-screen as per the '''Screen Space Fade''' KV.
Draw distances can also be applied selectively to props, even prop_static, with the '''Start Fade Dist/Pixels''' and '''End Fade Dist/Pixels''' [[keyvalue]]s. As the names suggest, these values can represent either distance in units or pixels on-screen as per the '''Screen Space Fade''' KV.

Revision as of 13:07, 9 January 2009

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.

Leaves

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 (a job performed by BSP), which abstract line-of-sight calculations (performed by VIS) to volumes of space instead of precise locations and, in the process, allow those calculations to occur when the map is compiled.

Visleaves in a corridor.

The image to the left shows how leaves might be created in a u-turn corridor (in reality they would be flush against the walls and each other). There is no line of sight between leaf one and three, and therefore when the camera is in one the contents of the other are not drawn. Calculating this is as simple for the processor as glancing at the map's pre-compiled visibility chart.

Consider leaf two however: 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 tools for when it isn't that we'll look at next.

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

Reducing VIS compile time

  • Stick to the grid as much as you can. Brush sizes that are powers of two are also good.
  • Use simple brushes. Do not carve unless you're sure the results will be OK.
  • Use detail brushes.
  • 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).

Inspecting leaves

The Orange Box version of Hammer has a new function to view the current map's leaves in the 3D view: Load Portal File">Map > Load Portal File. This displays leaf edges that touch other edges as thick blue lines. It's a fantastic learning tool, as if you compile your map without VIS or RAD (then reload its portal file to refresh the display) you can see your changes' effects very quickly.

Ep1 users must rely on glview.

Tip.pngTip:For even more clarity use auto visgroups to remove objects from your map that don't block visibility – i.e. everything but "World Geometry".

There are also a couple of console command that can visualise leaves in-game:

mat_leafvis
An in-game console command that draws the leaf that the camera is currently in as a red outline.
mat_wireframe
Shows what is being drawn behind walls. You will be able to see leaves popping in and out of view with this enabled.

Hints

tools\toolshint
All leaves draw at the same time until we hint.

Unfortunately, leaves don't always work out so well as they did in our first example. Consider the alternative layout on the left (in practice things would be configured as per the first image, but put that aside for a moment): 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 which tells VBSP to split any leaves it intersects along its plane. Faces that should not split leaves must be textured with tools\toolsskip. In our example, we would place a hint where the purple 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.

Tip.pngTip:It's a good idea to use hints to separate expensive and cheap areas of the same leaf, if doing so will reduce the amount of time that the expensive areas are drawn for.

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 free-standing wall) there’s no point in creating lots of extra leaves around it.

In these situations you want func_detail. It's an internal entity which makes the compilers ignore the brush when calculating visibility, without otherwise affecting its behaviour. It's not uncommon for large portions of a map's brushes to be detail.

Areaportals

tools\toolsareaportal
Teal lines indicate good areaportal locations.

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.

In this situation we should create Areaportals at the mouth of selected openings. These make the engine perform the per-object line of sight testing that 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 one blocks enough objects from view.

The image has areaportal locations marked over each mouth, but placing all four would likely hinder performance more than help it. Your strategy depends on the relative cost of each area - in most situations, creating the large areaportal to the right and leaving the corridors alone would be best.

(It is possible to use hints to reduce visibility in this situation, but only with a ridiculous number of them at very precise angles, which impacts performance in its own way. If you can't see across a room for hint brushes then you should be using an areaportal!)

Tip.pngTip:Areaportals are also useful because they can be closed to completely and cheaply block visibility past them. It's a good idea to attach an areaportal to every window-less door in your map, so that they can automatically perform this function.
Warning.pngWarning:Areaportals can cause problems if placed incorrectly, so be sure to read about them carefully.

Occluders

tools\toolsoccluder

Sometimes you want to block visibility in a way that visleaves simply don't allow: consider a destructible free-standing wall behind which are standing several expensive character models. You don't want to draw the models if they aren't being seen, but without any connected world brushes to work with except the ground you can't do it by separating leaves.

An Occluder is the tool for the job. It's a brush that hides models (not brushes, alas) behind it when enabled in a similar manner to an areaportal hiding things that aren't behind it. For obvious reasons, it's should be entirely contained inside an opaque object.

An occluder is quite expensive, and should only be used when several costly character models or a large area need to be culled. Unlike an areaportal it isn't linked to the leaf system, so can exist wherever you need it without creating leaks.

Draw distance

If you are dealing with a large open area without any cover at all then there isn't a lot you can do, save reducing the number of objects you're drawing, but employ fog to disguise a low draw distance by setting a 'far z_clip plane' further than the fog distance.

Draw distances can also be applied selectively to props, even prop_static, with the Start Fade Dist/Pixels and End Fade Dist/Pixels keyvalues. As the names suggest, these values can represent either distance in units or pixels on-screen as per the Screen Space Fade KV.

func_lod is a special brush entity that can fade out. You can't use any brushes tied to it as any other entity, however!

Sample maps

  • sourcesdk_content\hl2\mapsrc\sdk_func_detail.vmf
  • sourcesdk_content\hl2\mapsrc\sdk_hints.vmf
  • sourcesdk_content\hl2\mapsrc\sdk_occluders.vmf

<< Return to Optimization (level design)