forked from LeenkxTeam/LNXSDK
SSGI rewrite
This commit is contained in:
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user