I decided to write this tutorial for the Empires mapping forum because this seems to be something the newer Empires mappers don't pay a lot of attention to. I hope it proves useful to someone. What the compiler actually does The compile button in Hammer is probably something you've gotten used to using to test your maps, and sure, maybe you understand what happens when you set Rad to "fast" or set BSP to "entities only". But do you really understand what you're doing when you compile a map? When you start that compile, Hammer starts an automated process which runs your VMF through three different programs. These programs are VBSP.exe, VVIS.exe, and VRAD.exe. The first program that your VMF is run through is VBSP.exe, short for Valve BSP. This takes your plain Valve Map File and generates a basic BSP file (Binary space partitioning) from it. The brushes and displacements are properly converted into geometry the game can understand, entities and such are converted so the game will understand them. This process never takes more than a couple of seconds. When it is done, the bare-bones BSP is output to the folder that the VMF was loaded from. When you do an "Entity only" compile, the process is slightly different. With "Entity only", VBSP.exe doesn't generate a new BSP file from the VMF, it just loads the existing one in the directory where the VMF is, and edits the entity information in it. Changing geometry, brushes, textures, or lighting in a map and then only doing an Entity compile will either be ineffective or cause problems. The next build program starts and loads the BSP that VBSP.exe just output. This program is VVIS.exe, short for Valve Visibility. The first few things this program does is prepare the fancier shaders such as water or cameras so in order for water to work properly you need to at least run fast VVIS. The much larger part of VVIS involves using the automatic Visleaf generator to make up the Visleafs of the map. If you don't know what a visleaf is, they are described in detail here, and you should make every effort to learn about them. This part of VVIS is very important if you're doing a compile that you plan on releasing. This part of VVIS will increase the FPS that players get in your map by a HUGE amount. If you do a "fast" VVIS compile, you forsake all FPS gains that the Visleaf generator would give you and the players end up rendering ALL of the map, ALL the time. VVIS is a very important and often skipped part of the compile, mostly because the Visleaf generator will take a frustratingly long time if your map is not at least semi-optimized. Why you should optimize and a rough guide of what to do is something I will cover in the section after this. After VVIS completes it's work, which usually takes 2 to 30 minutes depending on map and cpu speed, it outputs the still partially complete BSP to the directory that it was loaded from. The last program in the process is VRAD.exe, short for Valve Radiosity Simulator. This program determines ALL the lighting in your map. If you don't run your BSP through VRAD at all, your map will have no lighting data at all and the engine will be forced to run it with mat_fullbright, which looks horribly, horribly ugly. This program takes the values you set all your lights to and runs them through it's Radiosity Simulator, which calculates the shading on all the different areas of the map, the way the light bounces off of surfaces to light nearby areas, and the way the shaded areas of the map look. This is probably the most important part in making your map look good. When you do a "full" VRAD compile with HDR, the compiler will put the BSP through VRAD twice, once for LDR (LDR is what you have if you don't have HDR) and once for HDR. A "fast" VRAD compile will usually only take a minute or two, but produces very rough lighting. A "full" VRAD compile will take usually 10 to 30 minutes. A "final" VRAD compile will usually take 30 minutes to an hour. Again, if you're doing a compile that you plan on releasing, you should at least do a full VRAD compile, if not a final HDR compile, but I go over that later in the tutorial. After VRAD.exe has finished, the compiler then takes your completed BSP and copies it to the /maps/ directory you specified. The compiler will then attempt to launch the game and run your map, if you selected the option. It's also nice to realize that the compiler leaves a copy of the compile log as a text file in whatever directory you loaded the VMF from, along with a copy of the finished BSP. Additionally, you may remember from when you first configured Hammer, under the Tools>Options>Build Programs menu, Hammer has 5 fields where it asks you the location of the executable files for the game, bsp, vis, rad, and the folder that the completed maps should be output to. It asks you this because different iterations of the source engine use slightly different build programs. Since Empires is on Source 2007, the build programs will all be found in "$SteamUserDir\sourcesdk\bin\source2007\bin". Why you should optimize your map Many novice mappers sit through 2 or 3 day long compiles where VVIS does incredible amounts of completely unnecessary calculations, and then whine about how much Source sucks. The reason behind these absurdly long compile times is the automatic Visleaf generator, and shitty mapper's refusal to understand it. Basically, this generator takes every world brush (any brush not tied to an entity) and calculates what areas of the map it would obscure at every viewing angle in the map. This can be an ENORMOUS task if the mapper hasn't spent the 30 seconds required to address this. To address this facet of VVIS, you take every brush that isnt big enough to properly obscure any part of the map from the player, and make it into a func_detail. Func_details, along with every other brush entity, will be ignored by the generator. The generator will also totally ignore the area inside of a func_viscluster, so you should use these in large, open parts of the map, such as the center of emp_isle. There are far better articles about how to optimize in hammer, and optimization is something every mapper should become familiar with. This is just a bit of info to make sure you're on the right track. Using "Expert" compile mode The "Expert" compile mode in hammer may seem a little bit intimidating at first but it's such a useful tool that it is definitely worth learning about. To access the "Expert" mode, you press the compile button in hammer and then click "Expert..." at the bottom left. It presents you with a slightly different compile option dialogue. In the top left there is a drop down menu of different compile configurations. These are basically what the "Normal" compile mode uses, only you have more control over what the compiler actually does. You can change what they do by adding Parameters in the "Parameters:" field. A useful parameter to add is "-low" if you want the compiler to only use idle cycles instead of all of your cpu, or use "-both" on $light_exe to compile the map for both LDR and HDR. There are many useful parameters you can add, some of which I will cover later, and you can find documentation for all of them on the Valve Developer Wiki. Final Compile settings Once you've tested your map a few times, ironed out all the bugs, and are ready to compile for a playable release, you don't want to just stick with a "Full" compile. With a "full" compile, models still don't get properly lit, props only cast shadows according to their collision models, and the lighting still isn't perfect. To do a proper release-ready compile, you want to go in the expert compile mode, select the "HDR Full Compile -Final (slow!)", and then add two extra parameters to $light_exe. Those two parameters are "-staticproppolys" and "-staticproplighting". This is important for a final release because "-staticproplighting" enables vertex lighting on static props, "-staticproppolys" tells VRAD to calculate shadows from props via their polys instead of collision models, "-final" allows VRAD to use more rays in its radiosity simulator which gives nicer lighting. It is important to do an HDR compile, too, even if you haven't added anything special for HDR. HDR makes the lighting look prettier in places where there is lots of contrast and shadows. Building your Cubemaps If you don't know what cubemaps are at all and haven't placed any in your map, this won't help you, but it's good to know anyway. Once you've done a final compile, you still have to load the game in the engine to build the Cubemaps. You have to open your console while your map is loaded and type in "buildcubemaps", and the client will start flashing a slideshow of small screenshots taken at each env_cubemap entity. If you compiled for both LDR and HDR, you will have to build Cubemaps twice, once when you have HDR disabled, and once when you have HDR enabled. The cubemap data gets automatically compressed into your BSP and the next time you reload the map, specularity and reflections will look correct. It is important to note that if you rename your BSP after you've built the cubemaps, it will cause problems.
I hope this tutorial documentation will be helpful to someone as these concepts are things I ignored/never understood for a long time, and now that I'm familiar with them they help me tremendously. I know that it seems like a wall of text but I think it's concise while still giving all necessary information. If anyone wants to help with formatting or has anything to add/correct it'd be greatly appreciated
use it for everything since there is probably very little visible, visblocking brush geometry in empires-maps ...
yes thats what i meant to say. if you really do visblocking and dont use keefs hack with draw distance and a "feature-complete" 3dskybox. i guess that is dependend on the layout though ...
By glancing over it, i think it pretty much sums up what i did with the last versions of bush and chain. I checked the compile setting for chain and i have this: -both -final -StaticPropPolys -TextureShadows -StaticPropLighting I have forgotten what TextureShadows does, but for some reason i think i needed it. And yes, 100% of the visible brushes in chain are func_detailed. I did visblocking by adding nodraw brushes. Nodraw brushes can be placed inside normal brushes without any problems (not only under displacements), and the number of visleafs can be decreased immensly this way. Intersecting normal brushes should be avoided though. Also i think all brushes that are func_detailed together (as one entity) are considered as one unit for the visibility calculations. If you put 80 brushes in one huge func_detail, and one of them is visible, i think the engine will draw them all. So don't put all brushes in one func_detail, but divide them into groups first. Turning each and every brush into a func_detail on it's own could cause you to reach entity limitations. Also, good job Varbles! Please become an official mapper and make real, good and respectable maps
I found Occluders to be useful in situations where visleaves wouldn't be able to help. I think I may write a separate tutorial on optimization specific to emp maps unless we have one already.
I think that's a very good idea. I myself never took the time to learn how to use occluders for example. I thought it was for small areas like windows, blocking off big areas, and my maps never really had places like that. For a detailed tutorial in optimization you'll gonna need pictures though . That's quite a lot more work than just summing things up.
For windows you could use areaportalwindows, and for interiors you could use areaportals to reduce the amount of geometry that's being drawn. I don't think that func_detail counts as an entity since it's stripped after compilation, although the compiler might still count it.
Just for completeness sake, TextureShadows allow the lighting to use alphas as light masking. It requires you have a file called lights.rad to determine which models will allow for it. The chainlink fencing used in hl2 is a good example. Code: lights/fluorescentcool001a 189 231 232 350 lights/fluorescentcool001b 236 255 182 350 lights/fluorescentcool002a 189 231 232 400 lights/fluorescentcool002b 236 255 182 400 lights/fluorescentcool003a 189 231 232 300 lights/fluorescentwarm001a 239 216 193 350 lights/fluorescentwarm002a 239 216 193 400 lights/fluorescentwhite001a 245 245 245 350 lights/fluorescentwhite002a 245 245 245 400 lights/hazzardred001a 228 37 0 300 lights/hazzardyellow001a 250 215 74 300 lights/HIDcool001a 145 222 172 650 lights/HIDcool001b 205 232 255 650 lights/HIDwarm001a 255 201 116 650 lights/white001 250 240 205 100 lights/white002 189 233 247 425 lights/white003 232 246 190 350 lights/white004 170 228 247 425 lights/white005 234 235 220 375 lights/white006 234 235 220 100 lights/blue001 166 180 196 200 166 180 196 100 lights/blue002 141 176 203 200 141 176 203 100 lights/red001 63 1 1 200 63 1 1 100 lights/white001_nochop 250 240 205 100 lights/white002_nochop 189 233 247 425 lights/white003_nochop 232 246 190 350 lights/white004_nochop 170 228 247 425 lights/white005_nochop 234 235 220 375 lights/white006_nochop 234 235 220 100 lights/incandescentcool001a 235 235 235 300 lights/incandescentwarm001a 250 226 129 300 glass/glassscreen001a 172 192 161 225 glass/glasspipe001f 214 72 44 200 glass/glassscreen001c 172 192 161 225 glass/glassscreen001d 211 187 134 225 glass/glassblock001a 70 194 209 200 composite/citadelfloor001a 103 143 203 200 props/tvscreen006a 196 0 0 200 shadertest/gooinglass 149 49 15 50 glass/glasswindow002e 189 233 247 425 glass/glasswindow035a 145 222 172 100 dev/DEV_INTERIORLIGHT02B 151 176 204 225 plaster/plasterwall029h 189 223 227 125 building_template/Building_Trainstation_Template001d 230 230 200 65 building_template/Building_Trainstation_Template001e 230 230 200 150 building_template/Building_Trainstation_window002d 230 230 200 300 building_template/Building_Trainstation_window002e 230 230 200 300 lights/physgunlight 189 231 232 20 noshadow tree_deciduous_01a_branches.vmt noshadow tree_deciduous_01a_leaves.vmt noshadow tree_deciduous_01a_lod.vmt noshadow tree_deciduous_01a_lod-leaves.vmt forcetextureshadow props_foliage/tree_dead01.mdl forcetextureshadow props_foliage/tree_dead02.mdl forcetextureshadow props_foliage/tree_dead03.mdl forcetextureshadow props_foliage/tree_dead04.mdl forcetextureshadow props_foliage/tree_dry01.mdl forcetextureshadow props_foliage/tree_dry02.mdl forcetextureshadow props_foliage/tree_pine_large.mdl forcetextureshadow props_foliage/tree_pine04.mdl forcetextureshadow props_foliage/tree_pine05.mdl forcetextureshadow props_foliage/tree_pine06.mdl forcetextureshadow props_foliage/tree_deciduous_01a.mdl forcetextureshadow props_foliage/tree_deciduous_02a.mdl forcetextureshadow props_wasteland/interior_fence001a.mdl forcetextureshadow props_wasteland/interior_fence001b.mdl forcetextureshadow props_wasteland/interior_fence001c.mdl forcetextureshadow props_wasteland/interior_fence001d.mdl forcetextureshadow props_wasteland/interior_fence001e.mdl forcetextureshadow props_wasteland/interior_fence001g.mdl forcetextureshadow props_wasteland/interior_fence002a.mdl forcetextureshadow props_wasteland/interior_fence002b.mdl forcetextureshadow props_wasteland/interior_fence002c.mdl forcetextureshadow props_wasteland/interior_fence002d.mdl forcetextureshadow props_wasteland/interior_fence002e.mdl forcetextureshadow props_wasteland/interior_fence002f.mdl forcetextureshadow props_wasteland/interior_fence003a.mdl forcetextureshadow props_wasteland/interior_fence003b.mdl forcetextureshadow props_wasteland/interior_fence003d.mdl forcetextureshadow props_wasteland/interior_fence003e.mdl forcetextureshadow props_wasteland/interior_fence003f.mdl forcetextureshadow props_wasteland/interior_fence004a.mdl forcetextureshadow props_wasteland/interior_fence004b.mdl forcetextureshadow props_forest/fence_barb_256.mdl forcetextureshadow props_forest/fence_barb_512.mdl forcetextureshadow props_forest/fence_border_128.mdl forcetextureshadow props_forest/fence_border_256.mdl forcetextureshadow props_forest/fence_border_512.mdl forcetextureshadow props_forest/fence_trail_128.mdl forcetextureshadow props_forest/fence_trail_256.mdl forcetextureshadow props_forest/fence_trail_512.mdl forcetextureshadow props_wasteland/exterior_fence_notbarbed002a.mdl forcetextureshadow props_wasteland/exterior_fence_notbarbed002b.mdl forcetextureshadow props_wasteland/exterior_fence_notbarbed002c.mdl forcetextureshadow props_wasteland/exterior_fence_notbarbed002d.mdl forcetextureshadow props_wasteland/exterior_fence_notbarbed002e.mdl forcetextureshadow props_wasteland/exterior_fence_notbarbed002f.mdl forcetextureshadow props_wasteland/exterior_fence001a.mdl forcetextureshadow props_wasteland/exterior_fence001b.mdl forcetextureshadow props_wasteland/exterior_fence002a.mdl forcetextureshadow props_wasteland/exterior_fence002b.mdl forcetextureshadow props_wasteland/exterior_fence002c.mdl forcetextureshadow props_wasteland/exterior_fence002d.mdl forcetextureshadow props_wasteland/exterior_fence002e.mdl forcetextureshadow props_wasteland/exterior_fence003a.mdl forcetextureshadow props_wasteland/exterior_fence003b.mdl forcetextureshadow props_foliage/fern01.mdl forcetextureshadow props_foliage/ferns01.mdl forcetextureshadow props_foliage/ferns02.mdl forcetextureshadow props_foliage/ferns03.mdl forcetextureshadow props_forest/fern01.mdl forcetextureshadow props_forest/fern01lg.mdl forcetextureshadow props_c17/fence03a.mdl copy this and save it in your %userprofile%/empires/empires folder as lights.rad. Then when you compile your maps they will take the models alpha texture into account when lighting. You will also need to adust your lightmap scale on areas that the shadow will cast onto based on the size of the opening. (This will highly impact compile times so be prepared and set it only to low numbers on just what you need it to.) I'll try to add couple of screenshots to show difference. Without -TextureShadows With -TextureShadows