Half-Life 2 Map Editing Optimization Guide


The brush-work in your level may get very complicated. For every brush that isn't an entity, the compile process will try to determine what the player can or cannot see when he is looking at this brush. This is okay for big walls, but you certainly don't need to have this done for every brush. Imagine you have a room with 300 small pebbles* ( all brushes ) spread accross the floor, four straight walls a floor and a roof. If you had to calculate what brushes can or can't be seen from any point in this room, you can be quick: all brushes can be seen at any time. The small pebbles won't cover any whole brushes, so we dont have to bother figuring out whether or not certain brushes don't need to be rendered because they are covered with the pebbles. Go AI. Unfortunately, the compile programs don't have AI and will try to calculate what you can or cannot see using every single pebble in the room. Yes, that is way over 300 calculations where none are required! What a waste of time! What can we do against that? There must be a way to tell the compile programs what brushes to ignore?

* It is never a good idea to make 300 brush-based pebbles, but this is used as an example. Please do not try to make a room with 300 brush-based pebbles, unless you have a death wish.

Like I said, entities aren't used in the visibility determining process. I will explain why and how in the visleafs chapter. Putting 1 and 1 together we can conclude that by turning all our pebbles into entities, we can tell the compile program to ignore the pebbles! But this is a waste of memory: all options of those entities (inputs, outputs, movements etc) will be loaded into memory. Say we tie our pebbles to a func_door, then the pebbles will use the memory of a func_door. All pebbles will be able to move and act like a func_door. Since the pebbles will never be used as a func_door, this is a waste of memory. So, in essence, we need an entity that is ignored in the visibility determining process, but also doesn't have any special functions so it doesn't use extra memory ingame. This entity listens to the name of func_detail.

A func_detail can be made like any other brush-based entity, simply select a number of brushes and press "tie to entity". Func_detailed brushes act just like world brushes: They are solid, cast shadows etc. There is only a minor bug, which causes light to bounce around a func_detail because the func_detail doesn't break up the world brushes around it (this effect is called lightbleeding, as the light is 'bleeding' around the brushes. Suffice to say that if you didn't understand that, don't worry about it. You will only see it when you make a large brush ( eg wall or floor ) func_detail which blocks light/casts shadows.

Lightbleeding is caused by func_details not breaking up world brushes around them. Because of the way the lighting is calculated, light is able to cross the light-blocking func_detail by travelling along the lightmaps of the world brushes around it. If a func_detail is between a very dark and a very light room, then the func_detail on the side of the dark room will appear dark ( as it should ) but with a light edge around it due to the lightbleeding. You can stop this by increasing the thickness of the func_detail, or by turning it back to a normal world brush.

It's handy to use the func_detail as default brush-based entity in the editor's options. It doesn't matter if you tie 1000 brushes to 1 func_detail or 1000 func_details, but usually it's easiest to group certain brushes into a single func_detail ( eg group all brushes making up a window into one func_detail ). It only makes editing easier, it doesn't matter ingame. You will probably do this automatically once you use get to use func_detail extensively. Because you will be using it a LOT. Or atleast you should be. Learn all about the main uses of this magical entity below.

Firstly, you must know that for determining what parts of your level can be seen from where, the compile programs ( vbsp.exe ) divide your level into areas, called 'visleafs'. Then vvis.exe will figure out whether area 'a' can see area 'b', or 'c', or 'd' etc. Consequently, each area doubles the work that has to be done! This is why reducing the amount of visleafs greatly reduces the time it takes to compile your map.

You must also know that these visleafs have the same rules for their shapes as normal brushes. That is, they can't be concave. Dividing a level into visleafs is similar to carving two brushes. What we are actually doing is carving the empty space in your level with ALL the world-brushes you made! Remember what I said about carving?

Don't carve. In the sole occasion where carving is ok, it's faster to do it yourself anyways.

And here we go having our level carved all over during the compile process! It's a VERY fast process, even with thousands of brushes it only takes a few seconds, but it does generate tons of visleafs. Ouch. So, what do we do? Simple, we make sure our level is the sole occasion where carving is ok! As I said, carving is usually okay of your brushes are square. So we must make sure our level is as square as possible. Everything in our level that isn't square, must become func_detail, or any other entity if you require their possibilities. Displacements are counted as entities already, so they dont need to be func_detail ( in fact, doing so will result in an error ). Actually, anything that we don't expect to hide big parts of the level behind them should become func_detail.

I will now discuss some images and try to explain to you what to func_detail and what not to.

1) pillars

Lets examine this overly simple room with four square pillars and one round one in the center.

A room with some pillars

Note that the brushes in the corners overlap: If these brushes are world brushes that doesn't matter, since vbsp will cut the overlapping parts away.

And now compare it to this image (which is a visual representation of how the visleafs are shaped in the level, topside)

Pillars cut up level into many visleafs

You probably don't even recognise the room, wtf happened? The compile tools tried to carve the pillars into the visleafs, resulting in this mess. There are over 20 visleafs in this simple room! However, since none of the pillars is big enough to actually hide huge parts of this level, we don't even need all those visleafs in the first place! Lets say we func_detail all pillars here, then we would get this image:

Only one visleaf after func_detailing all pillars

ONE visleaf! What a difference. It allmost makes me cry.

2) A detailed wall

This next wall is pretty detailed, I can't even imagine how horrible this would look in visleafs

Example of a very detailed wall

This is how this wall looks like in Glview

