Sign in to follow this  
TheImpWithNoName

Directx 9 SSAO Problems

Recommended Posts

I've been trying for the last few weeks to implement the Starcraft 2 implementaion of SSAO as detailed in Games Programming Gems 8 and it's bamboozling me. I need to implement it in my direct x 9 application for my final university project and while I've got it to do something, it is a wrong something.

I'm not sure whether it's a problem with the SSAO code itself or with the data I'm passing into it.

Here's a shot of my scene with just the SSAO ambient term:

[attachment=1472:Untitled-1.jpg] <- The screen on the left is looking at the scene through a wall - so you shouldn't be able to see the SSAO but you can for some reason. THe shot on the right is looking at it from the front. The SSAO also seems to move and shift when the camera angle changes.

I can render out my depth and normals to a D3DFMT_A16B16G16R16F texture - storing depth in a and normals in rgb and that works okay. I'm not sure though if I'm working in the same space for both the depth shader and the SSAO shader. I would really appreciate some advice on this.

Depth Shader

[code]uniform extern float4x4 gWVP;
uniform extern float4x4 gWV;


struct CreateDepthMap_VSIn
{

float4 Position : POSITION;
float3 Normal: NORMAL;

};


struct CreateDepthMap_VSOut
{

float4 Position: POSITION;
float Depth: TEXCOORD0;
float3 Normal: TEXCOORD1;

};

CreateDepthMap_VSOut CreateDepthMapVS(CreateDepthMap_VSIn Input)
{

CreateDepthMap_VSOut Out = (CreateDepthMap_VSOut)0;

Out.Position = mul(Input.Position, gWVP);

Out.Depth = Out.Position.z/500.0f;

Out.Normal.rgb = 0.5f * (normalize(Input.Normal) + 1.0f);


return Out;
}

float4 CreateDepthMapPS(CreateDepthMap_VSOut Input):COLOR
{


return float4(Input.Normal.r, Input.Normal.g, Input.Normal.b, Input.Depth);

}

technique CreateDepthMapTech
{
pass CreateDepthMap
{
vertexShader = compile vs_3_0 CreateDepthMapVS();
pixelShader = compile ps_3_0 CreateDepthMapPS();
}
}[/code]

And the SSAO part of my lighting shader

[code]//---------------------------------------------------------------------------------------------------------------------------
//SSAO functions
//---------------------------------------------------------------------------------------------------------------------------

//shader code to map pixel from screen space to view space

//p_vReciepDepthBufferSize = 1.0/ depth buffer width and height in pixels (512x512??)
//p_vCameraFrustrumSize = Full width and height of camera frustrum at the camera's near plane in world space

float2 = vVip_vReciepDepthBufferSize = (1.0f/512.0f, 1.0f/512.0f);
float2 p_vCameraFrustrumSize = (512.0f,512.0f);

float3 TwoDPosToViewPos( float3 i_VPOS, out float2 vScreenUV)
{
float2 vViewSpaceUV = i_VPOS * p_vReciepDepthBufferSize;
vScreenUV = vViewSpaceUV;

//from 0..1 to 0..2
vViewSpaceUVewSpaceUV * float2(2.0f, -2.0f);
//from 0..2 to -1..1
vViewSpaceUV = vViewSpaceUV + float2 (-1.0f, 1.0f);
vViewSpaceUV = vViewSpaceUV * p_vCameraFrustrumSize * 0.5f;

return float3 (vViewSpaceUV.x, vViewSpaceUV.y, 1.0f) * tex2D (DepthMapSampler, vScreenUV).a;

}


//hlsl code used to implement occlusion function

float OcclusionFunction( float fDistance, float fFullOcclusionThreshold, float fNoOcclusionThreshold, float fOcclusionPower)
{
const float c_OcclusionEpsilon = 0.01f;

if( fDistance > c_OcclusionEpsilon)
{
//past this distance there is no occlusion
float fNoOcclusionRange = fNoOcclusionThreshold - fFullOcclusionThreshold;

if( fDistance < fFullOcclusionThreshold )
return 1.0f;
else return max( 1.0f - pow( abs((fDistance - fFullOcclusionThreshold) / fNoOcclusionRange), fOcclusionPower ), 0.0f );

}
else return 0.0f;

}

