Sign in to follow this  
BattleMetalChris

Rendering and applying Shadow maps

Recommended Posts

I'm working through Frank D Luna's 'Introduction To 3D Game Programming with Directx 10' and I'm trying to implement shadow maps.

I have a RenderableSurface class which creates a depth stencil view and also a shader resource (and it can also create a render target view and shader resource for that if neccesary). I render to that from the point of view of the light, then bind the resulting depth map as a resource for the shader which draws the main scene.

I currently am using a single parallel light source. I use D3DXMatrixLookAtLH to produce the light's view matrix and D3DXMatrixOrthoLH to produce the light's projection matrix, and pass both these to the shader which draws the shadowmaps.

Before the draw call to draw the shadowmaps, I use OMSetRenderTargets to bind the depth stencil view stored in the light's RenderableSurface, and bind the render target as NULL (or at least, an array with a NULL, as this is what OMSetRenderTargets needs - according to the book, you don't need a rendertarget if you're only using the depth map). I've also tried with with a rendertarget and still get the same problem.

Once the shadowmaps for that frame are stored, I then set the render target and depth stencils back to the main ones and render the scene normally (this part is working fine, apart from the shadowmaps).

When I draw my shadowed objects, I get the shader resource view of the depth map from the light, and pass this into the shader. The problem is that although the depth map seems to be rendering, anything it contains is either 0 or 1, rather the range of floating-point z values you'd expect.

Running things through PIX, the shadowmap seems to be rendering fine, the vertex shader produces nice floating point z values (which are around 0.4 give or take 0.1). This is the right kind of values you'd expect right?

However, when I pass it into the shader to render the scene, the depth map seems to contain only 0 or 1 values rather than the nice range of floating points. I tried sampling the depthmap for the diffuse colour, just to see what it contained and it produced this:

[img]http://dl.dropbox.com/u/22129898/shadowMap.png[/img]


The shape looks correct (the scene is two cubes one on top of each other with the light source above and slightly off diagonally, using an orthogonal projection). The cubes also spin slowly and the map animates appropriately as they spin, so I'm sure I've got my world, view and projection matrices correct when I render the shadowmap. As you can see though, the sample is just returning 1 (which shows as red in the diffuse, as the depth map is just a single 32 bit float) or zero (black).

Here's my shadowmap shader:

[code]
#include "Helper.fx"

struct VS_OUTPUT
{
float4 PosH : SV_POSITION;
};


VS_OUTPUT VS( float4 Pos : POSITION)
{
matrix WorldViewProj = mul (mul(WorldMatrix, ViewMatrix), ProjectionMatrix);
VS_OUTPUT output = (VS_OUTPUT)0;
output.PosH = mul(Pos, WorldViewProj);

return output;
}


void PS( VS_OUTPUT input ) // void as we don't need to return a colour
{

}

//--------------------------------------------------------------------------------------
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );

}
}

[/code]

and here's the code which creates the depth stencil and shader resource view for it

[code]
void RenderableSurface::buildDepthMap()
{
ID3D10Texture2D* depthMap = 0;
D3D10_TEXTURE2D_DESC texDesc;

texDesc.Width = m_width;
texDesc.Height = m_height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_R32_TYPELESS;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D10_USAGE_DEFAULT;
texDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = 0;

HelperFunctions::checkError(m_device->CreateTexture2D(&texDesc, 0, &depthMap), "DirectX Error", "Error creating Depth Map for Renderable Surface: ");

D3D10_DEPTH_STENCIL_VIEW_DESC dsvDesc;
dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
dsvDesc.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Texture2D.MipSlice = 0;
HelperFunctions::checkError(m_device->CreateDepthStencilView(depthMap, &dsvDesc, &m_depthMapDSV), "DirectX Error", "Error creating Depth Stencil View for Renderable Surface: ");

D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = texDesc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
HelperFunctions::checkError(m_device->CreateShaderResourceView(depthMap, &srvDesc, &m_depthMapSRV), "DirectX Error", "Error creating Resource View for Depth map for Renderable Surface: ");

// view saves a reference to the texture so we can delete our reference
depthMap->Release();
}

[/code]

Share this post


Link to post
Share on other sites
Hmm.. it's definitely to do with the values not being written to (or possibly sampled from) the depthmap correctly.

I altered the shadowmap shader and the light so that the final NDC coords get written to the render target, then set that as the input to the main shader instead of the depth map. This gets sampled correctly, I extract the rendered light-space z and my shadow maps work.

Can anyone see what might be wrong with my depthmap then?

Here's the new shadowmap shader:

[code]
#include "Helper.fx"

struct VS_OUTPUT
{
float4 PosH : SV_POSITION;
float4 OtherPos : TEXCOORD0;
};

VS_OUTPUT VS( float4 Pos : POSITION)
{
matrix WorldViewProj = mul (mul(WorldMatrix, ViewMatrix), ProjectionMatrix);
VS_OUTPUT output = (VS_OUTPUT)0;
output.PosH = mul(Pos, WorldViewProj);
output.OtherPos = output.PosH;
return output;
}


float4 PS( VS_OUTPUT input ) : SV_Target
{
return input.OtherPos;
}

//--------------------------------------------------------------------------------------
technique10 Render
{
pass P0
{
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, PS() ) );

}
}
[/code]

One thing I did notice is in stepping through the shadowmap pixelshader in PIX, PosH is sent to the pixel shader in screen-space coords with x and y as actual pixel coordinates and with z = 0 and w = 1 (so, a typical value might be (104, 168, 0, 1)) wheras OtherPos is in Normalized Device Coordinates, with the z and w correct, even though OtherPos is set with 'output.OtherPos = output.PosH;' in the pixel shader.

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