I was goofing around with SSAO and I realized something.
Firstly, here’s my SSAO fragment shader code:
#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:
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
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:
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: