I'm trying to implement SSAO based on this tutorial. My setup:
- OpenGL 3.2
- Forward renderer
- View-space depth and normal in a single 16-bit floating point texture.
The result I get is this:
The black area follows the camera and is always in the center of the screen. This is my depth/normal pass shader:
#version 150 core
#extension GL_ARB_explicit_attrib_location : enable
uniform mat4 _ViewMatrix;
uniform mat4 _ViewProjectionMatrix;
uniform mat4 modelMatrix;
layout (location = 0) in vec4 aPosition;
layout (location = 2) in vec3 aNormal;
out vec4 vPosition;
out vec3 vNormal;
// Vertex shader.
void main()
{
gl_Position = _ViewProjectionMatrix * modelMatrix * aPosition;
mat4 modelViewMatrix = _ViewMatrix * modelMatrix;
vPosition = modelViewMatrix * aPosition;
vNormal = mat3( modelViewMatrix ) * aNormal;
}
// Fragment shader:
#version 150 core
in vec4 vPosition;
in vec3 vNormal;
out vec4 outDepthNormal;
void main()
{
outDepthNormal = vec4( vPosition.z, normalize( vNormal ));
}
This is my SSAO shader:
// Vertex shader:
#version 150 core
#extension GL_ARB_explicit_attrib_location : enable
uniform float uTanHalfFov;
uniform float uAspectRatio;
layout (location = 0) in vec4 aPosition;
layout (location = 1) in vec2 aTexCoord;
out vec2 vTexCoord;
noperspective out vec3 vViewDir;
void main()
{
gl_Position = aPosition;
vTexCoord = aTexCoord;
vViewDir = vec3( -aPosition.x * uTanHalfFov * uAspectRatio, -aPosition.y * uTanHalfFov, 1.0 );
}
// Fragment shader:
#version 150 core
uniform sampler2D depthNormalMap;
uniform sampler2D noiseMap;
uniform mat4 _ProjectionMatrix;
uniform int uKernelSize;
const int MAX_KERNEL_SIZE = 128;
uniform vec3 uKernelOffsets[ MAX_KERNEL_SIZE ];
uniform float uRadius;
uniform float uPower;
in vec2 vTexCoord;
noperspective in vec3 vViewDir;
out vec4 fragColor;
float ssao( in mat3 kernelBasis, in vec3 originPos, in float radius )
{
float occlusion = 0.0;
for (int i = 0; i < uKernelSize; ++i)
{
vec3 samplePos = kernelBasis * uKernelOffsets[i];
samplePos = samplePos * radius + originPos;
// project sample position:
vec4 offset = _ProjectionMatrix * vec4( samplePos, 1.0 );
offset.xy /= offset.w; // only need xy
offset.xy = offset.xy * 0.5 + 0.5; // scale/bias to texcoords
// get sample depth:
float sampleDepth = texture( depthNormalMap, offset.xy ).r;
float rangeCheck = smoothstep( 0.0, 1.0, radius / abs( originPos.z - sampleDepth ) );
occlusion += rangeCheck * step( sampleDepth, samplePos.z );
}
occlusion = 1.0 - (occlusion / float( uKernelSize ));
return pow( abs( occlusion ), uPower );
}
void main()
{
vec2 noiseTexCoords = vec2( textureSize( depthNormalMap, 0 )) / vec2( textureSize( noiseMap, 0 ) );
noiseTexCoords *= vTexCoord;
// get view space origin:
float originDepth = texture( depthNormalMap, vTexCoord ).r;
vec3 originPos = normalize( vViewDir ) * originDepth;
// get view space normal:
vec3 normal = normalize( texture( depthNormalMap, vTexCoord ).gba );
// construct kernel basis matrix:
vec3 rvec = normalize( texture( noiseMap, noiseTexCoords ).rgb );
vec3 tangent = normalize( rvec - normal * dot( rvec, normal ) );
vec3 bitangent = cross( tangent, normal );
mat3 kernelBasis = mat3( tangent, bitangent, normal );
fragColor = vec4( ssao( kernelBasis, originPos, uRadius ) );
}
I guess something is going wrong with the depth reconstruction.