[TUTORIAL] Blue noise dithering PostProcess Material to fix banding in low-contrast gradients

Color banding in gradients is one of those 1990s low bit-depth graphics artifacts we just can’t seem to escape…

But after watching this amazing talk by the wizards at PlayDead on how they used blue noise dithering coupled with temporal antialiasing to all but eliminate banding in Inside:

I’ve been convinced there must be an easy way to accomplish this in Unreal, ideally with little to no technical hacking.

Now thanks to this article (specifically the material diagram at the very bottom under “Bonus: How to use with Unreal Engine 4 Materials”):

https://developer.oculus.com/blog/te…t-2d-dithering

I’d like to share how I got it working with very little effort or technical skill.

NOTE: this technique seems to work bests with low-contrast gradients (such as in the example at the bottom of this post).
For high contrast gradients (such as going from full dark to full light), or a scene with high contrast edges moving quickly (which can be smeared by introducing noise before TAA), you might instead consider using a low level of the default Post Process Image Effects Grain (such Grain Intensity = 0.1, Grain Jitter = 1.0). While this method requires very little effort or technical skill, it’s not a silver bullet :wink:

Tutorial:

EDIT: this ZIP file contains the needed texture spritesheet, base material, and material instance (just extract to your project Content folder)

1. Make sure you have Temporal Antialiasing enabled in your Project Settings -> Rendering -> Default Settings (I believe this is only available with Deferred Rendering)

2. As mentioned in the above article, download the Free Blue Noise textures from the bottom of this page (released under Creative Commons Public Domain):

http://momentsingraphics.de/BlueNoise.html

3. Extract the files “LDR_LLL1_0.png” through “LDR_LLL1_63.png” (64 images total) from the 64x64 subfolder within the ZIP file, and use a sprite sheet maker (such as the free version of Texture Packer) to create an 8x8 sprite sheet made up of those images… then import that it into your project

OR, simply right-click and save this 8x8 sprite sheet I created for this example:

4. Create a new material in your project

5. Set the material domain to Post Process

6. Set the material Blendable Location to “Before Tonemapping” to apply temporal antialiasing after this dither material – otherwise you’ll just have noisy banding :wink:

7. Recreate this material graph, using the blue noise texture you imported above in the Texture Sample node:

[revised to use flipbook to animate noise over time, to get rid of “orange peel” effect]

8. If you like, create a Material Instance of the above material, so that you can easily tweak the dither Strength parameter (I found 0.05 was plenty to achieve the desired effect)

9. Create a PostProcess actor in your level, enable Infinite Extent (Unbound), and add a Post Process Material array element pointing to your material (or material instance)

Examples (note: screenshots don’t do it justice, the grain is reduced by TAA in-editor and in-game, but will be reliant on framerate):

(the top is before, the bottom is after)

Hope this helps!

3 Likes

do you think this would help smoothen shadow effects from cascade on landscape?
it’s a bit of a different beast since the banding is much more pronounced then your usual gradient banding - also its not on a smooth color/surface.

If you mean this: https://answers.unrealengine.com/questions/142799/landscape-directional-light-shadow-stripes.html

I don’t believe so… the blue noise + TAA just breaks up the sharp border between color bands, while those shadow cascades bands have smoother, larger divisions.

The above technique is quite simple to attempt, and you could experiment with the size/scaling of the noise texture, or having multiple overlapped noise textures at different scales. But this technique works because the TAA smooths out the added single-pixel noise into smooth shading, so might not be effective for larger scaled noise.

If you try it, let me know how it turns out… cascaded shadows are another area rife with visual artifacts that we just can’t seem to be rid of until ray tracing becomes cheap (computationally and financially).

For me, the real problem would be the per frame cost.
While the function is quite simple, adding the processing to a 4k or 8k image can really degrade performance.
and like you noted. Users who can pay the cost probably have ray tracing…

See first post, updated step 3 and material graph in step 7:

Now the postprocess material uses a flipbook material node to animate the blue noise texture over time, in order to avoid “orange peel” effect that appears with single static noise texture.

Nice @acatalept !

Unfortunately I can’t reproduce your scene with color banding to test the noise :frowning:

Would you have a test scene with the issue, please? So I could test your technique by myself.

Thank you!

I fixed the image links in the first post so they should now be visible.

It’s basically a bright point light in a dense fog, with some flat-shaded (non-textured) cubes (the swirling particles in the middle are irrelevant to this issue). Depending on your monitor and how large the image appears on screen (note that you can click the images to display full size), the banding should be visible in the medium/darker tones of the first image, further away from the light source as you approach the edges of the image. It’s especially noticeable in this scene as it manifests not only as hard divisions in brightness of the color, but also appears to alter the hue of adjacent bands so that overall they average out to the intended color (there is only one color in the scene).

This problem might also be partially/totally mitigated in-engine by modern HDR/10-bit/12-bit displays, if you’re lucky enough to be using one of those :wink: (although the images in my post above are 8-bit, so should preserve the banding that I see on my 8-bit display)