

float RT(vec3 dir, vec3 position, float noise)
{

    vec3 clipPosition = toClipSpace3(position);

    float rayLength = ((position.z + dir.z * sqrt(3.0) * far) > -sqrt(3.0) * near) ? (-sqrt(3.0) * near - position.z) / dir.z : sqrt(3.0) * far;

    vec3 end = toClipSpace3(position + dir * rayLength);

    vec3 direction = end - clipPosition;
    float len = max(abs(direction.x) / texelSize.x, abs(direction.y) / texelSize.y);

    vec3 stepv = direction / len;

    float scaledNoise = 32.0 * noise + 1.0;

    vec3 scaledStep = stepv * scaledNoise;

    vec3 spos = clipPosition + scaledStep;

    spos.xy += offsets[framemod8] * texelSize * 0.5;

    float sp = linZ(texelFetch(depthtex0, ivec2(spos.xy / texelSize), 0).r);

    float currZ = linZ(spos.z);
    float out1 = 1.0 - float((sp < currZ && distance(sp, currZ) / currZ < noise * 0.2));

    return out1;
}

vec2 R2_samples(int n)
{
    vec2 alpha = vec2(0.75487765, 0.56984026);
    return fract(alpha * n);
}
vec3 GenerateUnitVector(vec2 xy)
{
    const float tau = radians(360.0);

    xy.x *= tau;
    xy.y = xy.y * 2.0 - 1.0;
    return vec3(vec2(cos(xy.x), sin(xy.x)) * sqrt(1.0 - xy.y * xy.y), xy.y);
}

vec3 GenerateCosineVector(vec3 vector, vec2 xy)
{

    return normalize(vector + GenerateUnitVector(xy));
}

float rtao(float skyLight, vec3 normal, vec3 fragpos)
{

    int samples = 4;
    float occlusion = 0.0;
    for (int i = 0; i < samples; i++)
    {
        int seed = frameCounter * int(samples) + i;
        vec2 ij = fract(R2_samples(seed) + blueNoise4(gl_FragCoord.xy).rg);
        vec3 L = GenerateCosineVector(normal, ij);

        occlusion += RT(mat3(gbufferModelView) * L, fragpos.xyz, InterleavedGradientNoise2(gl_FragCoord.xy));
    }

    return pow(occlusion / float(samples), 1.75);
}
