#version 330 core in vert_t { vec2 tex_coords; } vert; out float frag_color; uniform sampler2D positions; uniform sampler2D normals; uniform sampler2D noise; uniform vec3 samples[64]; uniform mat4 projection; const vec2 noise_scale = vec2(1600.0 / 4.0, 900.0 / 4.0); void main() { vec3 position = texture(positions, vert.tex_coords).rgb; vec3 normal = texture(normals, vert.tex_coords).rgb; vec3 random = texture(noise, vert.tex_coords * noise_scale).rgb; vec3 tangent = normalize(random - normal * dot(random, normal)); vec3 bitangent = cross(normal, tangent); mat3 TBN = mat3(tangent, bitangent, normal); int nsamples = 64; float radius = 0.5; float bias = 0.025; float occlusion = 0.0; for (int i = 0; i < nsamples; i++) { vec3 sample = TBN * samples[i]; sample = position + sample * radius; vec4 offset = vec4(sample, 1.0); offset = projection * offset; offset.xyz /= offset.w; offset.xyz = offset.xyz * 0.5 + 0.5; float depth = texture(positions, offset.xy).z; float range_check = smoothstep(0.0, 1.0, radius / abs(position.z - depth)); occlusion += (depth >= sample.z + bias ? 1.0 : 0.0) * range_check; } occlusion = 1.0 - (occlusion / nsamples); frag_color = occlusion; }