📄 shader_particlesystem.cpp
字号:
m_pD3DDev->SetVertexShaderConstant(VSC_RND_NUM_VECTORS, &rndNumVectors, 1);
float x, y, z, w;
float const kRandMax = static_cast<float>(RAND_MAX);
float const kIAOver2 = 16807.0f/2.0f;
struct _timeb currentTime;
_ftime(¤tTime);
srand( (unsigned)currentTime.time );
for (int i = 0; i < kNumRndVectors; ++i)
{
x = kIAOver2 * static_cast<float>(rand())/kRandMax;
y = kIAOver2 * static_cast<float>(rand())/kRandMax;
z = kIAOver2 * static_cast<float>(rand())/kRandMax;
w = kIAOver2 * static_cast<float>(rand())/kRandMax;
D3DXVECTOR4 rndVector(x, y, z, w);
m_pD3DDev->SetVertexShaderConstant(VSC_RND_START + i, &rndVector, 1);
}
// particle start, direction, and perpendicular direction
D3DXVECTOR4 startPosition(-0.0f, 0.0f, 0.0f, 1.0f);
m_pD3DDev->SetVertexShaderConstant(VSC_START_POSITION, &startPosition, 1);
D3DXVECTOR3 direction(-0.2f, 1.0f, 0.0f);
D3DXVec3Normalize(&direction, &direction);
m_pD3DDev->SetVertexShaderConstant(VSC_DIRECTION, &direction, 1);
D3DXVECTOR3 dirPerp1(0.0f, 0.0f, 1.0f);
D3DXVec3Cross( &dirPerp1, &dirPerp1, &direction);
D3DXVec3Normalize(&dirPerp1, &dirPerp1);
m_pD3DDev->SetVertexShaderConstant(VSC_DIR_PERPENDICULAR1, &dirPerp1, 1);
D3DXVECTOR3 dirPerp2(0.0f, 0.0f, 0.0f);
D3DXVec3Cross( &dirPerp2, &dirPerp1, &direction);
D3DXVec3Normalize(&dirPerp2, &dirPerp2);
m_pD3DDev->SetVertexShaderConstant(VSC_DIR_PERPENDICULAR2, &dirPerp2, 1);
D3DXVECTOR4 halfGravity(0.0f, -0.9f, 0.0f, 0.0f);
m_pD3DDev->SetVertexShaderConstant(VSC_HALF_GRAVITY, &halfGravity, 1);
}
HRESULT CShaderPSystem::Free()
{
SAFE_RELEASE(m_pParticleVB);
SAFE_RELEASE(m_pFloorVB);
SAFE_RELEASE(m_pFloorTexture);
SAFE_RELEASE(m_pParticleTexture);
if (m_pD3DDev)
{
m_pD3DDev->DeleteVertexShader(mFloorShader);
m_pD3DDev->DeleteVertexShader(mParticleShader);
SAFE_RELEASE(m_pD3DDev);
}
SAFE_DELETE(mpMouseUI);
return S_OK;
}
HRESULT CShaderPSystem::Start()
{
return S_OK;
}
HRESULT CShaderPSystem::Tick(EBTimer* pTimer)
{
HRESULT hr = S_OK;
D3DXMATRIX matWorld;
D3DXMATRIX matView;
D3DXMATRIX matProj;
D3DXMATRIX matWorldViewProj;
DWORD const kSmokeColor = D3DCOLOR_RGBA(125, 105, 95, 0);
DWORD const kSkyColor = D3DCOLOR_RGBA( 70, 80, 65, 0);
// clear the backbuffer
hr = m_pD3DDev->SetRenderState(D3DRS_FILLMODE, (mbWireFrame) ? D3DFILL_WIREFRAME : D3DFILL_SOLID);
hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, kSkyColor, 1.0, 0);
// set up the camera/projection
// Setup the world and projection matrices
D3DXMatrixIdentity(&matWorld);
D3DXMatrixPerspectiveFovLH(&matProj, D3DXToRadian(60.0f), 1.0f, 0.01f, 200.0f);
// update the view matrix from the keyboard
SetViewFromKeyboardInput(pTimer, matView);
// Setup the composite matrix to get vertices to projection space
D3DXMatrixMultiply( &matWorldViewProj, &matWorld, &matView);
D3DXMatrixMultiply( &matWorldViewProj, &matWorldViewProj, &matProj);
D3DXMatrixTranspose(&matWorldViewProj, &matWorldViewProj);
// write the matrix to the vertex shader constants
m_pD3DDev->SetVertexShaderConstant(VSC_WORLDVIEW_PROJ_0, &matWorldViewProj(0, 0), 4);
// update current time
struct _timeb now;
_ftime(&now);
float kDifference(static_cast<float>(now.time - mStartTime.time));
kDifference += static_cast<float>(0.001f * (now.millitm - mStartTime.millitm));
kDifference += 10000.0f; // fudge it to randoomize particles more
D3DXVECTOR4 currentTime(kDifference, kDifference, kDifference, kDifference);
// but only if we are not freezing the current frame
if (! mbFreezeFrame)
m_pD3DDev->SetVertexShaderConstant(VSC_CURRENT_TIME, ¤tTime, 1);
// done writing constants, just draw the VBs now
// draw the floor first!
// all color comes from texture, no alpha at all
m_pD3DDev->SetRenderState(D3DRS_FOGENABLE, false );
m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pD3DDev->SetRenderState(D3DRS_ZWRITEENABLE, true);
hr = m_pD3DDev->SetStreamSource(0, m_pFloorVB, sizeof(FloorVertex));
hr = m_pD3DDev->SetVertexShader( mFloorShader );
hr = m_pD3DDev->SetTexture(0, m_pFloorTexture);
hr = m_pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
if (FAILED(hr))
return hr;
// now the particles
// all color comes from diffuse of vertex
m_pD3DDev->SetRenderState(D3DRS_FOGENABLE, true );
m_pD3DDev->SetRenderState(D3DRS_FOGCOLOR, kSmokeColor);
m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
// particles have alpha, but are not (cannot be) depth-sorted. Thus, disable z-writing
// to avoid funny alpha-occlusion
m_pD3DDev->SetRenderState(D3DRS_ZWRITEENABLE, false);
hr = m_pD3DDev->SetStreamSource(0, m_pParticleVB, sizeof(PSystemVertex));
hr = m_pD3DDev->SetVertexShader(mParticleShader);
hr = m_pD3DDev->SetTexture(0, m_pParticleTexture);
assert(10 < kNumParticles);
hr = m_pD3DDev->DrawPrimitive(D3DPT_POINTLIST, 0, mNumParticles);
return hr;
}
void CShaderPSystem::Keyboard(DWORD vKey, UINT nFlags, bool bDown)
{
eEBKeyAction Action = TranslateEffectKey(vKey, 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 Space/Pause Toggle Pausing Animation\n\n +/- - Increase/Reduce Number of Particles\n\n Left Button & Mouse - Rotate Camera\n\n Shift Left Button & Mouse - Pan Camera \n\n Ctrl Left Button & Mouse - Move Camera In & Out\n\n",
"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:
{
mbFreezeFrame = !mbFreezeFrame;
m_dwEffectDirtyFlags |= EBEFFECT_DIRTY_PUBLICSTATE;
}
break;
case EB_RESET:
{
mbFreezeFrame = false;
mNumParticles = kStartParticles;
m_dwEffectDirtyFlags |= EBEFFECT_DIRTY_PUBLICSTATE;
mpMouseUI->Reset();
}
break;
case EB_ADD:
mNumParticles += max(5, mNumParticles/10);
if (mNumParticles > kNumParticles)
mNumParticles = kNumParticles;
break;
case EB_SUBTRACT:
mNumParticles -= max(5, mNumParticles/10);
if (mNumParticles < 10)
mNumParticles = 10;
break;
default:
m_bKey[vKey] = bDown;
}
}
void CShaderPSystem::SetViewFromKeyboardInput(EBTimer* pTimer, D3DXMATRIX &matView)
{
float const kSpeed = pTimer->GetSecsPerFrame() * 10.0f;
float const moveSpeed = kSpeed * 2.0f;
D3DXVECTOR3 const yVector(0.0f, 1.0f, 0.0f);
D3DXVECTOR3 lookDir(0.0f, 0.0f, 1.0f);
D3DXVECTOR4 position;
D3DXMATRIX matLookRotations;
D3DXMatrixTranspose(&matLookRotations, &(mpMouseUI->GetRotationMatrix()));
D3DXVec3TransformNormal(&lookDir, &lookDir, &matLookRotations);
float const h = D3DXVec3Dot(&yVector, &lookDir);
D3DXVECTOR3 xzProjectedLookDirection(lookDir - h*yVector);
D3DXVec3Normalize(&xzProjectedLookDirection, &xzProjectedLookDirection);
D3DXVECTOR3 rightVector;
D3DXVec3Cross(&rightVector, &yVector, &xzProjectedLookDirection);
if(m_bKey[VK_UP] || m_bKey[VK_NUMPAD8])
mpMouseUI->Translate( moveSpeed*xzProjectedLookDirection);
if(m_bKey[VK_DOWN] || m_bKey[VK_NUMPAD2])
mpMouseUI->Translate(- moveSpeed*xzProjectedLookDirection);
if(m_bKey[VK_LEFT] || m_bKey[VK_NUMPAD4])
mpMouseUI->Translate(- 0.5f*moveSpeed*rightVector);
if(m_bKey[VK_RIGHT] || m_bKey[VK_NUMPAD6])
mpMouseUI->Translate( 0.5f*moveSpeed*rightVector);
if(m_bKey[VK_PRIOR])
mpMouseUI->Translate( 0.25f*moveSpeed*yVector);
if(m_bKey[VK_NEXT])
mpMouseUI->Translate(- 0.25f*moveSpeed*yVector);
D3DXVec3Transform(&position, &D3DXVECTOR3(0.0f, 1.0f, -5.0f), &mpMouseUI->GetTranslationMatrix());
D3DXVECTOR3 const camPosition = D3DXVECTOR3(position.x, max(0.1f, position.y), position.z);
D3DXVECTOR3 const vLookatPt = camPosition + lookDir;
D3DXMatrixLookAtLH(&matView, &camPosition, &vLookatPt, &yVector);
}
HRESULT CShaderPSystem::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 1...)
if(pCaps->MaxSimultaneousTextures < 1)
{
m_strLastError = "Device does not support 1 simultaneous textures!";
return E_FAIL;
}
// only need very few, simple register combiners...
if(pCaps->MaxTextureBlendStages < 2)
{
m_strLastError = "Device does not support 2 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;
}
// point primitives?!
if (pCaps->MaxPointSize == 1.0f)
{
m_strLastError = "Device does not support point-sprites!";
return E_FAIL;
}
return S_OK;
}
void CShaderPSystem::MouseMove(HWND hWnd, int x, int y)
{
mpMouseUI->OnMouseMove(x, y);
}
void CShaderPSystem::MouseButton(HWND hWnd, eButtonID button, bool bDown, int x, int y)
{
if(button == MOUSE_LEFTBUTTON)
{
if(bDown)
mpMouseUI->OnLButtonDown(x, y);
else
mpMouseUI->OnLButtonUp(x, y);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -