informa
2 MIN READ
Featured Blog

Banding and Dithering

I came across a very interesting presentation that talks about how to avoid "banding" artifacts in game graphics.  The author uses dithering to add noise to an image and break up the visible lines your eye can detect.

I came across a very interesting presentation that talks about how to avoid "banding" artifacts in game graphics.  The author uses dithering to add noise to an image and break up the visible lines your eye can detect.  This even works with audio.  When noise is added to the mix, the original tune appears to become more high-fidelity than it actually is:

I was able to use this concept to improve the appearance of banding in shadow acne in a low-resolution spotlight with a large volume.  Here is the original situation, purposely created to maximize the banding effect:

Attached Image

And here is the result when some slight dithering is added:

Attached Image

The trick to dithering is to know how much noise to add.  If we add too much it starts becoming very apparent:

Attached Image

You want to calculate your noise amplitude as the difference between the two discrete levels you are trying to bridge.  In the case of the spotlight shader, random noise is being added to the z coordinate of the shadow lookup, so I want the noise amplitude to be equal to the minimum depth difference the shadowmap can display.  I calculated this as follows, but more experimentation is needed to make sure its right:

float noiselevel = 0.000001 * lightrange.y; shadowcoord.z += rand(lightnormal.xy) * noiselevel - noiselevel * 0.5;

You also want to make sure your random seed is really random.  Using the screen coordinate alone produces bad results because the same random seeds will stay in place as you look around and cause visible patterns.  If you use the "currenttime" shader uniform the noise will constantly change as the camera stays still, resulting in a film grain effect.  I find it is best to multiply the xy components of the fragment coordinate by some other vec2 value.

Here's another example with a directional light exhibiting a banding appearance due to a low angle on the ground:

Attached Image

And here is the improved image with dithering applied:

Attached Image

This code does not eliminate shadow acne, it just breaks it up with some random noise so that your eye can't as easily detect a continuous line.

The same technique can be used to improve the appearance of the new godrays shader I am working on.  With only 16 samples for the rays, banding is very easily visible in this image.

Attached Image

When we add a random offset to the ray starting position, with an amplitude equal to the length of the distance between steps, banding disappears.

Attached Image

Of course more samples are always better, but even at higher sample counts, dithering makes a huge improvement in quality.  Leadwerks Engine 2 actually used 64 samples, with worse results than what I got using just 16 samples above.  The ease with which I can now modify shaders in Leadwerks Editor and see the results instantly really helped develop these techniques. 

Latest Jobs

Xbox Game Studios

Redmond, Washington
10.5.22
Technical Lighting Artist

Innogames

Hamburg, Germany
10.5.22
Game Designer - Elvenar

Six Foot

Houston, TX
10.3.22
Six Foot Director, Player Relations

Hometopia Inc.

Remote
10.7.22
Lead Engineer
More Jobs   

CONNECT WITH US

Explore the
Subscribe to
Follow us

Game Developer Job Board

Game Developer Newsletter

@gamedevdotcom

Explore the

Game Developer Job Board

Browse open positions across the game industry or recruit new talent for your studio

Browse
Subscribe to

Game Developer Newsletter

Get daily Game Developer top stories every morning straight into your inbox

Subscribe
Follow us

@gamedevdotcom

Follow us @gamedevdotcom to stay up-to-date with the latest news & insider information about events & more