Faster SSAO

This is an optimized version of @martinish’s shader. I refactored almost everything.
It’s simpler (no mist) but it still looks great. Here’s a comparison:

@martinish’s version:

My version:


(Tested in UPBGE)

Here’s the code:


uniform sampler2D bgl_DepthTexture;
uniform sampler2D bgl_RenderedTexture;
uniform float bgl_RenderedTextureWidth;
uniform float bgl_RenderedTextureHeight;


#define PI 3.14159265
#define SQRT5 2.2360679775


float width = bgl_RenderedTextureWidth;
float height = bgl_RenderedTextureHeight;


vec2 texCoord = gl_TexCoord[0].st;


float znear = 0.3; //Z-near
float zfar = 60.0; //Z-far


//user variables
int samples = 32; //ao sample count


float radius = 3.0; //ao radius
float aoclamp = 0.2; //depth clamp - reduces haloing at screen edges


float diffarea = 0.3; //self-shadowing reduction
float gdisplace = 0.5; //gauss bell center
float aowidth = 8.0; //gauss bell width


bool onlyAO = false; //use only ambient occlusion pass?
float lumInfluence = 0.6; //how much luminance affects occlusion


float readDepth(in vec2 coord) {
    return (2.0 * znear) / (zfar + znear - texture2D(bgl_DepthTexture, coord).x * (zfar - znear));
}


float compareDepths(in float depth1, in float depth2, inout int far) {   
    float garea = aowidth; //gauss bell width    
    float diff = (depth1 - depth2) * 100.0; //depth difference (0-100)


    //reduce left bell width to avoid self-shadowing 
    if (diff < gdisplace) {
       garea = diffarea;
    } else {
       far = 1;
    }
    return pow(2.7182, -2.0 * (diff - gdisplace) * (diff - gdisplace) / (garea * garea));
}   


float calAO(float depth, float dw, float dh) {
    float dd = radius;
    float temp = 0.0;
    float temp2 = 0.0;
    float coordw = gl_TexCoord[0].x + dw * dd;
    float coordh = gl_TexCoord[0].y + dh * dd;
    float coordw2 = gl_TexCoord[0].x - dw * dd;
    float coordh2 = gl_TexCoord[0].y - dh * dd;
    
    vec2 coord = vec2(coordw, coordh);
    vec2 coord2 = vec2(coordw2, coordh2);
    
    int far = 0;
    temp = compareDepths(depth, readDepth(coord),far);
    if (far > 0) {
        temp2 = compareDepths(readDepth(coord2), depth, far);
        temp += (1.0 - temp) * temp2;
    }
    
    return temp;
} 


void main(void) {
    float depth = readDepth(texCoord);
    
    float dclamp = clamp(depth, aoclamp, 1.0);
    float w = (1.0 / width) / dclamp;
    float h = (1.0 / height) / dclamp;
    
    float dl = PI * (3.0 - SQRT5);
    float dz = 1.0 / float(samples);
    float l = 0.0;
    float z = 1.0 - (dz / 2.0);
    
    float ao = 0.0;


    for (int i = 0; i <= samples; i++)    {     
        float r = 1.0 - z;
        float pw = cos(l) * r;
        float ph = sin(l) * r;
        
        ao += calAO(depth, pw * w, ph * h) * dz;


        z -= dz;
        l += dl;
    }


    vec3 color = texture2D(bgl_RenderedTexture, texCoord).rgb;
    float lum = (color.r + color.g + color.b) / 3.0;
    vec3 ambientOcc = mix(vec3(1.0 - ao), vec3(1.0), lum * lumInfluence);
    
    if (!onlyAO) {
        gl_FragColor = vec4(color * ambientOcc, 1.0);
    } else {
        gl_FragColor = vec4(ambientOcc, 1.0);
    }
}

That is awesome! great work.

Super cool! This looks a lot cleaner too!

Yeah seriously, this is impressive. For some reason it give my particular game character/objects a better and different look than martin’s. (BGE)