Archive | Maj 2016

Runtime texture atlas generation

Texture atlas – what is it

Texture atlas is a image containing collections of sub-images. Each of these sub-images representing a texture.

Application can use multiple texture atlases.

Why

Rendering a texture require setting it as active. This operation is time consuming. Since atlas is a single texture containing many of different sub-textures, active texture switches are much rarer. Renderer use region of texture atlas to render concrete texture.

Reducing OpenGL state changes, can give significant performance gains.

Runtime texture atlas generation

Texture atlas can be pre-generated. There are many tools to do it. Usually tool generates also some meta-data file containing coordinates of each sub-texture inside atlas.

Texture atlas can also be generated runtime. Images representing a texture are copied into single large, in-memory image.

Pros of runtime generation

Simplified development process

Images can be added to project (or resource file) immediately. In case of pre-generated texture atlas, image has to be merged in to atlas each time artist submit one.

Image size

Texture size has to be equal to power of two. If not, render process may suffer performance hit. Some OpenGL implementation do not load image at all. Image placed in texture atlas can be any size (Smaller then atlas size).

Optimizations

There are hundreds of different devices. Some of them differ in screen resolution, maximum texture size, etc. Building texture atlas during runtime gives opportunity to optimize textures. On low-end devices, that do not use high-resolution textures, images can be down-sized. So textures would better suited for the particular machine.

Size of texture atlas can be adapted for the machine. OpenGL function glGetIntegerv(GL_MAX_TEXTURE_SIZE …) returns maximum size of the texture. Value can be used to set atlas dimension.

Cons

Creation takes time

Obviously all images merged into texture has to be loaded into memory, and printed into single large one. Additional image resizing also takes extra time.

Implementation description

Runtime texture atlas generation process consists of two phases: * Calculating placement of each sub-texture. * „Painting” sub-textures on atlas texture.

In this post, I will describe only first phase.

Canvas

Texture atlas texture must have dimensions. These values can be based on machine’s GL_MAX_TEXTURE_SIZE. The safest are 1024×1024. All devices should support these.

The canvas on which sub-textures are going to be placed is represented by rectangle:

{ x= 0, y = 0, width = 1024, hight = 1024}

Lets define a list, collection or whatever, which will contain rectangles of free space on canvas. Initially collection will contain single rectangle. The one describing whole canvas.

Divide and conquer

The canvas is just a big rectangle. Image which is going to be added to atlas is smaller rectangle. Smaller subtracted from bigger give surface that can be described as two rectangles:
img1
Sub-texture (green background) was added. Space left (blue rectangle, and red rectangle).

Now. The collections of canvas free space has to be changed. Rectangle which represents whole canvas has to be removed. And two new rectangles has to be add.

Sub-texture coordinates has to be stored somewhere.

Lets add another sub-texture (black background).

img3

Another two rectangles representing free space ware created (orange and white background)

Horizontal or vertical

Surface after subtraction can be divided in two ways. Horizontal or vertical.

img2

Choose one better suited for your textures.

Algorithm

As you may figure it out. Algorithm is quite simple:

  • Get your sub-texture’s dimensions.
  • Find free rectangle that fits sub-texture dimensions.
  • Subtract sub-textures’s dimensions from found rectangle. The result of the subtraction will be two rectangles
  • Store sub-texture coordinates (rectangle) in separate collection.
  • Remove found rectangle from list.
  • Add two new rectangles (result of subtraction) to list.
  • If image does not fit into texture atlas, generate new texture atlas
  • Repeat for each sub-texture

Matching

Whole process of finding fitting rectangle can be optimized by sorting the list.

Padding

Leave at least 1 pixel space between sub-textures. OpenGL does not work based on pixels, but on normalized values. That means some inaccuracies may be added, and „leaks” between textures can be visible.

Coordinates

The result of atlas generation process, should be list of rectangles – coordinates of each sub-texture. The list has to be transformed in to OpenGL texture coordinates list.

Result

example

Tips

  • Coordinate systems can be different. OpenGL’s {0,0} point lays in left, bottom corner. Qt for example, using top left.
  • Sub-texture itself can be atlas (Inception?). For example texture containing font glyphs. sub-sub-texture coordinates has to recalculated.
Reklamy