Filmic HDR tone mapping
[oweals/minetest.git] / client / shaders / nodes_shader / opengl_fragment.glsl
1 uniform sampler2D baseTexture;
2 uniform sampler2D normalTexture;
3 uniform sampler2D textureFlags;
4
5 uniform vec4 skyBgColor;
6 uniform float fogDistance;
7 uniform vec3 eyePosition;
8
9 varying vec3 vPosition;
10 varying vec3 worldPosition;
11 varying float area_enable_parallax;
12
13 varying vec3 eyeVec;
14 varying vec3 tsEyeVec;
15 varying vec3 lightVec;
16 varying vec3 tsLightVec;
17
18 bool normalTexturePresent = false;
19
20 const float e = 2.718281828459;
21 const float BS = 10.0;
22
23 #ifdef ENABLE_TONE_MAPPING
24
25 /* Hable's UC2 Tone mapping parameters
26         A = 0.22;
27         B = 0.30;
28         C = 0.10;
29         D = 0.20;
30         E = 0.01;
31         F = 0.30;
32         W = 11.2;
33         equation used:  ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
34 */
35
36 vec3 uncharted2Tonemap(vec3 x)
37 {
38         return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03334;
39 }
40
41 vec4 applyToneMapping(vec4 color)
42 {
43         color = vec4(pow(color.rgb, vec3(2.2)), color.a);
44         const float gamma = 1.6;
45         const float exposureBias = 5.5;
46         color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
47         // Precalculated white_scale from 
48         //vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
49         vec3 whiteScale = vec3(1.036015346);
50         color.rgb *= whiteScale;
51         return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
52 }
53 #endif
54
55 void get_texture_flags()
56 {
57         vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
58         if (flags.r > 0.5) {
59                 normalTexturePresent = true;
60         }
61 }
62
63 float intensity(vec3 color)
64 {
65         return (color.r + color.g + color.b) / 3.0;
66 }
67
68 float get_rgb_height(vec2 uv)
69 {
70         return intensity(texture2D(baseTexture, uv).rgb);
71 }
72
73 vec4 get_normal_map(vec2 uv)
74 {
75         vec4 bump = texture2D(normalTexture, uv).rgba;
76         bump.xyz = normalize(bump.xyz * 2.0 - 1.0);
77         return bump;
78 }
79
80 float find_intersection(vec2 dp, vec2 ds)
81 {
82         float depth = 1.0;
83         float best_depth = 0.0;
84         float size = 0.0625;
85         for (int i = 0; i < 15; i++) {
86                 depth -= size;
87                 float h = texture2D(normalTexture, dp + ds * depth).a;
88                 if (depth <= h) {
89                         best_depth = depth;
90                         break;
91                 }
92         }
93         depth = best_depth;
94         for (int i = 0; i < 4; i++) {
95                 size *= 0.5;
96                 float h = texture2D(normalTexture,dp + ds * depth).a;
97                 if (depth <= h) {
98                         best_depth = depth;
99                         depth += size;
100                 } else {
101                         depth -= size;
102                 }
103         }
104         return best_depth;
105 }
106
107 float find_intersectionRGB(vec2 dp, vec2 ds)
108 {
109         const float depth_step = 1.0 / 24.0;
110         float depth = 1.0;
111         for (int i = 0 ; i < 24 ; i++) {
112                 float h = get_rgb_height(dp + ds * depth);
113                 if (h >= depth)
114                         break;
115                 depth -= depth_step;
116         }
117         return depth;
118 }
119
120 void main(void)
121 {
122         vec3 color;
123         vec4 bump;
124         vec2 uv = gl_TexCoord[0].st;
125         bool use_normalmap = false;
126         get_texture_flags();
127
128 #ifdef ENABLE_PARALLAX_OCCLUSION
129         vec2 eyeRay = vec2 (tsEyeVec.x, -tsEyeVec.y);
130         const float scale = PARALLAX_OCCLUSION_SCALE / PARALLAX_OCCLUSION_ITERATIONS;
131         const float bias = PARALLAX_OCCLUSION_BIAS / PARALLAX_OCCLUSION_ITERATIONS;
132
133 #if PARALLAX_OCCLUSION_MODE == 0
134         // Parallax occlusion with slope information
135         if (normalTexturePresent && area_enable_parallax > 0.0) {
136                 for (int i = 0; i < PARALLAX_OCCLUSION_ITERATIONS; i++) {
137                         vec4 normal = texture2D(normalTexture, uv.xy);
138                         float h = normal.a * scale - bias;
139                         uv += h * normal.z * eyeRay;
140                 }
141 #endif
142
143 #if PARALLAX_OCCLUSION_MODE == 1
144         // Relief mapping
145         if (normalTexturePresent && area_enable_parallax > 0.0) {
146                 vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE;
147                 float dist = find_intersection(uv, ds);
148                 uv += dist * ds;
149 #endif
150         } else if (GENERATE_NORMALMAPS == 1 && area_enable_parallax > 0.0) {
151                 vec2 ds = eyeRay * PARALLAX_OCCLUSION_SCALE;
152                 float dist = find_intersectionRGB(uv, ds);
153                 uv += dist * ds;
154         }
155 #endif
156
157 #if USE_NORMALMAPS == 1
158         if (normalTexturePresent) {
159                 bump = get_normal_map(uv);
160                 use_normalmap = true;
161         }
162 #endif
163
164         if (GENERATE_NORMALMAPS == 1 && normalTexturePresent == false) {
165                 float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP));
166                 float t  = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP));
167                 float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP));
168                 float r  = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y));
169                 float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP));
170                 float b  = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP));
171                 float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP));
172                 float l  = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y));
173                 float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
174                 float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
175                 bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0);
176                 use_normalmap = true;
177         }
178
179         vec4 base = texture2D(baseTexture, uv).rgba;
180
181 #ifdef ENABLE_BUMPMAPPING
182         if (use_normalmap) {
183                 vec3 L = normalize(lightVec);
184                 vec3 E = normalize(eyeVec);
185                 float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0);
186                 float diffuse = dot(-E,bump.xyz);
187                 color = (diffuse + 0.1 * specular) * base.rgb;
188         } else {
189                 color = base.rgb;
190         }
191 #else
192         color = base.rgb;
193 #endif
194
195         vec4 col = vec4(color.rgb * gl_Color.rgb, 1.0); 
196         
197 #if MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_OPAQUE
198         float alpha = gl_Color.a;
199         if (fogDistance != 0.0) {
200                 float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
201                 alpha = mix(alpha, 0.0, d);
202         }
203         col = vec4(col.rgb, alpha);
204 #else
205         if (fogDistance != 0.0) {
206                 float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
207                 col = mix(col, skyBgColor, d);
208         }
209         col = vec4(col.rgb, base.a);
210 #endif
211
212 #ifdef ENABLE_TONE_MAPPING
213         gl_FragColor = applyToneMapping(col);
214 #else
215         gl_FragColor = col;
216 #endif
217 }