What is Color Banding? And what is it not?
What is Color Banding? And what is it not?

			

You can choose!


Read the article or watch the movie.
Both contain the same content.


I didn’t embed the video directly to avoid any tracking from Google and complications with the DSGVO.
I didn’t believe in color banding. I trusted some half-knowledge for years and now I write about it so that you don’t make the same mistake.
I’ll explain what color banding is and that texture-compression might look very similar – it’s important to recognize the difference to choose the right tools to fight it. But first I’ll give you a short overview why I got trapped in half-knowledge.


My Struggle

I was like the dudes above when it came to Color Depth. With 24 Bit per pixel (smart people say 24 bpp) you get freakin’ 16.7 million colors! 
  Depending on where you look  they say that the human eye can distinguish up to “only” 10 Million colors. Without any clue about color depth and RGB color channels I said things like:

This let me struggle when suddenly graphic cards where able to calculate with 32bpp. I still wouldn’t have any idea about color channels and especially not what an alpha channel could be. But I had enough half knowledge to say stuff like:

Nobody else in my “hood” would know more so my statement sounded well-grounded. Unfortunately with such a thinking it was impossible for me to explain these abrupt changes in the color:

I mean … we’re talking 24bpp bro’ – more colors than you can see!!!!111 How is this even possible?! With the years and by stopping myself from hiding behind half knowledge I found an answers:

24/32bpp isn’t enough, bro’!
24/32bpp is just the sum of 8bit for every of the three color channels (red, green and blue) and maybe an alpha channel. 
8 Bits per channel. 
That’s a maximum of 256 colors per channel – doesn’t sound that much anymore, right?

And if you now imagine a gradient reaching from black to white on a monitor with a resolution of 1920 pixels width you’ll quickly learn that you have to stretch your 256 colors so that you get ~8 pixels wide color bands (1920 pixels / 256 colors = 7.5 pixels per color).

8 Pixels isn’t that much but most times you don’t have gradients going from one extreme to another. Here’s another gradient with only 30 shades and you can already see some banding.

You can find all this dry theory in many other articles and after reading about the 256-colors-per-channel-limitation I though:


Fight Color Banding
If the problem really depends on the limitation of colors (and not from texture compression which is explained later) you can’t magically create more of them but you can use Dithering to hide the limitations!

“Dither is an intentionally applied form of noise […]”  “[…] to ease the transition between two colors, without adding any new colors to the palette.”
– wikipedia.org & pixeljoint.com


What this basically does is shown below. I guess especially Retro-Pixel-Artists do such stuff every day but isn’t this amazing? What a great way to hide the actual color limitation.

Note that we game developers are in the lucky position that we can use such tricks while other industries really depend in accuracy. Here’s an interesting example:

“While dithering produces a visually smooth image, the pixels no longer correlate to the source data. This matters in mission critical applications like diagnostic imaging where a tumor may only be one or two pixels big.”
Source: 30-Bit Color Technology for NVIDIA® Quadro®

If you are interested in technical details about dithering, make sure you read Banding in Games: A Noisy Rant and all the other links I posted in the “Links & Resources” section. But now let’s talk about a similar looking phenomenon:

It looks like Color Banding but it’s not!
It’s important too see what “real” color banding is and what only might look like it. Here are some examples for color banding imitators:



If you have more examples like these, feel free to let me know!


Example 1: Texture Compression
Now let’s get to a bigger part which might be a bit more common. If you take the texture blob below and use it even for huge effects like the haze around a sun or an aura around an explosion, all will be fine, even if this smallish texture gets scaled up drastically:

You might see some color banding but this is because of the limitations of the 256-color-per-channel-limitation (explained above):


In the upper case you can’t do much but it gets ugly when game engines use compressed texture data (should be almost always the case) which means for DXT1 for example that the texture will have 65536 colors (16bpp) instead of the possible 16.7 million (24bpp) and get some compression artifacts. The good news: The texture will need way less memory and most of the times still look pretty good.
Most of the times. In this example you can clearly see how the texture got more “wobbly” due the compression:

In this case it’s easy to see that the compression is the problem. But with a shiny background and maybe seeing only a part of the texture (because it’s for example used as a huge haze) you might think:


