From 013c8653ff27dac853e031575e3ffddb272a282b Mon Sep 17 00:00:00 2001 From: Onek8 Date: Fri, 10 Jul 2026 12:43:24 -0700 Subject: [PATCH] SSGI rewrite --- .../deferred_light/deferred_light.frag.glsl | 2 +- leenkx/Shaders/ssgi_pass/ssgi_pass.frag.glsl | 156 ++++++++++-------- 2 files changed, 90 insertions(+), 68 deletions(-) diff --git a/leenkx/Shaders/deferred_light/deferred_light.frag.glsl b/leenkx/Shaders/deferred_light/deferred_light.frag.glsl index 0a9a51f5..3ee1a85b 100644 --- a/leenkx/Shaders/deferred_light/deferred_light.frag.glsl +++ b/leenkx/Shaders/deferred_light/deferred_light.frag.glsl @@ -379,7 +379,7 @@ void main() { #ifdef _SSGI vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb; - fragColor.rgb += ssgiColor * albedo; + fragColor.rgb += ssgiColor * basecolor; #endif #ifdef _EmissionShadeless diff --git a/leenkx/Shaders/ssgi_pass/ssgi_pass.frag.glsl b/leenkx/Shaders/ssgi_pass/ssgi_pass.frag.glsl index 03a89cb3..b92838a3 100644 --- a/leenkx/Shaders/ssgi_pass/ssgi_pass.frag.glsl +++ b/leenkx/Shaders/ssgi_pass/ssgi_pass.frag.glsl @@ -28,10 +28,12 @@ in vec2 texCoord; out vec4 fragColor; const float GOLDEN_ANGLE = 2.39996323; -const int RAY_STEPS = 12; +const int RAY_STEPS = 6; +const int BINARY_STEPS = 3; vec2 getProjectedCoord(const vec3 viewPos) { vec4 projectedCoord = P * vec4(viewPos, 1.0); + if (projectedCoord.w <= 0.0) return vec2(-1e5); projectedCoord.xy /= projectedCoord.w; projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; #ifdef _InvY @@ -40,16 +42,12 @@ vec2 getProjectedCoord(const vec3 viewPos) { return projectedCoord.xy; } -vec3 cosineSampleHemisphere(vec3 n, vec2 rand) { - float phi = PI * 2.0 * rand.x; - float cosTheta = sqrt(1.0 - rand.y); - float sinTheta = sqrt(rand.y); - - vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); - - vec3 tangent, bitangent; +float linearZ(const float depth) { + return -P[3].z / (depth + P[2].z); +} + +void buildTBN(vec3 n, out vec3 tangent, out vec3 bitangent) { vec3 absN = abs(n); - if (absN.x <= absN.y && absN.x <= absN.z) { tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0))); } else if (absN.y <= absN.z) { @@ -58,46 +56,70 @@ vec3 cosineSampleHemisphere(vec3 n, vec2 rand) { tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0))); } bitangent = cross(n, tangent); - +} + +vec3 sampleHemisphere(vec3 n, vec3 tangent, vec3 bitangent, float phi, float cosTheta) { + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); return normalize(tangent * h.x + bitangent * h.y + n * h.z); } -vec3 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist) { +vec3 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist, float jitter) { float stepSize = maxDist / float(RAY_STEPS); - vec3 pos = origin + dir * minDist; + float rayDist = minDist + stepSize * (jitter - 1.0); + vec3 pos = origin + dir * rayDist; float prevDepthDiff = 0.0; - float hadValidPrev = 0.0; + bool hasPrev = false; - for (int i = 1; i <= RAY_STEPS; i++) { + for (int i = 0; i < RAY_STEPS; i++) { pos += dir * stepSize; + rayDist += stepSize; vec2 uv = getProjectedCoord(pos); + if (uv.x < -100.0) return vec3(-1.0); + uv = clamp(uv, vec2(0.001), vec2(0.999)); - vec2 sampleUV = clamp(uv, vec2(0.001), vec2(0.999)); - - float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r * 2.0 - 1.0; + float sampleDepth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0; if (sampleDepth == 1.0) { - hadValidPrev = 0.0; + hasPrev = false; continue; } + + float depthDiff = pos.z - linearZ(sampleDepth); + float thickness = maxDist * 0.075 + rayDist * 0.125; - vec3 sampleViewPos = getPosView2(invP, sampleDepth, sampleUV); - float depthDiff = pos.z - sampleViewPos.z; - float rayDist = length(pos - origin); - float thickness = 0.15 + rayDist * 0.25; + bool crossed = hasPrev && (prevDepthDiff > 0.0) && (depthDiff <= 0.0); + bool withinThickness = (depthDiff <= 0.0) && (-depthDiff < thickness); - float crossed = hadValidPrev * step(0.0, prevDepthDiff) * step(depthDiff, 0.0); - float withinThickness = step(abs(depthDiff), thickness); - - if (crossed > 0.5 || withinThickness > 0.5) { - float distWeight = 1.0 - (rayDist / maxDist); - distWeight = max(0.0, distWeight * distWeight); + if (crossed || withinThickness) { + vec3 bPos = pos; + vec3 bDir = dir * stepSize; + for (int j = 0; j < BINARY_STEPS; j++) { + bDir *= 0.5; + bPos -= bDir; + vec2 bUV = getProjectedCoord(bPos); + bUV = clamp(bUV, vec2(0.001), vec2(0.999)); + float bDepth = textureLod(gbufferD, bUV, 0.0).r * 2.0 - 1.0; + if (bDepth == 1.0) { + bPos += bDir; + continue; + } + if (bPos.z - linearZ(bDepth) > 0.0) bPos += bDir; + } - return vec3(sampleUV, distWeight); + vec2 bestUV = getProjectedCoord(bPos); + if (bestUV.x < -100.0) return vec3(-1.0); + bestUV = clamp(bestUV, vec2(0.001), vec2(0.999)); + + float hitDist = length(bPos - origin); + float distWeight = max(0.0, 1.0 - (hitDist / maxDist)); + distWeight *= distWeight; + + return vec3(bestUV, distWeight); } prevDepthDiff = depthDiff; - hadValidPrev = 1.0; + hasPrev = true; } return vec3(-1.0); @@ -111,77 +133,77 @@ void main() { } vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); - vec2 enc = g0.rg; - vec3 n; - n.z = 1.0 - abs(enc.x) - abs(enc.y); - n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); - n = normalize(n); + vec3 n = getNor(g0.rg); + vec3 basecolor = textureLod(gbuffer1, texCoord, 0.0).rgb; vec3 viewNormal = V3 * n; vec3 viewPos = getPosView2(invP, depth, texCoord); #ifdef _CPostprocess - float radius = PPComp12.y; - float strength = PPComp12.x; + float radius = PPComp12.y * 2.0; + float strength = PPComp12.x * 0.5; #else - float radius = ssgiRadius; - float strength = ssgiStrength; + float radius = ssgiRadius * 2.0; + float strength = ssgiStrength * 0.5; #endif - float noise = fract(52.9829189 * fract(0.06711056 * texCoord.x * 1000.0 + 0.00583715 * texCoord.y * 1000.0)); + radius = min(radius, max(-viewPos.z / P[1].y, 0.05)); + + float noise = fract(52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y)); vec3 gi = vec3(0.0); - int validSamples = 0; + float missWeight = 0.0; // min distance to avoid self shadowing artiffacts float minDist = radius * 0.05; + vec3 tangent, bitangent; + buildTBN(viewNormal, tangent, bitangent); + for (int i = 0; i < ssgiSamples; i++) { - float fi = float(i) + noise; - vec2 rand = vec2( - fract(fi * 0.7548776662 + noise), - fract(fi * 0.5698402909 + noise * 1.5) - ); + float phi = float(i) * GOLDEN_ANGLE + noise * PI2; + float cosTheta = sqrt(max(0.0, 1.0 - (float(i) + 0.5) / float(ssgiSamples))); + float jitter = fract(noise + float(i) * 0.618034); - vec3 rayDir = cosineSampleHemisphere(viewNormal, rand); - vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist); + vec3 rayDir = sampleHemisphere(viewNormal, tangent, bitangent, phi, cosTheta); + vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist, jitter); - if (hitResult.x < 0.0) continue; + if (hitResult.x < 0.0) { + missWeight += 1.0; + continue; + } vec2 hitUV = hitResult.xy; float distWeight = hitResult.z; - vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 1.0).rgb; + vec3 hitN = getNor(textureLod(gbuffer0, hitUV, 0.0).rg); + float emitterCos = max(0.0, dot(V3 * hitN, -rayDir)); + if (emitterCos <= 0.0) { + missWeight += 1.0; + continue; + } + + vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 0.0).rgb; #ifdef _Sun - vec4 hitG0 = textureLod(gbuffer0, hitUV, 0.0); - vec2 hitEnc = hitG0.rg; - vec3 hitN; - hitN.z = 1.0 - abs(hitEnc.x) - abs(hitEnc.y); - hitN.xy = hitN.z >= 0.0 ? hitEnc.xy : octahedronWrap(hitEnc.xy); - hitN = normalize(hitN); float hitNdotL = max(0.0, dot(hitN, sunDir)); - vec3 hitRadiance = hitAlbedo * sunCol * hitNdotL; + vec3 hitRadiance = hitAlbedo * (sunCol * hitNdotL + vec3(0.4)); #else - vec3 hitRadiance = hitAlbedo * 0.5; + vec3 hitRadiance = hitAlbedo * 0.4; #endif #ifdef _EmissionShaded hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb; #endif - gi += hitRadiance * distWeight; - validSamples++; + gi += hitRadiance * (distWeight * emitterCos); } - if (validSamples > 0) { - gi /= float(validSamples); - } - - gi *= strength; + gi += basecolor * 0.1 * missWeight; + gi *= 2.0 * strength / float(ssgiSamples); #ifdef _EmissionShaded - gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3; + gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3; #endif fragColor = vec4(min(gi, vec3(2.0)), 1.0);