f53a170539
We also now pre-expose our lighting before writing to the HDR buffers. This solves some precision issues and prevents the Sun from producing infinite values.
102 lines
3.5 KiB
GLSL
102 lines
3.5 KiB
GLSL
#version 330 core
|
|
|
|
layout(location = 0) out vec4 fragColor;
|
|
|
|
in vec3 ray_dir;
|
|
in vec3 ray_dir_view;
|
|
|
|
uniform bool is_envmap;
|
|
uniform sampler2D sky_view_tex;
|
|
uniform sampler2D transmittance_tex;
|
|
|
|
uniform vec3 fg_SunDirection;
|
|
uniform float fg_CameraDistanceToEarthCenter;
|
|
uniform float fg_EarthRadius;
|
|
uniform vec3 fg_CameraViewUp;
|
|
|
|
const float ATMOSPHERE_RADIUS = 6471e3;
|
|
|
|
const float SUN_HALF_ANGULAR_DIAMETER = 0.0047560222116845481; // radians(0.545 deg / 2)
|
|
const float SUN_COS_HALF_ANGULAR_DIAMETER = 0.9999886901476798392; // cos(radians(0.545 deg / 2))
|
|
const float SUN_SIN_HALF_ANGULAR_DIAMETER = 0.0047560042817014138; // sin(radians(0.545 deg / 2))
|
|
|
|
// math.glsl
|
|
float M_PI();
|
|
float sqr(float x);
|
|
float saturate(float x);
|
|
// atmos_spectral.glsl
|
|
vec4 get_sun_spectral_irradiance();
|
|
vec3 linear_srgb_from_spectral_samples(vec4 L);
|
|
// exposure.glsl
|
|
vec3 apply_exposure(vec3 color);
|
|
|
|
/*
|
|
* Limb darkening
|
|
* http://www.physics.hmc.edu/faculty/esin/a101/limbdarkening.pdf
|
|
*/
|
|
vec4 get_sun_darkening_factor(float cos_theta)
|
|
{
|
|
// Coefficients sampled for wavelengths 630, 560, 490, 430 nm
|
|
const vec4 u = vec4(1.0);
|
|
const vec4 alpha = vec4(0.429, 0.502, 0.575, 0.643);
|
|
float sin_theta = sqrt(1.0 - sqr(cos_theta));
|
|
float center_to_edge = saturate(sin_theta / SUN_SIN_HALF_ANGULAR_DIAMETER);
|
|
float mu = sqrt(1.0 - sqr(center_to_edge));
|
|
vec4 factor = vec4(1.0) - u * (vec4(1.0) - pow(vec4(mu), alpha));
|
|
return factor;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
vec3 ray_dir = normalize(ray_dir);
|
|
float azimuth = atan(ray_dir.y, ray_dir.x) / M_PI() * 0.5 + 0.5;
|
|
// Undo the non-linear transformation from the sky-view LUT
|
|
float l = asin(ray_dir.z);
|
|
float elev = sqrt(abs(l) / (M_PI() * 0.5)) * sign(l) * 0.5 + 0.5;
|
|
|
|
vec4 sky_radiance = texture(sky_view_tex, vec2(azimuth, elev));
|
|
// When computing the sky texture we assumed an unitary light source.
|
|
// Now multiply by the sun irradiance.
|
|
sky_radiance *= get_sun_spectral_irradiance();
|
|
|
|
if (is_envmap == false) {
|
|
// Render the Sun disk
|
|
vec3 vs_ray_dir = normalize(ray_dir_view);
|
|
float cos_theta = dot(vs_ray_dir, fg_SunDirection);
|
|
|
|
if (cos_theta >= SUN_COS_HALF_ANGULAR_DIAMETER) {
|
|
float normalized_altitude =
|
|
(fg_CameraDistanceToEarthCenter - fg_EarthRadius)
|
|
/ (ATMOSPHERE_RADIUS - fg_EarthRadius);
|
|
|
|
float sun_zenith_cos_theta = dot(-vs_ray_dir, fg_CameraViewUp);
|
|
|
|
vec2 uv = vec2(sun_zenith_cos_theta * 0.5 + 0.5,
|
|
clamp(normalized_altitude, 0.0, 1.0));
|
|
vec4 transmittance = texture(transmittance_tex, uv);
|
|
|
|
vec4 darkening_factor = get_sun_darkening_factor(cos_theta);
|
|
|
|
// To get the actual sun radiance we should divide the irradiance
|
|
// by the solid angle subtended by the Sun, but the resulting
|
|
// radiance is too big to store in an rgb16f buffer. Also the bloom
|
|
// gets blown out too much.
|
|
// Instead, just multiply by a fixed value that looks good enough.
|
|
vec4 sun_radiance = get_sun_spectral_irradiance() * 500.0;
|
|
|
|
sun_radiance *= transmittance * darkening_factor;
|
|
|
|
sky_radiance += sun_radiance;
|
|
}
|
|
}
|
|
|
|
vec3 sky_color = linear_srgb_from_spectral_samples(sky_radiance);
|
|
|
|
if (is_envmap == false) {
|
|
// Only pre-expose when not rendering to the environment map.
|
|
// We want the non-exposed radiance values for IBL.
|
|
sky_color = apply_exposure(sky_color);
|
|
}
|
|
|
|
fragColor = vec4(sky_color, 1.0);
|
|
}
|