]> git.lizzy.rs Git - dragonfireclient.git/blob - client/shaders/nodes_shader/opengl_fragment.glsl
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / client / shaders / nodes_shader / opengl_fragment.glsl
1 uniform sampler2D baseTexture;
2
3 uniform vec3 dayLight;
4 uniform vec4 skyBgColor;
5 uniform float fogDistance;
6 uniform vec3 eyePosition;
7
8 // The cameraOffset is the current center of the visible world.
9 uniform vec3 cameraOffset;
10 uniform float animationTimer;
11 #ifdef ENABLE_DYNAMIC_SHADOWS
12         // shadow texture
13         uniform sampler2D ShadowMapSampler;
14         // shadow uniforms
15         uniform vec3 v_LightDirection;
16         uniform float f_textureresolution;
17         uniform mat4 m_ShadowViewProj;
18         uniform float f_shadowfar;
19         uniform float f_shadow_strength;
20         uniform vec4 CameraPos;
21         uniform float xyPerspectiveBias0;
22         uniform float xyPerspectiveBias1;
23         
24         varying float adj_shadow_strength;
25         varying float cosLight;
26         varying float f_normal_length;
27         varying vec3 shadow_position;
28         varying float perspective_factor;
29 #endif
30
31
32 varying vec3 vNormal;
33 varying vec3 vPosition;
34 // World position in the visible world (i.e. relative to the cameraOffset.)
35 // This can be used for many shader effects without loss of precision.
36 // If the absolute position is required it can be calculated with
37 // cameraOffset + worldPosition (for large coordinates the limits of float
38 // precision must be considered).
39 varying vec3 worldPosition;
40 varying lowp vec4 varColor;
41 #ifdef GL_ES
42 varying mediump vec2 varTexCoord;
43 #else
44 centroid varying vec2 varTexCoord;
45 #endif
46 varying vec3 eyeVec;
47 varying float nightRatio;
48
49 const float fogStart = FOG_START;
50 const float fogShadingParameter = 1.0 / ( 1.0 - fogStart);
51
52 #ifdef ENABLE_DYNAMIC_SHADOWS
53
54 // assuming near is always 1.0
55 float getLinearDepth()
56 {
57         return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
58 }
59
60 vec3 getLightSpacePosition()
61 {
62         return shadow_position * 0.5 + 0.5;
63 }
64 // custom smoothstep implementation because it's not defined in glsl1.2
65 // https://docs.gl/sl4/smoothstep
66 float mtsmoothstep(in float edge0, in float edge1, in float x)
67 {
68         float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
69         return t * t * (3.0 - 2.0 * t);
70 }
71
72 #ifdef COLORED_SHADOWS
73
74 // c_precision of 128 fits within 7 base-10 digits
75 const float c_precision = 128.0;
76 const float c_precisionp1 = c_precision + 1.0;
77
78 float packColor(vec3 color)
79 {
80         return floor(color.b * c_precision + 0.5)
81                 + floor(color.g * c_precision + 0.5) * c_precisionp1
82                 + floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
83 }
84
85 vec3 unpackColor(float value)
86 {
87         vec3 color;
88         color.b = mod(value, c_precisionp1) / c_precision;
89         color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
90         color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
91         return color;
92 }
93
94 vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
95 {
96         vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
97
98         float visibility = step(0.0, realDistance - texDepth.r);
99         vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
100         if (visibility < 0.1) {
101                 visibility = step(0.0, realDistance - texDepth.b);
102                 result = vec4(visibility, unpackColor(texDepth.a));
103         }
104         return result;
105 }
106
107 #else
108
109 float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
110 {
111         float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
112         float visibility = step(0.0, realDistance - texDepth);
113         return visibility;
114 }
115
116 #endif
117
118
119 #if SHADOW_FILTER == 2
120         #define PCFBOUND 2.0 // 5x5
121         #define PCFSAMPLES 25
122 #elif SHADOW_FILTER == 1
123         #define PCFBOUND 1.0 // 3x3
124         #define PCFSAMPLES 9
125 #else
126         #define PCFBOUND 0.0
127         #define PCFSAMPLES 1
128 #endif
129
130 #ifdef COLORED_SHADOWS
131 float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
132 {
133         vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
134         float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
135         return depth;
136 }
137 #else
138 float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
139 {
140         float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
141         float depth = realDistance - texDepth;
142         return depth;
143 }
144 #endif
145
146 #define BASEFILTERRADIUS 1.0
147
148 float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
149 {
150         // Return fast if sharp shadows are requested
151         if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0)
152                 return 0.0;
153
154         vec2 clampedpos;
155         float y, x;
156         float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance);
157         // A factor from 0 to 1 to reduce blurring of short shadows
158         float sharpness_factor = 1.0;
159         // conversion factor from shadow depth to blur radius
160         float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
161         if (depth > 0.0 && f_normal_length > 0.0)
162                 // 5 is empirical factor that controls how fast shadow loses sharpness
163                 sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0);
164         depth = 0.0;
165
166         float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
167                         * f_textureresolution / 2.0 / f_shadowfar;
168         float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node
169
170         return max(BASEFILTERRADIUS * f_textureresolution / 4096.0,  sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS);
171 }
172
173 #ifdef POISSON_FILTER
174 const vec2[64] poissonDisk = vec2[64](
175         vec2(0.170019, -0.040254),
176         vec2(-0.299417, 0.791925),
177         vec2(0.645680, 0.493210),
178         vec2(-0.651784, 0.717887),
179         vec2(0.421003, 0.027070),
180         vec2(-0.817194, -0.271096),
181         vec2(-0.705374, -0.668203),
182         vec2(0.977050, -0.108615),
183         vec2(0.063326, 0.142369),
184         vec2(0.203528, 0.214331),
185         vec2(-0.667531, 0.326090),
186         vec2(-0.098422, -0.295755),
187         vec2(-0.885922, 0.215369),
188         vec2(0.566637, 0.605213),
189         vec2(0.039766, -0.396100),
190         vec2(0.751946, 0.453352),
191         vec2(0.078707, -0.715323),
192         vec2(-0.075838, -0.529344),
193         vec2(0.724479, -0.580798),
194         vec2(0.222999, -0.215125),
195         vec2(-0.467574, -0.405438),
196         vec2(-0.248268, -0.814753),
197         vec2(0.354411, -0.887570),
198         vec2(0.175817, 0.382366),
199         vec2(0.487472, -0.063082),
200         vec2(0.355476, 0.025357),
201         vec2(-0.084078, 0.898312),
202         vec2(0.488876, -0.783441),
203         vec2(0.470016, 0.217933),
204         vec2(-0.696890, -0.549791),
205         vec2(-0.149693, 0.605762),
206         vec2(0.034211, 0.979980),
207         vec2(0.503098, -0.308878),
208         vec2(-0.016205, -0.872921),
209         vec2(0.385784, -0.393902),
210         vec2(-0.146886, -0.859249),
211         vec2(0.643361, 0.164098),
212         vec2(0.634388, -0.049471),
213         vec2(-0.688894, 0.007843),
214         vec2(0.464034, -0.188818),
215         vec2(-0.440840, 0.137486),
216         vec2(0.364483, 0.511704),
217         vec2(0.034028, 0.325968),
218         vec2(0.099094, -0.308023),
219         vec2(0.693960, -0.366253),
220         vec2(0.678884, -0.204688),
221         vec2(0.001801, 0.780328),
222         vec2(0.145177, -0.898984),
223         vec2(0.062655, -0.611866),
224         vec2(0.315226, -0.604297),
225         vec2(-0.780145, 0.486251),
226         vec2(-0.371868, 0.882138),
227         vec2(0.200476, 0.494430),
228         vec2(-0.494552, -0.711051),
229         vec2(0.612476, 0.705252),
230         vec2(-0.578845, -0.768792),
231         vec2(-0.772454, -0.090976),
232         vec2(0.504440, 0.372295),
233         vec2(0.155736, 0.065157),
234         vec2(0.391522, 0.849605),
235         vec2(-0.620106, -0.328104),
236         vec2(0.789239, -0.419965),
237         vec2(-0.545396, 0.538133),
238         vec2(-0.178564, -0.596057)
239 );
240
241 #ifdef COLORED_SHADOWS
242
243 vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
244 {
245         float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
246         if (radius < 0.1) {
247                 // we are in the middle of even brightness, no need for filtering
248                 return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
249         }
250
251         vec2 clampedpos;
252         vec4 visibility = vec4(0.0);
253         float scale_factor = radius / f_textureresolution;
254
255         int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
256         samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
257         int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
258         int end_offset = int(samples) + init_offset;
259
260         for (int x = init_offset; x < end_offset; x++) {
261                 clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
262                 visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
263         }
264
265         return visibility / samples;
266 }
267
268 #else
269
270 float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
271 {
272         float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
273         if (radius < 0.1) {
274                 // we are in the middle of even brightness, no need for filtering
275                 return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
276         }
277
278         vec2 clampedpos;
279         float visibility = 0.0;
280         float scale_factor = radius / f_textureresolution;
281
282         int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
283         samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
284         int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
285         int end_offset = int(samples) + init_offset;
286
287         for (int x = init_offset; x < end_offset; x++) {
288                 clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
289                 visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
290         }
291
292         return visibility / samples;
293 }
294
295 #endif
296
297 #else
298 /* poisson filter disabled */
299
300 #ifdef COLORED_SHADOWS
301
302 vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
303 {
304         float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
305         if (radius < 0.1) {
306                 // we are in the middle of even brightness, no need for filtering
307                 return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
308         }
309
310         vec2 clampedpos;
311         vec4 visibility = vec4(0.0);
312         float x, y;
313         float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
314         bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
315         float scale_factor = radius / bound / f_textureresolution;
316         float n = 0.0;
317
318         // basic PCF filter
319         for (y = -bound; y <= bound; y += 1.0)
320         for (x = -bound; x <= bound; x += 1.0) {
321                 clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
322                 visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
323                 n += 1.0;
324         }
325
326         return visibility / max(n, 1.0);
327 }
328
329 #else
330 float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
331 {
332         float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
333         if (radius < 0.1) {
334                 // we are in the middle of even brightness, no need for filtering
335                 return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
336         }
337
338         vec2 clampedpos;
339         float visibility = 0.0;
340         float x, y;
341         float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
342         bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
343         float scale_factor = radius / bound / f_textureresolution;
344         float n = 0.0;
345
346         // basic PCF filter
347         for (y = -bound; y <= bound; y += 1.0)
348         for (x = -bound; x <= bound; x += 1.0) {
349                 clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
350                 visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
351                 n += 1.0;
352         }
353
354         return visibility / max(n, 1.0);
355 }
356
357 #endif
358
359 #endif
360 #endif
361
362 #if ENABLE_TONE_MAPPING
363
364 /* Hable's UC2 Tone mapping parameters
365         A = 0.22;
366         B = 0.30;
367         C = 0.10;
368         D = 0.20;
369         E = 0.01;
370         F = 0.30;
371         W = 11.2;
372         equation used:  ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
373 */
374
375 vec3 uncharted2Tonemap(vec3 x)
376 {
377         return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333;
378 }
379
380 vec4 applyToneMapping(vec4 color)
381 {
382         color = vec4(pow(color.rgb, vec3(2.2)), color.a);
383         const float gamma = 1.6;
384         const float exposureBias = 5.5;
385         color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
386         // Precalculated white_scale from
387         //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
388         vec3 whiteScale = vec3(1.036015346);
389         color.rgb *= whiteScale;
390         return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
391 }
392 #endif
393
394
395
396 void main(void)
397 {
398         vec3 color;
399         vec2 uv = varTexCoord.st;
400
401         vec4 base = texture2D(baseTexture, uv).rgba;
402         // If alpha is zero, we can just discard the pixel. This fixes transparency
403         // on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
404         // and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
405 #ifdef USE_DISCARD
406         if (base.a == 0.0)
407                 discard;
408 #endif
409 #ifdef USE_DISCARD_REF
410         if (base.a < 0.5)
411                 discard;
412 #endif
413
414         color = base.rgb;
415         vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
416
417 #ifdef ENABLE_DYNAMIC_SHADOWS
418         if (f_shadow_strength > 0.0) {
419                 float shadow_int = 0.0;
420                 vec3 shadow_color = vec3(0.0, 0.0, 0.0);
421                 vec3 posLightSpace = getLightSpacePosition();
422
423                 float distance_rate = (1.0 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 10.0));
424                 if (max(abs(posLightSpace.x - 0.5), abs(posLightSpace.y - 0.5)) > 0.5)
425                         distance_rate = 0.0;
426                 float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1,  posLightSpace.z),0.0);
427
428                 if (distance_rate > 1e-7) {
429
430 #ifdef COLORED_SHADOWS
431                         vec4 visibility;
432                         if (cosLight > 0.0 || f_normal_length < 1e-3)
433                                 visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
434                         else
435                                 visibility = vec4(1.0, 0.0, 0.0, 0.0);
436                         shadow_int = visibility.r;
437                         shadow_color = visibility.gba;
438 #else
439                         if (cosLight > 0.0 || f_normal_length < 1e-3)
440                                 shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
441                         else
442                                 shadow_int = 1.0;
443 #endif
444                         shadow_int *= distance_rate;
445                         shadow_int = clamp(shadow_int, 0.0, 1.0);
446
447                 }
448
449                 // turns out that nightRatio falls off much faster than
450                 // actual brightness of artificial light in relation to natual light.
451                 // Power ratio was measured on torches in MTG (brightness = 14).
452                 float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);
453
454                 // Apply self-shadowing when light falls at a narrow angle to the surface
455                 // Cosine of the cut-off angle.
456                 const float self_shadow_cutoff_cosine = 0.035;
457                 if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) {
458                         shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
459                         shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
460                 }
461
462                 shadow_int *= f_adj_shadow_strength;
463
464                 // calculate fragment color from components:
465                 col.rgb =
466                                 adjusted_night_ratio * col.rgb + // artificial light
467                                 (1.0 - adjusted_night_ratio) * ( // natural light
468                                                 col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) +  // filtered texture color
469                                                 dayLight * shadow_color * shadow_int);                 // reflected filtered sunlight/moonlight
470         }
471 #endif
472
473 #if ENABLE_TONE_MAPPING
474         col = applyToneMapping(col);
475 #endif
476
477         // Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
478         // the fog will only be rendered correctly if the last operation before the
479         // clamp() is an addition. Else, the clamp() seems to be ignored.
480         // E.g. the following won't work:
481         //      float clarity = clamp(fogShadingParameter
482         //              * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
483         // As additions usually come for free following a multiplication, the new formula
484         // should be more efficient as well.
485         // Note: clarity = (1 - fogginess)
486         float clarity = clamp(fogShadingParameter
487                 - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
488         col = mix(skyBgColor, col, clarity);
489         col = vec4(col.rgb, base.a);
490
491         gl_FragColor = col;
492 }