float dither_shift_half = (dither_shift * 0.5); // The noise should vary between +- 0.5

By multiplying 1/255 by 0.5, it places that value at exactly the midpoint between two 8-bit shades, where the slightest deviation from its value will cause it to be rounded either up or down to the nearest 255th at 8-bit output stage. So if any slight amount of noise were to be added , it would cause that pixel to increase by 1/255th, else decrease by 1/255th, and so you get a randomised pattern of noise.

]]>#if dither_method == 1 // Ordered dithering

//Calculate grid position

float grid_position = frac( dot(tex,(RFX_ScreenSize * 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,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

color.rgb += dither_shift_RGB;

float3 color = colorInput.rgb;

float dither_bit = 8.0; //Number of bits per channel. Should be 8 for most monitors.

//Pseudo Random Number Generator

// — PRNG 1 – Reference —

float seed = dot(tex, float2(12.9898,78.233)); //I could add more salt here if I wanted to

float sine = sin(seed); //cos also works well. Sincos too if you want 2D noise.

float noise = frac(sine * 43758.5453 + tex.x); //tex.x is just some additional salt – it can be taken out.

//Calculate how big the shift should be

float dither_shift = (1.0 / (pow(2,dither_bit) – 1.0)); // Using noise to determine shift. Will be 1/255 if set to 8-bit.

float dither_shift_half = (dither_shift * 0.5); // The noise should vary between +- 0.5

dither_shift = dither_shift * noise – dither_shift_half; // MAD

//shift the color by dither_shift

color.rgb += float3(-dither_shift, dither_shift, -dither_shift); //subpixel dithering

Basically, CeeJay’s prior colour transformations (such as S-curves, vignette and such) are calculated at high precision values – 3 or 4 decimal place floating point precision. His Dither.h shader then uses these high precision values to dither “towards” the lower precision 255-shade (8-bit) output by adding noise as required, which is in line with how the original article describes the process. Whereas the LUT shader used for monitor calibration (1D texture LUT) already starts out as low precision values based on an 8-bit texture (they are still handled as 3 or 4 decimal place floating point numbers internally, but they are effectively truncated to the nearest 1/255th, or decimal 0.0039), so there are no intermediate values to dither it “towards”. If we had instead used say a 16-bit 1D texture LUT then we could start out with high precision values that aren’t truncated to nearest 0.0039, and CeeJay’s dither.h shader should work well.

As to how AMD is doing it, I believe they are doing a similar thing to CeeJay – starting with the 16-bit precision values which reside in the video card gamma table (contrary to some claims which say it’s 10-bit – the Set/GetDeviceGammaRamp functions accept a 16-bit parameter), and then applying pixel shader dithering to produce the final 8-bit output. Ordered dithering and error diffusion seem to be quite cheap processing wise – in reshade I’m seeing only a 1% GPU overhead.

In testing I note CeeJay’s/AMD’s method is produces much less visible noise since it only adds noise as required, whereas my aforementioned “method1” where noise is applied to the whole image first, results in more noise since all pixels receive noise regardless of how “far away” their initial high precision values are from the final lower precision output, and I’m guessing all this extra noise is why it doesn’t seem to work so well on 6-bit monitors which already employ their own dithering.

]]>THanks ]]>

i tried to implement this algorithm in C# but i got few issues

can you help me? if possible please share your code

Thanks ]]>