56 lines
2.2 KiB
GLSL
56 lines
2.2 KiB
GLSL
#version 450 core
|
|
#include "common.glsl"
|
|
// Half-res world-space hemisphere SSAO. Normals are reconstructed from depth
|
|
// (picking the flatter neighbour per axis to avoid smearing across edges).
|
|
|
|
in vec2 vUV;
|
|
layout(binding = 0) uniform sampler2D uDepth;
|
|
uniform float uRadius;
|
|
uniform float uIntensity;
|
|
layout(location = 0) out vec4 fragColor;
|
|
|
|
const int SAMPLES = 14;
|
|
|
|
vec3 posAt(vec2 uv) { return worldFromDepth(uv, texture(uDepth, uv).r); }
|
|
|
|
void main() {
|
|
float d = texture(uDepth, vUV).r;
|
|
if (d >= 1.0) {
|
|
fragColor = vec4(1.0);
|
|
return;
|
|
}
|
|
vec3 P = worldFromDepth(vUV, d);
|
|
vec2 t = 1.0 / vec2(textureSize(uDepth, 0));
|
|
vec3 px = posAt(vUV + vec2(t.x, 0)), nx = posAt(vUV - vec2(t.x, 0));
|
|
vec3 py = posAt(vUV + vec2(0, t.y)), ny = posAt(vUV - vec2(0, t.y));
|
|
vec3 dx = length(px - P) < length(P - nx) ? px - P : P - nx;
|
|
vec3 dy = length(py - P) < length(P - ny) ? py - P : P - ny;
|
|
vec3 N = normalize(cross(dx, dy));
|
|
if (dot(N, uCamPos.xyz - P) < 0.0) N = -N;
|
|
|
|
float rot = ign(gl_FragCoord.xy) * 6.2831853;
|
|
vec3 T = normalize(cross(N, abs(N.y) < 0.9 ? vec3(0, 1, 0) : vec3(1, 0, 0)));
|
|
vec3 B = cross(N, T);
|
|
float centerLin = linearDepth(d);
|
|
// Larger radius further away keeps the effect stable on screen.
|
|
float radius = uRadius * (0.8 + centerLin * 0.01);
|
|
|
|
float occ = 0.0;
|
|
for (int i = 0; i < SAMPLES; ++i) {
|
|
float fi = (float(i) + 0.5) / float(SAMPLES);
|
|
float a = float(i) * 2.399963 + rot;
|
|
float r = sqrt(fi);
|
|
float z = sqrt(max(0.0, 1.0 - r * r));
|
|
vec3 k = (T * cos(a) * r + B * sin(a) * r + N * z) * mix(0.15, 1.0, fi * fi);
|
|
vec3 S = P + N * 0.03 + k * radius;
|
|
vec4 clip = uViewProj * vec4(S, 1.0);
|
|
vec2 suv = clip.xy / clip.w * 0.5 + 0.5;
|
|
if (any(lessThan(suv, vec2(0.0))) || any(greaterThan(suv, vec2(1.0)))) continue;
|
|
float sceneLin = linearDepth(texture(uDepth, suv).r);
|
|
float range = smoothstep(0.0, 1.0, radius / max(abs(centerLin - sceneLin), 1e-3));
|
|
occ += step(sceneLin, clip.w - 0.02) * range;
|
|
}
|
|
float ao = 1.0 - occ / float(SAMPLES);
|
|
fragColor = vec4(pow(clamp(ao, 0.0, 1.0), uIntensity * 1.6));
|
|
}
|