Now those are a lot of visleafs. Lets see. This is a wall (no shit Sherlock). Generally, a wall shouldn't become a func_detail because it blocks visibility. But in our case we can safely turn this into a func_detail, since the four windows allow the player to see through the wall. This wall hardly blocks visibility (no more than the pillars in the last example) and so should be turned into a func_detail so the map compiles faster. By doing so we saved roughly 50 visleafs. But what if there weren't any windows? The wall would still cut this corner into tons of visleafs, and we can't turn the wall into a func_detail since it would make the player render the other side of the wall while the player couldn't see that side at all. The solution? A hidden wall! We can still turn this entire wall into a func_detail, but then add a much simpler ( and straight ) wall inside the func_detail that does the visibility blocking! Because this wall is a single brush, there wouldn't be any more leafs than needed and we still have 100% visibility blocking. Offcourse we can do the same with the outer walls of our level. If we func_detail these walls we would get a leak, but by adding a hidden wall inside these func_details we would stop the leak. Just like we do when placing a hidden wall ( or floor ) under a displacement. Always make the hidden wall nodraw, and always place the hidden wall inside, or directly behind the func_detail. If you would leave a gap between the func_detail and the hidden wall you would get unused space, which the player can't get to, but it still gets rendered!

putting a NODRAW-brush behind detailed brushes

In situation 1 the NODRAW brush (yellow) is inside the detail entity (black). If you were standing at 1, you would see a very detailed wall, but there wouldn't be any extra visleafs because the nodraw brush would be used for making them. In situation 2 the nodraw-brush is directly behind the detail-brush. Though not as optimal as 1, it is still acceptable. In situation 3 however, there is a gap between the nodraw-brush and the detail entity. A player standing at 3 would not only get the nice side of the detail entity rendered, he would also get the backside of the detail brush rendered, not to mention the fact that the other two walls at the side and the floor and ceiling are bigger than they need to be. Therefore, 3 is the worst situation.

It usually is a good idea to place a clip-brush around detailed objects to make sure players don't get stuck in them. Clip-brushes ( brushes with the any of the clip-textures, search for 'clip' in the texture browser ) block players from going to certain places, for instance tiny nooks and corners in/around detailed objects.

The 'hidden wall' technique is also good when making rounded walls, or roofs. Talking about roofs...

3) roofs

Sometimes you have brushes sticking out, like roofs, which cause extra visleafs. Usually, this is not needed. Take the following example:

Two buildings with slanted roofs

These are two big buildings, with slanted roofs, which stick a bit out. This may seem like a little thing, but lets see what these little things can cause:

Ragnarok is nigh, aye

OH, SHIT. This crap is horrible. I'm not even gonna count the number of visleafs these two buildings have caused with their fancy roofs. We could make both buildings func_detail entirely, but that would mean the player can see the high poly objects behind the buildings.

Note that some visleafs in this example are cut because of other reasons, see the chapter about visleafs for that.

Offcourse if we can't make the buildings func_detail entirely, we must make them func_detail partly. Bear in mind that "the squarer the better" and use that to know how far to go. Compare the next two images, one where only the roof ir func_detailed, and the next where the entire 2nd floor is func_detailed. I'm sure you can figure out how the second is the best option.

Pretty good situation:roofs func_detailed

Better situation:roofs and atticks func_detailed

Never forget that these examples don't reflect YOUR map, they are just examples. If a player can go into these houses, there are windows in them, or other buildings where a player can climb upwards, all these rules can still be used to reduce the number of visleafs, but that may not be good for the framerate in your map. You will read more about this in the next two chapters.

If your buildings have things like balconies and/or drains or other brush-based objects hanging on the walls or roof, be sure to func_detail them if they aren't already an entity. Things like these rarely block visibility, and only cause your map to compile longer!

4) stairs

Stairs. Yes. Stairs. They allow you to climb to the next level in both real-life as the amount of visleafs your map has. If you don't make all those steps entities, you will get a visleaf for every step. Please look at the following pictures to understand that. I don't think you will need comments to understand them. The first picture is an editor shot of the stairs, then a picture with all the steps and sides not func_detailed and lastly one where the stairs and sides are func_detailed:

Our stairs in Hammer

Same stairs in Glview

Same stairs func_detailed

Sideways, this is the right situation of the picture below:

Examples of func_detailing stairs

The big triangular brush is a world brush, the small ones are the steps. I could offcourse used the left situation here, but since the walls and ceiling are already going upwards, we might as wel have the fake floor go upwards aswell.

So, in summary:

A (group of) brush(es) should be func_detailed when:

a)If the player stands on one side of the brush(es), he sees a lot more or less than when he is standing on the other side looking in the same direction. (like the pillars)

b)The brush(es) is/are detailed or small ( like the details on the wall, or the stair-steps )

c)The brush(es) is/are not square or straight ( like all cylinders or arches, or the middle pillar in the pillar example )

d)The brush(es) are at an angle ( like the roofs )

e)The brush(es) jut out into a room while no visblocking is required

You should add a hidden nodraw brush inside this func_detail if you still need the visibility blocking properties of the (group of) brushes you just func_detailed. You will learn more about when you need these visibility blocking properties in the next two chapters.

If you ever want to know how your level is divided into visleafs ( this is very handy to find out whether or not you have func_detailed enough, and/or you missed some stuff, use Glview. Read more about this program and how to use it here

If you are new to func_detailing, use Glview a lot to find out how your level is divided into visleafs. You won't even believe how much visleafs a single brush can make. And you will never learn either, unless you use Glview ( or the ingame alternative ) to experiment

The example map made by Valve dealing with func_detail can be found in "sourcesdk_content\hl2\mapsrc\sdk_func_detail.vmf"

«- Previous Chapter Next Chapter -»

© Webdesign Copyright by Kolezan, contents Copyright by Ralph 'zombie@computer' van Hoorn