diff --git a/shaders/lib/universal/SSBO.glsl b/shaders/lib/universal/SSBO.glsl index 7b8bfd85..2719f554 100644 --- a/shaders/lib/universal/SSBO.glsl +++ b/shaders/lib/universal/SSBO.glsl @@ -18,5 +18,6 @@ layout(std430, binding = 1) SSBO_DECLARED_TPYE buffer ExposureData { layout(std430, binding = 2) SSBO_DECLARED_TPYE buffer CloudData { mat4 shadowViewProj; mat4 shadowViewProjInv; + mat4 prevShadowViewProj; vec2 upscaleJitter; } cloud; diff --git a/shaders/lib/utility/Matrix.glsl b/shaders/lib/utility/Matrix.glsl index d45a9d33..a4d6e168 100644 --- a/shaders/lib/utility/Matrix.glsl +++ b/shaders/lib/utility/Matrix.glsl @@ -20,8 +20,17 @@ mat4 BuildOrthoMat(float width, float height, float near, float far) { return mat4( -2.0 * rw, 0.0, 0.0, 0.0, 0.0, -2.0 * rh, 0.0, 0.0, - 0.0, 0.0, 2.0 * rd, 0.0, - 0.0, 0.0, (near + far) * rd, 1.0 + 0.0, 0.0, 2.0 * rd, (near + far) * rd, + 0.0, 0.0, 0.0, 1.0 + ); +} + +mat4 BuildInvOrthoMat(float width, float height, float near, float far) { + return mat4( + -0.5 * width, 0.0, 0.0, 0.0, + 0.0, -0.5 * height, 0.0, 0.0, + 0.0, 0.0, 0.5 * (far - near), 0.5 * (near + far), + 0.0, 0.0, 0.0, 1.0 ); } @@ -32,8 +41,8 @@ mat4 BuildPerspectiveMat(float fov, float aspect, float near, float far) { return mat4( f / aspect, 0.0, 0.0, 0.0, 0.0, f, 0.0, 0.0, - 0.0, 0.0, (near + far) * rd, -1.0, - 0.0, 0.0, near * far * rd * 2.0, 0.0 + 0.0, 0.0, (near + far) * rd, near * far * rd * 2.0, + 0.0, 0.0, -1.0, 0.0 ); } diff --git a/shaders/program/prepare/GenCloudShadow.comp b/shaders/program/prepare/GenCloudShadow.comp index 905ac6b4..a322194b 100644 --- a/shaders/program/prepare/GenCloudShadow.comp +++ b/shaders/program/prepare/GenCloudShadow.comp @@ -1,10 +1,10 @@ /* -------------------------------------------------------------------------------- - Revelation Shaders + Revelation Shaders - Copyright (C) 2026 HaringPro - Apache License 2.0 + Copyright (C) 2026 HaringPro + Apache License 2.0 -------------------------------------------------------------------------------- */ @@ -37,17 +37,22 @@ writeonly uniform image2D cloudShadowImg; #include "/lib/atmosphere/Common.glsl" #include "/lib/atmosphere/clouds/Shape.glsl" +const float windAngle = radians(CLOUD_LOW_WIND_ANGLE); +const vec3 windDir = vec3(cos(windAngle), 0.5, sin(windAngle)); +const vec3 windVelocity = windDir * CLOUD_LOW_WIND_SPEED; + //======// Main //================================================================================// void main() { - ivec2 tid = ivec2(gl_GlobalInvocationID.xy); + ivec2 tid = ivec2(gl_GlobalInvocationID.xy); + const vec2 rSize = rcp(textureSize(cloudShadowTex, 0)); - // Checkerboard render cloud shadow map - ivec2 offset = checkerboardOffset2x2[frameCounter & 3]; - if ((tid & 1) == offset || historyReset) { - float dither = BlueNoise(tid, frameCounter); + // Checkerboard render cloud shadow map + ivec2 offset = checkerboardOffset2x2[frameCounter & 3]; + if ((tid & 1) == offset || historyReset) { + float dither = BlueNoise(tid, frameCounter); - vec2 uv = (vec2(tid) + dither) * rcp(textureSize(cloudShadowTex, 0)); - vec3 rayPos = SetupCloudShadowPos(uv) + atmosphereViewPos; + vec2 uv = (vec2(tid) + 0.5) * rSize; + vec3 rayPos = SetupCloudShadowPos(uv + (dither - 0.5) * rSize) + atmosphereViewPos; // Increase steps for lower elevation float steps = float(CLOUD_SHADOW_SAMPLES) * (2.0 - shadowDirWorld.y); @@ -59,6 +64,8 @@ void main() { rayPos += shadowDirWorld * intersection.x; rayPos += rayStep * fract(dither + PHI); + vec3 cloudPos = rayPos - atmosphereViewPos + shadowDirWorld * dot(intersection, vec2(0.5)); + float extinction = 0.0; const float threshold = -log2(cloudMinTransmittance) / cumulusExtinction; @@ -78,10 +85,21 @@ void main() { float strength = linearstep(0.02, 0.05, shadowDirWorld.y) * sqrt(CLOUD_SHADOW_STRENGTH); float cloudShadow = oms(strength) + transmittance * strength; - // Accumulate - float weight = rcp(min(frameCounter, 32) * float(!historyReset) + 1.0); - cloudShadow = mix(texelFetch(cloudShadowTex, tid, 0).x, cloudShadow, weight); + // Reproject and accumulate + vec3 motionVector = -windVelocity; + motionVector *= global.worldTimeDiff * 0.05; + motionVector += cameraMovement; + vec2 prevUV = transMAD(cloud.prevShadowViewProj, cloudPos).xy; + prevUV *= rcp(length(prevUV) * 0.5 + 0.5); + prevUV = prevUV * 0.5 + 0.5; + + vec2 prevValue = textureLod(cloudShadowTex, prevUV, 0).xy; + float frameIdx = min(fma(prevValue.y, 256.0, 1.0), 16.0); + if (saturate(prevUV) == prevUV && frameIdx > 2.0 && !historyReset) { + float weight = rcp(frameIdx); + cloudShadow = mix(prevValue.x, cloudShadow, weight); + } - imageStore(cloudShadowImg, tid, vec4(cloudShadow)); - } + imageStore(cloudShadowImg, tid, vec4(cloudShadow, frameIdx * rcp(256.0), 0.0, 0.0)); + } } diff --git a/shaders/program/prepare/UpdateSSBO.comp b/shaders/program/prepare/UpdateSSBO.comp index 3a52ee4f..84d16e80 100644 --- a/shaders/program/prepare/UpdateSSBO.comp +++ b/shaders/program/prepare/UpdateSSBO.comp @@ -36,6 +36,9 @@ const ivec3 workGroups = ivec3(1, 1, 1); #include "/lib/universal/Random.glsl" +const mat4 shadowProj = BuildOrthoMat(CLOUD_SHADOW_DISTANCE * 32.0, CLOUD_SHADOW_DISTANCE * 32.0, 0.0, cumulusTopRadius); +const mat4 shadowInvProj = BuildInvOrthoMat(CLOUD_SHADOW_DISTANCE * 32.0, CLOUD_SHADOW_DISTANCE * 32.0, 0.0, cumulusTopRadius); + //======// Main //================================================================================// void main() { // Compute illuminance @@ -51,9 +54,9 @@ void main() { #ifdef CLOUDS #ifdef CLOUD_SHADOWS - mat4 projMat = BuildOrthoMat(CLOUD_SHADOW_DISTANCE * 32.0, CLOUD_SHADOW_DISTANCE * 32.0, 0.0, cumulusTopRadius); - cloud.shadowViewProj = projMat * shadowModelView; - cloud.shadowViewProjInv = inverse(cloud.shadowViewProj); + cloud.prevShadowViewProj = cloud.shadowViewProj; + cloud.shadowViewProj = shadowProj * shadowModelView; + cloud.shadowViewProjInv = shadowModelViewInverse * shadowInvProj; #endif cloud.upscaleJitter = Halton23(frameCounter + 211); diff --git a/shaders/shaders.properties b/shaders/shaders.properties index 87bcd784..3e8bfd73 100644 --- a/shaders/shaders.properties +++ b/shaders/shaders.properties @@ -228,7 +228,7 @@ image.cloudOriginImg = cloudOriginTex RGBA RGBA16F HALF_FLOAT false true 0.333 image.cloudOriginImg = cloudOriginTex RGBA RGBA16F HALF_FLOAT false true 0.25 0.25 #endif -image.cloudShadowImg = cloudShadowTex RED R8 UNSIGNED_BYTE false false 512 512 +image.cloudShadowImg = cloudShadowTex RG RG8 UNSIGNED_BYTE false false 512 512 # image.envBRDFImg = envBRDFTex RG RG16F HALF_FLOAT false false 256 256