[HLSL Code] Basic Dithering

share shaders here
  • Author
  • Message
Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

[HLSL Code] Basic Dithering

Dithering under enbeffect.fx for HDR to rgba8888

Image

up close:
Image


So here is a basic noise generator.

Code: Select all

// ALU noise in Next-gen post processing in COD:AW 
float InterleavedGradientNoise( float2 uv )
{
    float3 magic = { 0.06711056, 0.00583715, 52.9829189 };
    return frac( magic.z * frac( dot( uv, magic.xy ) ) );
}
And here is the dithering part. Just add it right before pixel shader output/return.
3 different alternatives here, linear, non-linear, energy-preserved

Code: Select all

    float dither_amp = 1.0;
    float noise = lerp(-0.5, 0.5, InterleavedGradientNoise( vPos )) * dither_amp; //or other noise method
//linear
    color.xyz  = color + noise / 255.0;
//non-linear
//    color.xyz = pow( pow( color.xyz, 1.0 / 2.2) + noise / 255.0, 2.2);
//Energy-preserved 
//    color.xyz = pow(color.xyz, 1.0/2.2);
//    color.xyz = color.xyz + noise * min(color.xyz + 0.5 * pow(1.0/255.0, 2.2), 0.75 * (pow(256.0/255.0, 2.2) - 1.0));
//    color.xyz = pow(color.xyz, 2.2);
Here is a demo comparison on linear, srgb space, and energy-preserving dither: shadertoy (low quality noise pattern for a better view on artifacts)
Image
[gdc16] Advanced Techniques and Optimization of HDR Color Pipelines
Noted that the difference between these methods are less obvious on higher bit depth.

and a demo implementation on reference enbeffect.fx.
enbeffect.fx
update 23/9. adds different modes, amplitude control.
(17.29 KiB) Downloaded 322 times
Last edited by kingeric1992 on 23 Sep 2016, 13:48, edited 1 time in total.
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube

Offline
User avatar
*master*
Posts: 136
Joined: 08 Nov 2012, 15:24

Re: [HLSL Code] Basic Dithering

Another method for [s]dithering[/s] noise generation is Valve's.

Code: Select all

