Optimization Tutorial

As a courtesy, please do not edit this while this message is displayed.
If this page has not been edited for at least several hours to a few days, please remove this template. This message is intended to help reduce edit conflicts; please remove it between editing sessions to allow others to edit the page.
The person who added this notice will be listed in its edit history should you wish to contact them.
By zombie@computer
Wikified by Battle Bott
View original at: http://www.student.kun.nl/rvanhoorn/Optimization.htm
There are a lot of ways you can optimize your map. I will try to deal with all of them, in one, orderly tutorial. There are two things you can optimize with this tutorial, the compile time (especially with vvis you can save hours) and offcourse the map itself while running it ingame
What I will discuss (be prepared: this is everything I could find about optimization!):
General Notices
First things first, the easiest way to optimize your map is carefull building. A few tips:
Don’t enclose your entire level in one box (saves both compile times and map speed)
This will generate extra leafs, lightmaps, clipping hulls, faces to be drawn, etc.
This includes skyboxes! The ideal skybox is as small as possible:
|
http://www.student.kun.nl/rvanhoorn/Optimization/skybox.JPG |
|
Fix leaks (increases map speed)
With leaks vbsp wont be able to divide your level into leafs (see chapter "hints"), so it wont create a portal file. Therefore, you can't use vvis or Glview. Leaks also make vbsp not know which faces it can skip, making your map only laggier and bigger, and vrad will not be able to light your map as good as without leaks. Water will also not work.
Leaks are holes in you map. Since the compilers will try to find out what the inside is of your level (so they dont have to create the outside) they will not be able to do that if the inside of your level is in contact with the outside. Think of your map as a spaceship: only when it's hull is completely air-tight, people (all the entities) will be able to live inside. If there's a hole leaking into space (the void) everybody will die. On our spaceship that is. Not in Hl2...
How to find leaks?
First of all, vbsp will write an error in the compile log. The leak error doesn't stand out, but if you look carefull you can see something like:
**** leaked ****
Entity info_player_deathmatch (22.94 -64.44 17.00) leaked!
It will report an entity (e.g. info_player_deathmatch) and some coordinates.
Now, when you go to [map->load pointfile] and load your pointfile (usually hammer can find it, if not, youll have to search manually for it (it's called "[mapname].lin" or "[mapname].pts")) a red line will appear, starting at the stated entity, and ending outside your level (in the black space, called the "void"). If you just follow that line, it will eventually pass through your leaking hole. If you cant find the entity the line starts, go to [tools-> go to coordinates] and fill in the coordinates mentioned in the log. Remember entities and displacements cant block leaks, therefore its easiest to hide all entities and displacements so you can spot the leak easier (you might have turned a wall into an entity which was supposed to seal your level for instance). In space you can't seal holes in a spaceship with humans, in maps you can't seal holes with entities. Simple as that. Better use vis-groups to hide all the entities and displacements. Removing the mentioned entity will only help if the entity itself is outside the level, but the level itself is sealed (e.g. when a person from our sealed spaceship is going for a space-walk). Also, leaks may be caused by invalid use of areaportal(window)s (in our spaceship, areaportal(window)s are airlocks inside bulkheads), but more on that later. If you've fixed the leak, there may still be another one. Therefore, unload the pointfile (under [menu] )and recompile.
If there's another leak, simply load the pointfile again. Keep doing that untill there are no more leaks.
Don't make world-brushes overlap.
Vvis doesn't like it, and it may create extra faces. It will also make your map less orderly. Your choice.
===Don't overdo dynamic lights. (increases map speed)===
Simply don't because they are quite hard to render. Hl2 simply isn't doom3. Also, if you are using point_spotlights, check the "no dynamic light"-flag, to see a big increase in performance.
Make brushes standard sizes.
Not only will it be easier for you to use them, but its also easier to find and prevent (small) leaks.
- Standard sizes are 8, 16, 32, 64, 128, 256, 512, 1024 units.
Some values inbetween (48, 96 etc) can also be "valid" for some textures. Using standard sizes will also enable you to stay on the grid and use textures without the need to shrink or stretch them to awkward values. This is not a hard rule, but it will make your life so much easier. To help doing this, I suggest you use a big grid (16 units) and only decrease its size when your making detail brushes.
Also, don't forget to keep your brushes on the grid, not doing so will result in a less orderly, bigger map.
Don't use carve for any non-square brushes.
And if you do, tidy it up after. If a wall consisting of dozens of brushes due to carving of a cylinder in it wont slow down you map, I don't know what will. The keypoints here are to:
- minimize brushes and faces as much as possible
- making sure all points are on the grid and prefeably as straight as possible so they are easier to handle, and less prone to make errors.
http://www.student.kun.nl/rvanhoorn/Optimization/carve.JPG
Yuck! Ohhhhh, smooth....hmmmm
Don't overdo water. (increases map speed)
On multyplayer-maps water usually is a no go, because it means a lot of lag. (unless some steam update fixed that) So think twice before you try to use it.
If your still set on using it, but find it creates (a little too) much lag, you can do the following things:
- change the type of water to cheap water. Either use the water_lod_controls-entity or just stick a water-texture with "cheap" in its name on the waterbrush.
the water_lod_controls entity changes the water from expensive to cheap as soon as the player is far enough from the water
(you specify that distance in this entity)
- reduce the size of your waterbrushes. Make waterbrushes as small as possible, NEVER let them overlap world-brushes, because they will still be rendered
but never be seen. Also, when dealing with displacements, remember water continues under them but the player will probably never see it.
- stick as few entities inside as possible. Any model touching the water (its bounding box to be exact) will be rendered with water-visibility-features, but they come with a higher price (they are essentially rendered TWICE. To reduce load, make sure model-entities that are outside the water don't touch the water with any part of their bounding box, if you dont want them to. Also remember when your water runs under displacements and you have some model sticking through the same displacement, it might still touch the water:
http://www.student.kun.nl/rvanhoorn/Optimization/water.JPG
like in this picture, where the green line is a displacement and the blue is a water brush. The pink object sticks in the water, meaning it needs to be rendered heavier, even though you wouldn't be able to see it sticking inside the water. Also, this waterbrush is much bigger that it has, it could stop at the place where its top and the displacement (green) meet.
Use "mat_showwatertextures 1" in the console to find out which entities are rendered twice because they touch the water-surface.
Map wisely
If the entire map can be seen from one point, theres not a lot of optimization you can do. Try to avoid large, open area's since you can't optimize them. Instead, try to block the player's view (that of vvis to be exact) with buildings or walls to make sure you can actually hide parts where the player isnt looking. (with or without the use of entities and hints) Also, adding lost of corners instead of straight hallways may enable you to optimize your map better, but it comes at a cost: Will your map still be any fun? Will it still look great? (did it ever?)
If these general rules don't help you, youll need heavier stuff. Bring in the artillery!!
Nodraw texture
This magical texture makes all faces which it is put on dissappear completely. You apply it as any other texture. You can find it searching for "nodraw" in the texture browser. When you use it on a face, the engine doesn't have to draw that face at all, meaning less load and faster maps. The effect for one face is minimal, but using it massively is a different matter. So when do you use it? As much as possible! Any face the player will never see, should get this nodraw texture. Think about things like the rear of walls the player never gets to see, or the roof of buildings, walls that are covered by entities (e.g. func_details). You can also use brushes with "nodraw" on all sides of a brush to close holes created by displacements (displacements don't seal leaks, but "nodraw"-brushes do). Only one exception: "nodraw" doesn't need to be applied to faces on the outside of the level, or ones that are already covered entirely by other world-brushes or func_details, since those faces are automatically removed by vbsp.
Brushes with "nodraw" on all sides (I will call them NODRAW-brushes from now on) are still solid, even though you can't see them! If you look at a brush with nodraw, you will either see a skybox (if your map has one), other parts of your level (if their leaf is visible and are behind the nodraw) or just HOM-effects (halls of mirrors, the effect when a certain part of your view isn't updated, looks like a hall of mirrors...)
You may prefer to build your entire level with "nodraw"-textures and only texture the faces you can actually see, to make sure the engine doesn't render more faces than it has to.
Nodraw can't be applied to displacements, luckily there's rarely a reason for it.
Note: "Nodraw" is also used for creating water, just apply it on all sides apart from the top one.
Func_detail
The func_detail is a strange entity, because it isnt one. The func_detail is only used to give vvis an easier job figuring out your level (to find out why, see chapter "hints"). How does it work? Well, as soon as you tie a brush (or a bunch of them) to a func_detail, these brushes become entities. Entities cant seal leaks, but they are also ignored by vvis. This can save hours of compiling, simply because vvis doesn't have to calculate what you can and cannot see when you are looking through these brushes. Another great thing about this method is, that you can predict way more accurate how your level will be divided into leafs, so its easier to manipulate them. Func_details act like world-brushes for the rest of their lives, so they cast shadows, are solid but they wont cut up geometry like world-brushes (they do seem to do it occasionally btw, I can't really predict when). They wont block visibility (the engine will render everything behind them), but that's the only, and most negative point about these entities. So don't make walls func_detail if they can block visibility to big/complicated rooms.
So what do you tie to func_details? Again, as much as possible. Good candidates are brushes that never have to block visibility, like pillars, stairs, fences or roofs of houses that jut out, complicated brushes like brushbased machines, anything that's round, or plain walls you don't want to cut up leafs, like the walls above doors, below and above windows (exceptions are when func_areaportals are used). I'm sure you can think of other uses for this great non-entity. Since func_details can't seal leaks, don't use them on outside walls of your level, and because they are ignored by vvis, don't tie entire walls to func_details because vvis will think you can see everything behind it (and the game will try to render that too).
As an example, Ive made a small level with a house, and two cylinders. In one shot Ive made the cylinders and the roof of the house a func_detail, on the other I didn't. The effects are amazing to say the least. Remember, each line represents a border of a visleaf, and each leaf add to the time vis takes to figure out your map!
1. the map (notice the two cylinders and the roof of the house).
http://www.student.kun.nl/rvanhoorn/Optimization/detail1.JPG
2. no func_detail, seen in glview (tool to display all leafs in your level, see chapter "hints" to find out how to use it.) I can count atleast dozens of leafs here
http://www.student.kun.nl/rvanhoorn/Optimization/detail2.JPG
3. func_detail (I know it's still not optimal, I could make the slanted roof a func_detail and save even more leafs. Remember however, that this may cause you to see more leafs and actually make your map laggier.) Only six leafs here...Now that's style!
http://www.student.kun.nl/rvanhoorn/Optimization/detail3.JPG
One last example is the stairs. there are two ways to make it into a func_detail:
http://www.student.kun.nl/rvanhoorn/Optimization/detail4.JPG
(left) You can not tie anything to func_detail and suffer from extra vistime (each step will create another leaf).
(middle)You can tie the entire stair, including whats under it to func_detail, but thats not always possible, so there's a third way.
(right) Lastly, you can choose to make the steps themselves func_detail while leaving the rest of the stairs normal. Only one leaf is created this way (with a slanted underside) but this is very acceptable. Its all up to your design. Remember to give the unseen faces a "NODRAW"-texture for extra safety
the example map from valve about func_detail can be found here: "sourcesdk_content\hl2\mapsrc\sdk_func_detail.vmf"
Hints (and introduction to visleafs)
To understand hints and be able to use them well, youll have to understand the entire vvis-process. Well, ill try to explain it as well as possible without too much text. When you run vbsp, it'll cut your level into area's, called leafs. It'll store its information in a portalfile (*.prt) which vvis pickes up to use.
What vvis does next, is calculate which leafs can see which. And when you are inside your map in the game, the engine only has to render the leafs that can be seen by the leaf you are in.
To explain this better, lets take a look at an example level:
http://www.student.kun.nl/rvanhoorn/Optimization/room1.JPG
When vbps cuts this map in leafs, it will only look at world brushes, that's why I've left entities out in the example. Displacements also aren't used. We'll run this map through vbsp and take a look at how its done:
http://www.student.kun.nl/rvanhoorn/Optimization/room2.JPG
this picture shows all leafs in this map. A total of 5. Now vvis will calculate which leafs can see which leafs:
green can see blue and red blue can see green and red red can see all other leafs yellow can see purple and red purple can see yellow and red
Note: Only if vvis is able to draw a direct, straight line between two leafs without intersecting world-brushes, it will consider those leafs visible to each other. It doesn't matter where in the leaf the player is! Therefore, sometimes smaller leafs have advantages over bigger leafs, because they are more accurate in determining where the player is so they don't see as much as with big leafs.
All this info is stored in the mapfile, and you are ready to run the level. Now, when you are in the green leaf, the engine only has to draw the leafs the green leaf can see according to vvis' calculations, in our case only blue and red. However, if you are in the red leaf, the engine still draws the entire level (because all leafs can be seen by the red leaf) , no matter where you are in the red leaf, even if you wouldn't be able to see parts of it from your position.
When even the smallest part of a leaf is considered visible from even the smallest part of a leaf the player is in, that entire leaf will be considered for rendering ingame. Remember, everything in a leaf belongs to it, so whether it's a brush, entity, model or light, it will only be drawn if the leaf it is in is thought to be visible.
If you want to know how YOUR map is divided into leafs, you'll have to do the following:
Play your map and type "mat_leafvis 1" in the console (type "sv_cheats 1" first). A wireframe box will be drawn showing the current leaf. As you move around in the level, the box will redraw each time a new leaf is entered.
Fun as that is, it wont help you much. You want to see each leaf in the entire level. To do that, you must use a special option for vbsp, and a special program accompanied by hammer.
In expert compile mode (I hope you know how that works) make a new configuration, called glview (this allows you to use it for all your maps), and create the following commands:
Executable | parameters |
$bsp_exe | -glview $path\$file |
glview | -portals $path\$file.gl |
- the command for glview isn't known by hammer, so youll have to find it yourself: press executable, and browse to glview.exe (in the sourcesdk\bin directory)
make sure both commands are set to run, and press GO!
This is what you see with the example level: (It's normally only black&white, I edited it with paint to make it clearer for you) You can use your mouse and the WASD-keys to move around your level when in Glview:
http://www.student.kun.nl/rvanhoorn/Optimization/room3.JPG
as you may see, vbsp has cut up the red leaf in two halves. (Along the brown face) This is because vbsp always cuts your level up at the green lines in the editor (and every 1024 units (= red/brown lines). You can choose to highlight these lines under [tools->options] tab 2d windows and select the highlight every...and enter 1024 units. If you look very carefull in the first pics, you can see the green line at the place of the brown cutting.
But is the cut helpful? I could have moved the entire level, so vbsp didn't cut the red leaf in two, but obviously I didn't. (just to teach you a lesson ;) )Well, to tell you the truth, it doesn't help our performance. Since all leafs seeing the red leaf can also see both halfs of it separately. With minor adjustments, however, this can be changed: (white lines mark visibility)
http://www.student.kun.nl/rvanhoorn/Optimization/room4.JPG
In this case, green can see blue, red and brown. Just like when red was still one big leaf. But, take a look at purple (the upper room). It cant see red, and therefore, one less leaf has to be drawn from purple. And vice-versa, when a player is in the red leaf, the purple leaf doesn't have to be drawn. From the other leafs no optimizing has been done, but purple and red have one leaf less to be drawn.
This is just an example of when smaller leafs have advantages over bigger leafs.
But, how can we force vbsp to cut a leaf in two? That's where we use HINT-brushes.
Here's how hinting works. First, you create a brush, with on all sides the "tools/toolsskip"-texture. (this texture makes those faces to be ignored by the compilers). Now, wherever you want a leaf to be split, create the "tools/toolshint"-texture. The leafs are split EXACTLY where the face with the hint texture is. You don't have to tie the brush to an entity.
You can also take a look at the example map made by valve in: "sourcesdk_content\hl2\mapsrc\sdk_hints.vmf" for more information on how to make these hint-brushes.
As an example, you can take a look at how I can cut up the red leaf in the above level:
http://www.student.kun.nl/rvanhoorn/Optimization/room5.JPG
(note: only the white face of the brush is HINT, the rest is SKIP. Also note that in the 3d view of hammer both textures are transparent at default)
Be sure to fit hint brushes to walls exactly, or else their effect *may* be lost. It will also make your level tidier.
An example to look at is a corner. Normally, nobody can look around a corner, unless he had x-ray vision. Therefore there's no reason to draw stuff that's around a corner. Lets see how we can improve a corner between two very complicated "rooms":
http://www.student.kun.nl/rvanhoorn/Optimization/room6.JPG
Each room has four pipes, offcourse they are func_detail, or else vbsp would have cut the level in dozens of leafs! (see func_detail) Not to mention all the cut-ups the pipes would have caused on the floors and ceilings. vbsp can cut the level using the brown, the pink or both lines. In any case, both players (the green boxes) can see everything, because the leafs they are in can see each other. That's therrible!! The engine has to draw all cylinders at once (yes, it can easily handle 8 cylinders, but just imagine each cylinder being something very complicated and big), while we can avoid that and increase FPS, simply by placing a HINT-brush:
http://www.student.kun.nl/rvanhoorn/Optimization/room7.JPG
By placing a hint-brush at a 45 degree corner (crossing the corner exactly), we have forced vbsp to cut up our level in theses three leafs. If we go look at our visibility table:
Red can see green, BUT CAN'T SEE BROWN Brown can see green, BUT CAN'T SEE RED Green can still see everything
We can see that neither of the players can see both rooms now, unless they are in the green leaf. But that is supposed to happen, because in the green leaf the player can see both rooms directly at once. Wow, look at the optimisation we have done! We could have also placed the hint at another angle, as long as it touches the middle angle it stil works. Remember, two leafs are only visible when vvis can draw a straight line from leaf to leaf without crossinh world-brushes?
You may think that this green leaf is still very difficult to render. And you are correct. We cant solve that using hints. We can, however, try to make sure both rooms can never be seen from the same point. To do that, we need to add more corners, to make sure vbsp will never make leafs in a way both rooms can be seen from one point, for instance by using an S-shaped hallway.
Let's examine a few more examples:
http://www.student.kun.nl/rvanhoorn/Optimization/rooms.JPG
We see here a few examples of when, and how to use Hints. In all cases we try to hide the green players from each other. The upper three work as they should. The left one illustrates that it doesn't even matter if its one hint-brush spanning the corner, as long as its angle is > 180 degrees the two players will not render each other, because no straight line can be drawn betwen their leafs. The bottom-left example shows you that can happen when the angle is less than 180 degrees. One can easily draw a straight line from leaf to leaf, resulting in non-functional hints. When the corner is 180 degrees, as in the middle top picture, you can suffice placing two hints like there. In fact, you can even make them closer to the players, but that would increase their effectivity (more stuff will be drawn "around the corner". ) see the example below the middle. Because you lowered the hints, vbsp is forces to cut up the top visleaf because VISLEAFS CAN'T BE CONCAVE (hollow at any side). No matter how vbsp cuts up this corner, the hints will always work less effective AND create extra leafs (more work for vvis). In our example, the left player can see leafs 1 and 2 (same surfaces as above), but the right player will see all three numbered leafs (which is more than the top example.). The two right pictures show you you should keep things as simple as possible. If you can suffice using one hint, like in the top example, do so. And, don't use hints if you don't need to, like in the bottom picture. there is absolutely no way vbsp can create leafs that enable both players to see each other, so there's no need to use hints here to hide the players from each other (you can offcourse use hints to hide parts of the halls). In the same example you can also see a nice wall (the middle one) that should NEVER be a func_detail: because func_details don't exist according to vvis, it will think both players will see each other and thats not what we want. Vbsp may even make it so both players here are in the same leaf.
Another example is THE WALL. (also demonstrated in sdk_hints.vmf)
http://www.student.kun.nl/rvanhoorn/Optimization/room8.JPG
Meet Weebl and Bob. Weeble and Bob can see everything the engine renders, but are very sad, because they can see those ugly pipes on the other side of the wall. Even though theres a wall, that is supposed to hide the pipes, they can still see the pipes. It's because vbsp did a piss-poor job:
http://www.student.kun.nl/rvanhoorn/Optimization/room9.JPG
The leaf they are in, can see the other leaf, and thus it is drawn. Too bad. But, luckily theres a cure: a hint-brush.