Jump to content
  • Advertisement
Sign in to follow this  

DX11 DX11 SSAO - Is this right? Again...

This topic is 1969 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys,


this is kind of a re post and I am sorry for that, but this just isn't really working, or I don't think it is. Here is the results:


Without SSAO diffuse:










With SSAO:



Now some HLSL code:

Texture2D t_dffmap : register(t0);
Texture2D t_depthmap : register(t1);
Texture2D t_normalmap : register(t2);
Texture2D t_random : register(t3);
Texture2D t_blmextract : register(t4);
SamplerState ss;

cbuffer PARAMSBUFFER : register(b0)
	float time;
	float hblur;
	float bloomExtract;
	float bloom;
	float pixelDisortion;
	float pixelDisorterAmount;
	float ssao;
	float space;

cbuffer BloomBuffer : register(b1)
	float BloomThreshold;
	float BloomSaturation;
	float BaseSaturation;
	float BloomIntensity;
	float BaseIntensity;

cbuffer SSAOBuffer : register(b2)
	float g_scale;
	float g_bias;
	float g_sample_rad;
	float g_intensity;

struct VS_Output
    float4 Pos : SV_POSITION;              
    float2 Tex : TEXCOORD0;
    float2 texCoord1 : TEXCOORD1;
    float2 texCoord2 : TEXCOORD2;
    float2 texCoord3 : TEXCOORD3;
    float2 texCoord4 : TEXCOORD4;
    float2 texCoord5 : TEXCOORD5;
    float2 texCoord6 : TEXCOORD6;
    float2 texCoord7 : TEXCOORD7;
    float2 texCoord8 : TEXCOORD8;
    float2 texCoord9 : TEXCOORD9;
VS_Output VShader(uint id : SV_VertexID)
    VS_Output Output;
    Output.Tex = float2((id << 1) & 2, id & 2);
    Output.Pos = float4(Output.Tex * float2(2,-2) + float2(-1,1), 0, 1);

	if (hblur == 1)
		float texelSize = 1.0f / 800;

		// Create UV coordinates for the pixel and its four horizontal neighbors on either side.
		Output.texCoord1 = Output.Tex + float2(texelSize * -4.0f, 0.0f);
		Output.texCoord2 = Output.Tex + float2(texelSize * -3.0f, 0.0f);
		Output.texCoord3 = Output.Tex + float2(texelSize * -2.0f, 0.0f);
		Output.texCoord4 = Output.Tex + float2(texelSize * -1.0f, 0.0f);
		Output.texCoord5 = Output.Tex + float2(texelSize *  0.0f, 0.0f);
		Output.texCoord6 = Output.Tex + float2(texelSize *  1.0f, 0.0f);
		Output.texCoord7 = Output.Tex + float2(texelSize *  2.0f, 0.0f);
		Output.texCoord8 = Output.Tex + float2(texelSize *  3.0f, 0.0f);
		Output.texCoord9 = Output.Tex + float2(texelSize *  4.0f, 0.0f);
    return Output;

// Helper for modifying the saturation of a color.
float4 AdjustSaturation(float4 color, float saturation)
    // The constants 0.3, 0.59, and 0.11 are chosen because the
    // human eye is more sensitive to green light, and less to blue.
    float grey = dot(color, float3(0.3, 0.59, 0.11));

    return lerp(grey, color, saturation);

// Ambient Occlusion Stuff --------------------------------------------------

float3 getPosition(in float2 uv)
	return t_depthmap.Sample(ss, uv).xyz;

float3 getNormal(in float2 uv)
	return normalize(t_normalmap.Sample(ss, uv).xyz * 2.0f - 1.0f);

float2 getRandom(in float2 uv)
	return normalize(t_random.Sample(ss, float2(800, 600) * uv / float2(64, 64)).xy * 2.0f - 1.0f);

float doAmbientOcclusion(in float2 tcoord,in float2 uv, in float3 p, in float3 cnorm)
	float3 diff = getPosition(tcoord + uv) - p;
	const float3 v = normalize(diff);
	const float d = length(diff)*g_scale;
	return max(0.0,dot(cnorm,v)-g_bias)*(1.0/(1.0+d))*g_intensity;

