Soft-Edged Shadows
Step 1: Rendering the shadow mapFirst, we need to create a texture that can hold the scene depth. Since we need to use this as a render target, we will also need to create a surface that holds the texture's surface data. The texture must be a floating point one because of the large range of depth values. The R32F format has sufficient precision and so we use it. Here's the codelet that is used to create the texture. // Create the shadow map if( FAILED( g_pd3dDevice->CreateTexture( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &g_pShadowMap, NULL ) ) ) { MessageBox( g_hWnd, "Unable to create shadow map!", "Error", MB_OK | MB_ICONERROR ); return E_FAIL; } // Grab the texture's surface g_pShadowMap->GetSurfaceLevel( 0, &g_pShadowSurf ); Now, to generate the shadow map, we need to render the scene's depth to the shadow map. To do this, we must render the scene with the light's world-view-projection matrix. Here's how we build that matrix. // Ordinary view matrix D3DXMatrixLookAtLH( &matView, &vLightPos, &vLightAim, &g_vUp ); // Projection matrix for the light D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian(30.0f), 1.0f, 1.0f, 1024.0f ); // Concatenate the world matrix with the above // two to get the required matrix matLightViewProj = matWorld * matView * matProj; Here are vertex and pixel shaders for rendering the scene depth. // Shadow generation vertex shader struct VSOUTPUT_SHADOW { float4 vPosition : POSITION; float fDepth : TEXCOORD0; }; VSOUTPUT_SHADOW VS_Shadow( float4 inPosition : POSITION ) { // Output struct VSOUTPUT_SHADOW OUT = (VSOUTPUT_SHADOW)0; // Output the transformed position OUT.vPosition = mul( inPosition, g_matLightViewProj ); // Output the scene depth OUT.fDepth = OUT.vPosition.z; return OUT; } Here, we multiply the position by the light's world-view-projection matrix (g_matLightViewProj) and use the transformed position's z-value as the depth. In the pixel shader, we output the depth as the color. float4 PS_Shadow( VSOUTPUT_SHADOW IN ) : COLOR0 { // Output the scene depth return float4( IN.fDepth, IN.fDepth, IN.fDepth, 1.0f ); } Voila! We have the shadow map. Below is a color coded version of the shadow map, dark blue indicates smaller depth values, whereas light blue indicates larger depth values.
|
|