文档章节

Practical Texture Atlases

小熊猫大暴走
 小熊猫大暴走
发布于 2011/12/17 23:47
字数 2136
阅读 127
收藏 0

Practical Texture Atlases

By Ivan-Assen Ivanov

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.

Atlas Creation Tool

The texture atlas tool in our art pipeline uses NVIDIA's atlas creation tool and texture compression tool (NVDXT) to perform all of the actual packing and compression of textures. NVDXT is the gold standard of texture compression, and the NVIDIA atlas creation tool, while not perfect (e.g. it doesn't handle correctly non-square textures), is quite useable. Replacing one or both of them with different tools using a similar interface would be easy.

Our tool takes as its input a directory tree of unpacked art assets and a configuration file (see Listing 1). It produces an atlas set: a number of compressed DDS textures and a remapping table binding original texture filenames to atlas filenames plus remapping coordinates.

The tool uses wildcards (regular expressions, actually) and NVDXT parameters as a general mechanism to sort images and specify how each image is to be processed. Each input texture filename is matched against several groups of regular expressions, which have associated NVDXT parameter sets. Within the group, the first matching regular expression for the filename is taken and its corresponding parameters are added to the NVDXT command line for this file; no more matches are attempted for this group, and the process continues with the next group of expressions.


[Global]
; use Kaiser filtering for all files
CommonNvdxtOptions = -Kaiser –RescaleKaiser 
OutputSet = HighTextureDetail

[Group1]
; regular expressions are tested top to bottom,
; so special rules must come before general rules

; special-case large buildings
Buildings/Coliseum.diffuse.tga = -prescale 1024 1024
Buildings/Townhall.diffuse.tga = -prescale 1024 1024
; default all other buildings to 512x512 for diffuse textures
Buildings/*.diffuse.tga = -prescale 512 512 
; ambient occlusion lightmaps can be coarser
Buildings/*.ao.tga = -prescale 256 256

; special-case small units
Units/Dog.diffuse.tga = -prescale 64 64
; default all units to 128x128
Units/*.diffuse.tga = -prescale 128 128

; default size for any other textures
* = -prescale 256 256

[Group2]
; use this group to specify pixel formats, orthogonal to sizes
*.diffuse.tga = -dxt1c
*.ao.tga = -L8
; everything else is also compressed
* = -dxt5

[Families]
; pack vegetation and particles textures in their separate atlases
Vegetation/* = 1
Particles/* = 2
; everything not matched here defaults to family 0 

Listing 1 - A sample configuration file for the atlas creation tool

One group is used to specify texture sizes by the filename prefix (e.g. /Buildings/* is resized to 512x512, but as an exception /Buildings/Coliseum/* is resized to 1024x1024), and another to specify pixel formats (e.g. *.diffuse.tga gets compressed to DXT5, and *.lightmap.tga gets compressed to L8, where the “diffuse” and “lightmap” suffixes, along with several others, are set by the art package exporter). An additional group of regular expression masks is used to assign a “family ID” to each texture, which is a way to force grouping of textures into the same atlas for specific purposes – e.g. all particle textures to be rendered separately via the particle system renderer, or all textures of vegetation objects to be used in building static vegetation batches.

After the desired compression settings for each input texture - size, pixel format and others, expressed as NVDXT command-line parameters – are determined by the described procedure, a texture compression cache is looked up using an MD5 hash of the file contents and the compression settings as a key. The cache is preserved across builds. It has two purposes: first, reusing the same file from a previous build avoids the expensive compression procedure.

Second, finding the same texture elsewhere in the current build, compressed exactly with the same settings, results in writing only an alias to its previous occurrence in the atlas remapping table, sparing precious texture memory in the relatively frequent case of artists using the same texture for several objects. Finally, if the cache lookup fails, NVDXT is invoked and its result is stored in the cache for future use.

After all input textures are in the desired compressed and resized form, they are split into groups by pixel format and family. Each group of files with the same pixel format and family is fed to NVIDIA's AtlasCreationTool. Its output is parsed and integrated into a single remapping table for all pixel formats and families.

During the build process, the atlas creation tool is run three times over the same folder tree with original art assets, but with different configuration files, to produce different atlas set for the three texture quality levels used by the game depending on the hardware capabilities and the settings chosen by the user. The configuration files differ by destination texture sizes and pixel formats. The exact texture sizes are produced with the help of a huge Excel table listing every object in the game, the world-space size of its mesh, and texture dimensions and pixel formats for low/medium/high detail. The table estimates the total required texture memory for each detail level; our target was 64 MB cards for low detail textures, correspondingly 128 for medium and 256 for high.

Thanks to the compression cache, the typical atlas creation portion of the build procedure takes on the order of 2-3 minutes, although rebuilding this cache from scratch can take considerably more.

Renderer Integration

Integrating the texture atlases in the renderer is a relatively isolated change, affecting the code in three places: the texture manager, the shaders and the render queue.

First, the texture manager used for loading textures by filename receives the additional responsibility of loading the atlas set with all its atlases and the remapping table. The internal representation of a loaded texture, which in the absence of atlases is just a device-specific texture pointer, becomes a structure with a texture pointer to the atlas holding the actual texture plus two pairs of texture remapping coordinates: one for scale and one for offset. For textures which are not in atlases, this is reduced to an identity remapping, zero offset and unit scaling, to allow them to be used with the same shaders. Whenever a “logical” texture has to be loaded into a texture sampler, the atlas-enabled texture manager actually loads the “physical” texture (the atlas) into the sampler, and these remapping coordinates into a reserved vertex shader constant register associated with the sampler.

The second modification is in the vertex shaders. For each set of texture coordinates a simple remapping function should be called to scale and offset them with the remapping constants for the appropriate sampler.

With these two changes the introduction of atlases remains completely transparent to the rest of the system. The basic operations with textures remain the same as without atlases: load texture by filename, and assign loaded texture to sampler. The actual benefits of texture atlases are reaped in the third integration point, where this transparency must be broken.

The render queue – that part of the renderer which has the responsibility of gathering all render objects for the current frame and to sort them, attempting to achieve both a minimal number of render state changes and a good front-to-back order – needs to query the texture manager for some form of “physical” atlas ID of each “logical” texture, and sort by these IDs. In the comparison function used for sorting, the atlas ID comparison should come after object material (as shader changes are more expensive than texture changes) and before distance to camera (so that groups of objects with the same shader and atlas are drawn front to back).

In practice, the atlas-enabled texture manager has two additional features. One of them is support for the different texture detail levels described in the previous section, which becomes simply a matter of loading a new atlas set. The other feature is support for textures not packed in the atlases, which is useful during development. On each load request, the texture manager first checks to see if the requested filename exists on disk; if it is found, it is loaded directly and the atlas set is ignored. This enables artists to quickly preview new versions of specific textures, without either going through the relatively slow atlas build procedure or working with a slower build without atlases.

Downsides of Texture Atlases

Texture atlases are not a panacea for all of the numerous problems around textures and their management, and they come with their own set of problems. For example, texture tiling is impossible, and all texture coordinates should fall within the unit square (0,0) – (1,1); this requires some retraining for artists who are used to the “free” wrapping of textures, but ultimately is not a problem for texturing meshes.

Another potential issue mentioned in the original NVIDIA whitepaper on atlases, the color bleeding between adjacent textures in the atlas at high mipmaps levels, was never observed by us in practice, but could probably happen with another set of art assets. It could be reduced by a more complex procedure of ordering textures within the atlas, using the average color of each texture to group together similar textures.

The greatest problem with the described static texture atlases is that they don't easily combine with any kind of asset streaming, or on-demand loading with fine granularity. For our particular project we had the requirement of fitting all the assets in memory all the time, because it is relatively common to have virtually all the art on-screen, making atlases a natural fit. If you need streaming, however, atlases should be built with that in mind, grouping together textures that will likely be loaded together, e.g. a farm house with all its possible yard animals, or a number of similar vegetation objects. The optimal batches could be calculated by a tool examining the structure of the levels on each build. The benefits of atlases in this case should be carefully weighted against the overhead of potentially loading unneeded texels.

_____________________________________________________

 

Return to the full version of this article with comments
Copyright � 2010 UBM Techweb

本文转载自:http://www.gamasutra.com/view/feature/2530/practical_texture_atlases.php

上一篇: QT 源码
小熊猫大暴走

小熊猫大暴走

粉丝 42
博文 276
码字总数 267492
作品 0
海淀
程序员
私信 提问
How I built a wind map with WebGL

Check out my WebGL-based wind power simulation demo! Let’s dive into how it works under the hood. I have an unflattering confession to make: for the last few years working at M......

voole
2018/06/21
111
0
opengl glGenerateMipmap函数生成的mipmap出错

各位大神,我自己生成了一个256*256的图像数据, 使用了glGenerateMipmap函数,然后使用glGetTexImage函数来读取mipmap第二层的数据,本来应该读出来的是64*64的图像数据,但为啥读出来是128...

sparklearner
2016/05/17
699
0
OpenGL多重纹理使用与理解

1.glActiveTextureARB的Active不能理解为激活,使发生作用!!! 应理解为选择(Select)某纹理单元 (Texture Unit),即表示后续的glEnable(GLTEXTURE2D);glBindTexture(GLTEXTURE2D, texture);作用...

小熊猫大暴走
2013/02/16
158
0
qml中opengl渲染yuv视频时,界面上的字体全变黑,按钮也不能用了,全部变黑。貌似被多重绘制

glViewport(x,y,width,height); //glEnable(GL_BLEND); //glEnable(GL_TEXTURE_2D); glClearDepth(1.0f); // glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glClear(GL_COLOR_BUFFER_B......

hequnshan
2017/03/22
547
0
显示小地图

原理是吧摄像机 拍摄到的内容 设置到 Renderer Texture 可归为3步 1.新建一个 Renderer Texture 2.目标摄像机的 Target Texture 设置为1 所新建的 Texture 3.新建一个Raw Image 纹理设置为 ...

梦想游戏人
2016/04/28
44
0

没有更多内容

加载失败,请刷新页面

加载更多

CSS--列表

一、列表标识项 list-style-type none:去掉标识项 disc:默认实心圆 circle:空心圆 squire:矩形 二、列表项图片 list-style-img: 取值:url(路径) 三、列表项位置 list-style-position:...

wytao1995
今天
4
0
linux 命令-文本比较comm、diff、patch

本文原创首发于公众号:编程三分钟 今天学了三个文本比较的命令分享给大家。 comm comm 命令比较相同的文本 $ cat charabc$ cat chardiffadc 比如,我有两个文件char和chardiff如上,...

编程三分钟
今天
7
0
QML教程

https://blog.csdn.net/qq_40194498/article/category/7580030 https://blog.csdn.net/LaineGates/article/details/50887765...

shzwork
今天
5
0
HA Cluster之5

对于使用heartbeat v2版的CRM配置的集群信息都是保存在一个名为cib.xml的配置文件中,存放在/var/lib/heartbeat/crm/下。CIB:Cluster Information Base,由于xml文件配置不是那么方便,所以...

lhdzw
今天
6
0
玩转Redis-Redis基础数据结构及核心命令

  《玩转Redis》系列文章主要讲述Redis的基础及中高级应用,文章基于Redis5.0.4+。本文主要讲述Redis的数据结构String,《玩转Redis-Redis基础数据结构及核心命令》相关操作命令为方便对比...

zxiaofan666
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部