📄 shadowvolume.cpp
字号:
V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) );
V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) );
// Initialize the vertex declaration
V_RETURN( pd3dDevice->CreateVertexDeclaration( MESHVERT::Decl, &g_pMeshDecl ) );
V_RETURN( pd3dDevice->CreateVertexDeclaration( SHADOWVERT::Decl, &g_pShadowDecl ) );
V_RETURN( pd3dDevice->CreateVertexDeclaration( POSTPROCVERT::Decl, &g_pPProcDecl ) );
// Initialize the font
V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
L"Arial", &g_pFont ) );
// Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the
// shader debugger. Debugging vertex shaders requires either REF or software vertex
// processing, and debugging pixel shaders requires REF. The
// D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the
// shader debugger. It enables source level debugging, prevents instruction
// reordering, prevents dead code elimination, and forces the compiler to compile
// against the next higher available software target, which ensures that the
// unoptimized shaders do not exceed the shader model limitations. Setting these
// flags will cause slower rendering since the shaders will be unoptimized and
// forced into software. See the DirectX documentation for more information about
// using the shader debugger.
DWORD dwShaderFlags = 0;
#ifdef DEBUG_VS
dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
#endif
#ifdef DEBUG_PS
dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
#endif
// Read the D3DX effect file
WCHAR str[MAX_PATH];
V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ShadowVolume.fx" ) );
// If this fails, there should be debug output as to
// they the .fx file failed to compile
V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags,
NULL, &g_pEffect, NULL ) );
// Determine the rendering techniques to use based on device caps
D3DCAPS9 Caps;
V_RETURN( pd3dDevice->GetDeviceCaps( &Caps ) );
if( Caps.PixelShaderVersion >= D3DPS_VERSION( 2, 0 ) )
g_hRenderScene = g_pEffect->GetTechniqueByName( "RenderScene" );
else
g_hRenderScene = g_pEffect->GetTechniqueByName( "RenderScene1x" );
// If 2-sided stencil is supported, use it.
if( Caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED )
{
g_hRenderShadow = g_pEffect->GetTechniqueByName( "RenderShadowVolume2Sided" );
g_hShowShadow = g_pEffect->GetTechniqueByName( "ShowShadowVolume2Sided" );
}
else
{
g_hRenderShadow = g_pEffect->GetTechniqueByName( "RenderShadowVolume" );
g_hShowShadow = g_pEffect->GetTechniqueByName( "ShowShadowVolume" );
}
// Load the meshes
V_RETURN( g_Background[0].Create( pd3dDevice, L"misc\\cell.x" ) );
g_Background[0].SetVertexDecl( pd3dDevice, MESHVERT::Decl );
V_RETURN( g_Background[1].Create( pd3dDevice, L"misc\\seafloor.x" ) );
g_Background[1].SetVertexDecl( pd3dDevice, MESHVERT::Decl );
V_RETURN( g_LightMesh.Create( pd3dDevice, L"misc\\sphere0.x" ) );
g_LightMesh.SetVertexDecl( pd3dDevice, MESHVERT::Decl );
V_RETURN( g_Mesh.Create( pd3dDevice, DEFMESHFILENAME ) );
g_Mesh.SetVertexDecl( pd3dDevice, MESHVERT::Decl );
// Compute the scaling matrix for the mesh so that the size of the mesh
// that shows on the screen is consistent.
ComputeMeshScaling( g_Mesh, &g_mWorldScaling );
// Setup the camera's view parameters
D3DXVECTOR3 vecEye(0.0f, 0.0f, -5.0f);
D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
g_Camera.SetViewParams( &vecEye, &vecAt );
g_LCamera.SetViewParams( &vecEye, &vecAt );
g_MCamera.SetViewParams( &vecEye, &vecAt );
// Create the 1x1 white default texture
V_RETURN( pd3dDevice->CreateTexture( 1, 1, 1, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, &g_pDefaultTex, NULL ) );
D3DLOCKED_RECT lr;
V_RETURN( g_pDefaultTex->LockRect( 0, &lr, NULL, 0 ) );
*(LPDWORD)lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );
V_RETURN( g_pDefaultTex->UnlockRect( 0 ) );
return S_OK;
}
//--------------------------------------------------------------------------------------
// This callback function will be called immediately after the Direct3D device has been
// reset, which will happen after a lost device scenario. This is the best location to
// create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever
// the device is lost. Resources created here should be released in the OnLostDevice
// callback.
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
HRESULT hr;
V_RETURN( g_DialogResourceManager.OnResetDevice() );
V_RETURN( g_SettingsDlg.OnResetDevice() );
if( g_pFont )
V_RETURN( g_pFont->OnResetDevice() );
if( g_pEffect )
V_RETURN( g_pEffect->OnResetDevice() );
g_Background[0].RestoreDeviceObjects( pd3dDevice );
g_Background[1].RestoreDeviceObjects( pd3dDevice );
g_LightMesh.RestoreDeviceObjects( pd3dDevice );
g_Mesh.RestoreDeviceObjects( pd3dDevice );
// Create a sprite to help batch calls when drawing many lines of text
V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
// Setup the camera's projection parameters
float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 20.0f );
g_MCamera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
g_LCamera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
g_pEffect->SetFloat( "g_fFarClip", 20.0f - EXTRUDE_EPSILON );
V( g_pEffect->SetMatrix( "g_mProj", g_Camera.GetProjMatrix() ) );
g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
g_HUD.SetSize( 170, 170 );
g_SampleUI.SetLocation( 0, pBackBufferSurfaceDesc->Height-200 );
g_SampleUI.SetSize( pBackBufferSurfaceDesc->Width, 150 );
int iY = 10;
g_SampleUI.GetControl( IDC_CHANGESCRIPT )->SetLocation( pBackBufferSurfaceDesc->Width - 200, iY += 24 );
// Generate the shadow volume mesh
GenerateShadowMesh( pd3dDevice, g_Mesh.GetMesh(), &g_pShadowMesh );
return S_OK;
}
//--------------------------------------------------------------------------------------
// This callback function will be called once at the beginning of every frame. This is the
// best location for your application to handle updates to the scene, but is not
// intended to contain actual rendering calls, which should instead be placed in the
// OnFrameRender callback.
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
// Update the camera's position based on user input
g_Camera.FrameMove( fElapsedTime );
g_MCamera.FrameMove( fElapsedTime );
g_LCamera.FrameMove( fElapsedTime );
// Let script engine handle this
D3DXMATRIX Matrix = *g_MCamera.GetWorldMatrix();
UpdatePlayerRotationX(fTime, &Matrix);
UpdatePlayerRotationY(fTime, &Matrix);
UpdatePlayerRotationZ(fTime, &Matrix);
UpdatePlayerPosition(fTime, (float*)&Matrix._41, (float*)&Matrix._42, (float*)&Matrix._43);
g_MCamera.SetWorldMatrix(Matrix);
}
//--------------------------------------------------------------------------------------
// Simply renders the entire scene without any shadow handling.
void RenderScene( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, bool bRenderLight )
{
HRESULT hr;
D3DXMATRIXA16 mWorldView;
D3DXMATRIXA16 mViewProj;
D3DXMATRIXA16 mWorldViewProjection;
// Get the projection & view matrix from the camera class
D3DXMatrixMultiply( &mViewProj, g_Camera.GetViewMatrix(), g_Camera.GetProjMatrix() );
// Render the lights if requested
if( bRenderLight )
{
D3DXHANDLE hCurrTech;
hCurrTech = g_pEffect->GetCurrentTechnique(); // Save the current technique
V( g_pEffect->SetTechnique( "RenderSceneAmbient" ) );
V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
D3DXVECTOR4 vLightMat( 1.0f, 1.0f, 1.0f, 1.0f );
V( g_pEffect->SetVector( "g_vMatColor", &vLightMat ) );
UINT cPasses;
ID3DXMesh *pMesh = g_LightMesh.GetMesh();
V( g_pEffect->Begin( &cPasses, 0 ) );
for( UINT p = 0; p < cPasses; ++p )
{
V( g_pEffect->BeginPass( p ) );
for( int i = 0; i < g_nNumLights; ++i )
{
for( UINT m = 0; m < g_LightMesh.m_dwNumMaterials; ++m )
{
mWorldView = g_aLights[i].m_mWorld * *g_LCamera.GetWorldMatrix() * *g_Camera.GetViewMatrix();
mWorldViewProjection = mWorldView * *g_Camera.GetProjMatrix();
V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
V( g_pEffect->SetVector( "g_vAmbient", &g_aLights[i].m_Color ) );
// The effect interface queues up the changes and performs them
// with the CommitChanges call. You do not need to call CommitChanges if
// you are not setting any parameters between the BeginPass and EndPass.
V( g_pEffect->CommitChanges() );
V( pMesh->DrawSubset( m ) );
}
}
V( g_pEffect->EndPass() );
}
V( g_pEffect->End() );
V( g_pEffect->SetTechnique( hCurrTech ) ); // Restore the old technique
D3DXVECTOR4 vAmb( AMBIENT, AMBIENT, AMBIENT, 1.0f );
V( g_pEffect->SetVector( "g_vAmbient", &vAmb ) );
}
// Render the background mesh
V( pd3dDevice->SetVertexDeclaration( g_pMeshDecl ) );
mWorldView = g_mWorldBack[g_nCurrBackground] * *g_Camera.GetViewMatrix();
mWorldViewProjection = g_mWorldBack[g_nCurrBackground] * mViewProj;
V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
UINT cPasses;
V( g_pEffect->Begin( &cPasses, 0 ) );
for( UINT p = 0; p < cPasses; ++p )
{
V( g_pEffect->BeginPass( p ) );
ID3DXMesh *pMesh = g_Background[g_nCurrBackground].GetMesh();
for( UINT i = 0; i < g_Background[g_nCurrBackground].m_dwNumMaterials; ++i )
{
V( g_pEffect->SetVector( "g_vMatColor", (D3DXVECTOR4*)&g_Background[g_nCurrBackground].m_pMaterials[i].Diffuse ) );
if( g_Background[g_nCurrBackground].m_pTextures[i] )
V( g_pEffect->SetTexture( "g_txScene", g_Background[g_nCurrBackground].m_pTextures[i] ) )
else
V( g_pEffect->SetTexture( "g_txScene", g_pDefaultTex ) );
// The effect interface queues up the changes and performs them
// with the CommitChanges call. You do not need to call CommitChanges if
// you are not setting any parameters between the BeginPass and EndPass.
V( g_pEffect->CommitChanges() );
V( pMesh->DrawSubset( i ) );
}
V( g_pEffect->EndPass() );
}
V( g_pEffect->End() );
// Render the mesh
V( pd3dDevice->SetVertexDeclaration( g_pMeshDecl ) );
mWorldView = g_mWorldScaling * *g_MCamera.GetWorldMatrix() * *g_Camera.GetViewMatrix();
mWorldViewProjection = mWorldView * *g_Camera.GetProjMatrix();
V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );
V( g_pEffect->Begin( &cPasses, 0 ) );
for( UINT p = 0; p < cPasses; ++p )
{
V( g_pEffect->BeginPass( p ) );
ID3DXMesh *pMesh = g_Mesh.GetMesh();
for( UINT i = 0; i < g_Mesh.m_dwNumMaterials; ++i )
{
V( g_pEffect->SetVector( "g_vMatColor", (D3DXVECTOR4*)&g_Mesh.m_pMaterials[i].Diffuse ) );
if( g_Mesh.m_pTextures[i] )
V( g_pEffect->SetTexture( "g_txScene", g_Mesh.m_pTextures[i] ) )
else
V( g_pEffect->SetText
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -