forked from LeenkxTeam/LNXSDK
SSGI rewrite
This commit is contained in:
@ -379,7 +379,7 @@ void main() {
|
|||||||
|
|
||||||
#ifdef _SSGI
|
#ifdef _SSGI
|
||||||
vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb;
|
vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb;
|
||||||
fragColor.rgb += ssgiColor * albedo;
|
fragColor.rgb += ssgiColor * basecolor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _EmissionShadeless
|
#ifdef _EmissionShadeless
|
||||||
|
|||||||
@ -28,10 +28,12 @@ in vec2 texCoord;
|
|||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
const float GOLDEN_ANGLE = 2.39996323;
|
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) {
|
vec2 getProjectedCoord(const vec3 viewPos) {
|
||||||
vec4 projectedCoord = P * vec4(viewPos, 1.0);
|
vec4 projectedCoord = P * vec4(viewPos, 1.0);
|
||||||
|
if (projectedCoord.w <= 0.0) return vec2(-1e5);
|
||||||
projectedCoord.xy /= projectedCoord.w;
|
projectedCoord.xy /= projectedCoord.w;
|
||||||
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
|
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
|
||||||
#ifdef _InvY
|
#ifdef _InvY
|
||||||
@ -40,16 +42,12 @@ vec2 getProjectedCoord(const vec3 viewPos) {
|
|||||||
return projectedCoord.xy;
|
return projectedCoord.xy;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 cosineSampleHemisphere(vec3 n, vec2 rand) {
|
float linearZ(const float depth) {
|
||||||
float phi = PI * 2.0 * rand.x;
|
return -P[3].z / (depth + P[2].z);
|
||||||
float cosTheta = sqrt(1.0 - rand.y);
|
}
|
||||||
float sinTheta = sqrt(rand.y);
|
|
||||||
|
void buildTBN(vec3 n, out vec3 tangent, out vec3 bitangent) {
|
||||||
vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
|
|
||||||
|
|
||||||
vec3 tangent, bitangent;
|
|
||||||
vec3 absN = abs(n);
|
vec3 absN = abs(n);
|
||||||
|
|
||||||
if (absN.x <= absN.y && absN.x <= absN.z) {
|
if (absN.x <= absN.y && absN.x <= absN.z) {
|
||||||
tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0)));
|
tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0)));
|
||||||
} else if (absN.y <= absN.z) {
|
} 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)));
|
tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
|
||||||
}
|
}
|
||||||
bitangent = cross(n, tangent);
|
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);
|
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);
|
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 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;
|
pos += dir * stepSize;
|
||||||
|
rayDist += stepSize;
|
||||||
vec2 uv = getProjectedCoord(pos);
|
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, uv, 0.0).r * 2.0 - 1.0;
|
||||||
|
|
||||||
float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r * 2.0 - 1.0;
|
|
||||||
if (sampleDepth == 1.0) {
|
if (sampleDepth == 1.0) {
|
||||||
hadValidPrev = 0.0;
|
hasPrev = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float depthDiff = pos.z - linearZ(sampleDepth);
|
||||||
|
float thickness = maxDist * 0.075 + rayDist * 0.125;
|
||||||
|
|
||||||
vec3 sampleViewPos = getPosView2(invP, sampleDepth, sampleUV);
|
bool crossed = hasPrev && (prevDepthDiff > 0.0) && (depthDiff <= 0.0);
|
||||||
float depthDiff = pos.z - sampleViewPos.z;
|
bool withinThickness = (depthDiff <= 0.0) && (-depthDiff < thickness);
|
||||||
float rayDist = length(pos - origin);
|
|
||||||
float thickness = 0.15 + rayDist * 0.25;
|
|
||||||
|
|
||||||
float crossed = hadValidPrev * step(0.0, prevDepthDiff) * step(depthDiff, 0.0);
|
if (crossed || withinThickness) {
|
||||||
float withinThickness = step(abs(depthDiff), thickness);
|
vec3 bPos = pos;
|
||||||
|
vec3 bDir = dir * stepSize;
|
||||||
if (crossed > 0.5 || withinThickness > 0.5) {
|
for (int j = 0; j < BINARY_STEPS; j++) {
|
||||||
float distWeight = 1.0 - (rayDist / maxDist);
|
bDir *= 0.5;
|
||||||
distWeight = max(0.0, distWeight * distWeight);
|
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;
|
prevDepthDiff = depthDiff;
|
||||||
hadValidPrev = 1.0;
|
hasPrev = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return vec3(-1.0);
|
return vec3(-1.0);
|
||||||
@ -111,77 +133,77 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
||||||
vec2 enc = g0.rg;
|
vec3 n = getNor(g0.rg);
|
||||||
vec3 n;
|
vec3 basecolor = textureLod(gbuffer1, texCoord, 0.0).rgb;
|
||||||
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 viewNormal = V3 * n;
|
||||||
vec3 viewPos = getPosView2(invP, depth, texCoord);
|
vec3 viewPos = getPosView2(invP, depth, texCoord);
|
||||||
|
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
float radius = PPComp12.y;
|
float radius = PPComp12.y * 2.0;
|
||||||
float strength = PPComp12.x;
|
float strength = PPComp12.x * 0.5;
|
||||||
#else
|
#else
|
||||||
float radius = ssgiRadius;
|
float radius = ssgiRadius * 2.0;
|
||||||
float strength = ssgiStrength;
|
float strength = ssgiStrength * 0.5;
|
||||||
#endif
|
#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);
|
vec3 gi = vec3(0.0);
|
||||||
int validSamples = 0;
|
float missWeight = 0.0;
|
||||||
|
|
||||||
// min distance to avoid self shadowing artiffacts
|
// min distance to avoid self shadowing artiffacts
|
||||||
float minDist = radius * 0.05;
|
float minDist = radius * 0.05;
|
||||||
|
|
||||||
|
vec3 tangent, bitangent;
|
||||||
|
buildTBN(viewNormal, tangent, bitangent);
|
||||||
|
|
||||||
for (int i = 0; i < ssgiSamples; i++) {
|
for (int i = 0; i < ssgiSamples; i++) {
|
||||||
float fi = float(i) + noise;
|
float phi = float(i) * GOLDEN_ANGLE + noise * PI2;
|
||||||
vec2 rand = vec2(
|
float cosTheta = sqrt(max(0.0, 1.0 - (float(i) + 0.5) / float(ssgiSamples)));
|
||||||
fract(fi * 0.7548776662 + noise),
|
float jitter = fract(noise + float(i) * 0.618034);
|
||||||
fract(fi * 0.5698402909 + noise * 1.5)
|
|
||||||
);
|
|
||||||
|
|
||||||
vec3 rayDir = cosineSampleHemisphere(viewNormal, rand);
|
vec3 rayDir = sampleHemisphere(viewNormal, tangent, bitangent, phi, cosTheta);
|
||||||
vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist);
|
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;
|
vec2 hitUV = hitResult.xy;
|
||||||
float distWeight = hitResult.z;
|
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
|
#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));
|
float hitNdotL = max(0.0, dot(hitN, sunDir));
|
||||||
vec3 hitRadiance = hitAlbedo * sunCol * hitNdotL;
|
vec3 hitRadiance = hitAlbedo * (sunCol * hitNdotL + vec3(0.4));
|
||||||
#else
|
#else
|
||||||
vec3 hitRadiance = hitAlbedo * 0.5;
|
vec3 hitRadiance = hitAlbedo * 0.4;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _EmissionShaded
|
#ifdef _EmissionShaded
|
||||||
hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb;
|
hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gi += hitRadiance * distWeight;
|
gi += hitRadiance * (distWeight * emitterCos);
|
||||||
validSamples++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validSamples > 0) {
|
gi += basecolor * 0.1 * missWeight;
|
||||||
gi /= float(validSamples);
|
gi *= 2.0 * strength / float(ssgiSamples);
|
||||||
}
|
|
||||||
|
|
||||||
gi *= strength;
|
|
||||||
|
|
||||||
#ifdef _EmissionShaded
|
#ifdef _EmissionShaded
|
||||||
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3;
|
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fragColor = vec4(min(gi, vec3(2.0)), 1.0);
|
fragColor = vec4(min(gi, vec3(2.0)), 1.0);
|
||||||
|
|||||||
Reference in New Issue
Block a user