[DX9} Cubic Shadow Mapping

Started by
17 comments, last by DJTN 13 years ago
I've been working on implementing Shadow Mapping for Point Lights for weeks now and I still do not have a shadow being drawn. Ive looked at tons of threads on the subject and the tutorials but seems I'm just not getting it. I either get everything drawn in shadow (black) or no shadow at all (current situation). Maybe someone here can point me in the right direction...

First I create a cube texture (6 sides). I render my scene with the following shader:


float4x4 xLightWorldViewProjection;

float4x4 xLightWorldView;

float xMaxDepth;

struct SMapVertexToPixel

{

float4 Position : POSITION;

float3 Depth : TEXCOORD0;

};



struct SMapPixelToFrame

{

float4 Color : COLOR0;

};





SMapVertexToPixel ShadowMapVertexShader( float4 inPos : POSITION)

{

SMapVertexToPixel Output = (SMapVertexToPixel)0;



Output.Position = mul(inPos, xLightWorldViewProjection);

Output.Depth = length(mul(inPos, xLightWorldView).xyz);



return Output;

}

SMapPixelToFrame ShadowMapPixelShader(SMapVertexToPixel PSIn)

{

SMapPixelToFrame Output = (SMapPixelToFrame)0;

float fDepthValue = PSIn.Depth;

Output.Color = float4(fDepthValue, fDepthValue, fDepthValue, 1.0f);



return Output;

}

technique ShadowMap

{

pass Pass0

{

VertexShader = compile vs_2_0 ShadowMapVertexShader();

PixelShader = compile ps_2_0 ShadowMapPixelShader();

}

}


I've seen the cube texture and it's getting rendered. As I move the light around I see the white square moveing in and out of each texture.

Then, when I draw my scene again, I pass the CubeTexture to my shader and sample it:




float4 texel = 0.0f;

float4 LightDirection = 0.0f;

LightDirection.xyz = input.Position.xyz - LightPosition;

float Distance = length( LightDirection.xyz );

float DepthColour = texCUBE(ShadowMapSampler, normalize(LightDirection.xyz)).x;



if ((Distance + 0.001f) > DepthColour)

{
not in shadow

texel = tex2D(texsampler, input.TexCoords);


}


With this code, everything gets drawn as normal, no shadows though

I think my problem may be in the light shader but I'm not sure.
Advertisement
Anyone know anything about Shadow Mapping here?
When making depth based shadows, you only render to a depth buffer by giving NULL as the color buffer. Only the vertex buffer's transformation and optional alpha clipping in the pixel shader is important since the color will not be saved.
A large single channel atlas will be used as input to the lights in the material shaders using shader resource views. When rendering to it, assign parts of it as the depth buffer with many depth stencil views.
Give the near and far clip planes from each camera as argument to the shaders that are making the comparison so that the depth to the light source can be compared with the real depth by lerping the [0..1] values with near and far depths.
To see if things are working, draw the depth atlas as images to the screen so that you divide the problem in half.
Wow... I'm even more confused.

Here are some images that I hope will help:

1.jpg

In this 1st image I've added a basic box.





3.jpg

In the 2nd image I've added a point light, right on top of the box. You'll also notice the 6 faces of the texture cube at the top left of the image. This is the shadow cube I'm sending to the lighting pixel shader. As you can see there are no shadows.





2.jpg

In this 3d image I've moved the light up a bit off the box. You can see it's trying to create the shadows but they are a mess and that is my problem.


I don't think my problem is creating the shadow maps. I could be wrong, but i think the problem is in my light/material PS code.


I'm using the light position in world space to get the light direction:
float3 lightDir = normalize(input.WorldPos - LightPosition);


I then calculate the Depth like this:
float pixelLightDepth = length(lightDir);


Sampling the texturecube I get the depth in the shadow map
float StoredDepthInShadowMap = texCUBE(ShadowMapSampler, normalize(float4(-(lightDir), 0.0f))).x;

