Texture compression

The engine uses zstd+bc7 compressed cubemap textures for faster processing in shaders and lower file sizes.

A nice primer on compressed textures: https://www.reedbeta.com/blog/understanding-bcn-texture-compression-formats/

Preparing

Get a package from https://github.com/KhronosGroup/KTX-Software/releases

You should get a bag of binaries named like ktx*, copy them to your ~/.local/bin.

Now you can convert and compress textures in one go by piping ktx create to ktx transcode.

Converting

If you have electricity/time to spare, throw in --uastc-quality 4 --uastc-rdo options.

Albedo maps / regular textures.

Those are typically srgb and should remain as that. Use bc7 codec.

ktx create \
  --encode uastc \
  --assign-tf srgb \
  --format R8G8B8A8_SRGB \
  --generate-mipmap \
  source.png \
  - | \
ktx transcode \
  --target bc7
  --zstd 22 \
  - \
  output.ktx2

Cubemaps

The key thing here is the file order in input.

ktx create \
  --encode uastc \
  --assign-tf srgb \
  --format R8G8B8_SRGB \
  --generate-mipmap \
  --cubemap \
  {right,left,top,bottom,front,back}.png \
  - | \
ktx transcode \
  --target bc7
  --zstd 22 \
  - \
  output.ktx2

For HDR maps you actually should use the bc6h codec, but it is rarely available.

Normals / linear textures

This one may need some fiddling. Depending on the original format and encoding you may have to convert it to a linear colorspace or not. Try different settings and see.

Using sRGB-encoded textures (get to linear space in the shader):

ktx create \
  --encode uastc \
  --assign-tf srgb \
  --generate-mipmap \
  --format-
  source.png \
  - | \
ktx transcode \
  --target bc7
  --zstd 22 \
  - \
  output.ktx2

Using linear-encoded texture (no conversion) and 2-channel maps (recover z in the shader):

ktx create \
  --encode uastc \
  --assign-tf srgb \
  --convert-tf linear \
  --format R8G8_UNORM \
  --normalize \
  --generate-mipmap \
  source.png \
  - | \
ktx transcode \
  --target bc5 \
  --zstd 22 \
  - \
  output.ktx2

Raw

You can skip compression altogether by transcoding into one of the r8 | rg8 | rgb8 | rgba8 formats.

You may wish to do so when:

  • Banding may appear if the image has a lots of smooth gradients.
  • GPU codecs operate on 2x2 blocks. It may turn out your image has an unlucky alignment resulting in massive loss of precision.
  • Compression codec may misinterpret data in semi-transparent images.
  • Using the tools results in a crash or something likewise bad and you won’t be bothered with that.
Links to this page