SSGI rewrite

This commit is contained in:
2026-07-10 12:43:24 -07:00
parent bd8b49a416
commit 013c8653ff
2 changed files with 90 additions and 68 deletions

View File

@ -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

View File

@ -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);