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