//hlsl code used to test occlusion by a neighbouring pixel

float TestOcclusion( float3 vViewPos, float3 vSamplePointDelta, float fOcclusionRadius, float fFullOcclusionThreshold, float fNoOcclusionThreshold, float fOcclusionPower)
{
float3 vSamplePoint = vViewPos + fOcclusionRadius * vSamplePointDelta;
float2 vSamplePointUV = vSamplePoint.xy/ vSamplePoint.z;
vSamplePointUV = vSamplePointUV / p_vCameraFrustrumSize / 0.5f;
vSamplePointUV = vSamplePointUV + float2( 1.0f, -1.0f);
vSamplePointUV = vSamplePointUV * float2( 0.5f, -0.5f);

float fSampleDepth = tex2D (DepthMapSampler, vSamplePointUV).a;

float fDistance = vSamplePoint.z - fSampleDepth;

return OcclusionFunction ( fDistance, fFullOcclusionThreshold, fNoOcclusionThreshold, fOcclusionPower);

}

//hlsl code used to generate a set of semi random 3D vectors at each pixel

float reflect( float3 vSample, float3 vNormal)
{
return normalize (vSample - 2.0f * dot (vSample, vNormal ) * vNormal);
}

float3x3 MakeRotation (float fAngle, float3 vAxis)
{

float fS;
float fC;
sincos( fAngle, fS, fC);
float fXX = vAxis.x * vAxis.x;
float fYY = vAxis.y * vAxis.y;
float fZZ = vAxis.z * vAxis.z;
float fXY = vAxis.x * vAxis.y;
float fYZ = vAxis.y * vAxis.z;
float fZX = vAxis.z * vAxis.x;
float fXS = vAxis.x * fS;
float fYS = vAxis.y * fS;
float fZS = vAxis.z * fS;
float fOneC = 1.0f - fC;

float3x3 result = float3x3 ( fOneC * fXX + fC, fOneC * fXY + fZS, fOneC * fZX - fYS, fOneC * fXY - fZS, fOneC * fYY + fC, fOneC * fYZ + fXS, fOneC * fZX + fYS, fOneC * fYZ - fXS, fOneC * fZZ + fC);
return result;

}

//SSAO filter
//i_VPOS is screen pixel coordinate as given by HLSL VPOS interpolant.
//p_vSSAOSamplePoints is a distribution of sample offsets for each sample

int iSampleCount = 16;
float p_fOcclusionRadius = 0.005f;
float p_fFullOcclusionThreshold = 0.5f;
float p_fOcclusionPower = 3.0f;
float p_fNoOcclusionThreshold =1.0f;

float3 p_vSSAOSamplePoints[16] =
{
float3(0.53812504, 0.18565957, -0.43192),
float3(0.13790712, 0.24864247, 0.44301823),
float3(0.33715037, 0.56794053, -0.005789503),
float3(-0.6999805, -0.04511441, -0.0019965635),
float3(0.06896307, -0.15983082, -0.85477847),
float3(0.056099437, 0.006954967, -0.1843352),
float3(-0.014653638, 0.14027752, 0.0762037),
float3(0.010019933, -0.1924225, -0.034443386),
float3(-0.35775623, -0.5301969, -0.43581226),
float3(-0.3169221, 0.106360726, 0.015860917),
float3(0.010350345, -0.58698344, 0.0046293875),
float3(-0.08972908, -0.49408212, 0.3287904),
float3(0.7119986, -0.0154690035, -0.09183723),
float3(-0.053382345, 0.059675813, -0.5411899),
float3(0.035267662, -0.063188605, 0.54602677),
float3(-0.47761092, 0.2847911, -0.0271716)
};


//get ssao term

