Welcome to the Speeds article. This one’s pretty much an industrial-strength article; so read slowly and of course, feel free to ask if you have questions. Well, we’ve got a lot of ground to cover; so let’s dig right in… “Why do I have to design my levels with speed in mind?” You might be asking this yourself. Well, the answer to that is complex; but to be blunt: Its so people can PLAY your map! Okay, so now that we know its important; what IS speed? Speed is usually measured by one of two things. In level-design circles with quake-engine games, “r_speeds” are often quoted and used as a measure. I’ll explain those later. The more “generic” (and more proper when speaking of a specific instance) measure of a game’s speed is FRAMES PER SECOND (or “FPS” – also referred to as “frame-rate”). Frames per second is a measure of how many times a new picture is painted on the computer monitor (each second of gameplay). The computer monitor you have is probably set to “refresh” its picture somewhere between 60 and 80 times per second (also known as “hertz”). The CRT itself scans across the screen surface in a series of horizontal lines at such a speed that an entire screen is completed at one of these rates (between 60 and 80 times per second). The CRT itself could care LESS about what color each pixel is (pixels are the individual colored dots on the screen); or how complex the lines are – it does its job on its own. The only thing that matters to IT, is what picture the video card is sending out over the cable.
This is where the speed limitation occurs: How quickly your video card can fit together an entire screen of data; and send it out to the CRT. The “minimum” acceptable for this frame-rate is usually considered to be in the mid 20’s – and the 30’s is what to shoot for. By comparison, movies run between 24 and 27 frames per second. Have you ever watched a movie and noticed how smooth the action is? That’s because movies are timed to be very close to the actual update-rate of the human eye. The slower the FPS, the more times your eye will capture the same scene – leading to jerky or seemingly imprecise images (note: This is NOT the same as “Lag”. Lag is actually jerky motion caused by slow updates over the ‘net. The way that networking in games is set up these days, your screen will often times only refresh as quickly as new data comes in – so the slower your connection; the more lag and slower frame-rate you may have…. but in this case it is NOT the level’s fault).
Not only does it mess with your brain’s sense of motion when seeing objects update infrequently; but computer games and animations are TIMED. That is, a certain animation should have X number of frames and take Y number of seconds to complete. If your computer can’t play ALL of the X number of frames, some will be dropped out so that the animation still completes within Y number of seconds… could you imagine the chaos that would result in a multiplayer match if everyone’s characters and screens were animating and working at different rates? It would be ghastly! But on the other hand, these dropped frames make the separate images that your brain receives much more different from one another – making it harder for your brain to perceive fluid movement, and for your brain to predict the action. So, obviously higher frame-rates are better. Now, you may have seen benchmarks on hardware sites showing off insanely high frame-rates and touting this as good; but the thing to remember is that those benchmarks are AVERAGES across a time period. The REASON the higher average score is better is NOT because you want to max your frame-rate; but because higher-scoring cards can traditionally perform better under harsher conditions (thus keeping their frame-rates above the 20’s); making them the better choice for you to max out your resolution and color and details, or play complex games. If a card could produce 30 FPS under ANY circumstance; it would be a MUCH better choice than one that could do simple scenes at 200 FPS, and complex ones at only 10 FPS.
The problem with measuring how well your map will perform by the FPS, is that EVERYONE has different hardware and setups – and runs in different resolutions, etc. CPU, memory, video card, resolution, details, sound, and other factors can ALL affect the FPS in a game. Because of this, and because of the wildly different hardware setups of gamers, there can be no way of ensuring a specific frame-rate in a given situation for anyone else but yourself.
Section 2, Enter R_speeds
The solution? Well; unfortunately the solution is based around estimates – with a little bit of trial and error thrown in. These estimates can be taken from a measuring device included in all Quake-engine games (that I know of). It’s called “r_speeds”. What r_speeds does, is print out on the screen (in the game) the number of polygons drawn each time the screen is updated. Using this, you can gauge how complex the scene is in any area, and from any angle. Since scene complexity directly affects how quickly the CPU and video card can update the screen, this is a good item to standardize on. You can adopt rough guidelines from this that apply to the majority of gamers’ systems – and the folks with truly geeked-out computers will never suffer; their hardware won’t be pushed to the limit – but your map WILL be playable by more people (i.e. the ones that don’t spend every last penny on hardware). There will be an r_speeds chart at the end of this document for you to use as a gauge.
Okay, so now you know what they are – but you still need to know how to use them. Here’s a “dissection” of what the r_speeds mean – notice there are two different versions; one for software mode and one for hardware mode. Both have their uses:
To get the r_speeds display, you must be running half-life in the “-dev –console” mode (those are the command line parameters you must specify when running the Half-Life executable). Once your map has loaded up, bring down the console (usually with the “~” key). Then, type “r_speeds 1” (without the quotes) to turn it on. “r_speeds 0” turns it off (again, without the quotes). Remember that r_speeds only display the CURRENT values based on what’s visible. You need to run around your level, try being in different parts of a room and seeing different things (backing into a corner or standing in the entrance of each room are two good ones to try), and trying to view as MUCH as possible at once (i.e. get to a spot where you can see a ton of detail; then stop moving and look at your r_speeds). Then, take the MAXIMUM number you could come up with; and use that for comparison to the charts. If you find your speeds unsatisfactory; I’ll be explaining later on how to correct for that.
But in the meantime, you may want to know how the computer comes UP with these values; so I figured I’d explain how the computer determines r_speeds. First off, almost every brush is broken up some during a compile. This is done to accommodate texture sizing and alignment, as well as other things. You can see this effect by typing in “r_drawflat 1” at the console (“r_drawflat 0” turns it off) – but this ONLY works in software mode. This shades every surface as a solid, flat color.
Then, in the game, the surfaces are divided into triangles when the scene goes to the video card to be rendered. Why triangles you say? Well, it could be for a number of reasons – but the main one is that ANY 3 vertices (in 3 dimensional space) will form a valid flat plane. This means that if everything is broken into triangles, you don’t have to worry about invalid surfaces – everything can be assumed to be valid, and calculated as such (saving time and giving greater speed). Now, this is done not ONLY on your brushes; but on models too (i.e. entities like doors, monsters, other players, etc). I’ve already shown that different video modes print out different things – but basically what is done, is every triangle that is sent through to the video card and on to the screen is counted up by the program; and it is THAT number which you see.
Section 3, Compile tools
So, now the question you might be asking is “how does the computer know what it has to draw each frame?”. While the WHOLE answer to this goes beyond the scope of this article, I will at least cover the compile tools. Take for granted that the computer can calculate your field of view (left to right, usually about a 90 degree arc), as I won’t go into ray-casting or any other algorithms on 3d-rendering and perspective correction.
Now, you have your map in WorldCraft (or your editor of choice). What happens when you run the compile tools is this: The MAP file stores brush and entity coordinates in text format. The QCSG and QBSP tools convert this to a preliminary BSP (Binary Space Partition) file. A BSP file is sort of a “lookup table”, that organizes all of your level into a hierarchy tree structure. Think of it like a real tree – the “leaves” are your individual brushes or bits of brushes; which are grouped together by twigs and smaller branches. These small areas are grouped together into larger areas by bigger branches, etc, etc. This creates a defined structure that the computer can use to check and identify your position at all times. HOWEVER, while the computer may know your immediate surroundings from this data, it does NOT know what the user can and cannot SEE; remember that this is just a tree that tells the computer what objects can be grouped and how they’re connected. Also, note that the programs work to create a “balanced” tree – that is, they try to subdivide everything into two equal halves. The compile tools can do this even on SINGLE brushes – so in order to make an area divide equally in half, QCSG or QBSP may end up cutting your existing brushes into multiple smaller ones.
Enter the VIS compile step. VIS works with portals. Portals are a concept used to determine the borders of different areas within the map. While QBSP and QCSG are merrily cutting up your map into sections to make the BSP, they ALSO treat the “interior” of the map (or “airspace”) as if it was a set of brushes as well. It is chopped up into convex shapes (just like normal brushes having to be convex), based on what objects are in each area (this also explains why “leaks” stop VIS from running – if your map has a leak, the entire “void” outside the map would become one HUGE “air-brush”!). Along this line, there is one IMPORTANT NOTE you should always remember: QCSG/QBSP can ONLY break up these “air-brushes” along planes that are defined by your solid brushes in the map. Here’s an example:
You must keep this in mind; so that you will have an accurate picture in your head as to how the compile tools are breaking up your map. Think of your solid objects as if they were “carving” the air.
This brings us back to portals. Portals are the BORDER between two of these “air-space” brushes. Think of them as a flat plane with no volume (i.e. they have no depth/thickness). It also helps to think of them like a very very thin sheet of glass; but in the game they don’t stop the player’s movement. Getting back to VIS: it takes a portal, and tries (in a whole bunch of ways; but always in straight lines) to see what OTHER portals can be seen from that starting portal. Once it has finished doing that for ONE portal, it moves on to the next; and must do this for EVERY portal in the entire map (now you can see why VIS might take a long time in some cases)! The easiest way to picture how VIS is working, is to use the “longest lines of sight” method. This means that you can imagine what VIS is doing by thinking of it in terms of trying to position the “eyeball” of VIS in an area, in such a way that it can see as many portals (or as far away) as possible; again, this is always in a STRAIGHT LINE.
The key thing to remember, is that the VIS information is stored in such a way that if one area can see a particular portal, ALL of the polygons in that second area will be drawn! Therefore, if your portals are poorly defined, your areas will cause lots of extra polygons to be rendered; increasing the load and r_speeds, and decreasing the frame-rate (see previous note about breaking up space ONLY along existing planes – you can see now that if the best planes for a portal don’t exist in a map, you will get a very inefficient VIS; and lots of over-draw – because poorly-chosen portals will be created instead).
To go back to our last example, note that in the plain “2 rooms and a straight hallway” that ALL portals can be seen; therefore, the ENTIRE map gets drawn when the player is in either of the rooms. However, the “hallway with a turn in it” prevents any one room from “seeing” the other (VIS can’t draw a straight line from one room’s “entrance/exit portal” to the other’s); so when the player is in one room, only THAT room and the hallway sections will be drawn.
Now, before you start thinking that this is a bad way to handle things (since the hallways are still being drawn), remember that the computer can never know exactly where you’ll be moving or what you can see if you make small alterations in your position – so it will always over-draw a small amount; but once again, inefficient designs or areas that VIS poorly can lead to much slower game-play, due to higher r_speeds.
Section 4, Other Sources Of Slowing
Unfortunately, high polygon counts (i.e. high r_speeds) are NOT the only thing that can cause poor framerates. One other major offender is dynamic lighting. Normally, QRAD calculates the lights in a level, and writes a table (called a “lightmap”) into the BSP file. This tells the game how to alter the colors and intensities of the brushes and entities in the game; to make the level appear to be lit. Dynamic lights cannot be stored this way; and the area that they affect must be continuously re-calculated by the CPU – as well as requiring a different “screen” to be calculated for every frame, even if you’re standing still. This means extra processing power must be used to make a new frame; and of course frame-rate then suffers.
Another possible offender is transparencies. Any object with transparencies again costs “overhead”. The reason for this is that to GET the effect of transparency, the computer has to get the original object color (like light blue in the case of glass), and apply THAT value to the texture that’s “behind” it currently; and then come up with a blend between the two (depending on the amount of transparency). Since the texture “behind” can change based on your viewing angle, no pre-calculation can be done to lower this extra CPU usage. Once again, the result is a drop in framerate – and since this is based on the number of transparent pixels, the larger the area that HAS these pixels (i.e. the larger the transparent object), the worse the slowing will be.
Third, monsters, creatures, and any other entities will slow down things. Not only do their polygons on-screen add to the video card’s load; but processing their AI or actions also costs CPU power – so once again you must make your areas suit the purpose that they’re for. In other words, if you want to have an epic battle between tons of creatures, use a LOW-detail area where the brushes and “wpoly” counts are pretty small; as all of those entity polygons and animations are going to add up. Likewise, if there’s only going to be a mouse running around a room (and no combat is expected to take place here), then by all means garnish the area with some more detail (within reason of course).
The fourth and final source of slowing that I want to touch on, is invalid solids. Not all of these will cause your compile to crash – they will be squashed and re-formed and mangled and SOMEHOW worked into the BSP file. This can make for all sorts of weird and funky displayed surfaces; and cause all kinds of trouble that, while not being evident on screen as anything more than a mis-shapen brush, may cause your whole map to run slower! The solution to that is easy: Always run a “Check map for problems” from within WorldCraft BEFORE you compile each time!
Section 5, Making it Better…
Okay, so I’ve gone through all this new jargon and all these new things for you to be aware of. How are you supposed to take advantage of that knowledge and make better maps? Well, for one thing, you should obviously be more cautious and conscious of ANY place in which you put dynamic lights or transparent objects. Overall r_speeds can be kept down by limiting details, or lines of sight. This is easier said than done in a lot of cases; and will take lots of fiddling around to get to work if you didn’t think about this in your initial designs.
Once again, we can go back to our portals example and note that putting a 90-degree corner in the hallway prevents the “other” room from being drawn unnecessarily; which will lower the r_speeds. You can check on the overdraw in your compiled map yourself (provided you did a full VIS when you compiled the map); simply go into the game in SOFTWARE mode, and type in “r_draworder 1” at the console (“r_draworder” 0 turns it off). This will reverse the order in which items are drawn on-screen; so far away things are drawn last. It lets you see the “overdraw” due to the way your map was VIS’ed.
Any kind of “VIS-blocking” like this that you can fit into your designs without making the map awkward are good. Also note that elevation changes (like stairs and ramps and ladders) can help block VIS as well – remember, its all about straight lines of sight.
Part 6, Conclusion
All of these things should definitely be kept in mind for future maps. Now that you know them, try to work on incorporating them during the design phase of your next project. Your map will be that much better for it; and getting low scores at review sites for speed just MIGHT be a thing of the past for you! Remember that there will always be tweaking and refining to be done; but the effort will pay off, as more players will be able to enjoy your map. Special thanks goes out to “WhatIs”; as he was the first person (that I know) to actually decode the compile tools themselves, and help me understand their inner workings (which are unfortunately WAY beyond the scope of this article).
Lastly, here’s that R_Speeds chart (Remember that high entity-polygon counts may lower these recommendations!):
As always, feel free to ask if you have any questions or comments; and good luck mapping!