From 94f4007793c77ca30266b969e7a47f34a068e572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Garc=C3=ADa=20Li=C3=B1=C3=A1n?= Date: Thu, 19 Aug 2021 12:50:01 +0200 Subject: [PATCH] HDR: Use precomputed uniforms for atmospheric scattering --- Shaders/HDR/atmos-aerial-perspective.frag | 32 ++++++++++------------ Shaders/HDR/atmos-multiple-scattering.frag | 18 ++++++------ Shaders/HDR/atmos-sky-view.frag | 30 ++++++++++---------- Shaders/HDR/atmos-transmittance.frag | 8 ++---- 4 files changed, 41 insertions(+), 47 deletions(-) diff --git a/Shaders/HDR/atmos-aerial-perspective.frag b/Shaders/HDR/atmos-aerial-perspective.frag index f95b37968..0b0bf283a 100644 --- a/Shaders/HDR/atmos-aerial-perspective.frag +++ b/Shaders/HDR/atmos-aerial-perspective.frag @@ -16,14 +16,16 @@ out vec4 fragColor; 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 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 ATMOSPHERE_RADIUS = 6471e3; const float TOTAL_SLICES = 32.0; @@ -43,11 +45,7 @@ vec3 getValueFromLUT(sampler2D lut, float sunCosTheta, float normalizedHeight); void main() { - vec3 up = normalize(fg_CameraPositionCart); - float sunCosTheta = dot(fg_SunDirectionWorld, up); - // Account for the depth layer we are currently in - // FIXME: We should probably be writing the pixel center float x = texCoord.x * TOTAL_SLICES; vec2 coord = vec2(fract(x), texCoord.y); // 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 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; + // Handle the camera being underground + float earthRadius = min(fg_EarthRadius, fg_CameraDistanceToEarthCenter); + float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS); float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius); float tmax; - if (cameraHeight < ATMOSPHERE_RADIUS) { + if (fg_CameraDistanceToEarthCenter < ATMOSPHERE_RADIUS) { // We are inside the atmosphere if (groundDist < 0.0) { // No ground collision, use the distance to the outer atmosphere @@ -99,8 +97,8 @@ void main() t = newT; vec3 samplePos = rayOrigin + rayDir * t; - float height = length(samplePos) - earthRadius; - float normalizedHeight = height / (ATMOSPHERE_RADIUS - earthRadius); + float height = length(samplePos) - fg_EarthRadius; + float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius); float mieScattering, mieAbsorption; vec3 rayleighScattering, ozoneAbsorption; @@ -110,9 +108,9 @@ void main() vec3 sampleTransmittance = exp(-dt*extinction); vec3 sunTransmittance = getValueFromLUT( - transmittance_lut, sunCosTheta, normalizedHeight); + transmittance_lut, fg_SunZenithCosTheta, normalizedHeight); vec3 multiscattering = getValueFromLUT( - multiscattering_lut, sunCosTheta, normalizedHeight); + multiscattering_lut, fg_SunZenithCosTheta, normalizedHeight); vec3 S = rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) + diff --git a/Shaders/HDR/atmos-multiple-scattering.frag b/Shaders/HDR/atmos-multiple-scattering.frag index 671a0b065..315e3554d 100644 --- a/Shaders/HDR/atmos-multiple-scattering.frag +++ b/Shaders/HDR/atmos-multiple-scattering.frag @@ -9,11 +9,10 @@ out vec3 fragColor; in vec2 texCoord; -uniform vec3 fg_CameraPositionCart; -uniform vec3 fg_CameraPositionGeod; - uniform sampler2D transmittance_lut; +uniform float fg_EarthRadius; + const float PI = 3.141592653; const float ATMOSPHERE_RADIUS = 6471e3; const int SQRT_SAMPLES = 4; @@ -44,8 +43,7 @@ void main() float sunCosTheta = texCoord.x * 2.0 - 1.0; vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta); - float earthRadius = length(fg_CameraPositionCart) - fg_CameraPositionGeod.z; - float altitude = mix(earthRadius, ATMOSPHERE_RADIUS, texCoord.y); + float altitude = mix(fg_EarthRadius, ATMOSPHERE_RADIUS, texCoord.y); vec3 rayOrigin = vec3(0.0, 0.0, altitude); vec3 Ltotal = vec3(0.0); @@ -58,7 +56,7 @@ void main() vec3 rayDir = generateRayDir(theta, phi); float atmosDist = raySphereIntersection(rayOrigin, rayDir, ATMOSPHERE_RADIUS); - float groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius); + float groundDist = raySphereIntersection(rayOrigin, rayDir, fg_EarthRadius); float tmax; if (groundDist < 0.0) { @@ -84,8 +82,8 @@ void main() t = newT; vec3 samplePos = rayOrigin + rayDir * t; - float height = length(samplePos) - earthRadius; - float normalizedHeight = height / (ATMOSPHERE_RADIUS - earthRadius); + float height = length(samplePos) - fg_EarthRadius; + float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius); float mieScattering, mieAbsorption; vec3 rayleighScattering, ozoneAbsorption; @@ -116,8 +114,8 @@ void main() float pHeight = length(p); vec3 up = p / pHeight; - float normHeight = (pHeight - earthRadius) - / (ATMOSPHERE_RADIUS - earthRadius); + float normHeight = (pHeight - fg_EarthRadius) + / (ATMOSPHERE_RADIUS - fg_EarthRadius); float sunZenithCosTheta = dot(sunDir, up); vec3 transmittanceFromGround = getValueFromLUT( diff --git a/Shaders/HDR/atmos-sky-view.frag b/Shaders/HDR/atmos-sky-view.frag index 8b4d08bb7..eaf13eb6e 100644 --- a/Shaders/HDR/atmos-sky-view.frag +++ b/Shaders/HDR/atmos-sky-view.frag @@ -13,13 +13,13 @@ out vec3 fragColor; in vec2 texCoord; -uniform vec3 fg_CameraPositionCart; -uniform vec3 fg_CameraPositionGeod; -uniform vec3 fg_SunDirectionWorld; - uniform sampler2D transmittance_lut; uniform sampler2D multiscattering_lut; +uniform float fg_SunZenithCosTheta; +uniform float fg_CameraDistanceToEarthCenter; +uniform float fg_EarthRadius; + const float PI = 3.141592653; 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 // model is already being rotated. - vec3 up = normalize(fg_CameraPositionCart); - float sunCosTheta = dot(fg_SunDirectionWorld, up); - vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta); + vec3 sunDir = vec3(-sqrt(1.0 - fg_SunZenithCosTheta*fg_SunZenithCosTheta), + 0.0, + fg_SunZenithCosTheta); float azimuth = 2.0 * PI * texCoord.x; // [0, 2pi] // 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] vec3 rayDir = vec3(cos(elev) * cos(azimuth), cos(elev) * sin(azimuth), sin(elev)); - float cameraHeight = length(fg_CameraPositionCart); - float earthRadius = cameraHeight - max(fg_CameraPositionGeod.z, 0.0); + vec3 rayOrigin = vec3(0.0, 0.0, fg_CameraDistanceToEarthCenter); - 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 groundDist = raySphereIntersection(rayOrigin, rayDir, earthRadius); float tmax; - if (cameraHeight < ATMOSPHERE_RADIUS) { + if (fg_CameraDistanceToEarthCenter < ATMOSPHERE_RADIUS) { // We are inside the atmosphere if (groundDist < 0.0) { // No ground collision, use the distance to the outer atmosphere @@ -86,8 +86,8 @@ void main() t = newT; vec3 samplePos = rayOrigin + rayDir * t; - float height = length(samplePos) - earthRadius; - float normalizedHeight = height / (ATMOSPHERE_RADIUS - earthRadius); + float height = length(samplePos) - fg_EarthRadius; + float normalizedHeight = height / (ATMOSPHERE_RADIUS - fg_EarthRadius); float mieScattering, mieAbsorption; vec3 rayleighScattering, ozoneAbsorption; @@ -97,9 +97,9 @@ void main() vec3 sampleTransmittance = exp(-dt*extinction); vec3 sunTransmittance = getValueFromLUT( - transmittance_lut, sunCosTheta, normalizedHeight); + transmittance_lut, fg_SunZenithCosTheta, normalizedHeight); vec3 multiscattering = getValueFromLUT( - multiscattering_lut, sunCosTheta, normalizedHeight); + multiscattering_lut, fg_SunZenithCosTheta, normalizedHeight); vec3 S = rayleighScattering * (rayleighPhase * sunTransmittance + multiscattering) + diff --git a/Shaders/HDR/atmos-transmittance.frag b/Shaders/HDR/atmos-transmittance.frag index 4121475f7..335209e44 100644 --- a/Shaders/HDR/atmos-transmittance.frag +++ b/Shaders/HDR/atmos-transmittance.frag @@ -11,8 +11,7 @@ out vec3 fragColor; in vec2 texCoord; -uniform vec3 fg_CameraPositionCart; -uniform vec3 fg_CameraPositionGeod; +uniform float fg_EarthRadius; const float ATMOSPHERE_RADIUS = 6471e3; const int TRANSMITTANCE_STEPS = 40; @@ -27,8 +26,7 @@ void main() float sunCosTheta = texCoord.x * 2.0 - 1.0; vec3 sunDir = vec3(-sqrt(1.0 - sunCosTheta*sunCosTheta), 0.0, sunCosTheta); - float earthRadius = length(fg_CameraPositionCart) - fg_CameraPositionGeod.z; - float altitude = mix(earthRadius, ATMOSPHERE_RADIUS, texCoord.y); + float altitude = mix(fg_EarthRadius, ATMOSPHERE_RADIUS, texCoord.y); vec3 rayOrigin = vec3(0.0, 0.0, altitude); float dist = raySphereIntersection(rayOrigin, sunDir, ATMOSPHERE_RADIUS); @@ -41,7 +39,7 @@ void main() t = newT; vec3 samplePos = rayOrigin + sunDir * t; - float height = length(samplePos) - earthRadius; + float height = length(samplePos) - fg_EarthRadius; float mieScattering, mieAbsorption; vec3 rayleighScattering, ozoneAbsorption;