Tentative fix for high altitude/low sun rendering artefacts in ALS skydome
[fg:toms-fgdata.git] / Shaders / skydome.frag
1 #version 120\r
2  \r
3 // Atmospheric scattering shader for flightgear\r
4 // Written by Lauri Peltonen (Zan)\r
5 // Implementation of O'Neil's algorithm\r
6 // Ground haze layer added by Thorsten Renk\r
7  \r
8 varying vec3 rayleigh;\r
9 varying vec3 mie;\r
10 varying vec3 eye;\r
11 varying vec3 hazeColor;\r
12 varying float ct;\r
13 varying float cphi;\r
14 varying float delta_z;\r
15 varying float alt;\r
16 varying float earthShade;\r
17  \r
18 uniform float overcast;\r
19 uniform float saturation;\r
20 uniform float visibility;\r
21 uniform float avisibility;\r
22 uniform float scattering;\r
23 uniform float cloud_self_shading;\r
24 uniform float horizon_roughness;\r
25 \r
26 const float EarthRadius = 5800000.0;\r
27 \r
28 float miePhase(in float cosTheta, in float g)\r
29 {\r
30   float g2 = g*g;\r
31   float a = 1.5 * (1.0 - g2);\r
32   float b = (2.0 + g2);\r
33   float c = 1.0 + cosTheta*cosTheta;\r
34   float d = pow(1.0 + g2 - 2.0 * g * cosTheta, 0.6667);\r
35  \r
36   return (a*c) / (b*d);\r
37 }\r
38  \r
39 float rayleighPhase(in float cosTheta)\r
40 {\r
41   //return 1.5 * (1.0 + cosTheta*cosTheta);\r
42   return 1.5 * (2.0 + 0.5*cosTheta*cosTheta);\r
43 }\r
44  \r
45 float rand2D(in vec2 co){\r
46     return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\r
47 }\r
48 \r
49 float simple_interpolate(in float a, in float b, in float x)\r
50 {\r
51 return a + smoothstep(0.0,1.0,x) * (b-a);\r
52 }\r
53 \r
54 float interpolatedNoise2D(in float x, in float y)\r
55 {\r
56       float integer_x    = x - fract(x);\r
57       float fractional_x = x - integer_x;\r
58 \r
59       float integer_y    = y - fract(y);\r
60       float fractional_y = y - integer_y;\r
61 \r
62       float v1 = rand2D(vec2(integer_x, integer_y));\r
63       float v2 = rand2D(vec2(integer_x+1.0, integer_y));\r
64       float v3 = rand2D(vec2(integer_x, integer_y+1.0));\r
65       float v4 = rand2D(vec2(integer_x+1.0, integer_y +1.0));\r
66 \r
67       float i1 = simple_interpolate(v1 , v2 , fractional_x);\r
68       float i2 = simple_interpolate(v3 , v4 , fractional_x);\r
69 \r
70       return simple_interpolate(i1 , i2 , fractional_y);\r
71 }\r
72  \r
73 float Noise2D(in vec2 coord, in float wavelength)\r
74 {\r
75 return interpolatedNoise2D(coord.x/wavelength, coord.y/wavelength);\r
76 \r
77 }\r
78  \r
79 void main()\r
80 {\r
81 \r
82   vec3 shadedFogColor = vec3(0.65, 0.67, 0.78);\r
83   float cosTheta = dot(normalize(eye), gl_LightSource[0].position.xyz);\r
84  \r
85   // position of the horizon line\r
86 \r
87   float lAltitude = alt + delta_z;\r
88   float radiusEye = EarthRadius + alt;\r
89   float radiusLayer = EarthRadius + lAltitude;\r
90   float cthorizon;\r
91   float ctterrain;\r
92 \r
93   if (radiusEye > radiusLayer) cthorizon = -sqrt(radiusEye * radiusEye - radiusLayer * radiusLayer)/radiusEye;\r
94   else cthorizon = sqrt(radiusLayer * radiusLayer - radiusEye * radiusEye)/radiusLayer;\r
95 \r
96   ctterrain = -sqrt(radiusEye * radiusEye - EarthRadius * EarthRadius)/radiusEye;\r
97 \r
98   vec3 color = rayleigh * rayleighPhase(cosTheta);\r
99   color += mie * miePhase(cosTheta, -0.8);\r
100 \r
101   vec3 black = vec3(0.0,0.0,0.0);\r
102 \r
103   \r
104   float ovc = overcast;\r
105 \r
106 \r
107 \r
108   float sat = 1.0 - ((1.0 - saturation) * 2.0);\r
109   if (sat < 0.3) sat = 0.3;\r
110 \r
111 \r
112   \r
113 \r
114 if (color.r > 0.58) color.r = 1.0 - exp(-1.5 * color.r);\r
115 if (color.g > 0.58) color.g = 1.0 - exp(-1.5 * color.g);\r
116 if (color.b > 0.58) color.b = 1.0 - exp(-1.5 * color.b);\r
117   \r
118 \r
119 \r
120 // fog computations for a ground haze layer, extending from zero to lAltitude\r
121 \r
122 \r
123 \r
124 float transmission;\r
125 float vAltitude;\r
126 float delta_zv;\r
127 \r
128 float costheta = ct;\r
129 \r
130 float vis = min(visibility, avisibility);\r
131 \r
132 \r
133  if (delta_z > 0.0) // we're inside the layer\r
134         {\r
135         if (costheta>0.0 + ctterrain) // looking up, view ray intersecting upper layer edge\r
136                 {\r
137                 transmission  = exp(-min((delta_z/max(costheta,0.1)),25000.0)/vis);\r
138                 //transmission = 1.0;\r
139                 vAltitude = min(vis * costheta, delta_z);\r
140                 delta_zv = delta_z - vAltitude;\r
141                 }\r
142 \r
143         else // looking down, view range intersecting terrain (which may not be drawn)\r
144                 {\r
145                 transmission = exp(alt/vis/costheta);\r
146                 vAltitude = min(-vis * costheta, alt);\r
147                 delta_zv = delta_z + vAltitude;\r
148                 }\r
149         }\r
150   else // we see the layer from above\r
151         {       \r
152         if (costheta < 0.0 + cthorizon) \r
153                 {\r
154                 transmission = exp(-min(lAltitude/abs(costheta),25000.0)/vis);\r
155                 transmission = transmission * exp(-alt/avisibility/abs(costheta));\r
156                 transmission = 1.0 - (1.0 - transmission) * smoothstep(0+cthorizon, -0.02+cthorizon, costheta);\r
157                 vAltitude = min(lAltitude, -vis * costheta);\r
158                 delta_zv = vAltitude; \r
159                 }\r
160         else\r
161                 {       \r
162                 transmission = 1.0;\r
163                 delta_zv = 0.0;\r
164                 }\r
165         }\r
166 \r
167 // combined intensity reduction by cloud shading and fog self-shading, corrected for Weber-Fechner perception law\r
168 float eqColorFactor = 1.0 - 0.1 * delta_zv/vis - (1.0 - min(scattering,cloud_self_shading));\r
169 \r
170 \r
171 // there's always residual intensity, we should never be driven to zero\r
172 if (eqColorFactor < 0.2) eqColorFactor = 0.2;\r
173 \r
174 \r
175 // postprocessing of haze color\r
176 vec3 hColor = hazeColor;\r
177 \r
178 \r
179 // high altitude desaturation\r
180 float intensity = length(hColor);\r
181 hColor = intensity * normalize (mix(hColor, intensity * vec3 (1.0,1.0,1.0), 0.7 * smoothstep(5000.0, 50000.0, alt)));\r
182 \r
183 hColor = clamp(hColor,0.0,1.0);\r
184 \r
185 // blue hue\r
186 hColor.x = 0.83 * hColor.x;\r
187 hColor.y = 0.9 * hColor.y;\r
188 \r
189 \r
190 \r
191 // further blueshift when in shadow, either cloud shadow, or self-shadow or Earth shadow, dependent on indirect \r
192 // light\r
193 \r
194 float fade_out = max(0.65 - 0.3 *overcast, 0.45);\r
195 intensity = length(hColor);\r
196 vec3 oColor = hColor;\r
197 oColor = intensity * normalize(mix(oColor,  shadedFogColor, (smoothstep(0.1,1.0,ovc)))); \r
198 oColor = clamp(oColor,0.0,1.0);\r
199 color = ovc *  mix(color, oColor * earthShade ,smoothstep(-0.1+ctterrain, 0.0+ctterrain, ct)) + (1.0-ovc) * color; \r
200 \r
201 \r
202 hColor = intensity * normalize(mix(hColor,  1.5 * shadedFogColor, 1.0 -smoothstep(0.25, fade_out,earthShade) ));\r
203 hColor = intensity * normalize(mix(hColor,  shadedFogColor, (1.0 - smoothstep(0.5,0.9,eqColorFactor)))); \r
204 hColor = hColor * earthShade;\r
205 \r
206 // accounting for overcast and saturation \r
207 \r
208 \r
209 \r
210 color = sat * color + (1.0 - sat) * mix(color, black, smoothstep(0.4+cthorizon,0.2+cthorizon,ct));\r
211 \r
212 \r
213 // the terrain below the horizon gets drawn in one optical thickness\r
214 vec3 terrainHazeColor = eqColorFactor * hColor; \r
215 \r
216 // determine a visibility-dependent angle for how smoothly the haze blends over the skydome\r
217 \r
218 float hazeBlendAngle = max(0.01,1000.0/avisibility + 0.3 * (1.0 - smoothstep(5000.0, 30000.0, avisibility)));\r
219 float altFactor = smoothstep(-300.0, 0.0, delta_z);\r
220 float altFactor2 =  0.2 + 0.8 * smoothstep(-3000.0, 0.0, delta_z);\r
221 hazeBlendAngle = hazeBlendAngle + 0.1 * altFactor;\r
222 hazeBlendAngle = hazeBlendAngle +  (1.0-horizon_roughness) * altFactor2 * 0.1 *  Noise2D(vec2(0.0,cphi), 0.3);\r
223 \r
224 terrainHazeColor = clamp(terrainHazeColor,0.0,1.0);\r
225 color = mix(color, terrainHazeColor ,smoothstep(hazeBlendAngle + ctterrain, 0.0+ctterrain, ct));\r
226 \r
227 \r
228 // mix fog the skydome with the right amount of haze\r
229 \r
230 hColor = clamp(hColor,0.0,1.0);\r
231 color = transmission * color  + (1.0-transmission) * eqColorFactor * hColor;\r
232 \r
233 \r
234   gl_FragColor = vec4(color, 1.0);\r
235   gl_FragDepth = 0.1;\r
236 \r
237 }\r
238 \r