Deband.fx (9551B)
1 /** 2 * Deband shader by haasn 3 * https://github.com/haasn/gentoo-conf/blob/xor/home/nand/.mpv/shaders/deband-pre.glsl 4 * 5 * Copyright (c) 2015 Niklas Haas 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Modified and optimized for ReShade by JPulowski 26 * https://reshade.me/forum/shader-presentation/768-deband 27 * 28 * Do not distribute without giving credit to the original author(s). 29 * 30 * 1.0 - Initial release 31 * 1.1 - Replaced the algorithm with the one from MPV 32 * 1.1a - Minor optimizations 33 * - Removed unnecessary lines and replaced them with ReShadeFX intrinsic counterparts 34 * 2.0 - Replaced "grain" with CeeJay.dk's ordered dithering algorithm and enabled it by default 35 * - The configuration is now more simpler and straightforward 36 * - Some minor code changes and optimizations 37 * - Improved the algorithm and made it more robust by adding some of the madshi's 38 * improvements to flash3kyuu_deband which should cause an increase in quality. Higher 39 * iterations/ranges should now yield higher quality debanding without too much decrease 40 * in quality. 41 * - Changed licensing text and original source code URL 42 * 3.0 - Replaced the entire banding detection algorithm with modified standard deviation and 43 * Weber ratio analyses which give more accurate and error-free results compared to the 44 * previous algorithm 45 * - Added banding map debug view 46 * - Added and redefined UI categories 47 * - Added depth detection (credits to spiro) which should be useful when banding only 48 * occurs in the sky texture for example 49 * - Fixed a bug in random number generation which was causing artifacts on the upper left 50 * side of the screen 51 * - Dithering is now applied only when debanding a pixel as it should be which should 52 * reduce the overall noise in the final texture 53 * - Minor code optimizations 54 * 3.1 - Switched to chroma-based analysis from luma-based analysis which was causing artifacts 55 * under some scenarios 56 * - Changed parts of the code which was causing compatibility issues on some renderers 57 */ 58 59 #include "ReShadeUI.fxh" 60 #include "ReShade.fxh" 61 62 uniform bool enable_weber < 63 ui_category = "Banding analysis"; 64 ui_label = "Weber ratio"; 65 ui_tooltip = "Weber ratio analysis that calculates the ratio of the each local pixel's intensity to average background intensity of all the local pixels."; 66 ui_type = "radio"; 67 > = true; 68 69 uniform bool enable_sdeviation < 70 ui_category = "Banding analysis"; 71 ui_label = "Standard deviation"; 72 ui_tooltip = "Modified standard deviation analysis that calculates nearby pixels' intensity deviation from the current pixel instead of the mean."; 73 ui_type = "radio"; 74 > = true; 75 76 uniform bool enable_depthbuffer < 77 ui_category = "Banding analysis"; 78 ui_label = "Depth detection"; 79 ui_tooltip = "Allows depth information to be used when analysing banding, pixels will only be analysed if they are in a certain depth. (e.g. debanding only the sky)"; 80 ui_type = "radio"; 81 > = false; 82 83 uniform float t1 < 84 ui_category = "Banding analysis"; 85 ui_label = "Standard deviation threshold"; 86 ui_max = 0.5; 87 ui_min = 0.0; 88 ui_step = 0.001; 89 ui_tooltip = "Standard deviations lower than this threshold will be flagged as flat regions with potential banding."; 90 ui_type = "slider"; 91 > = 0.007; 92 93 uniform float t2 < 94 ui_category = "Banding analysis"; 95 ui_label = "Weber ratio threshold"; 96 ui_max = 2.0; 97 ui_min = 0.0; 98 ui_step = 0.01; 99 ui_tooltip = "Weber ratios lower than this threshold will be flagged as flat regions with potential banding."; 100 ui_type = "slider"; 101 > = 0.04; 102 103 uniform float banding_depth < 104 ui_category = "Banding analysis"; 105 ui_label = "Banding depth"; 106 ui_max = 1.0; 107 ui_min = 0.0; 108 ui_step = 0.001; 109 ui_tooltip = "Pixels under this depth threshold will not be processed and returned as they are."; 110 ui_type = "slider"; 111 > = 1.0; 112 113 uniform float range < 114 ui_category = "Banding detection & removal"; 115 ui_label = "Radius"; 116 ui_max = 32.0; 117 ui_min = 1.0; 118 ui_step = 1.0; 119 ui_tooltip = "The radius increases linearly for each iteration. A higher radius will find more gradients, but a lower radius will smooth more aggressively."; 120 ui_type = "slider"; 121 > = 24.0; 122 123 uniform int iterations < 124 ui_category = "Banding detection & removal"; 125 ui_label = "Iterations"; 126 ui_max = 4; 127 ui_min = 1; 128 ui_tooltip = "The number of debanding steps to perform per sample. Each step reduces a bit more banding, but takes time to compute."; 129 ui_type = "slider"; 130 > = 1; 131 132 uniform int debug_output < 133 ui_category = "Debug"; 134 ui_items = "None\0Blurred (LPF) image\0Banding map\0"; 135 ui_label = "Debug view"; 136 ui_tooltip = "Blurred (LPF) image: Useful when tweaking radius and iterations to make sure all banding regions are blurred enough.\nBanding map: Useful when tweaking analysis parameters, continuous green regions indicate flat (i.e. banding) regions."; 137 ui_type = "combo"; 138 > = 0; 139 140 // Reshade uses C rand for random, max cannot be larger than 2^15-1 141 uniform int drandom < source = "random"; min = 0; max = 32767; >; 142 143 float rand(float x) 144 { 145 return frac(x / 41.0); 146 } 147 148 float permute(float x) 149 { 150 return ((34.0 * x + 1.0) * x) % 289.0; 151 } 152 153 float3 PS_Deband(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target 154 { 155 float3 ori = tex2Dlod(ReShade::BackBuffer, float4(texcoord, 0.0, 0.0)).rgb; 156 157 if (enable_depthbuffer && (ReShade::GetLinearizedDepth(texcoord) < banding_depth)) 158 return ori; 159 160 // Initialize the PRNG by hashing the position + a random uniform 161 float3 m = float3(texcoord + 1.0, (drandom / 32767.0) + 1.0); 162 float h = permute(permute(permute(m.x) + m.y) + m.z); 163 164 // Compute a random angle 165 float dir = rand(permute(h)) * 6.2831853; 166 float2 o; 167 sincos(dir, o.y, o.x); 168 169 // Distance calculations 170 float2 pt; 171 float dist; 172 173 for (int i = 1; i <= iterations; ++i) { 174 dist = rand(h) * range * i; 175 pt = dist * BUFFER_PIXEL_SIZE; 176 177 h = permute(h); 178 } 179 180 // Sample at quarter-turn intervals around the source pixel 181 float3 ref[4] = { 182 tex2Dlod(ReShade::BackBuffer, float4(mad(pt, o, texcoord), 0.0, 0.0)).rgb, // SE 183 tex2Dlod(ReShade::BackBuffer, float4(mad(pt, -o, texcoord), 0.0, 0.0)).rgb, // NW 184 tex2Dlod(ReShade::BackBuffer, float4(mad(pt, float2(-o.y, o.x), texcoord), 0.0, 0.0)).rgb, // NE 185 tex2Dlod(ReShade::BackBuffer, float4(mad(pt, float2( o.y, -o.x), texcoord), 0.0, 0.0)).rgb // SW 186 }; 187 188 // Calculate weber ratio 189 float3 mean = (ori + ref[0] + ref[1] + ref[2] + ref[3]) * 0.2; 190 float3 k = abs(ori - mean); 191 for (int j = 0; j < 4; ++j) { 192 k += abs(ref[j] - mean); 193 } 194 195 k = k * 0.2 / mean; 196 197 // Calculate std. deviation 198 float3 sd = 0.0; 199 200 for (int j = 0; j < 4; ++j) { 201 sd += pow(ref[j] - ori, 2); 202 } 203 204 sd = sqrt(sd * 0.25); 205 206 // Generate final output 207 float3 output; 208 209 if (debug_output == 2) 210 output = float3(0.0, 1.0, 0.0); 211 else 212 output = (ref[0] + ref[1] + ref[2] + ref[3]) * 0.25; 213 214 // Generate a binary banding map 215 bool3 banding_map = true; 216 217 if (debug_output != 1) { 218 if (enable_weber) 219 banding_map = banding_map && k <= t2 * iterations; 220 221 if (enable_sdeviation) 222 banding_map = banding_map && sd <= t1 * iterations; 223 } 224 225 /*------------------------. 226 | :: Ordered Dithering :: | 227 '------------------------*/ 228 //Calculate grid position 229 float grid_position = frac(dot(texcoord, (BUFFER_SCREEN_SIZE * float2(1.0 / 16.0, 10.0 / 36.0)) + 0.25)); 230 231 //Calculate how big the shift should be 232 float dither_shift = 0.25 * (1.0 / (pow(2, BUFFER_COLOR_BIT_DEPTH) - 1.0)); 233 234 //Shift the individual colors differently, thus making it even harder to see the dithering pattern 235 float3 dither_shift_RGB = float3(dither_shift, -dither_shift, dither_shift); //subpixel dithering 236 237 //modify shift acording to grid position. 238 dither_shift_RGB = lerp(2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position); //shift acording to grid position. 239 240 return banding_map ? output + dither_shift_RGB : ori; 241 } 242 243 technique Deband < 244 ui_tooltip = "Alleviates color banding by trying to approximate original color values."; 245 > 246 { 247 pass 248 { 249 VertexShader = PostProcessVS; 250 PixelShader = PS_Deband; 251 } 252 }