summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/render/bgfx/fs_distortion.sc
blob: a80286cfb1a8a93dab9f248e2f2f15da040085bd (plain) (blame)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
$input v_color0, v_texcoord0

// license:BSD-3-Clause
// copyright-holders:Ryan Holtz,ImJezze
//-----------------------------------------------------------------------------
// Distortion Effect
//-----------------------------------------------------------------------------

#include "../../../../../3rdparty/bgfx/examples/common/common.sh"

// Autos
uniform vec4 u_screen_dims;
uniform vec4 u_rotation_type;

// User-supplied
uniform vec4 u_curvature;
uniform vec4 u_round_corner;
uniform vec4 u_smooth_border;
uniform vec4 u_vignetting;
uniform vec4 u_reflection;

// Samplers
SAMPLER2D(s_tex, 0);

// Functions

// www.stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader/
float rand(vec2 seed)
{
	// irrationals for pseudo randomness
	vec2 i = vec2(23.140692, 2.6651442); // e^pi (Gelfond constant), 2^sqrt(2) (Gelfond-Schneider constant)

	return fract(cos(dot(seed, i)) * 123456.0);
}

// www.dinodini.wordpress.com/2010/04/05/normalized-tunable-sigmoid-functions/
float normalizedSigmoid(float n, float k)
{
	// valid for n and k in range of -1.0 and 1.0
	return (n - n * k) / (k - abs(n) * 2.0 * k + 1.0);
}

// www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float roundBox(vec2 p, vec2 b, float r)
{
	return length(max(abs(p) - b + r, 0.0)) - r;
}

vec2 GetRatioCorrection()
{
	float ScreenQuadRatio = 1.0;

	return ScreenQuadRatio > 1.0f
		? vec2(1.0, 1.0f / ScreenQuadRatio)
		: vec2(ScreenQuadRatio, 1.0);
}

float GetNoiseFactor(float n, float random)
{
	// smaller n become more noisy
	return 1.0 + random * max(0.0, 0.25 * pow(2.7182817, -8.0 * n));
}

float GetVignetteFactor(vec2 coord, float amount)
{
	vec2 VignetteCoord = coord;

	float VignetteLength = length(VignetteCoord);
	float VignetteBlur = (amount * 0.75) + 0.25;

	// 0.5 full screen fitting circle
	float VignetteRadius = 1.0 - (amount * 0.25);
	float Vignette = smoothstep(VignetteRadius, VignetteRadius - VignetteBlur, VignetteLength);

	return saturate(Vignette);
}

float GetSpotAddend(vec2 coord, float amount)
{
	vec2 RatioCorrection = GetRatioCorrection();

	// normalized screen quad ratio
	vec2 QuadRatio = vec2(1.0, u_screen_dims.y / u_screen_dims.x);

	// normalized screen quad ratio
	// upper right quadrant
	vec2 spotOffset = vec2(-0.25, 0.25); // 0 degrees
	if (u_rotation_type.x == 1.0)
		spotOffset = vec2(-0.25, -0.25); // 90 degrees
	if (u_rotation_type.x == 2.0)
		spotOffset = vec2(0.25, -0.25); // 180 degrees
	if (u_rotation_type.x == 3.0)
		spotOffset = vec2(0.25, 0.25); // 270 degrees

	vec2 SpotCoord = (coord + spotOffset * RatioCorrection) / RatioCorrection;

	float SpotBlur = amount;

	// 0.5 full screen fitting circle
	float SpotRadius = amount * 0.75;
	float Spot = smoothstep(SpotRadius, SpotRadius - SpotBlur, length(SpotCoord));

	float SigmoidSpot = amount * normalizedSigmoid(Spot, 0.75);

	// increase strength by 100%
	SigmoidSpot = SigmoidSpot * 2.0;

	return saturate(SigmoidSpot);
}

float GetRoundCornerFactor(vec2 coord, float radiusAmount, float smoothAmount)
{
	vec2 RatioCorrection = GetRatioCorrection();

	// reduce smooth amount down to radius amount
	smoothAmount = min(smoothAmount, radiusAmount);

	float range = min(u_screen_dims.x, u_screen_dims.y) * 0.5;
	float radius = range * max(radiusAmount, 0.0025);
	float smooth_val = 1.0 / (range * max(smoothAmount, 0.0025));

	// compute box
	float box = roundBox(u_screen_dims.xy * (coord * 2.0f), u_screen_dims.xy * RatioCorrection, radius);

	// apply smooth
	box *= smooth_val;
	box += 1.0 - pow(smooth_val * 0.5, 0.5);

	float border = smoothstep(1.0, 0.0, box);

	return saturate(border);
}

// www.francois-tarlier.com/blog/cubic-lens-distortion-shader/
vec2 GetDistortedCoords(vec2 centerCoord, float amount)
{
	// lens distortion coefficient
	float k = amount;

	// cubic distortion value
	float kcube = amount * 2.0;

	// compute cubic distortion factor
	float r2 = centerCoord.x * centerCoord.x + centerCoord.y * centerCoord.y;
	float f = kcube == 0.0 ? 1.0 + r2 * k : 1.0 + r2 * (k + kcube * sqrt(r2));

   	// fit screen bounds
	f /= 1.0 + amount * 0.5;

	// apply cubic distortion factor
   	centerCoord *= f;

	return centerCoord;
}

vec2 GetCoords(vec2 coord, float distortionAmount)
{
	vec2 RatioCorrection = GetRatioCorrection();

	// center coordinates
	coord -= 0.5;

	// apply ratio difference between screen and quad
	coord /= RatioCorrection;

	// distort coordinates
	coord = GetDistortedCoords(coord, distortionAmount);

	// revert ratio difference between screen and quad
	coord *= RatioCorrection;

	// un-center coordinates
	coord += 0.5;

	return coord;
}

// Shader

void main()
{
	// Screen Curvature
	vec2 BaseCoord = GetCoords(v_texcoord0, u_curvature.x * 0.25); // reduced amount

	vec2 BaseCoordCentered = BaseCoord;
	BaseCoordCentered -= 0.5;

	// Color
	vec4 BaseColor = texture2D(s_tex, BaseCoord);
	BaseColor.a = 1.0;

	// Clamp
	if (BaseCoord.x > 1.0 || BaseCoord.y > 1.0 || BaseCoord.x < 0.0 || BaseCoord.y < 0.0)
		BaseColor.rgb = vec3(0.0, 0.0, 0.0);
	
	// Vignetting Simulation
	vec2 VignetteCoord = BaseCoordCentered;

	float VignetteFactor = GetVignetteFactor(VignetteCoord, u_vignetting.x);
	BaseColor.rgb *= VignetteFactor;

	// Light Reflection Simulation
	vec3 LightColor = vec3(1.0, 0.90, 0.80); // color temperature 5.000 Kelvin

	vec2 SpotCoord = BaseCoordCentered;
	vec2 NoiseCoord = BaseCoordCentered;

	float SpotAddend = GetSpotAddend(SpotCoord, u_reflection.x);
	float NoiseFactor = GetNoiseFactor(SpotAddend, rand(NoiseCoord));
	BaseColor.rgb += SpotAddend * NoiseFactor * LightColor;

	// Round Corners Simulation
	vec2 RoundCornerCoord = BaseCoordCentered;

	float roundCornerFactor = GetRoundCornerFactor(RoundCornerCoord, u_round_corner.x, u_smooth_border.x);
	BaseColor.rgb *= roundCornerFactor;

	gl_FragColor = BaseColor;
}