Strange shadow map results

Started by
4 comments, last by Tsus 12 years, 1 month ago
Having an issue with my shadow mapping. The picture explains.

Click to enlarge if you cannot read the text.
vLjWZ.jpg

Here is the shader to generate the shadow map

float4x4 dsObjectWorld : WORLD;

float4x4 dsLightView : VIEW;
float4x4 dsLightProjection : PROJECTION;


void vsDSShadowMap(float4 iPos : POSITION0,
out float4 oPos : POSITION0,
out float oDepth : TEXCOORD0)
{
float4 vWorldPos = mul(iPos, dsObjectWorld);
float4 vLightViewPos = mul(vWorldPos, dsLightView);
oPos = mul(vLightViewPos, dsLightProjection);

oDepth = oPos.z / oPos.w;
}

void psDSShadowMap(float iDepth : TEXCOORD0,
out float4 oDepth : COLOR0)
{
oDepth = float4(iDepth, 0.0f, 0.0f, 1.0f);
}

technique ShadowMap
{
pass ShadowMapRender
{
VertexShader = compile vs_2_0 vsDSShadowMap();
PixelShader = compile ps_2_0 psDSShadowMap();
}
}


And the calculation shader

float4x4 cameraViewProjectionInverse;

float4x4 lightView : VIEW;
float4x4 lightProjection : PROJECTION;

texture colorMap;
texture normalMap;
texture depthMap;
texture prevAccumulation;
texture shadowMap;

//Color map from GBuffer
sampler ColorMap =
sampler_state
{
Texture = <colorMap>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};

//Normal map from GBuffer
sampler NormalMap =
sampler_state
{
Texture = <normalMap>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};

//Depth map from GBuffer
sampler DepthMap =
sampler_state
{
Texture = <depthMap>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};

//The lights shadow map(if it casts)
sampler ShadowMap =
sampler_state
{
Texture = <shadowMap>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};

//Sample the previously accumulated light map
sampler PrevAccumulation =
sampler_state
{
Texture = <prevAccumulation>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};

void vsLightMap(float4 iPos : POSITION0,
float2 iUV : TEXCOORD0,
out float4 oPos : POSITION0,
out float2 oUV : TEXCOORD0)
{
oPos = iPos;
oUV = iUV;
}

void psLightMap(float2 iUV : TEXCOORD0,
out float4 oColor : COLOR0)
{
//Read buffer data
float4 mapColor = tex2D(ColorMap, iUV);
float4 mapNormal = tex2D(NormalMap, iUV);
float mapDepth = tex2D(DepthMap, iUV).x;
float4 lightMapPrev = tex2D(PrevAccumulation, iUV);

//Put pixel into world position
//Convert from UV coordinates to clip space
float4 pixelWorldPosition;
pixelWorldPosition.x = (iUV.x * 2.0f) - 1.0f;
pixelWorldPosition.y = ((iUV.y * 2.0f) - 1.0f) * -1;
pixelWorldPosition.z = mapDepth;
pixelWorldPosition.w = 1.0f;
pixelWorldPosition = mul(pixelWorldPosition, cameraViewProjectionInverse);
pixelWorldPosition /= pixelWorldPosition.w;

//Get pixel position from light's view
float4 pixelLightView = mul(pixelWorldPosition, lightView);
float4 pixelLightPos = mul(pixelLightView, lightProjection);
pixelLightPos /= pixelLightPos.w;

//Hard frustum test.
//If position is not visible to the light, shade then return
if(pixelLightPos.x < -1.0f || pixelLightPos.x > 1.0f
|| pixelLightPos.y < -1.0f || pixelLightPos.y > 1.0f
|| pixelLightPos.z < 0.0f || pixelLightPos.z > 1.0f)
{
//TODO once color output has been correctly tested, take the accumulation buffer into consideration
oColor = mapColor * 0.5;
return;
}

//Convert pixel position to UV to sample shadow map
float pixelU = pixelLightPos.x / 2 + 0.5f;
float pixelV = (pixelLightPos.y / -2) + 0.5f;
float2 pixelUV = float2(pixelU, pixelV);

//Sample shadow map to get depth from light view
float lightViewDepth = tex2D(ShadowMap, pixelUV);

//TODO once color output has been correctly tested, take the accumulation buffer into consideration
if(lightViewDepth + 0.001f <= pixelLightPos.z)
{
oColor = mapColor * 0.5;

return;
}
else
{
oColor = mapColor;

return;
}
}

technique SpotLight
{
pass p0
{
VertexShader = compile vs_2_0 vsLightMap();
PixelShader = compile ps_2_0 psLightMap();
}

}



Thanks for any advice =)
Advertisement
Hi!

You did the perspective division in the vertex shader. This means, you output a non-linear depth value, which is interpolated by the rasterizer. This will give wrong results. Instead, pass the z and w component of the light space position to the pixel shader and do the division there.
The rest looks good, so hopefully this small change will resolve the issue.

Cheers!
Ok, so I made the change you were talking about

void vsDSShadowMap(float4 iPos : POSITION0,
out float4 oPos : POSITION0,
out float2 oDepth : TEXCOORD0)
{
float4 vWorldPos = mul(iPos, dsObjectWorld);
float4 vLightViewPos = mul(vWorldPos, dsLightView);
oPos = mul(vLightViewPos, dsLightProjection);

oDepth = float2(oPos.z, oPos.w);
}

void psDSShadowMap(float2 iDepth : TEXCOORD0,
out float4 oDepth : COLOR0)
{
oDepth = float4(iDepth.x / iDepth.y, 0.0f, 0.0f, 1.0f);
}


But unfortunately I am getting the same results.

I appreciate your time, and any other Ideas you may have!
Hi!

In which range are your near and far planes? If they are too far apart, you get numerical problems. However, I think it is more likely that the computation of the light space depth value isn’t the same. Have the projection matrices dsLightProjection and lightProjection the same parameters (i.e. near and far planes)? Also, which format do you use for the depth map / shadow map? DXGI_FORMAT_R32_FLOAT?

Aside from that I would check, whether the reconstructed world position is correct. Perhaps try to add a further texture with the world position to your g-buffer and then output the distance between the exact world position and the reconstructed world position.

Also how does it look like when you output instead of the shaded and shadowed pixel the light space depth / the shadow map value? I expect the gray levels to be a little different. Maybe we can see something suspicious here, which might help us.

Cheers!
sorry, I didn't get a chance to work on this today. May I PM you later?

sorry, I didn't get a chance to work on this today. May I PM you later?

Sure!

This topic is closed to new replies.

Advertisement