Guide: Texture Optimisation - Channel Packing

  1. Basic info: Why?

As You might know regular color image is in fact made of 3 separate grayscale images that correspond to one of three colors Red, Green, Blue. That are displayed on top of each other to give human eye illusion of color. Each grayscale image is called channel.


Additional there is fourth channel - Alpha that corresponds to image’s opacity/transparency.

This is how basically images on computers work and how image formats, monitors and GPUs are designed to support. Everyone that do computer graphics should know that.

But in 3d just color information is not enough and we have many more different types of data saved as bitmaps
eg: Specular color, normal map, roughnes, specular f0, ior, heigh, bump, etc.

unpacked setup:


Easiest way of making material from textures is to load and connect them where they are needed.
But there is slight problem with that.

In EEVEE every opened texture is loaded as uncompressed RGBA bitmap (with some exceptions?)
Input texture format does not change anything at all. So even if your roughness map is 2048x2048, 300kb grayscale tiff it will be loaded as 16MB RGBA (8bits per channel) bitmap.

In example as above half of memory used for textures is wasted (RGBa, Rgba, Rgba, RGBa).
So If we cant load grayscale images as grayscale images without wasting memory, what can we do?

  1. Channel Packing

Channel packing is method of optimizing memory usage by placing different textures into channels of single image.


eg. 4 channels of different data packed into same texture

Pros and cons:

  • +saves up to 4 times of texture space
  • +it is not hard
  • –tiny time consuming (you have to pack textures and prepare shader for them)
  • –all packed textures have same mapping and resolution

This method is commonly used in game development cause vram is valuable resource.

  1. Using in Blender

Setting up is easy: Just use split RGB node for RGB… and Alpha output for A


and change alpha type to channelpack to not affect other channels
obraz

  1. Channel order (and Block Compression)

There is no general rule of what texture should go to which channel, like there is (X,±Y, Z) in normal maps.
In game engines it is common to pack Roughness/Gloss, Metallic and AmbientOcclusion to single image.
Often you might find ORM from Unreal or MetalicSmoothness from Unity (which is dumb). Or sometimes other combinations like AlbedoSmoothnes + Normal (for non metalic surface without AO).

Blender currently does not support texture compression like S3 DXT, but you have to take in mind that in game engines, textures are compressed using block compression algorithms that often have uneven bits per channel.

Most common are:
DXT1 for RGB that stores 5:6:5 bits per channel. So in green you should put more important texture.
DXT5 for RGBA stores 5:6:5:8 bits per channel. So Alpha, then green, then rest.
and BC4 8:8 (only red and green) usually for normalmaps on DX11< GPU

Whait, what? Normalmap on only two channels?
Yeap, thats right.
You can make that normalmap uses only 2 channels out of 4 and you can squeze roughnes and metallic there. But it cost a little bit of shader computation (and inacuracy of sqrt?). You can also ‘unpack normal map’ in blender like that:

  1. Packing itself

If You texture Your models in Substance Painter it is nobrainer to texture pack because there are nice presets and setting your own is fast ans easy:

Unreal:


Unity standard: MetalicSmoothness (Mecallic- RGB, Glossy - A)
Unity HDRP:

If not. You can use splitting/combining channels in GIMP, Photoshop: But in many applications that are not for 3d artist packing alpha is tricky or impossible (because premultiply)


Video format from someone else:

10 Likes