Back to tutorial index page

Lighting the level, more advanced techniques

In a previous section using light entities has been discussed. Light can be emitted from entities or from surfaces textured in certain shaders, such as sky, lights, or some lava or fog.

In order to avoid ugly 'spotting', where strange pools of light appear, do not place light ents too close to geometry. More light ents, with lower light values, generally give better results than single entities with high values. Try to use a sky that suits the look and feel of your level. Experiment with different skies to try to find the correct brightness and sun angle, choose a texture that gives you the required brightness and the most interesting shadows.

Newer games, such as Doom 3, have real time or dynamic lighting. Lights flicker on and off and cast moving shadows that resemble those in the real world. This is not possible in Quake 3, but the remarkable Q3map2 does give us the option of 'faking' dynamic lighting through shader trickery.  

Although the images in fig.1 and 2 can not depict dynamic lighting in a still picture, both these areas use this technique. The flaming torches would emit a flickering light, so it seems reasonable to try to recreate that effect. Be careful in the use of dynamic lighting, as with all shaders, over use impacts upon performance in terms of a loss of frame rate. Also, any one surface must not receive light from any more than 4 dynamic light sources.

So how is it done?



A light ent is created or selected in the normal way. Bring up the entity editing window and add the key _style and then a value of your choice, normally somewhere between 1 and 12, in this case 10 was selected, see fig.3 below. Some experimentation is required to achieve the look that is required.


Fairly simple so far? Things get a little more complicated now. When the map is compiled Q3map2 generates a custom shader and texture folder, used in game to achieve the flickering light and shadow effects. The texture folder, which will have the same name as the map, is placed automatically in the maps folder and the shader, named q3map2_mymapname.shader, is placed in the scripts folder. Both the texture folder and the shader must be included in the .pk3 for distribution, just like other custom map content. Each time the level is compiled the texture folder and shader are updated, so be careful to include the current versions of the textures and shader with the .bsp (the compiled map).

Sometimes it may be necessary or desirable to have the light source some distance from the area where you require the light to fall. This 'spot light' effect can be achieved by targeting a light entity at a target_position or an info_null entity (fig.4). Create the light ent, then create the info_null (under info, in the entity menu). Select the light, then the info_null, next press Ctrl k to connect the entities. Unfortunately GTK can not show lighting effect in real time, so it is necessary to compile the map in order to observe the effect you have created. Sometimes it may take 3 or 4 attempts to achieve the result you want, adjusting the strength of the light source and the distance and angle from the info_null.



Applying the clip brush and optimising the level for bots


The use of the clip brush has been touched on before. Clips are used to simplify geometry, make models appear solid or prevent players and bots from reaching areas they should not. There are 3 kinds of clip brush used: Common/playerclip, which blocks players and bots, common/botclip, which blocks only bots, and weapclip, which blocks players, bots and weapon fire.

To smooth passage through the level, playerclip is used extensively, encasing architecture completely within in smooth simple geometric shapes. If an examination of the sample map is made, it will be seen that almost an entire level is formed by clip brushes, nearly every surface is covered by a clip brush of one type or another (see fig.1 below).


A good test for where to apply clip brushes is to compile the level as a test, and run around the walls in the map. If you become snagged at any point, that area requires smoothing out with the clip brush. It is perfectly fine to overlap clip brushes. They are not visible in game, so optimising clips in the same way that is required for rendered surfaces is not necessary. In fact, the more simplified clip brushes are kept, the better, in most cases.

Clipping the level leads onto optimising a map for bot play. The most comprehensive tutorial available on this subject can be found on Cardigan's site. The single most important concept to grasp about bots, is that they like things simple. Smooth rectangular blocks are navigated far more easily than complicated geometry with many angled faces. Uneven surfaces should be player or botclipped. Areas where bots could never go, such as high areas above their heads can also cause confusion and should be filled with botclip. Patches of any description will complicate navigation for bots. All patches should be encased in simplified botclip brushes, see fig.2 below.