float4 PostProcessingSSAO2( float3 i_VPOS)
{
float2 vScreenUV; //this will become useful later
float3 vViewPos = TwoDPosToViewPos ( i_VPOS, vScreenUV);

float2 p_vSrcImageSize = (64.0, 64.0);

const float c_scalingConstant = 256.0f;
float3 vRandomNormal = (normalize(tex2D (RandomVecSampler, vScreenUV * p_vSrcImageSize/c_scalingConstant).xyz *2.0f - 1.0f));
float3x3 rotMatrix = MakeRotation(1.0f, vRandomNormal);


half fAccumBlock = 0.0f;
for( int i = 0; i < iSampleCount; i++)
{
float3 vSamplePointDelta = reflect( p_vSSAOSamplePoints[i], vRandomNormal);
float fBlock = TestOcclusion(vViewPos, vSamplePointDelta, p_fOcclusionRadius, p_fFullOcclusionThreshold, p_fNoOcclusionThreshold, p_fOcclusionPower);
fAccumBlock += fBlock;

}

fAccumBlock /= iSampleCount;

return 1.0f - fAccumBlock;

}[/code]

[code]////Then in the pixel shader :

float4 SSAO = PostProcessingSSAO2(input.vPos);

float4 specular = gSpecMtrl*spec*light[i].gSpecLight;
float4 diffuse = gDiffuseMtrl*diff*light[i].gDiffuseLight;

//float4 ambient = (gAmbMtrl*globalamb*light[i].gAmbLight)*SSAO;


float4 ambient = SSAO;


finalCol += ambient;//*texColor+(diffuse*texColor + specular)/atten;
finalCol.a=gDiffuseMtrl.a*texColor.a;[/code]

Any help would be greatly appreciated - my brain is on the verge of exploding here.

Share this post


Link to post
Share on other sites
Firstly, shouldnt you output normalized view space depth?
Because you are writing projection space depth divided by the far plane distance (I guess that 500.0f is the far plane distance)

Secondly, shouldnt you transform the normals from object space to world space?

Also, you should only normalize the depth and the normals in the pixel shader:

[code]
VSOUT VS(VSIN in)
{
VSOUT out;

out.position = mul(in.position, gWVP);
out.normal = mul(in.normals, gW);
out.viewspacedepth = mul(in.position, gWV).z);
}

float4 PS(VSOUT in):COLOR
{
float3 normal = 0.5f * (normalize(in.normal) + 1.0f);

return float4(normal.x, normal.y, normal.z, in.viewsapcedepth/500.0f);
}
[/code]

Make sure you dont have any special blend or depth state on.

Share this post


Link to post
Share on other sites
[quote name='TiagoCosta' timestamp='1298395600' post='4777586']
Firstly, shouldnt you output normalized view space depth?
Because you are writing projection space depth divided by the far plane distance (I guess that 500.0f is the far plane distance)

Secondly, shouldnt you transform the normals from object space to world space?

Also, you should only normalize the depth and the normals in the pixel shader:

[code]
VSOUT VS(VSIN in)
{
VSOUT out;

out.position = mul(in.position, gWVP);
out.normal = mul(in.normals, gW);
out.viewspacedepth = mul(in.position, gWV).z);
}

float4 PS(VSOUT in):COLOR
{
float3 normal = 0.5f * (normalize(in.normal) + 1.0f);

return float4(normal.x, normal.y, normal.z, in.viewsapcedepth/500.0f);
}
[/code]

Make sure you dont have any special blend or depth state on.
[/quote]


Thankies so much for the reply! :D

I had tried before to render the view space depth...but it didn't work at all. And now, using that piece of code " mul(in.position, gWV).z;" instead of what I was doing seems to work.

Funny, it's like my shader wasn't getting the world view matrix properly for some reason...and now it mysteriously is. Another mystery of programming I guess. :rolleyes:

And I did have Alpha Blending on! I set it in the main file and not the shader, so I overlooked it. Now I can't see through all my objects! Thank you!

Though, it still doesn't look completely right:

[attachment=1484:Untitled-2.jpg]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this