forked from LeenkxTeam/LNXSDK
189 lines
4.5 KiB
GLSL
189 lines
4.5 KiB
GLSL
#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);
|
|
}
|