// End

float4 PShader(VS_Output input) : SV_TARGET
	if (bloomExtract == 1)
		// Look up the original image color.
		float4 c = t_dffmap.Sample(ss, input.Tex);

		// Adjust it to keep only values brighter than the specified threshold.
		return saturate((c - BloomThreshold) / (1 - BloomThreshold));
	float4 color = float4(1.0f, 1.0f, 1.0f, 1.0f);
	if (pixelDisortion == 1)
		// Distortion factor
		float NoiseX = pixelDisorterAmount * (time/1000) * sin(input.Tex.x * input.Tex.y+time/1000);
		NoiseX=fmod(NoiseX,8) * fmod(NoiseX,4); 

		// Use our distortion factor to compute how much it will affect each
		// texture coordinate
		float DistortX = fmod(NoiseX,5);
		float DistortY = fmod(NoiseX,5+0.002);
		// Create our new texture coordinate based on our distortion factor
		input.Tex = float2(DistortX,DistortY);

	float4 dffMAP = t_dffmap.Sample(ss, input.Tex);

	if (hblur == 1)
		float weight0, weight1, weight2, weight3, weight4;
		float normalization;

		// Create the weights that each neighbor pixel will contribute to the blur.
		weight0 = 1.0f;
		weight1 = 0.9f;
		weight2 = 0.55f;
		weight3 = 0.18f;
		weight4 = 0.1f;

		 // Create a normalized value to average the weights out a bit.
		normalization = (weight0 + 2.0f * (weight1 + weight2 + weight3 + weight4));

		// Normalize the weights.
		weight0 = weight0 / normalization;
		weight1 = weight1 / normalization;
		weight2 = weight2 / normalization;
		weight3 = weight3 / normalization;
		weight4 = weight4 / normalization;

		// Add the nine horizontal pixels to the color by the specific weight of each.
		color += t_dffmap.Sample(ss, input.texCoord1) * weight4;
		color += t_dffmap.Sample(ss, input.texCoord2) * weight3;
		color += t_dffmap.Sample(ss, input.texCoord3) * weight2;
		color += t_dffmap.Sample(ss, input.texCoord4) * weight1;
		color += t_dffmap.Sample(ss, input.texCoord5) * weight0;
		color += t_dffmap.Sample(ss, input.texCoord6) * weight1;
		color += t_dffmap.Sample(ss, input.texCoord7) * weight2;
		color += t_dffmap.Sample(ss, input.texCoord8) * weight3;
		color += t_dffmap.Sample(ss, input.texCoord9) * weight4;
		color *= dffMAP;
	if (ssao == 1)
		// Apply SSAO

		const float2 vec[4] = {float2(1,0),float2(-1,0),

		float3 p = getPosition(input.Tex);
		float3 n = getNormal(input.Tex);
		float2 rand = getRandom(input.Tex);

		float ao = 0.0f;
		float rad = g_sample_rad/p.z; // g_s_r

		//**SSAO Calculation**//
		int iterations = 1;
		for (int j = 0; j < iterations; ++j)
		  float2 coord1 = reflect(vec[j],rand)*rad;
		  float2 coord2 = float2(coord1.x*0.707 - coord1.y*0.707,
					  coord1.x*0.707 + coord1.y*0.707);
		  ao += doAmbientOcclusion(input.Tex,coord1*0.25, p, n);
		  ao += doAmbientOcclusion(input.Tex,coord2*0.5, p, n);
		  ao += doAmbientOcclusion(input.Tex,coord1*0.75, p, n);
		  ao += doAmbientOcclusion(input.Tex,coord2, p, n);
		color.rgb *= ao;

	if(bloom == 1)
		// Look up the bloom and original base image colors.
		float4 cbloom = t_blmextract.Sample(ss, input.Tex);
		float4 base = color;
		// Adjust color saturation and intensity.
		cbloom = AdjustSaturation(cbloom, BloomSaturation) * BloomIntensity;
		base = AdjustSaturation(base, BaseSaturation) * BaseIntensity;
		// Darken down the base image in areas where there is a lot of bloom,
		// to prevent things looking excessively burned-out.
		base *= (1 - saturate(cbloom));
		// Combine the two images.
		color = base + cbloom;

	return color;



The variables for the SSAO is the following:



SSAOParameters.g_sample_rad = 3;
SSAOParameters.g_scale = 1;
SSAOParameters.g_intensity = 1;
SSAOParameters.g_bias = 0.001f;
Now what on earth, if, am I doing wrong?
Thank You
Edited by Migi0027

Share this post

Link to post
Share on other sites

Do you have an image with SSAO enabled?  The only thing that looks odd is the fact that your shadow isn't filled at all, but that isn't really relevant to SSAO at all.

Share this post

Link to post
Share on other sites

Sorry, some kind of error occurred so the rest of the post wasn't shown. Please re read the post, or at least the bottom.



Share this post

Link to post
Share on other sites

Do you have an image with SSAO enabled?  The only thing that looks odd is the fact that your shadow isn't filled at all, but that isn't really relevant to SSAO at all.


Ohh and the box, it's because receive shadows (variable) has been disabled for that box, I was just unlucky. biggrin.png

Share this post

Link to post
Share on other sites

The basics of SSAO appear to be generally working, as the samples tend to be darker near a corner.  However, you seem to have some sort of a depth bias in your calculations, because further into the scene things are getting darker.  If you look at the floor plane then you can see the difference between the foreground and the background, even though they have the exact same occluders in their local areas.


When you select the samples to take, are they being done in screen space or are they reprojected into world space?

Share this post

Link to post
Share on other sites

The darkness in the scene with SSAO, can it be because of my depth buffer?


I'm just trying to find a possible solution for this problem.

Share this post

Link to post
Share on other sites

Ohh, this might be useful:


The shader for normal and depth rendering:

cbuffer ConstantObjectBuffer : register (b0)
	matrix worldMatrix;
	matrix viewMatrix;
	matrix projectionMatrix;

	float state;
	float _instance;
	float _alphamap;
	float pad;

struct VOut
    float4 position : SV_POSITION;
    float4 depthPosition : TEXTURE0;
	float4 normal : NORMAL;
	float2 texcoord : TEXCOORD;
	float Depth : DEPTH;

Texture2D t_alphamap;
SamplerState ss;

VOut VShader(float4 position : POSITION, float4 normal : NORMAL, float2 texcoord : TEXCOORD, float3 instancePosition : INSTANCEPOS)
    VOut output;

	if (_instance == 1)
		position.x += instancePosition.x;
		position.y += instancePosition.y;
		position.z += instancePosition.z;

    position.w = 1.0f;
	output.texcoord = texcoord;

	// Calculate the position of the vertex against the world, view, and projection matrices.
    output.position = mul(position, worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);

	output.normal = normal;

	// Store the position value in a second input value for depth value calculations.
	output.depthPosition = output.position;
	output.Depth = output.position.z;

    return output;

float4 PShader(VOut input) : SV_TARGET
	float4 color = float4(1,1,1,1);

	if (state == 5 || state == 2) // DEPTH
		float depthValue = input.depthPosition.z / input.depthPosition.w;

		color = float4(depthValue, depthValue, depthValue, 1);
	else if (state == 6) // NORMALS
		float3 viewSpaceNormalizedNormals = 0.5 * normalize (input.normal) + 0.5;
		color = float4(viewSpaceNormalizedNormals, 1);

	return color;


Don't worry about the ifs, what's really important is if I'm mapping the depth and normal buffers correctly?

Share this post

Link to post
Share on other sites

It looks like you are using perspective depth, which would probably explain the increasing darkness as you move into the scene.  You are using screen space offsets from the pixel being processed, which aren't linear with z, so your pixels that are far away are skewed toward being occluded.


What you should be doing is to find the linear space position of the current pixel, then add a linear space vector offset to it, then reproject that point back to projection space and sample the point.  That would (most likely) make the darkening go away.

Share this post

Link to post
Share on other sites

Sorry, but how would I achieve that Jason Z?


Some of these topics are still quite new for me as this is self taught, so I'm still trying to understand every single bit.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!