Optimize GMod Map Performance: More FPS Through Visibility
Optimize a GMod map: understand visleafs and the PVS, use func_detail, hint/skip, areaportals, occluders and fade distances, then measure in game.
A GMod map runs smoothly when the engine has to draw as little as possible per frame. Visibility gives you the most leverage: simple world brushes as sight blockers, details as func_detail, areaportals at chokepoints and fade distances for props. After that you measure in game instead of guessing.
How the engine decides what to draw
During compilation VBSP splits the inside of the map into visleafs, which are convex pieces of space. VVIS then calculates for every leaf which other leafs could be seen from it. That list is called the PVS (Potentially Visible Set).
In game the engine determines which leaf the camera is in and only draws what lies in the leafs of that PVS and inside the field of view. Two consequences matter:
- Visibility applies per leaf, not per position. If any spot in one leaf can see into another, the whole content of that other leaf counts as visible.
- Only world brushes block visibility. Brush entities,
func_detail, displacements and props do not, even if you cannot see through them.
Good optimization therefore starts with the layout: rooms, corners and offset doorways separate areas from each other. No tool can rescue a single huge hall afterwards.
func_detail: take details out of the visibility calculation
Every world brush cuts leafs. Many small brushes create many small leafs and portals, which makes the compile longer and visibility messy. Select everything that does not separate areas and turn it into func_detail with Ctrl+T: pillars, steps, frames, trims, furniture made of brushes.
As a rule of thumb, walls, floors and ceilings that close off rooms stay world brushes. The rest becomes detail. Keep in mind that func_detail does not seal the map. An outer wall made of detail brushes causes a leak. If your compile gets stuck in VVIS, see VVIS taking forever.
Hint and skip: cut leafs on purpose
Sometimes VBSP cuts badly, for example at a corridor corner, so that one leaf reaches around the corner and sees far too much. A hint brush lets you define the cutting plane yourself:
- Create a brush and apply
tools/toolsskipto all faces. - Apply
tools/toolshintto exactly the face where the cut should happen. - Position the brush so that the hint face runs, for example, diagonally through the corner.
Use hints sparingly. Every extra cut creates new leafs and portals. You can check whether a hint helps in Hammer via Map > Load Portal File, which displays the leaf boundaries in the editor.
Areaportals and occluders
A func_areaportal is a thin brush with the texture tools/toolsareaportal that completely fills an opening such as a door or a window. It works in two ways:
- Open: The engine only draws the part of the area behind it that is actually visible through the opening. This also affects props and other entities.
- Closed: The area behind it is not drawn at all. You can link the portal to a door so that it opens and closes with it.
Areaportals divide the map into areas. All connections between two areas have to be closed with portals, otherwise the compile reports a leak at the areaportal. For windows that are only looked through from close by there is func_areaportalwindow, which hides the area beyond a certain distance.
In open terrain, where no walls separate anything, func_occluder helps. It hides models that are completely behind it, but no brush geometry. The occluding faces get tools/toolsoccluder, all others tools/toolsnodraw. Occluders cost processing time themselves and only pay off when a large surface hides many props.
Props, lightmaps and invisible faces
- Fade distances: Props have the properties "Start Fade Dist" and "End Fade Dist" (on
prop_staticthey are labelled "Start Fade Dist/Pixels" and "End Fade Dist/Pixels"). Small objects such as bottles or signs do not have to be drawn from far away. The smaller the prop, the earlier it may disappear. - The right prop type: Anything that never moves becomes a
prop_static. Physics props put extra load on physics and networking on a full server. - Lightmap scale: The default is 16. On large, evenly lit surfaces, values such as 32 or 64 save memory and file size. Use smaller values only where shadows need to be sharp. More on this in the Source Engine lighting guide.
- Nodraw: Faces nobody will ever see get
tools/toolsnodraw. This applies to back sides, faces underneath displacements and spots covered by props. Faces pointing into the void outside the map are removed by VBSP automatically. - Distant scenery: Far-away landscape belongs in a 3D skybox, not into the map as real geometry.
Measure in game instead of guessing
Test with a full compile. With fast VVIS the engine draws more than necessary, so the numbers mean little. In GMod, mat_wireframe, mat_leafvis, r_DrawPortals and r_lockpvs are cheat-protected and need sv_cheats 1; cl_showfps and +showbudget are not.
| Command | What it shows |
|---|---|
cl_showfps 1 | Frame rate |
+showbudget | How the time per frame is split, for example between world, props and physics. -showbudget hides the panel again |
mat_wireframe 1 | Everything that is drawn as wireframe, even behind walls. This shows what the engine renders despite a wall |
mat_leafvis 1 | Outline of the visleaf the camera is in |
r_DrawPortals 1 | Outlines of the areaportals |
r_lockpvs 1 | Freezes visibility so you can walk around and check what was drawn from the old position |
Work systematically: first find the spots with the lowest frame rate, look at them with mat_wireframe 1 to see what is drawn unnecessarily, and only then place hints, areaportals or fade distances on purpose. If the compile log shows warnings you cannot place along the way, the Map Scanner suggests causes and fixes for known messages.
FAQ
Does func_detail really give more FPS?
Directly, func_detail mainly shortens the compile. In game the gain is smaller: the map has fewer leafs, and the faces of world brushes are cut into fewer pieces. Too much detail hurts, though: anything marked as func_detail no longer blocks visibility.
Why is my map slow even though VVIS ran?
Often the layout is too open, so that almost everything is visible from almost everywhere. Other causes are very many props without fade distances, expensive water or dynamic lights. +showbudget shows which category eats the time.
Do displacements block visibility?
No. Displacements neither seal the map nor block visibility. Put simple world brushes with tools/toolsnodraw under hills and behind rock walls when another area begins behind them.
Where do areaportals make sense?
At chokepoints between areas with a lot of content, meaning doors, windows and passages. In a wide open space they do little, because almost everything is visible through the opening anyway.