new and fast SSAO

The reason it doesn’t work with nvidia cards is because the back buffer has 0 alpha bits, which means that when the back buffer is read into a texture, there is no alpha data. For some reason, ATI drivers create a back buffer with 8 alpha bits, which is why the copy into the render texture copies the alpha values as well.

This problem should fix itself with phase 2 of Harmony when I move the 2D filter system over to FBOs.

I still couldn’t get any of the versions to work, but I think it may actually have something to do with the build of Blender that I’m running. I tried one of your older SSAO filters in version 2.49, and it worked(aside from the horrendous z-buffer precision issues- my gpu distributes the z-buffer precision in a weird way. Close things have far too much z-precision, and far things have far too little). However, I couldn’t get that same filter to run at all in 2.5, even after lots of tweaks.

WoW, good to know! Then we will have super frames with 2D filters enabled!

This looks fantastic, but im a noob so a little explaining on how to set it up, use it?

can someone explain me this (picture) … i have last blender 2.64 and the same thing is with all versions of SSAO from all threads … filter works only at top right corner =/


Not exactly sure what causes this, but a quick fix is to make the view full screen. If I get some free time I could take a look at martinsh’s latest filter and look to fix that problem properly.

Ex.

I get the same here in my AMD HD5850, even in full screen i get it.

I don’t know if that is a new bug, but it seems that gl_TexCoord[3] is not working correct.
I have changed gl_TexCoord[3] to gl_TexCoord[0].

Attachments

SSAO_2.64.blend (1.62 MB)

Im having trouble retrieving the ssao script from the .blend… Can someone just post the SSAO script please?

This script has settings for my outdoor environment, make sure to tweak the user variables if it does not work for your scene.

/*
SSAO GLSL shader v1.2
assembled by Martins Upitis (martinsh) (devlog-martinsh.blogspot.com)
original technique is made by Arkano22 (www.gamedev.net/topic/550699-ssao-no-halo-artifacts/)

changelog:
1.2 - added fog calculation to mask AO. Minor fixes.
1.1 - added spiral sampling method from here:
(http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere)
*/
uniform sampler2D bgl_DepthTexture;
uniform sampler2D bgl_RenderedTexture;
uniform float bgl_RenderedTextureWidth;
uniform float bgl_RenderedTextureHeight;

#define PI    3.14159265

float width = bgl_RenderedTextureWidth; //texture width
float height = bgl_RenderedTextureHeight; //texture height

vec2 texCoord = gl_TexCoord[0].st;

//------------------------------------------
//general stuff

//make sure that these two values are the same for your camera, otherwise distances will be wrong.

float znear = 0.05; //Z-near
float zfar = 1000.0; //Z-far

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

float radius = 10.0; //ao radius
float aoclamp = 0.45; //depth clamp - reduces haloing at screen edges
bool noise = false; //use noise instead of pattern for sample dithering
float noiseamount = 0.001; //dithering amount

float diffarea = 0.45; //self-shadowing reduction
float gdisplace = 0.6; //gauss bell center
float aowidth = 1.0; //gauss bell width

bool mist = true; //use mist?
float miststart = 0.0; //mist start
float mistend = 1000.0; //mist end

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

//--------------------------------------------------------

vec2 rand(vec2 coord) //generating noise/pattern texture for dithering
{
    float noiseX = ((fract(1.0-coord.s*(width/2.0))*0.25)+(fract(coord.t*(height/2.0))*0.75))*2.0-1.0;
    float noiseY = ((fract(1.0-coord.s*(width/2.0))*0.75)+(fract(coord.t*(height/2.0))*0.25))*2.0-1.0;
    
    if (noise)
    {
        noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0;
        noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0;
    }
    return vec2(noiseX,noiseY)*noiseamount;
}

float doMist()
{
    float zdepth = texture2D(bgl_DepthTexture,texCoord.xy).x;
    float depth = -zfar * znear / (zdepth * (zfar - znear) - zfar);
    return clamp((depth-miststart)/mistend,0.0,1.0);
}

float readDepth(in vec2 coord) 
{
    if (gl_TexCoord[0].x<0.0||gl_TexCoord[0].y<0.0) return 1.0;
    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;
    }
    
    float gauss = pow(2.7182,-2.0*(diff-gdisplace)*(diff-gdisplace)/(garea*garea));
    return gauss;
}   

float calAO(float depth,float dw, float dh)
{   
    //float dd = (1.0-depth)*radius;
    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);
    //DEPTH EXTRAPOLATION:
    if (far > 0)
    {
        temp2 = compareDepths(readDepth(coord2),depth,far);
        temp += (1.0-temp)*temp2;
    }
    
    return temp;
} 

void main(void)
{
    vec2 noise = rand(texCoord); 
    float depth = readDepth(texCoord);
    
    float w = (1.0 / width)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x));
    float h = (1.0 / height)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y));
    
    float pw;
    float ph;
    
    float ao;
    
    float dl = PI*(3.0-sqrt(5.0));
    float dz = 1.0/float(samples);
    float l = 0.0;
    float z = 1.0 - dz/2.0;
    
    for (int i = 0; i <= samples; i ++)
    {     
        float r = sqrt(1.0-z);
        
        pw = cos(l)*r;
        ph = sin(l)*r;
        ao += calAO(depth,pw*w,ph*h);        
        z = z - dz;
        l = l + dl;
    }
    
    ao /= float(samples);
    ao = 1.0-ao;    
    
    if (mist)
    {
    ao = mix(ao, 1.0,doMist());
    }
    
    vec3 color = texture2D(bgl_RenderedTexture,texCoord).rgb;
    
    vec3 lumcoeff = vec3(0.299,0.587,0.114);
    float lum = dot(color.rgb, lumcoeff);
    vec3 luminance = vec3(lum, lum, lum);
    
    vec3 final = vec3(color*mix(vec3(ao),vec3(1.0),luminance*lumInfluence));//mix(color*ao, white, luminance)
    
    if (onlyAO)
    {
    final = vec3(mix(vec3(ao),vec3(1.0),luminance*lumInfluence)); //ambient occlusion only
    }
    
    
    gl_FragColor = vec4(final,1.0); 
    
}

Umm, I don’t think this is normal…


Any ideas on how to fix this? BTW I’m one of those unlucky saps with Intel GFX.

The other blends you provided along with tweaking the values is not working on my end.

Thanks for the blend Martin its a very clever and effective version of SSAO. It would be nice if we could pass in textures to the custom filter but in lieu of that feature this is a great solution. Thanks very much for posting.

I had to crank up the luminosity effect setting

Is there any way the color of the AO to be changed to something different than black?

Yes, just change the ambient color under the world properties.

man im not getting the effect on my whole screen?? its just the half screen?


This is excellent. Should I use your forum name for credit?

Why does the ssao render over top of partially transparent materials? It makes some things look very strange. Is there a way to fix this? I have shadeless enabled and it doesn’t help.

How can you make the effect darker?