The idea behind the atlasgen tool is to keep all raw and uncompressed textures in a working directory with a free directory layout. The textures are then divided into different sets (this could be a plain set, or a set that will be placed in an atlas) with a certain conversion rule. For example, a texture set could be "all diffuse asphalt textures on level 5". These textures are placed in a set with a format set to DXT5 compressed DDS.
The atlasgen tools takes the raw textures, applies the conversion rule and outputs either a converted set or a baked atlas in a directory structure that can be read by the texture database.
Here is a quick sample of using the atlasgen tool. Create a file my_atlas.xml:
<texture_node name="example" file_format="dds"> <atlas name="atlas" texel_format="AF_DXT5" width="2048" height="2048"> <image name="texture1"/> <image name="texture2"/> <image name="texture3"/> </atlas> </texture_node>
Create three textures named texture1/2/3.tga (several different texture formats are valid, for example dds and bmp) in c:/my/raw/textures which can be contained by a 2048x2048 atlas.
Run this commandline:
atlasgen c:/my/raw/textures my_atlas.xml c:/path/to/game/data/textures
This will produce an atlas in example/atlas relative to the games texture directory containing the three textures texture1, 2 and 3.
The atlasgen tool is invoked from the commandline and takes three arguments; the textures root, a texture set definition xml file and an output root. The textures root is the directory containing all source textures that are referenced by the texture set definition xml. The texture set definition xml is a file specifying what textures should be placed in the atlas and in which order, or simply a grouping of textures. The directory set as textures root should not contain several textures with the same name in its subtree since textures are referenced by name only. The tool will produce a number of texture sets/atlases from the texture set definition to the output root (this is typically the directory set as base for the texture database).
Example:
atlasgen c:/my/raw/textures texture_tree.xml c:/path/to/game/data/textures
Syntax:
The texture database is used for loading and managing textures.
The script must explicitly tell the texture database which texture sets it is allowed to load from by loading one or several scope xml definitions:
<scope> <texture_set name="sets/level5/diffuse_asphalt" /> <texture_set ... /> </scope
The scopes are loaded by calling the texture database load function:
Application.add_to_dynamic_texture_scope( "/data/levels/level5/texture_scope.xml" );
All loaded scopes are unloaded by calling the texture database unload function:
Application.unload_dynamic_texture_scopes();
Texture sets may also be addressed recursively:
<texture_set name="sets/level5" />
This will load all sets below level 5.
The context parameter "enforce_texture_sets" (set by default) determines if the texture database should allow texture references outside scoped sets. If this flag is set to false, texture sets will be loaded automatically if a texture is found in a set in the database. Note that for textures present in several sets one of these sets will be loaded at random.
The xml file supplied to the tool can either be a texture set definition or an atlas set definition, or both placed in a tree of texture nodes. A texture set is a group of textures with a common conversion rule, but which will not be placed in an atlas. An atlas set is a group of textures that will be placed in an atlas. Texture nodes have the union of all atlas and texture set definition parameters and can be used to recursively inherit options for texture sets and atlases - if a parameter is not specified, the value set by the parent node is used:
<texture_node name="any_name"> <texture_node name="bump" texel_format="AF_BUMP_A8L8"> <atlas name="atlas" ... > <texture_set name="texset" ... > </texture_node> <texture_node name="diffuse" texel_format="AF_DXT5"> <atlas name="atlas" ... > <texture_set name="texset" ... > </texture_node> </texture_node>
Texture nodes are used to group several atlases or texture sets that share common settings. The texture database name of a texture set or atlas will be the concatenated name of the set and all its parents. The example above would yield the sets "any_name/bump/atlas", "any_name/bump/texset", "diffuse/atlas" etc.
Below texture sets/atlases a number of image tags are placed that determine which textures should be members of the set:
<texture_set name="texset"> <image name="asphalt" /> </texture_set>
These parameters apply to both atlases and texture sets:
- name (required) - the name of the set/group
- category - category of texture - "vehicle", "building" etc. Used for determining what mips to drop on lower texture quality levels.
- file_format - file format of output file(s), "dds", "png" or "bmp" are valid values
- texel_format - format of output image data:
- AF_A8R8G8B8 - uncompressed
- AF_DXT1, AF_DXT3, AF_DXT5 - S3TC compressed
- AF_BUMP_A8L8 - compressed bumpmap, red will be placed in alpha, green in luminance
- AF_BUMP_DXT5 - compressed bumpmap, red will be placed in alpha, red and blue are zeroed
- mip_filter - filter used for generating mips, see section on mip_filtering for details
- nr_mips - 0 means generate all mips, other number clamps the number of mips
- drop_mips - removes this number of mips from the top of all input textures; for an atlas also drops the output resolution
- allow_autoload - if set to false, this set will not be loaded by the texture database even if enforce_texture_sets is set to false, but it will be loaded if override_allow_autoload is set to true.
- textures_root, textures_root1, ... - specifies that atlasgen should look for textures in the roots commandline_root/parent_roots/textures_root (and maybe commandline_root/parent_roots/textures_rootX etc). Typically this parameter is used to speed up indexing.
These parameters apply only to atlases:
- width, height - max atlas resolution
- halftexel_offsets - determines what inset to calculate UV offset/scale values with - values are "false", "true", "onetexel_offsets", "twotexel_offsets", "threetexel_offsets"
- pad_texels_u, pad_texels_v - dilates edge texels of all atlased textures by this amount, can be used to decrease color bleeding.
- autofill - if set, atlas or set will be populated with all textures found below commandline_root/autofill. Setting this parameter also forces autosplit to true.
- autosplit - if set, atlas will packed and splitted automatically rather than in the image specification order - read the section on atlas_packing for details on this and packing parameters.
These parameters apply to image tags below both atlases and texture sets:
- name - name of source texture, will also be used as name for texture in set by default
- mip_filter - filter to use for generating mips, see section on mip_filtering
- rename_to - if set, this name will be used as name of texture in set
- width, height - resize image to this dimension - dimensions must be those of a mip level for the image
These parameters apply to image tags below atlases only:
- pad_texels_u, pad_texels_v - overrides the texel padding set by the atlas
- rotation - rotation of texture in atlas, 0, 90, 180 or 270 degrees
- halftexel_offsets - overrides the offset rule set by the atlas
- used_by - one or more numbers separated by space signifying texture membership of different groups; used by autopacking to maintain group coherence
Atlases can either be constructed by manual packing, or by automated packing and splitting. Manual packing gives the atlas designer full control over which textures are placed next to each other, how they are oriented and atlas area usage. Automated packing creates one or more atlases using certain heuristics. Manual packing is typically used for constructing atlases with a fixed set of source textures, and automated packing is typically used for packing generated textures such as lightmaps. If any of the autosplit or autofill parameters are set, automatic packing and splitting will be invoked.
The textures are inserted in the atlas in the order in which they are specified in the xml file.
Each texture will be inserted in first left-to-right, then top-to-bottom order.
The width and height parameters specifies the maximum width and height of the atlas; if this area is not fully covered by the specified image tags it will be shrunk to the lowest power of 2 containing the images.
If a texture is x-tiling (the string "_x_" is somewhere in the texture name), the texture will be stretched to cover an entire row before insertion. The same applies to y-tiling textures; they will be stretched to cover an entire column. This means that there can never be both x-and y-tiling textures in the same atlas.
Textures can be rotated 90, 180 and 270 degrees clockwise by specifiying the rotation parameter of the image tag. An x- or y-tiling texture rotated 90 or 270 degrees will switch tiling direction.
If a texture cannot be fitted into the atlas using these rules, an error will be raised.
Example: This is an empty atlas (. denotes empty space) with a max width and height of 8:
........ ........ ........ ........ ........ ........ ........ ........
Inserting a 2x2 texture (denoted by x) will yield this atlas:
xx...... xx...... ........ ........ ........ ........ ........ ........
After insert of a 4x1 texture:
xxxxxx.. xx...... ........ ........ ........ ........ ........ ........
After insert of a 4x2 texture:
xxxxxx.. xxxxxx.. ..xxxx.. ........ ........ ........ ........ ........
After insert of a 4x1 x-tiling texture:
xxxxxx.. xxxxxx.. ..xxxx.. xxxxxxxx -- stretched to cover entire width ........ ........ ........ ........
If no more image tags are specified, this will happen before the atlas is generated:
The width of all tiling textures will be adjusted to the maximum width used by the atlas:
xxxxxx.. xxxxxx.. ..xxxx.. xxxxxx.. ........ ........ ........ ........
(The 4x1 x-tiling texture is stretched to 6x1)
The atlas will be shrunk to the lowest possible power of 2 (in this case a height of 4):
xxxxxx.. xxxxxx.. ..xxxx.. xxxxxx..
All tiling textures will be stretched to the width/height of the atlas:
xxxxxx.. xxxxxx.. ..xxxx.. xxxxxxxx
Tiling textures can be placed in the same atlas as non-tiling textures.
Tiling textures will be stretched to the width/height of the atlas, hence atlases containing tiling textures should have a max height/width corresponding to the largest tiling texture.
Since all stretched tiling textures means wasted space, tiling textures of the same dimension should be placed in the same atlas.
Color bleeding is noticeable when two textures with dissimilar border texels are placed next to each other. The rotation parameter can be used to rotate textures so that neighbouring texels are close in color.
Padding breaks the power-of-two structure in the atlas and makes it harder to pack atlases with 100% used space, but can be useful in special cases to prevent color bleeding. For instance, two 256x2 x-tiling textures of different color can be padded with one texel in the y-direction while still preserving power-of-two height.
Rotation can be used to make y-tiling textures x-tiling.
If a texture is placed in an atlas, the entire atlas will be loaded into texture memory when the texture is referenced. This means that any other texture in the atlas which is not referenced is a waste of memory.
Render atom splits occur when a texture switch is required in any channel. If a bump texture is used with several different diffuse textures, the different diffuse textures should be placed together in one atlas to avoid splits.
If automatic atlas packing is invoked, the tool will take all textures in the set and try to produce one or more atlases with as good usage as possible. Finding the optimal layout of textures within the atlas is a hard problem, and so the tool uses different heuristics to pack the atlas in a reasonable time. The heuristics can be customized using these parameters for the atlas:
- autopacking_template - this parameter sets good values for the other parameters, and should always be used unless there are special circumstances. Available templates are lightmaps, mission_specific, silhouettes.
- min_usage - required minimal usage quota for an atlas (0.0 - 1.0) - if an atlas does not reach the minimum usage, the atlas is split. Set to high if memory footprint of generated output should be as low as possible.
- preecook_strat - if set, all textures will be rotated prior to insertion so that one axis is as large as possible. Values are NO_PRECOOKING, MAJOR_UDIM, MAJOR_VDIM.
- packing_order_strat - inserts textures in this order. Values are:
- BY_PRECOOK - means either DESC_UDIM_ASC_VDIM or DESC_VDIM_ASC_UDIM based on how textures were precooked.
- DESC_DIM - textures are inserted in descending dimension (ie. width*height)
- DESC_UDIM_ASC_VDIM - textures are inserted in descending u-dimension, ascending v-dimension
- DESC_VDIM_ASC_UDIM - textures are inserted in descending v-dimension, ascending u-dimension
- insertion_strat - a single texture will be inserted left-to-right, top-to-bottom using this strategy:
- PIXEL_STEP - Stepping by pixels
- PIXEL_STEP_EXPANDING_SQUARE - Stepping by pixels, expanding square insertion area
- SMALL_STEP - Stepping by dimensions of smallest texture in atlas
- SMALL_STEP_EXPANDING_SQUARE - Stepping by dimensions of smallest texture in atlas, expanding square insertion area
- removal_strat0, removal_strat1, ... - if a set of textures does not fit into the atlas, this will be the strategy for which texture to remove from set. The TILING removal strategy may not find a texture to remove, in which case the next strategy listed will be used. Removal strategies:
- FURTHEST - requires a positions.xml file with texture center point vectors to be present, will remove texture with longest distance to AABB corner. Used for packing lightmaps where spatial coherence is important.
- BIGGEST - removes texture with biggest dimension
- SMALLEST - removes texture with smallest dimension
- TILING - removes biggest tiling texture
- SMALLEST_FROM_SMALLEST_GROUP - actually removes biggest texture from the smallest group of textures (groups are assigned to textures with the used_by parameter). This is used to minimize splits inside groups of textures.
- try_alt_insertion - if set, a different insertion strategy will be tried in case of atlas construction failure (due to insufficient usage or insertion failure)
- try_rotate - if set, textures will be rotated and reinserted on insertion failure
- rebalancing_interval - insertion tree will be rebalanced every rebalancing_interval successful insert. Used for performance tuning.
A good idea if hand-tuning of heuristics is required is to use the -draft flag for faster atlas output.
Several different filters are available for creating the downsampled mips:
BOX_GAMMA produces mips by averaging quadrants of the original image in linear color space. The filter never distorts mips, but does not preserve as much detail as KAISER_GAMMA. Use for high-frequency textures.
KEEP simply uses the existing mip-levels of the source texture (if no mip-levels exist the default mipmap filtering is used). Use this option if hand-edited mips must be used (such as alpha-masked textures).
KAISER_GAMMA uses a Kaiser filter in linear color space and should produce the highest-quality mip maps with least color-loss and most preservation of detail. The filter has problems with high-frequency textures, use BOX_GAMMA for these.
KAISER_GAMMA_CRISP is the same as KAISER_GAMMA but with a higher filter sharpness, producing less smooth mips. This filter is intended for filtering of bumpmaps where the increased grain is less noticeable and preservation of contrast is desirable.
BOX works like BOX_GAMMA but in ramped color space.
NEAREST_NEIGHBOUR samples one pixel of each quadrant.
BILINEAR, BSPLINE, BICUBIC and CATMULLROM are generic catch-all filters.
CATMULLROM_SHARPEN/PRESHARPEN/PRESHARPEN_HARD performs Catmull-Rom downsampling with a sharpness convolution filter applied prior to or after downsampling. This filter produces somewhat distorted mips and should be reserved for bumpmaps where very high contrast at lower miplevels is required.