Watch the bots play the level. Examine areas they have trouble with, and add common/botdonotenter  brushes (tells bots not to enter a particular area) or more botclip. Bots tended to get stuck to the right of the little flight of steps shown in fig.3. A simple remedy for this was to place a triangular shaped clip brush next to the stairs, so that as the bots exit the top of the spiral stairs, they are funnelled round to the front of the troublesome stairs.

Often bots will not act in what would seem like a logical manner at all. Some areas may not be visited or certain jump pads ignored. The solution is tweaking, tweaking and more tweaking (fig.6). Bots do not like to use jump pads where 'air control' is required. Step onto the trigger and see where you end up. The jump pad should place you neatly at your target level, if you need to move in the air, bots will struggle, or ignore the jump pad. If the path connecting the trigger to it's target passes through any solid geometry, this also can cause bots to reject the jump pad. Try adjusting the size of the trigger brush, this can also influence whether or not bots will use the pad. Sometimes bots will refuse to visit a certain area. This can be a result of small clusters, more about that later. Ensure the ignored area is clipped and smoothed, so there is nothing that might be confusing the bots. The items you place in a map will encourage bots to circulate, just as real players. Try to scatter items, like a paper trail, for the bots to follow. Apart from at jump or launch pads, bots will not go for suspended items. Having an understanding of individual bot behaviour can be helpful. One particular bot may handle certain aspects of a map better than others, but this is largely a case of trial and error. Knowing bot preferences for weapons or items is a definate help. Placing a Super Shot Gun in an area in a map where Bones is included as a bot, will almost certainly encourage at least one bot to visit that area! If, despite your best efforts, bots still refuse to enter an area, or use a corridor, try inserting an item_botroam or two (fig.7). Item_botroams are bot only entities, they can be given a key of weight, and a numerical value. The higher the value of the key set, the more the attraction to the bot. Much care is needed when using botroams. Play can very easily become unbalanced if you set the value too high, or not alter in the slightest, if you set it too low. Unfortunately item_botroam entities are always on, there is no respawn time after a bot has collected them, this can cause constant revisiting of the entity's location. Placing an item_botroam on a jump pad trigger sometimes causes bot to repeatedly bounce up and down like they were on a trampoline. Setting a high value to begin with is generally the best approach, start with 400. Much recompiling will be required, but then adjust the value until bots act reasonably sensibly. Try to use item_botroams as a last resort, if all else fails, rather than as a first course of action.


Previously in the tutorial clusters were mentioned, if you took a look at  Cardigan's article you will probably have a good idea what clusters are. Simply, the map is divided up into areas in order to make bit navigation easier. If the map is one huge cluster, from the bot's point of view every item will be visible. Although this will tend to make bots play with more intelligence,  it can cause bot-stutter, sudden slow downs in the game as the computer is forced to make large amounts of calculations. Each cluster has a number of reachable areas. It is good practice to try to have clusters with similar numbers of areas in each. The number of reachable areas often has little to do with the size of the cluster. Take a look at the bspc log. At the bottom it will give the number of clusters and the number of areas with in each cluster. Life would be much easier if there was a utility in GTK which allowed you to import clusters and areas into the editor, unfortunately there is not. Fire up Q3, and load the map in devmap mode. In the console type, /bot_testclusters 1, at the top of the screen a read out will appear, informing you which cluster you are now in. Minus numbers can be ignored, these appear when you are in the air, or inside a clusterportal (more on that in a moment). Try to locate where each cluster is. Pay particular attention to areas where bots are reluctant to visit, and see if these areas have been made into small clusters in their own right. Also pay attention to areas of the map that give the warning solid!, as far as bots are concerned, these parts of the level are off limits. Having gathered this information, what now? We are going to try to make improvements to the .bspc by forcing the creation (or not) of clusters. The main tools to achieve this are the common/clip brushes (especially botclip) and the common/clusterportal brush. Clusterportals are placed to create clusters. They act as doorways, through which entry to and from separate clusters takes place. Clusterportals would normally be placed in doorways, but not necessarily. They should be no more than 8 units thick and  be simple rectangular shapes. The edges of the clusterportals must touch solid geometry or clip brushes on all sides. An intended cluster must be closed off completely by clusterportals. Every entry/exit of an area must contain a clusterportal brush, or the cluster will leak and not be formed. Clusterportals will only work in places where they can be walked or run through, they will not work in places where they are dropped through. Also note that areas of your map that are connected by jump pads or teleporters, or other targeted entities will be formed into a single cluster. Fig.5 below shows an example of this. The jump pad from the cave area throws the player up into the central area. These two separate areas in the map are therefore fused into a single cluster. In the Capture The Flag version of the sample map (a discussion on how to convert the map to Capture The Flag is covered in a separate tutorial), clusterportals have been placed in the centre of the level. This is shown in fig.4. Clusterportals are completely surrounded by clip brushes and are simple rectangular shapes. As a result the map is divided into 2 equal clusters with the same number of reachable areas.

