Megatextures in Rage
The shooter Rage by ID Software implements a technique known as Megatextures or Virtual Textures that basically mimics a MMU to handle textures larger than the graphics cards memory. The implementation scales from consoles to hi-end PCs and allows to use the same assets on all platforms – a huge plus for the artists. They also don’t have to think about the texture memory budget and where they can repeat a texture without the player noticing it. The whole game world can be textured in a unique way and the engine figures out at runtime which parts are needed and loads them into the GPU memory.
The book ‘GPU Pro: Advanced Rendering Techniques’ edited by Wolfgang Engel (known for the ShaderX books) features two articles covering Virtual Textures: ‘Virtual Texture Mapping 101’ by M. G. Chajdas et al. and ‘Accelerating Virtual Texturing using CUDA’ by C. Hollemeersch et al. The slides from a talk of J.M.P. van Waveren from ID gives a nice introduction into the implementation used in Rage. These slides also show screenshots of a debugging mode that show the texture tiles in the game engine. Luckily, these debug options were not removed in the final game, just hidden :-)
Using the games console, the following commands can be used to get a better impression of the technical side of the engine:
|vt_restart||Discards the old cache and starts rebuilding the texture cache. You can see the texture mipmap levels switching from coarse to fine levels during a few seconds.|
|vt_singleStep 0||Deactivates swapping in new tiles – if you move around now, you can see which mipmap levels were loaded for previously not rendered parts of the level.|
|vt_singleStep -1||Reactivates Virtual Texturing.|
|toggle vt_showPageNumbers; vt_restart||Adds tile borders and the tile number in each tile.|
|toggle vt_showPageMips; vt_restart||Visualizes the mipmap levels: Red are high-resolution tiles, green coarse levels.|
|toggle vt_showFeedbackStreaming||Shows which parts of the rendered image needs a higher resolution tile.|
|toggle vt_showFeedbackBuffer||Visualizes the feedback buffer used to calculate the missing tiles.|
As we can see here, in small indoor areas the best mipmap resolution (red) can be loaded and the persons have higher detailed textures than the environment:
Let’s look at a larger out-door scene: The skybox is not part of the virtual texturing but an additional static texture (the same is true for billboards of bushes and animations of explosions etc.). This animations shows three steps of the tile loading :
The feedback buffer for this scene shows for which parts of the image tiles in the desired mipmap level exist (green) and where the largest difference to the desired level and the cached level exist (purple):
Note that the buffer has a size of 160×120 pixels and thus does not have the aspect ratio of the screen. Finally, the feedback steam:
It’s also interesting to see which parts of the scene stay how long in the cache and which parts are swapped in even if the player never looked at the corresponding geometry. For this, restart the virtual texturing to flush the old cache and wait for the textures to get swapped in. Don’t move during that period to only request tiles for currently visible parts of the scene. Then turn the virtual texturing off and look around.
This is the starting position at which I first reloaded all virtual textures and that turned the updating of the texture off:
Note that the building on the right is half visible. Looking to the right, blurry textures get visible, but even as we never looked in that direction before, there are parts of the map preloaded:
The feedback buffer probably shows best which parts are preloaded.
If you have access to this game (the PC version has become cheap quite quickly) I can only recommend playing around with these commands. Also, a big thank you goes to ID Software for leaving these commands in the final game!
Here are some recordings of the debug commands in action:
Note that in second 22 I restarted the cache filling.
During the rotation at the beginning you can see how new tiles are loaded into the cache (on the left side).
This was done with ‘toggle vt_showPageColors; vt_restart’ which gives each tile a random color, so each tile update is clearly visible.