Weird SSAO halo

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 :stuck_out_tongue:

Initial results:

https://anuj-rao.tinytake.com/media/3e6002?filename=1474366755903_20-09-2016-06-19-00.png&sub_type=thumbnail_preview&type=attachment&width=700&height=427&_felix_session_id=a8b84e98fb6c0e7088ab4e1cbef1bc40&salt=OTgyNDQ0XzQwODc4MTA

After change:

https://anuj-rao.tinytake.com/media/3e5fe9?filename=1474366614222_20-09-2016-06-16-36.png&sub_type=thumbnail_preview&type=attachment&width=700&height=425&_felix_session_id=a8b84e98fb6c0e7088ab4e1cbef1bc40&salt=OTgyNDMxXzQwODc3ODU