forked from crosire/reshade-shaders
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Deband.fx
131 lines (117 loc) · 4.45 KB
/
Deband.fx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
* Deband shader by haasn
* https://github.com/mpv-player/mpv/blob/master/video/out/opengl/video_shaders.c
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*
* You can alternatively redistribute this file and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Modified and optimized for ReShade by JPulowski
* http://reshade.me/forum/shader-presentation/768-deband
*
* Do not distribute without giving credit to the original author(s).
*
* 1.0 - Initial release
* 1.1 - Replaced the algorithm with the one from MPV
* 1.1a - Minor optimizations
* Removed unnecessary lines and replaced them with ReShadeFX intrinsic counterparts
*/
uniform float Threshold <
ui_type = "drag";
ui_min = 0.0; ui_max = 0.25;
ui_label = "Cut-Off Threshold";
ui_tooltip = "Higher numbers increase the debanding strength dramatically but progressively diminish image details.";
> = 0.004;
uniform float Range <
ui_type = "drag";
ui_min = 1; ui_max = 64;
ui_label = "Initial Radius";
ui_tooltip = "The radius increases linearly for each iteration. A higher radius will find more gradients, but a lower radius will smooth more aggressively.";
> = 16.0;
uniform int Iterations <
ui_type = "drag";
ui_min = 1; ui_max = 16;
ui_tooltip = "The number of debanding steps to perform per sample. Each step reduces a bit more banding, but takes time to compute. Note that the strength of each step falls off very quickly, so high numbers (> 4) are practically useless.";
> = 1;
uniform float Grain <
ui_type = "drag";
ui_min = 0; ui_max = 0.5;
ui_label = "Additional Noise";
ui_tooltip = "Add some extra noise to the image. This significantly helps cover up remaining quantization artifacts. Higher numbers add more noise.";
> = 0.006;
#include "ReShade.fxh"
uniform int drandom < source = "random"; min = 0; max = 5000; >;
float rand(float x)
{
return frac(x * 0.024390243);
}
float permute(float x)
{
return ((34.0 * x + 1.0) * x) % 289.0;
}
float3 average(sampler2D tex, float2 pos, float range, inout float h)
{
// Helper: Compute a stochastic approximation of the avg color around a pixel
// Compute a random rangle and distance
float dist = rand(h) * range; h = permute(h);
float dir = rand(h) * 6.2831853; h = permute(h);
float2 pt = dist * ReShade::PixelSize;
float2 o = float2(cos(dir), sin(dir));
// Sample at quarter-turn intervals around the source pixel
float3 ref[4];
ref[0] = tex2Dlod(tex, float4(pos + pt * float2( o.x, o.y), 0, 0)).rgb;
ref[1] = tex2Dlod(tex, float4(pos + pt * float2(-o.y, o.x), 0, 0)).rgb;
ref[2] = tex2Dlod(tex, float4(pos + pt * float2(-o.x, -o.y), 0, 0)).rgb;
ref[3] = tex2Dlod(tex, float4(pos + pt * float2( o.y, -o.x), 0, 0)).rgb;
// Return the (normalized) average
return (ref[0] + ref[1] + ref[2] + ref[3]) * 0.25;
}
float3 PS_Deband(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
// Initialize the PRNG by hashing the position + a random uniform
float3 m = float3(texcoord, drandom * 0.0002) + 1.0;
float h = permute(permute(permute(m.x) + m.y) + m.z);
// Sample the source pixel
float3 avg, diff, col = tex2D(ReShade::BackBuffer, texcoord).rgb;
for (int i = 1; i <= Iterations; i++)
{
// Sample the average pixel and use it instead of the original if the difference is below the given threshold
avg = average(ReShade::BackBuffer, texcoord, i * Range, h);
diff = abs(col - avg);
col = lerp(avg, col, diff > Threshold * i);
}
if (Grain > 0.0)
{
// Add some random noise to smooth out residual differences
float3 noise;
noise.x = rand(h); h = permute(h);
noise.y = rand(h); h = permute(h);
noise.z = rand(h); h = permute(h);
col += Grain * (noise - 0.5);
}
return col;
}
technique Deband
{
pass
{
VertexShader = PostProcessVS;
PixelShader = PS_Deband;
}
}