forked from crosire/reshade-shaders
-
Notifications
You must be signed in to change notification settings - Fork 0
/
FilmGrain.fx
101 lines (77 loc) · 3.28 KB
/
FilmGrain.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
/**
* FilmGrain version 1.0
* by Christian Cann Schuldt Jensen ~ CeeJay.dk
*
* Computes a noise pattern and blends it with the image to create a film grain look.
*/
uniform float Intensity <
ui_type = "drag";
ui_min = 0.0; ui_max = 1.0;
ui_tooltip = "How visible the grain is. Higher is more visible.";
> = 0.50;
uniform float Variance <
ui_type = "drag";
ui_min = 0.0; ui_max = 1.0;
ui_tooltip = "Controls the variance of the Gaussian noise. Lower values look smoother.";
> = 0.40;
uniform float Mean = 0.5;
uniform int SignalToNoiseRatio <
ui_type = "drag";
ui_min = 0; ui_max = 16;
ui_label = "Signal-to-Noise Ratio";
ui_tooltip = "Higher Signal-to-Noise Ratio values give less grain to brighter pixels. 0 disables this feature.";
> = 6;
uniform float Timer < source = "timer"; >;
#include "ReShade.fxh"
float3 FilmGrainPass(float4 vpos : SV_Position, float2 texcoord : TexCoord) : SV_Target
{
float3 color = tex2D(ReShade::BackBuffer, texcoord).rgb;
//float inv_luma = dot(color, float3(-0.2126, -0.7152, -0.0722)) + 1.0;
float inv_luma = dot(color, float3(-1.0/3.0, -1.0/3.0, -1.0/3.0)) + 1.0; //Calculate the inverted luma so it can be used later to control the variance of the grain
/*---------------------.
| :: Generate Grain :: |
'---------------------*/
const float PI = 3.1415927;
//time counter using requested counter from ReShade
float t = Timer * 0.0022337;
//PRNG 2D - create two uniform noise values and save one DP2ADD
float seed = dot(texcoord, float2(12.9898, 78.233));// + t;
float sine = sin(seed);
float cosine = cos(seed);
float uniform_noise1 = frac(sine * 43758.5453 + t); //I just salt with t because I can
float uniform_noise2 = frac(cosine * 53758.5453 - t); // and it doesn't cost any extra ASM
//Get settings
float stn = SignalToNoiseRatio != 0 ? pow(inv_luma, (float)SignalToNoiseRatio) : 1.0; // Signal to noise feature - Brighter pixels get less noise.
float variance = (Variance*Variance) * stn;
float mean = Mean;
//Box-Muller transform
uniform_noise1 = (uniform_noise1 < 0.0001) ? 0.0001 : uniform_noise1; //fix log(0)
float r = sqrt(-log(uniform_noise1));
r = (uniform_noise1 < 0.0001) ? PI : r; //fix log(0) - PI happened to be the right answer for uniform_noise == ~ 0.0000517.. Close enough and we can reuse a constant.
float theta = (2.0 * PI) * uniform_noise2;
float gauss_noise1 = variance * r * cos(theta) + mean;
//float gauss_noise2 = variance * r * sin(theta) + mean; //we can get two gaussians out of it :)
//gauss_noise1 = (ddx(gauss_noise1) - ddy(gauss_noise1)) * 0.50 + gauss_noise2;
//Calculate how big the shift should be
//float grain = lerp(1.0 - Intensity, 1.0 + Intensity, gauss_noise1);
float grain = lerp(1.0 + Intensity, 1.0 - Intensity, gauss_noise1);
//float grain2 = (2.0 * Intensity) * gauss_noise1 + (1.0 - Intensity);
//Apply grain
color = color * grain;
//color = (grain-1.0) *2.0 + 0.5;
//color = lerp(color,colorInput.rgb,sqrt(luma));
/*-------------------------.
| :: Debugging features :: |
'-------------------------*/
//color.rgb = frac(gauss_noise1).xxx; //show the noise
//color.rgb = (gauss_noise1 > 0.999) ? float3(1.0,1.0,0.0) : 0.0 ; //does it reach 1.0?
return color.rgb;
}
technique FilmGrain
{
pass
{
VertexShader = PostProcessVS;
PixelShader = FilmGrainPass;
}
}