

float ld(float dist)
{
    return (2.0 * near) / (far + near - dist * (far - near));
}

vec2 tapLocation(int sampleNumber, float spinAngle, float r0)
{
    float alpha = (float(sampleNumber + r0) * 0.142857);
    float angle = alpha * 552.64 + spinAngle * 6.28;

    float sin_v, cos_v;

    sin_v = sin(angle);
    cos_v = cos(angle);

    return vec2(cos_v, sin_v) * alpha;
}

float dbao(float dither, float depth)
{
    const int samples = 4;
    const float piSquared = PI * PI;
    float twoNear = 2.0 * near;
    float farMinusNear = far - near;
    float farPlusNear = far + near;
    float twoFar = 2.0 * far;
    float invAspectRatio = 1.0 / aspectRatio;
    float gbufferProj = gbufferProjection[1][1];

    float ao = 0.0;
    float d = twoNear / (farPlusNear - depth * farMinusNear);
    vec2 scale = (piSquared * dither * vec2(invAspectRatio, 1.0) * gbufferProj) / (piSquared * far * d);

    for (int i = 1; i <= samples; i++)
    {
        float x = i + dither;
        float n = fract(x * 1.414) * PI;
        vec2 offset = vec2(cos(n), sin(n)) * x / samples * scale;

        vec2 texCoordOffsetPlus = texcoord.xy + offset;
        vec2 texCoordOffsetMinus = texcoord.xy - offset;

        float depthTexPlus = texture2D(depthtex0, texCoordOffsetPlus).r;
        float depthTexMinus = texture2D(depthtex0, texCoordOffsetMinus).r;

        float sd1 = twoNear / (farPlusNear - depthTexPlus * farMinusNear);
        float sd2 = twoNear / (farPlusNear - depthTexMinus * farMinusNear);

        float sample1 = (d - sd1) * twoFar;
        float sample2 = (d - sd2) * twoFar;

        float angle1 = clamp(0.5 - sample1, 0.0, 1.0);
        float angle2 = clamp(0.5 - sample2, 0.0, 1.0);

        float dist1 = clamp(0.25 * sample1 - 1.0, 0.0, 1.0);
        float dist2 = clamp(0.25 * sample2 - 1.0, 0.0, 1.0);

        ao += clamp(angle1 + dist1 + angle2 + dist2, 0.0, 1.0);
    }

    return ao / samples;
}
