阴影映射,这是常用的技术了,具体技术解释就不说了,SDK中也有,还是阅读代码吧。
1OnResetDevice
// Create the shadow map texture
V_RETURN( pd3dDevice->CreateTexture( ShadowMap_SIZE, ShadowMap_SIZE,
1, D3DUSAGE_RENDERTARGET,
D3DFMT_R32F,
D3DPOOL_DEFAULT,
&g_pShadowMap,
NULL ) );
创建阴影纹理。注意D3DUSAGE是RENDERTARGET,格式只有一个通道,因为只需要深度值。
// Create the depth-stencil buffer to be used with the shadow map
// We do this to ensure that the depth-stencil buffer is large
// enough and has correct multisample type/quality when rendering
// the shadow map. The default depth-stencil buffer created during
// device creation will not be large enough if the user resizes the
// window to a very small size. Furthermore, if the device is created
// with multisampling, the default depth-stencil buffer will not
// work with the shadow map texture because texture render targets
// do not support multisample.
DXUTDeviceSettings d3dSettings = DXUTGetDeviceSettings();
V_RETURN( pd3dDevice->CreateDepthStencilSurface( ShadowMap_SIZE,
ShadowMap_SIZE,
d3dSettings.d3d9.pp.AutoDepthStencilFormat,
D3DMULTISAMPLE_NONE,
0,
TRUE,
&g_pDSShadow,
NULL ) );
这里还用到了模版来进行深度测试,使用原因见注释。
// Initialize the shadow projection matrix
D3DXMatrixPerspectiveFovLH( &g_mShadowProj, g_fLightFov, 1, 0.01f, 100.0f );
创建阴影图的透视矩阵。
2OnFrameRender
//
// Render the shadow map
//
LPDIRECT3DSURFACE9 pOldRT = NULL;
V( pd3dDevice->GetRenderTarget( 0, &pOldRT ) );
LPDIRECT3DSURFACE9 pShadowSurf;
if( SUCCEEDED( g_pShadowMap->GetSurfaceLevel( 0, &pShadowSurf ) ) )
{
pd3dDevice->SetRenderTarget( 0, pShadowSurf );
SAFE_RELEASE( pShadowSurf );
}
LPDIRECT3DSURFACE9 pOldDS = NULL;
if( SUCCEEDED( pd3dDevice->GetDepthStencilSurface( &pOldDS ) ) )
pd3dDevice->SetDepthStencilSurface( g_pDSShadow );
{
CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Shadow Map" );
RenderScene( pd3dDevice, true, fElapsedTime, &mLightView, &g_mShadowProj );
}
if( pOldDS )
{
pd3dDevice->SetDepthStencilSurface( pOldDS );
pOldDS->Release();
}
pd3dDevice->SetRenderTarget( 0, pOldRT );
SAFE_RELEASE( pOldRT );
这一段代码涉及到RenderTarget和DepthStencil的改变。改变RT和DS后,调用RenderScene渲染ShadowMap。
//
// Now that we have the shadow map, render the scene.
//
const D3DXMATRIX* pmView = g_bCameraPerspective ? g_VCamera.GetViewMatrix() :
&mLightView;
// Initialize required parameter
V( g_pEffect->SetTexture( "g_txShadow", g_pShadowMap ) );
// Compute the matrix to transform from view space to
// light projection space. This consists of
// the inverse of view matrix * view matrix of light * light projection matrix
D3DXMATRIXA16 mViewToLightProj;
mViewToLightProj = *pmView;
D3DXMatrixInverse( &mViewToLightProj, NULL, &mViewToLightProj );
D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &mLightView );
D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &g_mShadowProj );
V( g_pEffect->SetMatrix( "g_mViewToLightProj", &mViewToLightProj ) );
CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Scene" );
RenderScene( pd3dDevice, false, fElapsedTime, pmView, g_VCamera.GetProjMatrix() );
上一段代码渲染好了阴影图,那么这一段代码就是利用阴影图渲染场景。
3RenderScene
if( bRenderShadow )
V( g_pEffect->SetTechnique( "RenderShadow" ) );
// Begin the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
if( !bRenderShadow )
V( g_pEffect->SetTechnique( "RenderScene" ) );
注意,这里的代码写得有点不清楚,对比两个if语句,我们可以得知,要不渲染阴影,要不渲染场景。
下面还有渲染灯光的,就省略了。下一节分析着色器。