Inspecting the shaders of Rage
Rage, the game by ID Software and shooter legend John Carmack, is fun to play. But it’s even more fun to play around with it.
I already presented ways to inspect the mechanics of ID Tech 5’s Virtual Textures, or MegaTextures as they are also called. However, if you are really curious about how that works, you want to read the shader files that are used to address the MegaTexture.
As ID Tech 5 (the engine of Rage) is implemented in OpenGL 3.2, the shaders have to be uploaded as sourcecode to the driver, so there must be a way of getting your hand on them – but before you think of intercepting OpenGL calls and worry that the sources could be obfuscated let me tell you, that it’s much simpler: Rage has a command line option to dump the shaderfiles: Just add +set r_dumpGeneratedGLSL 1 to the command line and the files get dumped to your steam directory Steam\steamapps\common\rage\base\generated\glsl .
They were obviously generated from an internal format to write the shaders for glsl (PC), cg (PS3) and probably hlsl (XBox360) at the same time. This explains why there are always the same functions in all shader files which encapsulate texture access and some basic math functions – using those wrappers makes it easy to write code that converts trivially to multiple shader languages.
I won’t quote any shaders here as those are copyrighted but if you own a PC version of this game you can just dump your own set and take a look. Don’t be afraid of the 848 files, half of them are for cg and for each vertex shader there is exactly one fragment shader – no mixing of shaders. You’ll end up with 212 shader programs with a lot of redundancy in it – if you have two slightly different materials you’ll get two shader programs which share 99% of their code.
What’s interesting is that most of the outdoor environment is basically just a texture lookup (in a virtual texture with color space conversion and an optional fog) – all lighting is prebaked! Even the dynamic lighting of persons is quite simple and reminds me of the simple light model of Half-Life 2. You might also want to look at the animation in the vertex shader: it’s a nice read of how to squeeze as much payload as possible into very few variables.
Do you want to learn more? Ok. Grab a copy of glintercept and place the provided OpenGL32.dll in your rage folder together with the config file (see the provided documentation). With that you can dump all OpenGL calls that are used to render one frame. In earlier Rage versions you could also use this tool to modify all shaders during the game and see what happens. Sadly, this broke with one of the recent updates – I blame the uniform buffers as this only seems to happen for shader programs that use UBOs and glintercept probably does not query the uniform buffer binding points before relinking the shaders so they can’t find the buffers anymore. Note that this is so far just a guess and I didn’t have to time to verify and fix that. But if you do – or haven’t updated your steam in a while – you can poke around in the lighting or virtual texturing code etc. For example, not the whole environment has even normals! Vehicles and persons have them, but in the environment it’s mixed (with the outlands don’t have any):
Objects without normals are white, the other show world-space normals in RGB. Note that persons have very detailed normal maps as have the pipes. One of the trashbags has a normal map, the next one doesn’t – a sign of the tiny amount of memory on consoles and PC ports that have to live with the same assets…
With the possibility to manipulate individual effects you can see how big the visual influence of them is, for example billboards:
If we deactivate them (by setting the alpha to 0.0) the scene looks more ‘dull’, less animated (it’s even more obvious when the clouds move):
To see how much this stresses the ROPs let’s set the alpha to 1.0 and see all the generated fragments:
Or set the color to a nice solid red to see all the tiny bushes:
It also takes manipulations like these to visualize problems with these simple billboards: you can’t find a correct draw order if the quads intersect:
(click to enlarge).
I guess I have spent more time playing around with these things, the virtual texturing and looking at single framedumps from glintercept than playing the game itself – but never the less, it was fun, and that’s what games are about, right?