Occasionally very small clusters are formed by the .bspc. These can confuse bots, who will refuse to use the offending regions. There are a number of approaches to solving this problem. Try clipping and clusterportal placement. If no improvement is achieved try one of the following 'hacks':

1. Place a large clusterportal brush, or several touching clusterportal brushes inside the region you want to eliminate the cluster. This can sometimes confuse the .bspc and force it to incorporate the area into another larger cluster.

2. Use a targeted entity to connect the clusters. If you don't require the entity for game play reasons, then place it in such away as players and bots can not get to it.





Finally, remember that optimising the level for bots takes time and practice. You will have to recompile the map many times until you achieve the result you want. It is, in all but a very few cases, something of a cop-out to decide that a map is not intended for bots. With effort and time most levels can be tweaked and polished until bots offer at the very least a reasonably enjoyable match. If bot play is ignored, chances are that your level will not remain on the hard drives of many people for very long at all, and all your hard work will have been for nothing.

Tweaking vis control

Building levels with vis control in mind has already been covered. In this section methods of fine tuning vis, and therefore what Q3 is rendering at any one time, will be discussed. If you haven't already, again let me stress the importance of reading Bill Brook's Hint Brushes and Spog's Q3map explanation. Some of the ground covered in those articles will be repeated here, but not all. The sample maps made for the purposes of this series of tutorials will be used to illustrate specific examples.

Although fairly highly detailed, the sample maps have been built with vis blocking in mind. The main areas are separated by solid vis blocking structures to prevent too much of the entire level being drawn at any one time. In a previous tutorial problems resulting from the 'sky bug' were discussed. If more than one area occurs in the same vis leaf node, it is possible to observe partially rendered geometry from one region through the sky brushes of another. Building with this in mind it should be possible to prevent this from happening, however a small error was made and it was possible to see part of the base area roof from the centre area. Although annoying at the time, it is useful to discuss the solution here as it directly effects vis control. Firstly, however, let us take a look at hint brushes, the reasons we need them in the sample map, and where they are placed.

There are 3 important console commands to use in the relation to vis control. In each case the level must be loaded in /devmap mode. Type a 1 after the command to toggle on, and the command again followed by 0 to toggle off. The console commands are:

/r_showtris, this draws the level as polygons being rendered by Q3.

/r_speeds, this shows a readout of the number of polygons being rendered.

/r_lockpvs, this culls areas of the map outside the leaf node that you occupy at the time of enabling.

These commands are essential for deciding where vis control requires a little tweaking. /r_showtris in particular is extremely useful for evaluating where areas of the map are being drawn that the player should not be able to see. Fig.1 below shows a view from the base area, looking back towards the centre area. The mass of tris in the centre of the image shows where a considerable portion of the middle of the map is being rendered. From this position it should not be possible to see any of the central area, so unnecessary strain is being placed upon the computer. Don't worry about some of the shots being in full bright mode, as compiling light is not required in order to assess vis.