float3 ScreenSpaceDither( float2 vScreenPos : SV_Position0 ) : SV_Target
{
	// Iestyn's RGB dither (7 asm instructions) from Portal 2 X360, slightly modified for VR
    float3 vDither = dot( float2( 171.0, 231.0 ), vScreenPos.xy+Timer.x*16777216) ;
    vDither.rgb = frac( vDither.rgb / float3( 103.0, 71.0, 97.0 ) );
    return vDither.rgb;
There's also the SweetFX dithering code, which works well in these situations. Though chromatic noise is down to your preference.
But I think gamma correction is really important when you do this, otherwise it looks like ugly noise unless you put it after the conversion. Take a look at this - I think it's at the least related to his algorithms there. I tested the fast version with my Dragon's Dogma ENB and the results were really good. (Made the previous code look really awful by comparison, oops.)
Last edited by roxahris on 16 Feb 2017, 19:03, edited 1 time in total.

Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

Re: [HLSL Code] Basic Dithering

As I said, you can change the noise function to your liking. (noise != dither)

Btw, doing dithering alone in effect.txt or sweetfx will not get the full potential of the technique, aka 0.5 = average of 0 and 1.
It merely adds noise so that the edge is less obvious, the overall block average is still the same as the ldr input, hence the banding will still occurred. Unless you're talking about a full-blown deband shader that generate the additional precision (the 0.5) by itself.

post update: adds alternative method and comparison.
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube

Offline
User avatar
*blah-blah-blah maniac*
Posts: 17427
Joined: 27 Dec 2011, 08:53
Location: Rather not to say

Re: [HLSL Code] Basic Dithering

I recommend to use multiplicative operation to avoid bugs like on night sky in Fallout 4. Who knows what kind of post processing applied, may be black levels greatly increased by effect.txt.
_________________
i9-9900k, 64Gb RAM, RTX 3060 12Gb, Win7

Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

Re: [HLSL Code] Basic Dithering

What happened to the night sky in fo4? My understanding on dithering is still about bumping the value up and down to hit neighboring steps.
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube

Offline
User avatar
*blah-blah-blah maniac*
Posts: 17427
Joined: 27 Dec 2011, 08:53
Location: Rather not to say

Re: [HLSL Code] Basic Dithering

You may check vanilla fallout 4 sky, it have dithering pattern visible on it. Was reported several times in the past for fixing. Of course you can just add math which ignores dithering when value is 0.
_________________
i9-9900k, 64Gb RAM, RTX 3060 12Gb, Win7

Offline
User avatar
*master*
Posts: 136
Joined: 08 Nov 2012, 15:24

Re: [HLSL Code] Basic Dithering

Oh. Is it wrong to think that adding noise to an image in such a way is dithering it? If it's just based on the texture coordinate it'll be a repeating pattern anyway, so I don't see what the difference is, barring that an RGB dithering pattern isn't one dimensional.

I'm not suggesting to use SweetFX to add dithering, of course that's pointless. I'm talking about the algorithm included in it, which I'll post here for posterity, as it's also a good alternative.

Code: Select all

    //SweetFX dithering by CeeJay.dk.
    float dither_bit = 8.0; //Bit-depth of output. Normally 8 but some LCD monitors are 7 or even 6-bit. 
    //Calculate grid position
    float grid_position = frac( dot( vScreenPos.xy - float2(0.5,0.5) , float2(1.0/16.0,10.0/36.0) + 0.25 ));
    //Calculate how big the shift should be
    float dither_shift = (0.25) * (1.0 / (pow(2.0,dither_bit) - 1.0));
    //Shift the individual colors differently, thus making it even harder to see the dithering pattern
    float3 dither_shift_RGB = float3(dither_shift, -dither_shift, dither_shift); //subpixel dithering
    //modify shift acording to grid position.
    dither_shift_RGB = lerp(2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position); //shift acording to grid position.
    //shift the color by dither_shift
    return dither_shift_RGB; //0.5/255.0 + dither_shift_RGB; 

Offline
User avatar
*blah-blah-blah maniac*
Posts: 530
Joined: 30 Jan 2012, 13:18

Re: [HLSL Code] Basic Dithering

SweetFX dither does the same, roughly. For best LDR artifact removal, a full deband shader is still best. Take a look at the ReShade Framework, there is a very good one already included. Port to ENB is elementary, I can do it, if needed.
Also, this here is not just "noise" per se, look at the zoomed in picture, it's some sort of zig zag pattern. And it gets rid of obvious banding nicely because the amount of noise is just as large as the single steps between the evenly colored areas. You can't deband 4 bit colors with that obviously.

Offline
*blah-blah-blah maniac*
Posts: 565
Joined: 05 Apr 2014, 10:29
Location: Taiwan

Re: [HLSL Code] Basic Dithering

@roxahris
It is still dithering, considering dithering means adding ripple to input.

But if you simply add noise to a data that was already compressed, the local sum of dithering will match to the discrete compressed data and not the uncompressed continuous raw input, which means banding will be visible at small gradient over a large area.

Visually, it would be like applying smoothing on steps, where the dither amplitude as smooth range. If the step width >> smoothing range, the result would looked more like steps instead of a continues slope.

@marty
Believe it or not, the noise parms & function are exact the same in the comparison pic with noise peak-to peak amplitude == 1/255. In fact, the tiny noise appears in the implementation on effect.txt is not supposed to be there at all....it might be caused by non-linear step size from gamma correction.

I tried...
Image
_________________
Intel Xeon L5639 6C12T @3.96GHz | Gigabyte ga-x58a-ud3r | MSI GTX680 4G | 48G RAM | Intel 760p Nvme w clover bootloader
Flickr
YouTube

Offline
User avatar
*master*
Posts: 136
Joined: 08 Nov 2012, 15:24

Re: [HLSL Code] Basic Dithering

Would that explain why some versions of the Valve algorithm I've seen have an offset like dither * 2 - 0.5, then? I've noticed that kind of smoothed-step problem before, but I worked around it by doing something like that too.

I'm not talking about LDR data at all. I don't see the point in using Deband with ENB unless the effect shader can't access the HDR data in the first place, which I don't think is the case for any recent releases. All it will do is smooth details and add noise, which brings us back full circle.
Post Reply