I was goofing around with SSAO and I realized something.

Firstly, here's my SSAO fragment shader code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #version 400 core
in vec2 passTextureCoords;
out vec4 outColour;
uniform sampler2D gPositionDepth; uniform sampler2D gNormals; uniform sampler2D noiseTexture; uniform vec3 samples[32]; uniform mat4 projMatrix;
const vec2 noiseScale = vec2(1280.0/4.0, 780.0/4.0);
void main(void){ vec3 fragPos = texture(gPositionDepth, passTextureCoords).xyz; vec3 normal = texture(gNormals, passTextureCoords).xyz; vec3 randomVec = texture(noiseTexture, passTextureCoords * noiseScale).xyz; vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal)).xyz; vec3 bitangent = cross(normal, tangent); mat3 TBN = mat3(tangent, bitangent, normal); float occlusion = 0; int radius = 2; for(int i = 0; i < 32; i++){ vec3 samp = TBN * samples[i]; samp = fragPos + samp * radius; vec4 offset = vec4(samp, 1.0); offset = projMatrix * offset; offset.xyz /= offset.w; offset.xyz = offset.xyz * 0.5 + 0.5; float sampleDepth = texture(gPositionDepth, offset.xy).z; float rangeCheck = abs(samp.z - sampleDepth) < radius ? 1.0 : 0.0; occlusion += (sampleDepth >= samp.z ? 1.0 : 0.0) * rangeCheck; } occlusion = 1 - occlusion/32; outColour = vec4(occlusion); } |

This works perfectly fine. No halos, nothing.

However, take a look at this part:

1 2 3 4 5 6
| float sampleDepth = texture(gPositionDepth, offset.xy).z; float rangeCheck = abs(samp.z - sampleDepth) < radius ? 1.0 : 0.0; occlusion += (sampleDepth >= samp.z ? 1.0 : 0.0) * rangeCheck; } occlusion = 1 - occlusion/32; |

I thought it didn't make sense. I mean, I should be checking if there's any geometry occluding the sample in the sample kernel. Following logic, I should be checking if sampleDepth is less than samp.z

But then I noticed that I was doing

1
| occlusion = 1 - occlusion/32; |

. Because of the subtraction of the normalized occlusion factor from 1, it was working properly.

So I tried changing it to the following:

1 2 3 4 5 6
| float sampleDepth = texture(gPositionDepth, offset.xy).z; float rangeCheck = abs(samp.z - sampleDepth) < radius ? 1.0 : 0.0; occlusion += (sampleDepth <= samp.z ? 1.0 : 0.0) * rangeCheck; } occlusion = occlusion/32; |

As you can see, I changed sampleDepth >= samp.z to sampleDepth <= samp.z, which makes more sense.

And I also removed the "1 - " part. But now there's a black halo around the mesh, and it doesn't look very nice. I see no reason why it should be like this. Maybe it's just me being dumb, I dunno

Initial results:

After change: