📄 shader_motionblur.cpp
字号:
// Setup render states
m_pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pD3DDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pD3DDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
m_pD3DDev->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
m_pD3DDev->SetVertexShaderConstant(CV_CONSTANTS, D3DXVECTOR4(0.0f,1.0f,0.0f,0.0f), 1);
// Projection set up
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH(&matProj, D3DXToRadian(60.0f), 1.0f, 1.0f, 1000.0f);
m_pNVDevice->SetProjectionTransform(&matProj);
return S_OK;
}
#pragma optimize ("", on)
HRESULT CShaderMotionBlur::Free()
{
for (int i = 6; --i >= 0; )
{
SAFE_RELEASE( m_pBlurredObjectIB[i] );
}
SAFE_RELEASE(m_pBlurredObjectVB);
SAFE_DELETE(m_pFloorMesh);
SAFE_DELETE(m_pBlurredObjectMesh);
SAFE_RELEASE(m_pBlurredObjectMap);
SAFE_DELETE(m_pNVDevice);
if (m_pD3DDev)
{
m_pD3DDev->DeleteVertexShader(m_dwMotionBlurShader);
SAFE_RELEASE(m_pD3DDev);
}
return S_OK;
}
HRESULT CShaderMotionBlur::Start()
{
return S_OK;
}
HRESULT CShaderMotionBlur::SetTransform(bool bWithBlur)
{
D3DXMATRIX matWorld, matView, matProj;
D3DXMATRIX matWorldView, matWorldViewIT;
float unused;
matWorld = m_pNVDevice->GetWorldTransform();
matView = m_pNVDevice->GetViewTransform();
matProj = m_pNVDevice->GetProjectionTransform();
D3DXMatrixMultiply(&matWorldView, &matWorld, &matView);
D3DXMatrixInverse( &matWorldViewIT, &unused, &matWorldView);
// Projection to clip space
D3DXMatrixTranspose(&matProj, &matProj);
m_pD3DDev->SetVertexShaderConstant(CV_PROJ_TXF_0, &matProj(0, 0), 4);
// Projection to view-space
D3DXMatrixTranspose(&matWorldView, &matWorldView);
m_pD3DDev->SetVertexShaderConstant(CV_CURR_WORLDVIEW_TXF_0, &matWorldView(0, 0), 3);
if (bWithBlur)
{
m_pD3DDev->SetVertexShaderConstant(CV_PREV_WORLDVIEW_TXF_0, &m_LastWorldTxf(0, 0), 3);
m_LastWorldTxf = matWorldView;
}
else
{
m_pD3DDev->SetVertexShaderConstant(CV_PREV_WORLDVIEW_TXF_0, &matWorldView(0, 0), 3);
}
// projection of normals to view-space
m_pD3DDev->SetVertexShaderConstant(CV_CURR_WORLDVIEW_IT_0, &matWorldViewIT(0, 0), 3);
return S_OK;
}
HRESULT CShaderMotionBlur::Tick(EBTimer* pTimer)
{
HRESULT hr = S_OK;
D3DXMATRIX matWorld;
D3DXMATRIX matView;
m_pD3DDev->SetRenderState(D3DRS_FILLMODE, (mbWireFrame) ? D3DFILL_WIREFRAME : D3DFILL_SOLID);
if (m_bPause)
return hr;
// Camera setup
D3DXVECTOR3 const vEyePt = D3DXVECTOR3( 0.0f, 2.0f, -30.0f);
D3DXVECTOR3 const vLookatPt = D3DXVECTOR3( 0.0f, -5.0f, 0.0f);
D3DXVECTOR3 const vUp = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUp);
m_pNVDevice->SetViewTransform(&matView);
hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, BACKGROUND_COLOR, 1.0, 0);
// Sea floor
D3DXMatrixScaling( &matWorld, 1.0f, 1.0f, 1.0f);
m_pNVDevice->SetWorldTransform(&matWorld);
SetTransform( false );
m_pFloorMesh->Render(m_pNVDevice);
// now lets draw the blurred object
float const kSpeed = (m_bEnableSpeed2x) ? 15.0f : 7.5f;
float const fKickFreq = kSpeed * pTimer->GetDuration();
float const fPhase = kSpeed * pTimer->GetDuration() / 3.0f;
m_pD3DDev->SetStreamSource(0, m_pBlurredObjectVB, sizeof(MotionBlurVertex));
m_pD3DDev->SetVertexShader(m_dwMotionBlurShader);
m_pD3DDev->SetTexture(0, m_pBlurredObjectMap);
// Move the blurred object in a circle
D3DXMATRIX matScale, matTrans1, matRotate1, matRotate2;
D3DXMATRIX matBank, matLocalRotate;
D3DXMatrixRotationY( &matLocalRotate, D3DX_PI/2.0f);
D3DXMatrixRotationX( &matBank, D3DX_PI/8.0f);
D3DXMatrixRotationZ( &matRotate1, 2*D3DX_PI);
D3DXMatrixRotationY( &matRotate2, fPhase );
D3DXMatrixScaling( &matScale, 2.0f, 2.0f, 2.0f );
D3DXMatrixTranslation( &matTrans1, -12*sinf(fPhase), sinf(fKickFreq), 10-30*cosf(fPhase) );
D3DXMatrixIdentity(&matWorld);
D3DXMatrixMultiply( &matWorld, &matTrans1, &matWorld);
D3DXMatrixMultiply( &matWorld, &matScale, &matWorld);
D3DXMatrixMultiply( &matWorld, &matRotate2, &matWorld);
D3DXMatrixMultiply( &matWorld, &matRotate1, &matWorld);
D3DXMatrixMultiply( &matWorld, &matBank, &matWorld);
D3DXMatrixMultiply( &matWorld, &matLocalRotate, &matWorld);
m_pNVDevice->SetWorldTransform(&matWorld);
// set the proper alpha colors
// do not really have to write these all the time...
FLOAT const kBlurAlpha = 0.1f;
// This is not correct for vertices with actual alpha!
// we should make sure we have the right alpha-constants in the registers...
// Would have to modify the Render() routine...
D3DXVECTOR4 vColorPrevious(1.0f, 1.0f, 1.0f, kBlurAlpha );
D3DXVECTOR4 vColorCurrent (1.0f, 1.0f, 1.0f, 1.0f );
m_pD3DDev->SetVertexShaderConstant( CV_PREV_COLOR, &vColorCurrent, 1 );
m_pD3DDev->SetVertexShaderConstant( CV_CURR_COLOR, &vColorCurrent, 1 );
float blurFraction(1.0f);
switch (meBlurLengthOption)
{
case HALFxBLURLENGTH:
blurFraction = 0.5f;
break;
case ONEHALFxBLURLENGTH:
blurFraction = 1.5f;
break;
default:
break;
}
D3DXVECTOR4 vOneOverExtent(m_OneOverExtent, 1.0f, blurFraction, 1.0f);
m_pD3DDev->SetVertexShaderConstant( CV_OBJECT_EXTEND, &vOneOverExtent, 1 );
// draw object once w/o blur
SetTransform( false );
// no need to write z the first time: we will write when drawing the second time!
m_pD3DDev->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
float fBias = (m_bEnableMotionBlur ) ? kSpeed/10.0f : 0.0f;
m_pD3DDev->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((LPDWORD) (&fBias)));
m_pBlurredObjectMesh->Render(m_pNVDevice);
// now draw it again with blur and alpha sorted
m_pD3DDev->SetVertexShaderConstant( CV_PREV_COLOR, &vColorPrevious, 1 );
SetTransform( m_bEnableMotionBlur );
// invert model-matrix and transform cam to model-space
D3DXMATRIX MatWorldInverse;
FLOAT det;
D3DXMatrixInverse(&MatWorldInverse, &det, &matWorld);
D3DXVECTOR4 vLookAtModel, vEyeModel;
D3DXVec3Transform(&vLookAtModel, &vLookatPt, &MatWorldInverse);
D3DXVec3Transform(&vEyeModel, &vEyePt, &MatWorldInverse);
D3DXVECTOR3 const vFromCam = vLookAtModel - vEyeModel;
// find the biggest component
if ( (abs(vFromCam.x) > abs(vFromCam.y))
&& (abs(vFromCam.x) > abs(vFromCam.z)) )
{
// x is largest
m_pD3DDev->SetIndices(m_pBlurredObjectIB[(vFromCam.x < 0) ? 0 : 1], 0);
}
else if ( (abs(vFromCam.y) > abs(vFromCam.x))
&& (abs(vFromCam.y) > abs(vFromCam.z)) )
{
// y is largest
m_pD3DDev->SetIndices(m_pBlurredObjectIB[(vFromCam.y < 0) ? 2 : 3], 0);
}
else
{
// z is largest
m_pD3DDev->SetIndices(m_pBlurredObjectIB[(vFromCam.z < 0) ? 4 : 5], 0);
}
// now lets write z
m_pD3DDev->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
// render the blurred object!
hr = m_pD3DDev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, m_numVertices, 0, m_numIndices/3);
// reset MIPMAP bias
fBias = 0.0f;
m_pD3DDev->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((LPDWORD) (&fBias)));
Sleep(50); // artificially kill frame rate to make blur apparent!
return hr;
}
HRESULT CShaderMotionBlur::ConfirmDevice(D3DCAPS8* pCaps, DWORD dwBehavior, D3DFORMAT Format)
{
// check vertex shading support
if(D3DSHADER_VERSION_MAJOR(pCaps->VertexShaderVersion) < 1)
{
m_strLastError = "Device does not support vertex shaders!";
return E_FAIL;
}
if(D3DSHADER_VERSION_MINOR(pCaps->VertexShaderVersion) < 1)
{
m_strLastError = "Device does not support 1.1 vertex shaders!";
return E_FAIL;
}
// check simultaneous texture support (only need 2...)
if(pCaps->MaxSimultaneousTextures < 2)
{
m_strLastError = "Device does not support 4 simultaneous textures!";
return E_FAIL;
}
// only need very few, simple register combiners...
if(pCaps->MaxTextureBlendStages < 2)
{
m_strLastError = "Device does not support 8 register combiners!";
return E_FAIL;
}
// need mipmapping
if ((pCaps->TextureCaps & D3DPTEXTURECAPS_MIPMAP) == 0)
{
m_strLastError = "Device does not support mip-mapping!";
return E_FAIL;
}
// and trilinear filtering between mipmaps
if ((pCaps->TextureFilterCaps & D3DPTFILTERCAPS_MIPFLINEAR) == 0)
{
m_strLastError = "Device does not support trilinear mip-mapping!";
return E_FAIL;
}
return S_OK;
}
void CShaderMotionBlur::Keyboard(DWORD dwKey, UINT nFlags, bool bDown)
{
unsigned int option = static_cast<unsigned int>(meBlurLengthOption);
eEBKeyAction Action = TranslateEffectKey(dwKey, nFlags, bDown);
switch ( Action )
{
case EB_HELP:
{
::MessageBoxEx( NULL, " Help : F1 - Help \n\n Home - Reset To Defaults \n\n W - Wireframe Toggle \n\n Pause/Space - Toggle pausing the animation \n\n +/- - Lengthen/Shorten Blur Length",
"Help", MB_ICONINFORMATION | MB_TASKMODAL, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) );
}
break;
case EB_WIREFRAME:
{
mbWireFrame = !mbWireFrame;
m_dwEffectDirtyFlags |= EBEFFECT_DIRTY_PUBLICSTATE;
}
break;
case EB_PAUSE:
{
m_bPause = !m_bPause;
m_dwEffectDirtyFlags |= EBEFFECT_DIRTY_PUBLICSTATE;
}
break;
case EB_RESET:
{
meBlurLengthOption = ONExBLURLENGTH;
m_dwEffectDirtyFlags |= EBEFFECT_DIRTY_PUBLICSTATE;
}
break;
case EB_ADD:
if (option < NUM_BLURLENGTHS-1)
++option;
meBlurLengthOption = static_cast<eBlurLengths>(option);
m_dwEffectDirtyFlags |= EBEFFECT_DIRTY_PUBLICSTATE;
break;
case EB_SUBTRACT:
if (option > FIRST_BLURLENGTH)
--option;
meBlurLengthOption = static_cast<eBlurLengths>(option);
m_dwEffectDirtyFlags |= EBEFFECT_DIRTY_PUBLICSTATE;
break;
default:
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -