1
0
Fork 0

HDR: Use precomputed uniforms for atmospheric scattering

This commit is contained in:
Fernando García Liñán 2021-08-19 12:50:01 +02:00
parent d4dfafaac7
commit 94f4007793
4 changed files with 41 additions and 47 deletions

View file

@ -16,14 +16,16 @@ out vec4 fragColor;
in vec2 texCoord; in vec2 texCoord;
uniform mat4 fg_ViewMatrixInverse;
uniform vec3 fg_CameraPositionCart;
uniform vec3 fg_CameraPositionGeod;
uniform vec3 fg_SunDirectionWorld;
uniform sampler2D transmittance_lut; uniform sampler2D transmittance_lut;
uniform sampler2D multiscattering_lut; uniform sampler2D multiscattering_lut;
uniform mat4 fg_ViewMatrixInverse;
uniform vec3 fg_CameraPositionCart;
uniform vec3 fg_SunDirectionWorld;
uniform float fg_SunZenithCosTheta;
uniform float fg_CameraDistanceToEarthCenter;
uniform float fg_EarthRadius;
const float PI = 3.141592653; const float PI = 3.141592653;
const float ATMOSPHERE_RADIUS = 6471e3; const float ATMOSPHERE_RADIUS = 6471e3;
const float TOTAL_SLICES = 32.0; const float TOTAL_SLICES = 32.0;
@ -43,11 +45,7 @@ vec3 getValueFromLUT(sampler2D lut, float sunCosTheta, float normalizedHeight);
void main() void main()
{ {
vec3 up = normalize(fg_CameraPositionCart);
float sunCosTheta = dot(fg_SunDirectionWorld, up);
// Account for the depth layer we are currently in // Account for the depth layer we are currently in
// FIXME: We should probably be writing the pixel center
float x = texCoord.x * TOTAL_SLICES; float x = texCoord.x * TOTAL_SLICES;
vec2 coord = vec2(fract(x), texCoord.y); vec2 coord = vec2(fract(x), texCoord.y);
// Depth goes from the 0 to DEPTH_RANGE in a squared distribution. // Depth goes from the 0 to DEPTH_RANGE in a squared distribution.
@ -59,16 +57,16 @@ void main()
vec3 fragPos = positionFromDepth(coord, 1.0); vec3 fragPos = positionFromDepth(coord, 1.0);
vec3 rayDir = vec4(fg_ViewMatrixInverse * vec4(normalize(fragPos), 0.0)).xyz; vec3 rayDir = vec4(fg_ViewMatrixInverse * vec4(normalize(fragPos), 0.0)).xyz;
float cameraHeight = length(fg_CameraPositionCart);
float earthRadius = cameraHeight - max(fg_CameraPositionGeod.z, 0.0);
vec3 rayOrigin = fg_CameraPositionCart; vec3 rayOrigin = fg_CameraPositionCart;
// Handle the camera being underground
float earthRadius = min(fg_EarthRadius, fg_CameraDistanceToEarthCenter);
float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS); float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS);
float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius); float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius);
float tmax; float tmax;
if (cameraHeight < ATMOSPHERE_RADIUS) { if (fg_CameraDistanceToEarthCenter < ATMOSPHERE_RADIUS) {
// We are inside the atmosphere // We are inside the atmosphere
if (groundDist < 0.0) { if (groundDist < 0.0) {
// No ground collision, use the distance to the outer atmosphere // No ground collision, use the distance to the outer atmosphere
@ -99,8 +97,8 @@ void main()
t = newT; t = newT;
vec3 samplePos = rayOrigin + rayDir * t; vec3 samplePos = rayOrigin + rayDir * t;
float height = length(samplePos) - earthRadius; float height = length(samplePos) - fg_EarthRadius;
float normalizedHeight = height / (ATMOSPHERE_RADIUS - earthRadius); float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius);
float mieScattering, mieAbsorption; float mieScattering, mieAbsorption;
vec3 rayleighScattering, ozoneAbsorption; vec3 rayleighScattering, ozoneAbsorption;
@ -110,9 +108,9 @@ void main()
vec3 sampleTransmittance = exp(-dt*extinction); vec3 sampleTransmittance = exp(-dt*extinction);
vec3 sunTransmittance = getValueFromLUT( vec3 sunTransmittance = getValueFromLUT(
transmittance_lut, sunCosTheta, normalizedHeight); transmittance_lut, fg_SunZenithCosTheta, normalizedHeight);
vec3 multiscattering = getValueFromLUT( vec3 multiscattering = getValueFromLUT(
multiscattering_lut, sunCosTheta, normalizedHeight); multiscattering_lut, fg_SunZenithCosTheta, normalizedHeight);
vec3 S = vec3 S =
rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) + rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) +

View file

@ -9,11 +9,10 @@ out vec3 fragColor;
in vec2 texCoord; in vec2 texCoord;
uniform vec3 fg_CameraPositionCart;
uniform vec3 fg_CameraPositionGeod;
uniform sampler2D transmittance_lut; uniform sampler2D transmittance_lut;
uniform float fg_EarthRadius;
const float PI = 3.141592653; const float PI = 3.141592653;
const float ATMOSPHERE_RADIUS = 6471e3; const float ATMOSPHERE_RADIUS = 6471e3;
const int SQRT_SAMPLES = 4; const int SQRT_SAMPLES = 4;
@ -44,8 +43,7 @@ void main()
float sunCosTheta = texCoord.x * 2.0 - 1.0; float sunCosTheta = texCoord.x * 2.0 - 1.0;
vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta); vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta);
float earthRadius = length(fg_CameraPositionCart) - fg_CameraPositionGeod.z; float altitude = mix(fg_EarthRadius, ATMOSPHERE_RADIUS, texCoord.y);
float altitude = mix(earthRadius, ATMOSPHERE_RADIUS, texCoord.y);
vec3 rayOrigin = vec3(0.0, 0.0, altitude); vec3 rayOrigin = vec3(0.0, 0.0, altitude);
vec3 Ltotal = vec3(0.0); vec3 Ltotal = vec3(0.0);
@ -58,7 +56,7 @@ void main()
vec3 rayDir = generateRayDir(theta, phi); vec3 rayDir = generateRayDir(theta, phi);
float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS); float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS);
float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius); float groundDist = raySphereIntersection(rayOrigin, rayDir, fg_EarthRadius);
float tmax; float tmax;
if (groundDist < 0.0) { if (groundDist < 0.0) {
@ -84,8 +82,8 @@ void main()
t = newT; t = newT;
vec3 samplePos = rayOrigin + rayDir * t; vec3 samplePos = rayOrigin + rayDir * t;
float height = length(samplePos) - earthRadius; float height = length(samplePos) - fg_EarthRadius;
float normalizedHeight = height / (ATMOSPHERE_RADIUS - earthRadius); float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius);
float mieScattering, mieAbsorption; float mieScattering, mieAbsorption;
vec3 rayleighScattering, ozoneAbsorption; vec3 rayleighScattering, ozoneAbsorption;
@ -116,8 +114,8 @@ void main()
float pHeight = length(p); float pHeight = length(p);
vec3 up = p / pHeight; vec3 up = p / pHeight;
float normHeight = (pHeight - earthRadius) float normHeight = (pHeight - fg_EarthRadius)
/ (ATMOSPHERE_RADIUS - earthRadius); / (ATMOSPHERE_RADIUS - fg_EarthRadius);
float sunZenithCosTheta = dot(sunDir, up); float sunZenithCosTheta = dot(sunDir, up);
vec3 transmittanceFromGround = getValueFromLUT( vec3 transmittanceFromGround = getValueFromLUT(

View file

@ -13,13 +13,13 @@ out vec3 fragColor;
in vec2 texCoord; in vec2 texCoord;
uniform vec3 fg_CameraPositionCart;
uniform vec3 fg_CameraPositionGeod;
uniform vec3 fg_SunDirectionWorld;
uniform sampler2D transmittance_lut; uniform sampler2D transmittance_lut;
uniform sampler2D multiscattering_lut; uniform sampler2D multiscattering_lut;
uniform float fg_SunZenithCosTheta;
uniform float fg_CameraDistanceToEarthCenter;
uniform float fg_EarthRadius;
const float PI = 3.141592653; const float PI = 3.141592653;
const float ATMOSPHERE_RADIUS = 6471e3; const float ATMOSPHERE_RADIUS = 6471e3;
@ -37,9 +37,9 @@ void main()
{ {
// Always leave the sun right in the middle of the texture as the skydome // Always leave the sun right in the middle of the texture as the skydome
// model is already being rotated. // model is already being rotated.
vec3 up = normalize(fg_CameraPositionCart); vec3 sunDir = vec3(-sqrt(1.0 - fg_SunZenithCosTheta*fg_SunZenithCosTheta),
float sunCosTheta = dot(fg_SunDirectionWorld, up); 0.0,
vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta); fg_SunZenithCosTheta);
float azimuth = 2.0 * PI * texCoord.x; // [0, 2pi] float azimuth = 2.0 * PI * texCoord.x; // [0, 2pi]
// Apply a non-linear transformation to the elevation to dedicate more // Apply a non-linear transformation to the elevation to dedicate more
@ -48,16 +48,16 @@ void main()
float elev = l*l * sign(l) * PI * 0.5; // [-pi/2, pi/2] float elev = l*l * sign(l) * PI * 0.5; // [-pi/2, pi/2]
vec3 rayDir = vec3(cos(elev) * cos(azimuth), cos(elev) * sin(azimuth), sin(elev)); vec3 rayDir = vec3(cos(elev) * cos(azimuth), cos(elev) * sin(azimuth), sin(elev));
float cameraHeight = length(fg_CameraPositionCart); vec3 rayOrigin = vec3(0.0, 0.0, fg_CameraDistanceToEarthCenter);
float earthRadius = cameraHeight - max(fg_CameraPositionGeod.z, 0.0);
vec3 rayOrigin = vec3(0.0, 0.0, cameraHeight); // Handle the camera being underground
float earthRadius = min(fg_EarthRadius, fg_CameraDistanceToEarthCenter);
float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS); float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS);
float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius); float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius);
float tmax; float tmax;
if (cameraHeight < ATMOSPHERE_RADIUS) { if (fg_CameraDistanceToEarthCenter < ATMOSPHERE_RADIUS) {
// We are inside the atmosphere // We are inside the atmosphere
if (groundDist < 0.0) { if (groundDist < 0.0) {
// No ground collision, use the distance to the outer atmosphere // No ground collision, use the distance to the outer atmosphere
@ -86,8 +86,8 @@ void main()
t = newT; t = newT;
vec3 samplePos = rayOrigin + rayDir * t; vec3 samplePos = rayOrigin + rayDir * t;
float height = length(samplePos) - earthRadius; float height = length(samplePos) - fg_EarthRadius;
float normalizedHeight = height / (ATMOSPHERE_RADIUS - earthRadius); float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius);
float mieScattering, mieAbsorption; float mieScattering, mieAbsorption;
vec3 rayleighScattering, ozoneAbsorption; vec3 rayleighScattering, ozoneAbsorption;
@ -97,9 +97,9 @@ void main()
vec3 sampleTransmittance = exp(-dt*extinction); vec3 sampleTransmittance = exp(-dt*extinction);
vec3 sunTransmittance = getValueFromLUT( vec3 sunTransmittance = getValueFromLUT(
transmittance_lut, sunCosTheta, normalizedHeight); transmittance_lut, fg_SunZenithCosTheta, normalizedHeight);
vec3 multiscattering = getValueFromLUT( vec3 multiscattering = getValueFromLUT(
multiscattering_lut, sunCosTheta, normalizedHeight); multiscattering_lut, fg_SunZenithCosTheta, normalizedHeight);
vec3 S = vec3 S =
rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) + rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) +

View file

@ -11,8 +11,7 @@ out vec3 fragColor;
in vec2 texCoord; in vec2 texCoord;
uniform vec3 fg_CameraPositionCart; uniform float fg_EarthRadius;
uniform vec3 fg_CameraPositionGeod;
const float ATMOSPHERE_RADIUS = 6471e3; const float ATMOSPHERE_RADIUS = 6471e3;
const int TRANSMITTANCE_STEPS = 40; const int TRANSMITTANCE_STEPS = 40;
@ -27,8 +26,7 @@ void main()
float sunCosTheta = texCoord.x * 2.0 - 1.0; float sunCosTheta = texCoord.x * 2.0 - 1.0;
vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta); vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta);
float earthRadius = length(fg_CameraPositionCart) - fg_CameraPositionGeod.z; float altitude = mix(fg_EarthRadius, ATMOSPHERE_RADIUS, texCoord.y);
float altitude = mix(earthRadius, ATMOSPHERE_RADIUS, texCoord.y);
vec3 rayOrigin = vec3(0.0, 0.0, altitude); vec3 rayOrigin = vec3(0.0, 0.0, altitude);
float dist = raySphereIntersection(rayOrigin, sunDir, ATMOSPHERE_RADIUS); float dist = raySphereIntersection(rayOrigin, sunDir, ATMOSPHERE_RADIUS);
@ -41,7 +39,7 @@ void main()
t = newT; t = newT;
vec3 samplePos = rayOrigin + sunDir * t; vec3 samplePos = rayOrigin + sunDir * t;
float height = length(samplePos) - earthRadius; float height = length(samplePos) - fg_EarthRadius;
float mieScattering, mieAbsorption; float mieScattering, mieAbsorption;
vec3 rayleighScattering, ozoneAbsorption; vec3 rayleighScattering, ozoneAbsorption;