Introduction
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.