73 lines
2.4 KiB
GLSL
73 lines
2.4 KiB
GLSL
#version 330 core
|
|
|
|
uniform sampler2D aerial_perspective_lut;
|
|
uniform sampler2D transmittance_lut;
|
|
|
|
uniform float fg_SunZenithCosTheta;
|
|
uniform float fg_CameraDistanceToEarthCenter;
|
|
uniform float fg_EarthRadius;
|
|
|
|
const float AERIAL_SLICES = 32.0;
|
|
const float AERIAL_LUT_TILE_SIZE = 1.0 / AERIAL_SLICES;
|
|
const float AERIAL_LUT_TEXEL_SIZE = 1.0 / 1024.0;
|
|
const float AERIAL_MAX_DEPTH = 128000.0;
|
|
const vec3 EXTRATERRESTRIAL_SOLAR_ILLUMINANCE = vec3(128.0);
|
|
|
|
const float ATMOSPHERE_RADIUS = 6471e3;
|
|
|
|
vec4 sampleAerialPerspectiveSlice(vec2 coord, int slice)
|
|
{
|
|
// Sample at the pixel center
|
|
float offset = slice * AERIAL_LUT_TILE_SIZE + AERIAL_LUT_TEXEL_SIZE * 0.5;
|
|
float x = coord.x * (AERIAL_LUT_TILE_SIZE - AERIAL_LUT_TEXEL_SIZE) + offset;
|
|
return texture(aerial_perspective_lut, vec2(x, coord.y));
|
|
}
|
|
|
|
vec4 sampleAerialPerspective(vec2 coord, float depth)
|
|
{
|
|
vec4 color;
|
|
// Map to [0,1]
|
|
float w = depth / AERIAL_MAX_DEPTH;
|
|
// Squared distribution
|
|
w = sqrt(clamp(w, 0.0, 1.0));
|
|
w *= AERIAL_SLICES;
|
|
if (w <= 1.0) {
|
|
// Handle special case of fragments behind the first slice
|
|
color = mix(vec4(0.0, 0.0, 0.0, 1.0),
|
|
sampleAerialPerspectiveSlice(coord, 0),
|
|
w);
|
|
} else {
|
|
w -= 1.0;
|
|
// Manually interpolate between slices
|
|
color = mix(sampleAerialPerspectiveSlice(coord, int(floor(w))),
|
|
sampleAerialPerspectiveSlice(coord, int(ceil(w))),
|
|
sqrt(fract(w)));
|
|
}
|
|
return color;
|
|
}
|
|
|
|
vec3 addAerialPerspective(vec3 color, vec2 coord, float depth)
|
|
{
|
|
vec4 aerialPerspective = sampleAerialPerspective(coord, depth);
|
|
return color * aerialPerspective.a + aerialPerspective.rgb
|
|
* EXTRATERRESTRIAL_SOLAR_ILLUMINANCE;
|
|
}
|
|
|
|
/**
|
|
* Get the illuminance of the Sun for a surface perpendicular to the Sun
|
|
* direction. The illuminance is calculated at the altitude of the viewer,
|
|
* which might or might not be correct in certain circumstances. If the object
|
|
* being illuminated is not too far from the viewer it's a good enough
|
|
* approximation.
|
|
*/
|
|
vec3 getSunIntensity()
|
|
{
|
|
float normalizedHeight = (fg_CameraDistanceToEarthCenter - fg_EarthRadius)
|
|
/ (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
|
|
|
vec2 coord = vec2(fg_SunZenithCosTheta * 0.5 + 0.5,
|
|
clamp(normalizedHeight, 0.0, 1.0));
|
|
vec3 transmittance = texture(transmittance_lut, coord).rgb;
|
|
|
|
return EXTRATERRESTRIAL_SOLAR_ILLUMINANCE * transmittance;
|
|
}
|