1// -*-C++-*-
2#version 120
3
4// written by Thorsten Renk, Oct 2011, based on default.frag
5// Ambient term comes in gl_Color.rgb.
6varying vec4 diffuse_term;
7varying vec3 normal;
8varying vec3 relPos;
9
10
11uniform float fg_Fcoef;
12
13uniform sampler2D texture;
14
15
16varying float yprime_alt;
17varying float mie_angle;
18
19varying float flogz;
20
21
22uniform float visibility;
23uniform float avisibility;
24uniform float scattering;
25uniform float terminator;
26uniform float terrain_alt;
27uniform float hazeLayerAltitude;
28uniform float overcast;
29uniform float eye_alt;
30uniform float cloud_self_shading;
31
32const float EarthRadius = 5800000.0;
33const float terminator_width = 200000.0;
34
35float alt;
36float eShade;
37
38float fog_func (in float targ, in float alt);
39vec3 get_hazeColor(in float light_arg);
40vec3 filter_combined (in vec3 color) ;
41
42float getShadowing();
43
44float luminance(vec3 color)
45{
46    return dot(vec3(0.212671, 0.715160, 0.072169), color);
47}
48
49
50
51void main()
52{
53
54  vec3 shadedFogColor = vec3(0.55, 0.67, 0.88);
55// this is taken from default.frag
56    vec3 n;
57    float NdotL, NdotHV, fogFactor;
58    vec4 color = gl_Color;
59    vec3 lightDir = gl_LightSource[0].position.xyz;
60    vec3 halfVector = gl_LightSource[0].halfVector.xyz;
61    vec4 texel;
62    vec4 fragColor;
63    vec4 specular = vec4(0.0);
64    float intensity;
65
66    float effective_scattering = min(scattering, cloud_self_shading);
67
68
69    vec4 light_specular = gl_LightSource[0].specular;
70
71    // If gl_Color.a == 0, this is a back-facing polygon and the
72    // normal should be reversed.
73    n = (2.0 * gl_Color.a - 1.0) * normal;
74    n = normalize(n);
75
76    NdotL = dot(n, lightDir);
77    if (NdotL > 0.0) {
78        float shadowmap = getShadowing();
79        color += diffuse_term * NdotL * shadowmap;
80        NdotHV = max(dot(n, halfVector), 0.0);
81        if (gl_FrontMaterial.shininess > 0.0)
82            specular.rgb = (gl_FrontMaterial.specular.rgb
83                            * light_specular.rgb
84                            * pow(NdotHV, gl_FrontMaterial.shininess)
85                            * shadowmap);
86    }
87    color.a = diffuse_term.a;
88    // This shouldn't be necessary, but our lighting becomes very
89    // saturated. Clamping the color before modulating by the texture
90    // is closer to what the OpenGL fixed function pipeline does.
91    color = clamp(color, 0.0, 1.0);
92    texel = texture2D(texture, gl_TexCoord[0].st);
93    fragColor = color * texel + specular;
94
95
96
97// here comes the terrain haze model
98
99
100float delta_z = hazeLayerAltitude - eye_alt;
101float dist = length(relPos);
102
103float mvisibility = min(visibility,avisibility);
104
105if (dist > 0.04 * mvisibility)
106{
107
108alt = eye_alt;
109
110
111float transmission;
112float vAltitude;
113float delta_zv;
114float H;
115float distance_in_layer;
116float transmission_arg;
117
118// angle with horizon
119float ct = dot(vec3(0.0, 0.0, 1.0), relPos)/dist;
120
121
122// we solve the geometry what part of the light path is attenuated normally and what is through the haze layer
123
124if (delta_z > 0.0) // we're inside the layer
125	{
126	if (ct < 0.0) // we look down
127		{
128		distance_in_layer = dist;
129		vAltitude = min(distance_in_layer,mvisibility) * ct;
130  		delta_zv = delta_z - vAltitude;
131		}
132	else 	// we may look through upper layer edge
133		{
134		H = dist * ct;
135		if (H > delta_z) {distance_in_layer = dist/H * delta_z;}
136		else {distance_in_layer = dist;}
137		vAltitude = min(distance_in_layer,visibility) * ct;
138  		delta_zv = delta_z - vAltitude;
139		}
140	}
141  else // we see the layer from above, delta_z < 0.0
142	{
143	H = dist * -ct;
144	if (H  < (-delta_z)) // we don't see into the layer at all, aloft visibility is the only fading
145		{
146		distance_in_layer = 0.0;
147		delta_zv = 0.0;
148		}
149	else
150		{
151		vAltitude = H + delta_z;
152		distance_in_layer = vAltitude/H * dist;
153		vAltitude = min(distance_in_layer,visibility) * (-ct);
154		delta_zv = vAltitude;
155		}
156	}
157
158
159// ground haze cannot be thinner than aloft visibility in the model,
160// so we need to use aloft visibility otherwise
161
162
163transmission_arg = (dist-distance_in_layer)/avisibility;
164
165
166float eqColorFactor;
167
168
169
170if (visibility < avisibility)
171	{
172	transmission_arg = transmission_arg + (distance_in_layer/visibility);
173	// this combines the Weber-Fechner intensity
174	eqColorFactor = 1.0 - 0.1 * delta_zv/visibility - (1.0 -effective_scattering);
175
176	}
177else
178	{
179	transmission_arg = transmission_arg + (distance_in_layer/avisibility);
180	// this combines the Weber-Fechner intensity
181	eqColorFactor = 1.0 - 0.1 * delta_zv/avisibility - (1.0 -effective_scattering);
182	}
183
184
185
186transmission =  fog_func(transmission_arg, alt);
187
188// there's always residual intensity, we should never be driven to zero
189if (eqColorFactor < 0.2) {eqColorFactor = 0.2;}
190
191
192float lightArg = (terminator-yprime_alt)/100000.0;
193vec3 hazeColor = get_hazeColor(lightArg);
194
195
196
197// now dim the light for haze
198eShade = 1.0 - 0.9 * smoothstep(-terminator_width+ terminator, terminator_width + terminator, yprime_alt);
199
200// Mie-like factor
201
202if (lightArg < 10.0)
203	{intensity = length(hazeColor);
204	float mie_magnitude = 0.5 * smoothstep(350000.0, 150000.0, terminator-sqrt(2.0 * EarthRadius * terrain_alt));
205	hazeColor = intensity * ((1.0 - mie_magnitude) + mie_magnitude * mie_angle) * normalize(mix(hazeColor,  vec3 (0.5, 0.58, 0.65), mie_magnitude * (0.5 - 0.5 * mie_angle)) );
206	}
207
208// high altitude desaturation of the haze color
209
210intensity = length(hazeColor);
211hazeColor = intensity * normalize (mix(hazeColor, intensity * vec3 (1.0,1.0,1.0), 0.7* smoothstep(5000.0, 50000.0, alt)));
212
213// blue hue of haze
214
215hazeColor.x = hazeColor.x * 0.83;
216hazeColor.y = hazeColor.y * 0.9;
217
218
219// additional blue in indirect light
220float fade_out = max(0.65 - 0.3 *overcast, 0.45);
221intensity = length(hazeColor);
222hazeColor = intensity * normalize(mix(hazeColor,  1.5* shadedFogColor, 1.0 -smoothstep(0.25, fade_out,eShade) ));
223
224// change haze color to blue hue for strong fogging
225//intensity = length(hazeColor);
226hazeColor = intensity * normalize(mix(hazeColor,  shadedFogColor, (1.0-smoothstep(0.5,0.9,eqColorFactor))));
227
228
229// reduce haze intensity when looking at shaded surfaces, only in terminator region
230
231float shadow = mix( min(1.0 + dot(normal,lightDir),1.0), 1.0, 1.0-smoothstep(0.1, 0.4, transmission));
232hazeColor = mix(shadow * hazeColor, hazeColor, 0.3 + 0.7* smoothstep(250000.0, 400000.0, terminator));
233
234
235
236
237// don't let the light fade out too rapidly
238lightArg = (terminator + 200000.0)/100000.0;
239float minLightIntensity = min(0.2,0.16 * lightArg + 0.5);
240vec3 minLight = minLightIntensity * vec3 (0.2, 0.3, 0.4);
241hazeColor *= eqColorFactor * eShade;
242hazeColor.rgb = max(hazeColor.rgb, minLight.rgb);
243
244// determine the right mix of transmission and haze
245
246fragColor.rgb = mix(hazeColor, fragColor.rgb,transmission);
247}
248
249fragColor.rgb = filter_combined(fragColor.rgb);
250
251gl_FragColor = fragColor;
252// logarithmic depth
253gl_FragDepth = log2(flogz) * fg_Fcoef * 0.5;
254}
255
256