SSAO - artifacts appearing 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&lt;float&gt; randomFloats(0.0f, 1.0f);
std::default_random_engine generator;
XMFLOAT3 tmpSample;
for (int i = 0; i &lt; 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 &lt; 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 &gt;= sample.z + bias ? 1.0 : 0.0);
}
occlusion = 1.0f - (occlusion / 64.0f);

return float4(occlusion, occlusion, occlusion, 1.0f);
}
Offset.xy is definatelly off because it just return XY coordinates from screenspace:


Clamping solved 'small copies of model' on the model itself, thanks!

sampleDepth actually looks like this and indeed is not in viewspace and it may really explain those little models now:


Using viewspace (offset = mul(projection, offset) ---> offset = mul(view, offset)) solves depth problem but final buffer is clear white. No effects are actually visible. What next step do you suggest? If depth comparing is correct now, what might be off?


UPDATE:
Comparision is working but in a wrong way. Below line results in just fully white buffer screen:

occlusion += (sampleDepth &gt;= sample.z + bias ? 1.0 : 0.0);


Changing it to:

occlusion += (sampleDepth &gt;= sample.z - bias ? 1.0 : 0.0);


Actually gives us comparision but it is really bold and doesn't include only holes and creases but whole model. Changing bias to small values like 0.001f doesn't help:


Update #2:
Directly comparing gives result presented below. However it doesn't seem satisfying enough to use as it seems to present rather edges than creases and holes:

occlusion += (sampleDepth == sample.z ? 1.0 : 0.0);