duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

TriDither.fxh (3475B)


      1 ////////////////////////////////////////////////////////////////////////////////
      2 // Triangular Dither                                                          //
      3 // By The Sandvich Maker                                                      //
      4 // Ported to ReShade by TreyM                                                 //
      5 ////////////////////////////////////////////////////////////////////////////////
      6 
      7 ////////////////////////////////////////////////////////////////////////////////
      8 //                                                                            //
      9 // Usage:                                                                     //
     10 //   Include this file in your shader like so: #include "TriDither.fx"        //
     11 //                                                                            //
     12 //   For shader developers, use this syntax to do a function call in your     //
     13 //   code as the last thing before exiting a given shader. You should dither  //
     14 //   anytime data is going to be truncated to a lower bitdepth. Color input   //
     15 //   must be a float3 value.                                                  //
     16 //                                                                            //
     17 //  input.rgb += TriDither(input.rgb, uv, bits);                              //
     18 //                                                                            //
     19 //     "bits" is an integer number that determines the bit depth              //
     20 //      being dithered to. Usually 8, sometimes 10                            //
     21 //      You can automate this by letting Reshade decide like so:              //
     22 //                                                                            //
     23 //  input += TriDither(input, uv, BUFFER_COLOR_BIT_DEPTH);                    //
     24 //                                                                            //
     25 //      Manual setup looks something like this for an 8-bit backbuffer:       //
     26 //                                                                            //
     27 //  input.rgb += TriDither(input.rgb, uv, 8);                                 //
     28 //                                                                            //
     29 ////////////////////////////////////////////////////////////////////////////////
     30 
     31 uniform float DitherTimer < source = "timer"; >;
     32 #define       remap(v, a, b) (((v) - (a)) / ((b) - (a)))
     33 
     34 float rand21(float2 uv)
     35 {
     36     float2 noise = frac(sin(dot(uv, float2(12.9898, 78.233) * 2.0)) * 43758.5453);
     37     return (noise.x + noise.y) * 0.5;
     38 }
     39 
     40 float rand11(float x)
     41 {
     42     return frac(x * 0.024390243);
     43 }
     44 
     45 float permute(float x)
     46 {
     47     return ((34.0 * x + 1.0) * x) % 289.0;
     48 }
     49 
     50 float3 TriDither(float3 color, float2 uv, int bits)
     51 {
     52     float bitstep = exp2(bits) - 1.0;
     53     float lsb = 1.0 / bitstep;
     54     float lobit = 0.5 / bitstep;
     55     float hibit = (bitstep - 0.5) / bitstep;
     56 
     57     float3 m = float3(uv, rand21(uv + (DitherTimer * 0.001))) + 1.0;
     58     float h = permute(permute(permute(m.x) + m.y) + m.z);
     59 
     60     float3 noise1, noise2;
     61     noise1.x = rand11(h); h = permute(h);
     62     noise2.x = rand11(h); h = permute(h);
     63     noise1.y = rand11(h); h = permute(h);
     64     noise2.y = rand11(h); h = permute(h);
     65     noise1.z = rand11(h); h = permute(h);
     66     noise2.z = rand11(h);
     67 
     68     float3 lo = saturate(remap(color.xyz, 0.0, lobit));
     69     float3 hi = saturate(remap(color.xyz, 1.0, hibit));
     70     float3 uni = noise1 - 0.5;
     71     float3 tri = noise1 - noise2;
     72 	return lerp(uni, tri, min(lo, hi)) * lsb;
     73 }