1
0
Fork 0
fgdata/Shaders/HDR/atmos-include.frag
Fernando García Liñán 9b9ae5cf38 HDR pipeline: even better atmospheric scattering
Implementation of "A Scalable and Production Ready Sky and Atmosphere Rendering Technique" by Sébastien Hillaire (2020).
2021-07-28 09:40:04 +02:00

78 lines
2.8 KiB
GLSL

// An implementation of Sébastien Hillaire's "A Scalable and Production Ready
// Sky and Atmosphere Rendering Technique".
#version 330 core
const float PI = 3.141592653;
// Atmosphere parameters
// Section 2.1 of [Bruneton08], units are inverse meters
const float mie_density_height_scale = 8.33333e-4; // Hm=1.2km
const float rayleigh_density_height_scale = 1.25e-4; // Hr=8km
const float mie_scattering = 3.996e-6;
const float mie_absorption = 4.4e-6;
const vec3 rayleigh_scattering = vec3(5.802, 13.558, 33.1) * vec3(1e-6);
const vec3 ozone_absorption = vec3(0.650, 1.881, 0.085) * vec3(1e-6);
const float g = 0.8;
const float gg = g*g;
const float mie_phase_scale = 3.0/(8.0*PI);
const float rayleigh_phase_scale = 3.0/(16.0*PI);
// Returns the distance between ro and the first intersection with the sphere
// or -1.0 if there is no intersection.
// -1.0 is also returned if the ray is pointing away from the sphere.
float raySphereIntersection(vec3 ro, vec3 rd, float radius)
{
float b = dot(ro, rd);
float c = dot(ro, ro) - radius*radius;
if (c > 0.0 && b > 0.0) return -1.0;
float d = b*b - c;
if (d < 0.0) return -1.0;
if (d > b*b) return (-b+sqrt(d));
return (-b-sqrt(d));
}
// Sample the sky medium properties at a height in meters, 0 being the ground
// and ~100km being the top of the atmosphere.
// Returns the total atmospheric extinction.
vec3 sampleMedium(in float height,
out float mieScattering, out float mieAbsorption,
out vec3 rayleighScattering, out vec3 ozoneAbsorption)
{
float densityMie = exp(-mie_density_height_scale * height);
float densityRayleigh = exp(-rayleigh_density_height_scale * height);
float densityOzone = max(0.0, 1.0 - abs(height-25.0e3)/15.0e3);
mieScattering = mie_scattering * densityMie;
mieAbsorption = mie_absorption * densityMie;
rayleighScattering = rayleigh_scattering * densityRayleigh;
ozoneAbsorption = ozone_absorption * densityOzone;
return mieScattering + mieAbsorption + rayleighScattering + ozoneAbsorption;
}
// Approximation of the Mie phase function with the Cornette-Shanks phase function
float miePhaseFunction(float cosTheta)
{
float num = (1.0 - gg) * (1.0 + cosTheta*cosTheta);
float den = (2.0 + gg) * pow((1.0 + gg - 2.0 * g * cosTheta), 1.5);
return mie_phase_scale * num / den;
}
float rayleighPhaseFunction(float cosTheta)
{
return rayleigh_phase_scale * (1.0 + cosTheta*cosTheta);
}
// Sample one of the LUTs (transmittance or multiple scattering) for a given
// normalized height inside the atmosphere [0,1] and the cosine of the Sun
// zenith angle.
vec3 getValueFromLUT(sampler2D lut, float sunCosTheta, float normHeight)
{
float x = clamp(sunCosTheta * 0.5 + 0.5, 0.0, 1.0);
float y = clamp(normHeight, 0.0, 1.0);
return texture(lut, vec2(x, y)).rgb;
}