1
0
Fork 0
fgdata/Shaders/skydome.frag
2012-03-08 23:22:27 +01:00

198 lines
5.3 KiB
GLSL

#version 120
// Atmospheric scattering shader for flightgear
// Written by Lauri Peltonen (Zan)
// Implementation of O'Neil's algorithm
varying vec3 rayleigh;
varying vec3 mie;
varying vec3 eye;
varying vec3 hazeColor;
varying float ct;
//varying float cosphi;
varying float delta_z;
varying float alt;
varying float earthShade;
uniform float overcast;
uniform float saturation;
uniform float visibility;
uniform float avisibility;
uniform float scattering;
const float EarthRadius = 5800000.0;
float miePhase(in float cosTheta, in float g)
{
float g2 = g*g;
float a = 1.5 * (1.0 - g2);
float b = (2.0 + g2);
float c = 1.0 + cosTheta*cosTheta;
float d = pow(1.0 + g2 - 2.0 * g * cosTheta, 0.6667);
return (a*c) / (b*d);
}
float rayleighPhase(in float cosTheta)
{
//return 1.5 * (1.0 + cosTheta*cosTheta);
return 1.5 * (2.0 + 0.5*cosTheta*cosTheta);
}
void main()
{
float cosTheta = dot(normalize(eye), gl_LightSource[0].position.xyz);
// position of the horizon line
float lAltitude = alt + delta_z;
float radiusEye = EarthRadius + alt;
float radiusLayer = EarthRadius + lAltitude;
float cthorizon;
float ctterrain;
if (radiusEye > radiusLayer) cthorizon = -sqrt(radiusEye * radiusEye - radiusLayer * radiusLayer)/radiusEye;
else cthorizon = sqrt(radiusLayer * radiusLayer - radiusEye * radiusEye)/radiusLayer;
ctterrain = -sqrt(radiusEye * radiusEye - EarthRadius * EarthRadius)/radiusEye;
vec3 color = rayleigh * rayleighPhase(cosTheta);
color += mie * miePhase(cosTheta, -0.8);
vec3 black = vec3(0.0,0.0,0.0);
float ovc = overcast;
float sat = 1.0 - ((1.0 - saturation) * 2.0);
if (sat < 0.3) sat = 0.3;
// float wscale = 1.732;
// an overexposure filter, the log() seems to be pretty expensive though
// if (color.x > 0.8) color.x = 0.8 + 0.8* log(color.x/0.8);
// if (color.y > 0.8) color.y = 0.8 + 0.8* log(color.y/0.8);
// if (color.z > 0.8) color.z = 0.8 + 0.8* log(color.z/0.8);
//vec3 fogColor = vec3 (gl_Fog.color.x, gl_Fog.color.y, gl_Fog.color.z);
// reduce the whiteout near the horizon generated by the single scattering approximation
if (ct > cthorizon) color = mix(color, black ,smoothstep(0.2+cthorizon, -0.2+cthorizon, ct));
else color = mix (color, black, smoothstep(0.2+cthorizon,-0.2+cthorizon, cthorizon));
// fog computations for a ground haze layer, extending from zero to lAltitude
float transmission;
float vAltitude;
float delta_zv;
float costheta = ct;
float vis= visibility;
// hack - in an effect volume the visibility only may be reduced, so we take care here
if (avisibility < visibility){vis = avisibility;}
if (delta_z > 0.0) // we're inside the layer
{
if (costheta>0.0 + ctterrain) // looking up, view ray intersecting upper layer edge
{
transmission = exp(-min((delta_z/max(costheta,0.1)),25000.0)/vis);
//transmission = 1.0;
vAltitude = min(vis * costheta, delta_z);
delta_zv = delta_z - vAltitude;
}
else // looking down, view range intersecting terrain (which may not be drawn)
{
transmission = exp(alt/vis/costheta);
vAltitude = min(-vis * costheta, alt);
delta_zv = delta_z + vAltitude;
}
}
else // we see the layer from above
{
if (costheta < 0.0 + cthorizon)
{
transmission = exp(-min(lAltitude/abs(costheta),25000.0)/vis);
transmission = transmission * exp(-alt/avisibility/abs(costheta));
transmission = 1.0 - (1.0 - transmission) * smoothstep(0+cthorizon, -0.02+cthorizon, costheta);
vAltitude = min(lAltitude, -vis * costheta);
delta_zv = vAltitude;
}
else
{
transmission = 1.0;
delta_zv = 0.0;
}
}
// combined intensity reduction by cloud shading and fog self-shading, corrected for Weber-Fechner perception law
float eqColorFactor;
eqColorFactor = 1.0 - 0.1 * delta_zv/vis - (1.0 -scattering);
// there's always residual intensity, we should never be driven to zero
if (eqColorFactor < 0.2) eqColorFactor = 0.2;
// postprocessing of haze color
vec3 hColor = hazeColor;
// high altitude desaturation
float intensity = length(hColor);
hColor = intensity * normalize (mix(hColor, intensity * vec3 (1.0,1.0,1.0), 0.7* smoothstep(5000.0, 50000.0, alt)));
// blue hue
hColor.x = 0.83 * hColor.x;
hColor.y = 0.9 * hColor.y;
// further blueshift when in shadow, either cloud shadow, or self-shadow or Earth shadow, dependent on indirect
// light
float fade_out = max(0.65 - 0.3 *overcast, 0.45);
intensity = length(hColor);
hColor = intensity * normalize(mix(hColor, 1.5* vec3 (0.45, 0.6, 0.8), 1.0 -smoothstep(0.25, fade_out,earthShade) ));
hColor = intensity * normalize(mix(hColor, 2.0 * vec3 (0.55, 0.6, 0.8), (1.0 - smoothstep(0.3,0.8,eqColorFactor))));
hColor = hColor * earthShade;
// accounting for overcast and saturation
color = ovc * mix(color, hazeColor * earthShade ,smoothstep(-0.1+ctterrain, 0.0+ctterrain, ct)) + (1-ovc) * color;
color = sat * color + (1.0 - sat) * mix(color, black, smoothstep(0.4+cthorizon,0.2+cthorizon,ct));
// the terrain below the horizon gets drawn in one optical thickness
vec3 terrainHazeColor = eqColorFactor * hColor;
color = mix(color, terrainHazeColor ,smoothstep(0.01 + ctterrain, 0.0+ctterrain, ct));
// mix fog the skydome with the right amount of haze
color = transmission * color + (1.0-transmission) * eqColorFactor * hColor;
gl_FragColor = vec4(color, 1.0);
gl_FragDepth = 0.1;
}