#version 450 #include "compiled.inc" #include "std/math.glsl" #include "std/gbuffer.glsl" uniform sampler2D gbuffer0; uniform sampler2D gbuffer1; uniform sampler2D gbufferD; #ifdef _EmissionShaded uniform sampler2D gbufferEmission; #endif uniform mat4 P; uniform mat4 invP; uniform mat3 V3; #ifdef _Sun uniform vec3 sunDir; uniform vec3 sunCol; #endif #ifdef _CPostprocess uniform vec3 PPComp12; #endif in vec2 texCoord; out vec4 fragColor; const float GOLDEN_ANGLE = 2.39996323; const int RAY_STEPS = 12; vec2 getProjectedCoord(const vec3 viewPos) { vec4 projectedCoord = P * vec4(viewPos, 1.0); projectedCoord.xy /= projectedCoord.w; projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; #ifdef _InvY projectedCoord.y = 1.0 - projectedCoord.y; #endif 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; 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) { tangent = normalize(cross(n, vec3(0.0, 1.0, 0.0))); } else { tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0))); } bitangent = cross(n, tangent); return normalize(tangent * h.x + bitangent * h.y + n * h.z); } vec3 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist) { float stepSize = maxDist / float(RAY_STEPS); vec3 pos = origin + dir * minDist; float prevDepthDiff = 0.0; float hadValidPrev = 0.0; for (int i = 1; i <= RAY_STEPS; i++) { pos += dir * stepSize; vec2 uv = getProjectedCoord(pos); vec2 sampleUV = clamp(uv, vec2(0.001), vec2(0.999)); float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r * 2.0 - 1.0; if (sampleDepth == 1.0) { hadValidPrev = 0.0; continue; } vec3 sampleViewPos = getPosView2(invP, sampleDepth, sampleUV); float depthDiff = pos.z - sampleViewPos.z; float rayDist = length(pos - origin); float thickness = 0.15 + rayDist * 0.25; 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); return vec3(sampleUV, distWeight); } prevDepthDiff = depthDiff; hadValidPrev = 1.0; } return vec3(-1.0); } void main() { float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; if (depth == 1.0) { fragColor = vec4(0.0, 0.0, 0.0, 1.0); return; } 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 viewNormal = V3 * n; vec3 viewPos = getPosView2(invP, depth, texCoord); #ifdef _CPostprocess float radius = PPComp12.y; float strength = PPComp12.x; #else float radius = ssgiRadius; float strength = ssgiStrength; #endif float noise = fract(52.9829189 * fract(0.06711056 * texCoord.x * 1000.0 + 0.00583715 * texCoord.y * 1000.0)); vec3 gi = vec3(0.0); int validSamples = 0; // min distance to avoid self shadowing artiffacts float minDist = radius * 0.05; 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) ); vec3 rayDir = cosineSampleHemisphere(viewNormal, rand); vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist); if (hitResult.x < 0.0) continue; vec2 hitUV = hitResult.xy; float distWeight = hitResult.z; vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 1.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; #else vec3 hitRadiance = hitAlbedo * 0.5; #endif #ifdef _EmissionShaded hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb; #endif gi += hitRadiance * distWeight; validSamples++; } if (validSamples > 0) { gi /= float(validSamples); } gi *= strength; #ifdef _EmissionShaded gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3; #endif fragColor = vec4(min(gi, vec3(2.0)), 1.0); }