The high cost of drawing thousands of different objects, no matter how simple, is among the greatest problems of PC renderers today. The high cost of individual render calls is compounded by the high cost of render state changes between different objects. One of the worst offenders in this regard is the texture change. In a complex game scene, there might be thousands of objects on the screen, using hundreds of different textures – one or several for each distinct type of objects.
Texture atlases are large textures made up of many separate textures. Each object's texture uses only a portion of the atlas texture. The perfect atlases would be ones hand-created by artists, but this approach is very inflexible: it makes adding or removing new texture assets to the game much more expensive in terms of artist time than it is reasonable to be.
This article describes the workings of real-world system for automatically generating texture atlases, from the atlas creation tool to the engine integration issues. It has been successfully used in Haemimont Games' Glory of the Roman Empire (working title), a strategy/simulation title for the PC scheduled to ship in the first half of 2006.
Theory and Benefits of Texture Atlases
For the basic theory behind texture atlases, the reader is referred to an article called “Improved Batching via Texture Atlases”, available from NVIDIA's developer site. In a nutshell, all the textures needed by the game are combined in several large atlas textures. A coordinate remapping table is built and loaded in the engine, and it is used to scale and offset texture coordinates for each object to select the appropriate subregion into the atlas.
|A texture atlas with 100 unit, vegetation and decoration textures|
Texture atlases greatly reduce the importance of different object textures as a factor in batching and sorting the scene. Typical packing ratios vary between 16-256 textures in an atlas; this means you can have 16-256 times less texture state changes per frame.
If your renderer implements any kind of static batching of world geometry into pre-computed vertex buffers (grass and small vegetation being the most common example), texture atlases allow you to batch together objects of different types, under the (realistic) constraint that all object textures happen to be allocated in the same atlas.
Having fewer physical textures is also greatly beneficial for sorting – if you sort by texture atlas, not by original texture, you will get much larger spans of objects using identical atlases in your render queue, which allows you to get your sorting order closer to the optimal front-to-back sorting.
Finally, the runtime cost of atlases is negligible in most scenarios: a 2D multiply-add operation per texture coordinate set in the vertex shader (which is rarely the bottleneck in real-world applications) and a float4 vertex shader constant register. In addition, there might be a small percentage of wasted texture space due to the packing – for example, if the textures don't completely fill the last atlas – which can be minimized by careful tweaking of the texture resolutions.