Having identified a problem with vis, how can the situation be improved? If you have read Bill Brook's article then you will already know the answer. We are going to use the hint texture to create artificial splits in the bsp tree. Brushes textured in the hint texture are structural, but invisible and non-solid. A common misconception is that hint brushes block vis themselves. This is incorrect. The job they do is to manipulate the vis calculation process by creating portals that otherwise would not exist. Where the vis process calculates that 2 portals can not see each other, culling will occur in game. This is a simple theory, yet sometimes much harder in practice to achieve. Fig.2 below shows the corridor that needs attention. All the detail brushes are filtered out as they have no effect upon vis. In the 2d window, examine the 2 selected brushes, marked A and B. The faces of the 2 brushes are cut on EXACTLY the same angle and meet at the corner of the corridor where it is intersected by a wall. Both brushes are made out of the common/skip texture, with only the angled faces textured in the common/hint texture. Common/skip is the one advance not covered by Bill Brook's tutorial. Skip informs the compiler to ignore any part of the brush that is textured by it. In this way only the faces textured as hint will cause portals avoiding unnecessary portal creation, as would happen with the original method. The down side of using common/skip is that only GTK 1.5 will filter skip/hint brushes out when you try to filter hint brushes from the map. Renaming the skip shader hint_skip, is one way around this. As both skip and hint are compiler only shaders this will cause no problems with missing textures in game. If the angled faces of the 2 hint brushes are not on the EXACT same angle their effect will be lost. Both brushes must end right up against other structural brushes, and they must meet right at the corner of the corridor. The compiler will calculate that the portal created by brush A could not see the portal created by brush B, and vice versa, therefore culling the map beyond.


Fig.3 depicts the same corridor as in fig.1, but this time after the hint brushes have been placed. Notice now how the central area of the map is no longer being drawn, hence saving valuable tris. If you are very observant, you may well notice that the frame rate indicator in the top right hand side of the screen shows more or less the same number. This doesn't mean hinting has had no effect, but rather is a result of a maximum frame rate being set.


Moving on to the central area of the map, fig.4 shows the cave area below being drawn at the same time as the region we are currently in. This problem will be dealt with in a slightly different way. Remember the sky bug problem? The base area is part of the same potentially visible set as the central area. Vis starts by splitting the map into 1024 by 1024 unit sections. This is known as the block size. An obvious and simple solution would be to reduce the dimensions of the block size. By splitting the map into smaller sections to calculate vis, it becomes less likely that another area becomes visible from somewhere else. To adjust the block size, select any brush that is not part of a group and press n to bring up the entity handling window. The entity selected is called worldspawn. Worldspawn is used for global effects on the level. Add the key _blocksize and a numerical value of 512, or 256 or 128. It should be mentioned that the smaller the size, the longer the vis process will take, but considering the default setting of 1024 was compiling vis in under a second, that's something we can live with. For very large terrain maps vis could be speeded up by actually increasing _blocksize values, but of course this may result in adverse effect upon performance.


The image shown in fig.6 is the same area as in fig.4 above, but with _blocksize reduced to 256. So why can _blocksize not be used to tweak vis by itself? Do we really need to spend time playing about with hint brushes?

The answer is yes. Look at fig.5, this is the same corridor as in fig.1 and 3. There are no hints placed in this version of the map, vis control has only been altered by reducing _blocksize. Compare how the central area is being rendered in fig.6, as opposed to fig.3 that shows the level compiled with hints in place and the _blocksize at the default 1024.


So apart from solving the sky bug problem has reducing the _blocksize had any other effect? Look at fig.6 and compare it to fig.4, notice how the cave area is no longer visible.


Through a combination of approaches, the most basic of which is good level planning and map making, vis is effectively controlled and the rendering of unnecessary tris avoided. Levels be far more highly detailed and still able to run fairly smoothly if similar care is taken.