9b9ae5cf38
Implementation of "A Scalable and Production Ready Sky and Atmosphere Rendering Technique" by Sébastien Hillaire (2020).
78 lines
2.8 KiB
GLSL
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;
|
|
}
|