“Oh, that’s color banding. I can not do anything about it. It’s the limitation of the 24bpp!”


But if you actually notice that in THIS case it is the compression which steals your colors, you can fight against it!
Four ways of fighting compression
Here I’ll present you some ways about what you can do against the compression problems:
1. The way of the smart Fox
You can read this article which describes really well how to optimize your image so that it looks well even with compression by using noise and precise color shifts.

2. No way. No compression.
If you have control over your pipeline you could not compress this special texture to avoid any compression artifacts and color shifts. This costs more space but if your texture isn’t too big and you don’t do this too often, it should be fine. Even if the texture is small and therefore contains not many color information, the graphic card will interpolate the values in-between very well. That’s why even small (uncompressed) textures work well for gradients.

3. The Way of the furious Programmer
I don’t recommend this but of course you could just use a huge 2048x2048px blob texture to make the artifacts visually smaller. Besides of that programmers will give you a death-stare you can’t avoid tiny artifacts which might be visible when the texture is scaled up a lot. In addition there some greenish/reddish color shifting going on which can also be a distraction:

Actually it’s really interesting that these color shift happen because not every color channel gets compressed with the same quality. With DXT1 for example the green channel gets 6 bit while red and blue only get 5 bit (makes 16 bit in total). This is because the human eye is more sensitive when it comes to green values.

4. The way of the not existing texture
I learned a really smart trick from Alex which is to not use textures at all. Details are written down in an other article: X:Rebirth – Geometric Lensflares. But for those who don’t like clicking links, here’s a preview:

And not to forget, the backgrounds in Homeworld were done via Vertex Color too! I wrote about this here.

Example 2: Faceted Geometry
Another nice example which has nothing to do with color banding but with the shading of narrow polygons. Here’s what the author described it as:

“what the… oh”….not banding, just faceted geometry…
– Banding in Games: A Noisy Rant


That’s it!
Thank you for reading and let me know if you like the content of this article or if something is wrong or needs to be added.

Update 1



Update 2

Konrad – a friend of mine – had an interesting idea which I would love to hear your opinion about. Instead of increasing all three of the RGB values simultaneously by +1 for creating a gradient, he mentioned to split it up and first add +1 to one channel, then add +1 to the next channel. Here’s an example:

At the top you see a standard color gradient (increased contrast for better visibility) where gray values are brightened up by adding +1 to all of the RGB channels.
At the bottom you see smaller color stripes where first the green channel gets +1 and then the blue channel. Of course this creates color where you intend to have only grey values but seeing it from far makes this detail less prominent.

Here’s an example with 1920 pixels width (click the link or Right-Click on the image and choose “Open in Tab”). The upper area of the image is a standard gradient and the lower area is a version created with the mentioned method. To me it looks a bit more smoother seeing it from far.
What do you think about this method? Was it used somewhere already – Is there a name for it? Or is it not usable because of problems with compression, post-effects or something else?
p.s. after tweeting this update pixelmager responded with this shaderToy link showing of several approaches to this topic. :,)




Links & Resources
Color Banding & Perception
[a01] Banding in Games: A Noisy Rant
[a02] Number of Colors Distinguishable by the Human Eye
[a03] Understanding the HP DreamColor 30-bit Panel
[a04] 30-Bit Color Technology for NVIDIA® Quadro®
[a05] High quality GIF with FFmpeg
[d01] Discussion: Is 32-bit color depth enough?
Compression
[a06] Making Quality Game Textures
[a07] DDS Types
[a08] Texture Compression
[a09] Real-Time Normal Map DXT Compression
[a10] Texture Compression Techniques and Tips
[a11] Real-Time YCoCg-DXT Compression
Dithering
[a12] Wikipedia: Dither
[a13] How to fix color banding with dithering
[a14] HDR Dithering
[a15] Dithering in Unreal
[a16] The Pixel Art Tutorial: Dithering
[a17] Dithering and Frame Rate Control (FRC)
sRGB, Gamma Correction, HDMI
[a18] GPU Gems 3: The Importance of Being Linear
[a19] A Standard Default Color Space for the Internet – sRGB
[a20] HDMI Standard, Cables and Color Depth
[a21] 10 Bit Color support on NVidia GPUs
					