I then compare the light depth with the shadowmap depth:
if ((pixelLightDepth ) <= StoredDepthInShadowMap) {texel = float4(0,0,0,1); }


Am I missing something here? or am I sampling and comparing depths wrong?
When you create the shadow map you should to this:
Vertex shader:

float4 positionWS = mul( inPos, worldMat );
output.positionLWVP = mul( inPos, worldViewProjMat );

output.lightVec = lightPosition - positionW.xyz;

return output;


[EDITED]Pixel shader:

float fDepthValue = length(PSIn.lightVec);

Output.Color = float4(fDepthValue, fDepthValue, fDepthValue, 1.0f);


And then sample the cubic shadow map like this:

lightDirection.xyz = lightPosition.xyz – positionWS
float distance = length(lightDirection.xyz);
lightDirection.xyz = lightDirection.xyz / distance;

float smDepth = texCUBE(ShadowMapSampler, float4(-(lightDirection.xyz), 0.0f)).x;

if(distance > shadowMapDepth + 0.0001f)
{

}
Thanks Tiago. I tried what you said and I'm still getting the same results just smaller, very smaller.

In your code in the sampler you have:
lightDirection.xyz = lightPosition.xyz – positionWS;


What is positionWS? I've been muling input.Position and the world matrix in my vertex shader and passing that in. I would assume this is incorrect and may be my problem.

Here is what I have for the Sampling in my light/material PS:

LightPosition is the lights position in worldspace...



float3 lightDirection = LightPosition - input.WorldPos;

float distance = length(lightDirection);

lightDirection = lightDirection / distance;



float smDepth = texCUBE(ShadowMapSampler, float4(-(lightDirection.xyz), 0.0f)).x;



if(distance < smDepth + 0.0001f)



What is positionWS?
PositionWS is the current pixel Position in World Space...

By the way:
if you normalize lightDir:

float3 lightDir = normalize(input.WorldPos - LightPosition);
float pixelLightDepth = length(lightDir);

The length of lightDir will always be 1.0f.

Im sorry, in my previous code I did a mistake:
In the pixel shader that you use to create the shadow map I wrote;

float fDepthValue = PSIn.lightVec;


but it should be:

float fDepthValue = length(PSIn.lightVec);

I made the change to the shader for the shadow map and this is what I have for the light shader:

float4 texel = tex2D(texsampler, input.TexCoords);
float3 lightDirection = LightPosition - input.WorldPos;
float distance = length(lightDirection);
lightDirection = lightDirection / distance;


float smDepth = texCUBE(ShadowMapSampler, float4(-(lightDirection.xyz), 0.0f)).x;


if(distance < smDepth + 0.001f)
{
texel = float4(0,0,0,1);
}


I'm getting a small round shadow when the light is almost completely touching the box.
You can see it in this image:

4.jpg


If the light is any futher away it dissapears completely.
What would cause it to be so small? Any idea's why I cant get this to work?

BTW - thanks for your help.

If the light is any futher away it dissapears completely.
What would cause it to be so small? Any idea's why I cant get this to work?

When you create the projection matrix, use a higher value in the zFar parameter...

[quote name='DJTN' timestamp='1300753410' post='4788900']
If the light is any futher away it dissapears completely.
What would cause it to be so small? Any idea's why I cant get this to work?

When you create the projection matrix, use a higher value in the zFar parameter...
[/quote]

Didn't change anything ,ugg...

When I'm drawing my shadowmap I'm setting the device world tranform like I would normally do before drawing the box in a normal render with Scale, Rotation and Position. For the device transform view I'm using the Light's view. I then pass in the shader param "xLightWorldViewProjection" with device world transform * the light's view projection. The light's view projection is based off the cube face I'm rendering and the lights position. I then multiply that by PerspectiveFovLH(PI / 2, 1.0f, 1f, 1000f).

Is this correct?

This topic is closed to new replies.

Advertisement