I am trying to implement SSAO using DirectX11 but instead I got white screen with few black dots on model. My suspect is that kernel generation or usage might be wrong. I've tried changing order of TBN matrix and sample multiplication order in pixel shader and it doesn't change results in any way:
In fact those "dots" are small models of model itself that appear on it instead of dark creases (Example with sphere model):
My G-Buffers looks like this (Position, normal, tangent, bitangent):
myKernelGeneration.cpp
//Create kernel for SSAO
std::uniform_real_distribution<float> randomFloats(0.0f, 1.0f);
std::default_random_engine generator;
XMFLOAT3 tmpSample;
for (int i = 0; i < SSAO_KERNEL_SIZE; i++)
{
//Generate random vector3 ([-1, 1], [-1, 1], [0, 1])
tmpSample.x = randomFloats(generator) * 2.0f - 1.0f;
tmpSample.y = randomFloats(generator) * 2.0f - 1.0f;
tmpSample.z = randomFloats(generator);
//Normalize vector3
XMVECTOR tmpVector;
tmpVector.m128_f32[0] = tmpSample.x;
tmpVector.m128_f32[1] = tmpSample.y;
tmpVector.m128_f32[2] = tmpSample.z;
tmpVector = XMVector3Normalize(tmpVector);
tmpSample.x = tmpVector.m128_f32[0];
tmpSample.y = tmpVector.m128_f32[1];
tmpSample.z = tmpVector.m128_f32[2];
//Multiply by random value all coordinates of vector3
//float randomMultiply = randomFloats(generator);
//tmpSample.x *= randomMultiply;
//tmpSample.y *= randomMultiply;
//tmpSample.z *= randomMultiply;
//Scale samples so they are more aligned to middle of hemisphere
float scale = float(i) / 64.0f;
scale = lerp(0.1f, 1.0f, scale * scale);
tmpSample.x *= scale;
tmpSample.y *= scale;
tmpSample.z *= scale;
//Pass value to array
m_ssaoKernel[i] = tmpSample;
}
myPixelShader.ps
Texture2D textures[3]; //position, normal, noise
SamplerState SampleType;
//////////////
// TYPEDEFS //
//////////////
cbuffer KernelBuffer
{
float3 g_kernelValue[64];
};
struct PixelInputType
{
float4 positionSV : SV_POSITION;
float2 tex : TEXCOORD0;
float4x4 projection : TEXCOORD1;
};
const float2 noiseScale = float2(1280.0f / 4.0f, 720.0f / 4.0f);
const float radius = 0.5f;
const float bias = 0.025f;
////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 ColorPixelShader(PixelInputType input) : SV_TARGET
{
float3 position = textures[0].Sample(SampleType, input.tex).xyz;
float3 normal = normalize(textures[1].Sample(SampleType, input.tex).rgb);
float3 randomVector = normalize(textures[2].Sample(SampleType, input.tex * noiseScale).xyz);
float3 tangent = normalize(randomVector - normal * dot(randomVector, normal));
float3 bitangent = cross(normal, tangent);
float3x3 TBN = { tangent, bitangent, normal };
float3 sample = float3(0.0f, 0.0f, 0.0f);
float4 offset = float4(0.0f, 0.0f, 0.0f, 0.0f);
float occlusion = 0.0f;
for (int i = 0; i < 64; i++)
{
sample = mul(TBN, g_kernelValue[i]);
sample = position + sample * radius;
offset = float4(sample, 1.0f);
offset = mul(input.projection, offset);
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5f + 0.5f;
float sampleDepth = textures[0].Sample(SampleType, offset.xy).z;
occlusion += (sampleDepth >= sample.z + bias ? 1.0 : 0.0);
}
occlusion = 1.0f - (occlusion / 64.0f);
return float4(occlusion, occlusion, occlusion, 1.0f);
}