Leave a comment

Terrain texture atlas construction

This post will go over more details about the construction of the texture atlas mentioned in this post, for which I am using an XNA content pipeline extension. There are some subtleties that bear mentioning.

First, we’ll assume we’re creating a 4 x 4 atlas of 512 x 512 textures, such as this one:

Terrain texture atlas

I have these defined in an XML file as external texture file references which get loaded and “processed” into the final atlas.

The first trick is maximizing the usable resolution of the atlas. We unfortunately can’t get our entire 512 x 512 worth. Here are some constraints:

  • the sub-textures are intended to wrap when rendered in the game
  • for performance and visual reasons we need mipmaps

Since the sub-textures are intended to wrap, we need at least a 1 pixel gutter surrounding each one. Since the shader will be sampling from 2 mipmaps using the same texture coordinates, it stands to reason that the gutter will need to be “relatively” the same size at each mip level (gutter shown in red below). Otherwise, we would get noticeable blurring when the GPU blends between mipmaps.

Mipmap gutters

We need at least a 1 pixel gutter at any mip level. This means at small mip levels the gutter will dominate the texture. A 2 x 2 image will still need a 1 pixel gutter. Working back up, this means the top level 512 x 512 mip level will consist of 256 x256 of usable data surrounded by a 128 pixel gutter. We’ve lost most of our usable resolution!

To address this, my atlas generator lets you specify the maximum number of mip levels for which you want an “accurate” representation of the textures. For instance, if it is 5, then we need a 1 pixel gutter for the 32 x 32 image (the smallest of (512, 256, 128, 64, 32)). Extrapolating back up, this means a 16 pixel gutter at 512 x 512, resulting in an effective 480 X 480 sub-texture:

Minimal gutter

The next step for each sub-texture is to scale it from its original size (512 x 512) to size it will occupy inside its gutter (480 x 480):

Shrink

Once this is done, we can begin filling in the (512 x 512) space it will occupy in the atlas. We copy the (480 x 480) center area. Follwing that we can copy over the 8 remaining edges and corners from opposite sides of the original. These form the gutter of the final sub-texture. A picture with some of these edges color-coded is best at explaining (apologies to the colorblind):

Copy

Seen at its resting place in the atlas:

Atlas2

Another thing to note is that you should not generate atlas mipmaps from top level of the atlas itself since this will re-introduce texture bleeding. Instead, each mip level needs to be generated from scratch using scaled down versions of the original images (with according changes to gutter size, etc…).

There is one final subtle detail. In the step where we scale the original image from (512 x 512) to (480 x 480) we actually introduce some artifacts at the edges. The scaling code I’m using isn’t aware that this texture is intended for wrapping. The result is that the pixel on the far left won’t include any information from its “neighbor” on the extreme right of the image – but it needs to since this represents the gutter/texture boundary which we’ll be sampling from in-game. The inaccuracy tends to be subtle, but you may notice that something “intangible” looks wrong – a barely visible seam where the texture wraps.

The “lazy” solution here is to make a temporary texture that is a (3 x 3) grid of the original texture (so (1536 x 1536)), and scale that down to the gutterized size (1440 x 1440), and then copy data out of the (480 x 480) center of the (1440 x 1440) downsize. The edges pixels will then have been properly filtered along with their neighbors on the “opposite” side of the texture:

Three

This last step does  increase compile time (where the content is processed) a fair amount since we’re moving so much data around. But the result is worth it if you’re into perfection.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Space Quest Historian

Adventure game blogs, Let's Plays, live streams, and more

Harebrained Schemes

Developer's blog for IceFall Games

kosmonaut's blog

3d GFX and more

Halogenica

Turn up the rez!

bitsquid: development blog

Developer's blog for IceFall Games

Game Development by Sean

Developer's blog for IceFall Games

Lost Garden

Developer's blog for IceFall Games

Memories

Developer's blog for IceFall Games

Casey's Blog

Developer's blog for IceFall Games

Blog

Developer's blog for IceFall Games

Rendering Evolution

Developer's blog for IceFall Games

Simon schreibt.

Developer's blog for IceFall Games

Dev & Techno-phage

Do Computers Dream of Electric Developper?

- Woolfe -

Developer's blog for IceFall Games

Ferrara Fabio

Game & Application Developer, 3D Animator, Composer.

Clone of Duty: Stonehenge

First Person Shooter coming soon to the XBOX 360

Low Tide Productions

Games and other artsy stuff...

BadCorporateLogo

Just another WordPress.com site

Sipty's Writing

Take a look inside the mind of a game developer.

Jonas Kyratzes

Writer, game designer, filmmaker.

%d bloggers like this: