
uniform sampler2D g_position;
uniform sampler2D g_normal;
uniform sampler2D noise;

uniform mat4 projection;
uniform vec3 samples[kernel_size];

layout (location = 0) out float frag_color;

const float radius = 60.0;
const float bias = 0.025;

void main() {
    vec3 frag_pos = texelFetch(g_position, ivec2(gl_FragCoord.xy * 2), 0).xyz;
    vec3 normal = texelFetch(g_normal, ivec2(gl_FragCoord.xy * 2), 0).xyz * 2.0 - 1.0;
    vec3 random = texture(noise, (gl_FragCoord.xy * 2.0) / 4.0, 0).xyz;

    vec3 tangent = normalize(random - normal * dot(random, normal));
    vec3 bitangent = cross(normal, tangent);
    mat3 tbn = mat3(tangent, bitangent, normal);

    float occlusion = 0.0;
    for (int i = 0; i < kernel_size; ++i) {
        vec3 sample = tbn * samples[i];
        sample = frag_pos + 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(g_position, offset.xy).z;
        float range_check = smoothstep(0.0, 1.0, 7.0 / abs(depth - frag_pos.z));
        occlusion += float(depth <= sample.z + bias) * range_check;
    }

    occlusion = 1.0 - (occlusion / float(kernel_size));
    frag_color = occlusion;
}
