OptimizationIf you have the time, read this
very good information source. It goes into more detail than here.
The theory behind map optimization is to NOT render what the player CAN'T see.
Upon compiling, the interior of the map is broken into multiple volumes, called "VisLeafs". For example a simple room with six sides will have one large VisLeaf: The inside of the room you move in.
Having a small area with many many VisLeafs will cause the game to slow down since it has to compute which of those VisLeafs can see which other. Likewise un-optimized VisLeafs may render more to the player then the player can actually see, which is a waste of resources.
There are three main ways you can optimize your map.
VisLeafs (Func_Detail)The first step to optimizing your map is to reduce the number of VisLeafs created.
First note that all World geometry breaks up the interior of the map into VisLeafs. This means that Entities do not. But what about Brushes? They all break up the map! To make them stop breaking up the map we need to make the Brushes into Entites! The Entity designed for this purpose is called "Func_Detail".
(NOTE: To view VisLeafs simple go "Map->Load Portal File" after compiling)
In the picture above we have two identical rooms, each with four columns inside. The blue lines represent the edges of each VisLeaf volume.
You can clearly see the room on the right has many VisLeafs, and looks very nasty and will cause a FPS drop, whereas the room on the left has few VisLeafs, and will run smoothly.
The difference is the room on the right has World-Geometry columns, and the room on the left has for Func_Detail columns. To the VisLeaf maker, the Func_Details are "Entites" and therefore 'invisible' and do not break up the interior of the map.
What should i make into a Func_Detail?
Simply, everything that adds a complication to an otherwise simple square room. Anything that has been cut, clipped, calved, rotated or vertex edited should be a Func_Detail, because otherwise they will create multiple VisLeafs.
Check out this link for a great way to scan your map for 'complex' brushes:
ubermicro.proboards.com/index.cgi?action=display&board=tutorials&thread=1634&page=1However, imagine you have a small house. It has two floors and multiple rooms. You do not want to Func_Detail every single interior wall, floor and ceiling, for this would make the inside of the house a single VisLeaf, meaning everything inside the house will be rendered at the same time. Each room should be it's own VisLeaf, so the walls should be World geometry. However objects inside the room should be Func_Detail. Note that the sloping roofs of the house are a good example for a Func_Detail.
Complex walls can be made simple by making all the bits that stick out from the wall (EG buttresses, window ledges, etc) separate brushes and Func_Detail.
Above is an excellent example of a curved wall. Curved walls are very pretty, but must be made into a Func_Detail else they break up the VisLeafs two per brush. That's a lot of VisLeafs in a small area! Note how the wall behind them is a separate brush, textured with NoDraw, since it's not visible in game. The VisLeaf maker will not see the curved wall and therefore think the room is a simple square.
You may ask, 'but what about Func_Brush?'. Func_Brush is a more advance version of Func_Detail. Func_Detail is static and just like a World block. Func_Brushs however can be given names and even parented to objects. This means they are Func_Details which can move with other Entities ('Parenting'), be destroyed by triggers ('Killed' via it's name), and can even be made to be non-solid, so you can walk through them. Since a Func_Brush has all these extra properties, it uses more system resources, and should only be used when needed, with Func_Detail being in more common use.
Skybox Optimisation A lot of maps simply build a large box around the map, hollow it and make it a skybox. This is incredibly bad and should never be done.
Compared to the above, a well made skybox can vastly reduce the number of VisLeafs in the map, since there is no 'wasted' space where VisLeafs are made, but a player doesn't ever go to / see.
A good example for skybox optimization can be found in
this link.
[More to Add]
HINT Texture HINT textures force VisLeafs to be split along the plane of the texture. This may sound as if it creates more VisLeafs, but it can better shape your VisLeafs to hide more stuff which the player cannot see, and therefore more optimized. It may also break VisLeafs in a 'nicer' way.
Since all HINT brush faces will break VisLeafs you generally only want one face of the brush to be a HINT texture. For all the others, the SKIP texture is used. These SKIP brush faces are not at all included in the map.
When a player walks around a corner, it is useful to only render what's around the corner at the very last moment, and as soon as the player rounds the corner, the world behind is hidden. This is best achieved by creating a diagonal VisLeaf, and to do this we need a HINT texture.
The HINT texture here will force a diagonal VisLeaf to be crated in the corner of the room.
As the player approaches the corner, before passing the HINT line, they can only see the VisLeaf behind them, and the one in the corner. As they cross the HINT line, all VisLeafs become visible. When they then exit the HINT area, the behind corridor is hidden. This is the idea way to optimize these corners.
In the above image, the corner of the building is clipped. This may cause a large diagonal VisLeaf to be created across the area, which may extend far out. This is an effect we do not want.
One solution would be to place to HINT textures to "complete" the building's square shape.
See how the VisLeafs are back in line with the grid and are no longer diagonal?
- 'completing the wall'
- Low Walls
- Big Sky Leafs Avoid (Touch too many other leafs)
Area Portals Func_AreaPortals render through them only what can be seen by a player.
A good demonstration of this property can be found
here.
Func_AreaPortalWindow additionally fades to black when the player is far from the entity.
To make an AreaPortal, drag out a brush, give it the AreaPortal texture (above), hit Ctrl+T and type in "areaportal" and click the corresponding entity.
Fill doorways with Func_AreaPortals, and windows with Func_AreaPortalWindow, the same thickness as the wall, (See discussion
here.) only if both sides are accessible to the player. Windows to empty non-accessible rooms should have a HINT texture to 'complete the wall' as described above.
Do not place a Func_AreaPortal filling a doorway with "very thick walls" (ie. a corridor!). It would be better to allow this to be automatically made into it's own VisLeaf. It may be beneficial, however, to put a 'normal' sized (8 or 16 units, general wall thickness) Func_AreaPortal at the end of a corridor if the room beyond contains many entities and will benefit from the Func_AreaPortal's properties.
Placing multiple Func_AreaPortals in the same line of sight (IE you can see through multiple at the same time) will actually decrease performance since many calculations are being performed at the same time. Try to only have a maximum of two Func_AreaPortals in the same line of sight. However:
Func_AreaPortalWindows may be used multiple times down a long corridor or tunnel. When a player is deep inside the tunnel, the Func_AreaPortalWindows that they are far away from will fade to black, making the tunnel simply looks dark in the distance, and cuts down how much is rendered to the current section(s) the player is in.
NoDraw Texture The NoDraw texture is an optimization feature because it is not rendered. It is a solid, see-through wall, which does break VisLeafs, and therefore can be used to seal maps. To see the texture in game often looks very bad, and therefore it is only used on Brush faces which are not seen by players.
When texturing your map, it is good to follow these guidelines:
While designing and building your map, use the "dev/" textures. These textures, especially the measure ones, will help you to quickly and efficiently build everything to scale. They are also very easily seen in Hammer and in Game, to help spot missed textures.
When you come to texture, start slowly and texture room by room:
1) Select all the Brushes in the room.
2) Make them all the NoDraw texture.
3) Use the Face Edit tool, and apply your textures one Brush face at a time, and
only to the faces which will be visible to the player.
Using this process means many Brush faces which are unseen will remain as NoDraw, and improve optimisation.
Some Brush faces will automatically become the NoDraw texture in game when you compile the map. These are Brush faces which are completely inside/hidden by another Brush face and a Brush face which touches the Void (outside the level).
I believe it is best to make these NoDraw yourself, as written above, for two reasons:
1) Its 'good practice' and makes you think about the optimisation.
2) NoDrawing textures which touch the void allow the Developer to use the button circled below to see through the NoDraw texture, instead of the opaque yellow texture.
This allows a Developer to see inside the map from any angle. If the textures were normal textures and left to become NoDraw on compile, the Developer would not have this advantage.
Only Brushes should be given the NoDraw texture. Displacements cannot have a NoDraw texture, and this will throw an error on compile.