📄 shader_particlesystem.cpp
字号:
/******************************************************************************
Copyright (C) 1999, 2000 NVIDIA Corporation
This file is provided without support, instruction, or implied warranty of any
kind. NVIDIA makes no guarantee of its fitness for a particular purpose and is
not liable under any circumstances for any damages or loss whatsoever arising
from the use or inability to use this file or items derived from it.
******************************************************************************/
#include "eb_effect.h"
#include "nvinc.h"
#include "shader_ParticleSystem.h"
#include "ParticleSystem.h"
using namespace std;
DECLARE_EFFECT_MAIN()
extern "C"
{
__declspec(dllexport) unsigned int GetNumEffects() { return 1; }
__declspec(dllexport) EBEffect* CreateEffect(unsigned int EffectNum)
{
return new CShaderPSystem();
}
}
CShaderPSystem::CShaderPSystem()
: m_pParticleVB(NULL)
, m_pFloorVB(NULL)
, m_pFloorTexture(NULL)
, m_pParticleTexture(NULL)
, mNumParticles(kStartParticles)
, mbFreezeFrame(false)
, mbWireFrame(false)
, mpMouseUI(NULL)
{
m_strEffectName = "Particle System";
m_strEffectLocation = "Vertex Shaders\\Physics";
m_strEffectPixelShader = "";
m_strEffectVertexShader = GetFilePath("particleSystem.nvv");
}
CShaderPSystem::~CShaderPSystem()
{
Free();
}
void CShaderPSystem::UpdateProperties()
{
EBEffect::UpdateProperties();
AddProperty(new EBProperty("Wireframe", OBJECT_MEMBER(mbWireFrame), EBTYPE_BOOL_PROP));
AddProperty(new EBProperty("Pause", OBJECT_MEMBER(mbFreezeFrame), EBTYPE_BOOL_PROP));
m_pVertexShaderEnum->AddEnumerant(new EBEnumValue(m_pVertexShaderEnum, "Physics in Vertex Shader", GetFilePath("particleSystem.nvv"), EBTYPE_STRING_PROP));
}
HRESULT CShaderPSystem::Initialize(IDirect3DDevice8* pDev)
{
ZeroMemory(&m_bKey[0], sizeof(bool) * kMaxVKey);
HRESULT hr;
m_pD3DDev = pDev;
pDev->AddRef();
//initialize mouse UI
D3DVIEWPORT8 viewport;
RECT rect;
m_pD3DDev->GetViewport(&viewport);
rect.left = rect.top = 0;
rect.bottom = viewport.Height;
rect.right = viewport.Width;
mpMouseUI = new MouseUI(rect, true);
mpMouseUI->SetRotationalSensitivityFactor(1.0f);
// create the floor quadrangle
hr = m_pD3DDev->CreateVertexBuffer( 4 * sizeof(FloorVertex), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &m_pFloorVB);
if (FAILED(hr))
return hr;
vector<DWORD> floorDecl;
floorDecl.push_back(D3DVSD_STREAM(0));
floorDecl.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT4));
floorDecl.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT2));
floorDecl.push_back(D3DVSD_END());
hr = LoadAndCreateShader(GetFilePath("particleFloor.vso"), &floorDecl[0], 0, SHADERTYPE_VERTEX, &mFloorShader);
if (FAILED(hr))
return hr;
FloorVertex* pFloor;
assert(m_pFloorVB != NULL);
hr = m_pFloorVB->Lock(0, 4 * sizeof(FloorVertex),(BYTE**)&pFloor, 0);
if (FAILED(hr))
{
m_strLastError = "Couldn't lock Floor buffer!";
return hr;
}
float const kFloorDimension = 101.0f;
pFloor->position = D3DXVECTOR4(-kFloorDimension, 0.0f, -kFloorDimension, 1.0f);
pFloor->texture = D3DXVECTOR2(0.0f, 0.0f);
++pFloor;
pFloor->position = D3DXVECTOR4( kFloorDimension, 0.0f, -kFloorDimension, 1.0f);
pFloor->texture = D3DXVECTOR2(0.0f, kFloorDimension);
++pFloor;
pFloor->position = D3DXVECTOR4(-kFloorDimension, 0.0f, kFloorDimension, 1.0f);
pFloor->texture = D3DXVECTOR2(kFloorDimension, 0.0f);
++pFloor;
pFloor->position = D3DXVECTOR4( kFloorDimension, 0.0f, kFloorDimension, 1.0f);
pFloor->texture = D3DXVECTOR2(kFloorDimension, kFloorDimension);
++pFloor;
m_pFloorVB->Unlock();
hr = D3DXCreateTextureFromFileEx(m_pD3DDev,
GetFilePath("wall.dds").c_str(),
D3DX_DEFAULT,
D3DX_DEFAULT,
0,
0,
D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,
D3DX_FILTER_LINEAR,
D3DX_FILTER_LINEAR,
0,
NULL,
NULL,
&m_pFloorTexture);
if (FAILED(hr))
{
m_strLastError = "Could not load texture wall.dds";
return hr;
}
// create the particles
hr = m_pD3DDev->CreateVertexBuffer( kNumParticles * sizeof(PSystemVertex), D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &m_pParticleVB);
if (FAILED(hr))
return hr;
vector<DWORD> Declaration;
Declaration.push_back(D3DVSD_STREAM(0));
Declaration.push_back(D3DVSD_REG(0, D3DVSDT_FLOAT4));
Declaration.push_back(D3DVSD_REG(1, D3DVSDT_FLOAT4));
Declaration.push_back(D3DVSD_REG(2, D3DVSDT_FLOAT3));
Declaration.push_back(D3DVSD_END());
hr = LoadAndCreateShader(GetFilePath("particleSystem.vso"), &Declaration[0], 0, SHADERTYPE_VERTEX, &mParticleShader);
if (FAILED(hr))
return hr;
PSystemVertex* pBuff;
assert(m_pParticleVB != NULL);
hr = m_pParticleVB->Lock(0, kNumParticles * sizeof(PSystemVertex),(BYTE**)&pBuff, 0);
if (FAILED(hr))
{
m_strLastError = "Couldn't lock buffer!";
return hr;
}
D3DXVECTOR4 timeSeeds;
D3DXVECTOR4 physics;
D3DXVECTOR3 color;
_ftime(&mStartTime);
srand( (unsigned)mStartTime.time );
float const kRandMax = static_cast<float>(RAND_MAX);
float const kIAOver2 = 16807.0f/2.0f;
// all following times are in seconds
float creationTime = 0.0f; // used to figure out how far along a particle is in its lifetime
float lifeTime = 4.0f; // life time of a particle. A particle becomes invisible at the end of its life time
float periodicityOffset = 0.3f; // a particle is reborn (reused) every (lifeTime+periodicityOffset)
float decay = -1.0f; // 2^decay = Eps, w/ Eps < 1, but close to 1, ie, -1 < decay < 0;
float velocity = 3.0f; // initial velocity of particle (direction vector multiplier)
float random;
// generate and copy particle values
for (int i = kNumParticles; --i >= 0; )
{
timeSeeds.x = creationTime;
creationTime += 2.0f*lifeTime/static_cast<float>(kNumParticles);
random = lifeTime + 4.0f * static_cast<float>(rand())/kRandMax;
timeSeeds.y = 1.0f/random;
timeSeeds.z = random + periodicityOffset * static_cast<float>(rand())/kRandMax;
timeSeeds.w = 1.0f/(timeSeeds.z);
physics.x = decay; // could be a random variation
physics.y = 1.0f/(physics.x*logf(2.0f));
random = velocity + 2.0f * static_cast<float>(rand())/kRandMax;
physics.z = random;
physics.w = kIAOver2 * static_cast<float>(rand())/kRandMax; // per vertex random-seed (to be added to constant seed)
random = static_cast<float>(rand())/kRandMax;
color.x = 0.9f + 0.1f * random;
random = static_cast<float>(rand())/kRandMax;
color.y = 0.6f + 0.4f * random;
random = static_cast<float>(rand())/kRandMax;
color.z = 0.0f + 0.25f * random;
pBuff->timeSeeds = timeSeeds;
pBuff->physics = physics;
pBuff->color = color;
++pBuff;
}
m_pParticleVB->Unlock();
// read a texture for the particle
hr = D3DXCreateTextureFromFileEx(m_pD3DDev,
GetFilePath("flare1.dds").c_str(),
D3DX_DEFAULT,
D3DX_DEFAULT,
0,
0,
D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,
D3DX_FILTER_LINEAR,
D3DX_FILTER_LINEAR,
0,
NULL,
NULL,
&m_pParticleTexture);
if (FAILED(hr))
{
m_strLastError = "Could not load texture flare1.dds";
return hr;
}
m_pD3DDev->SetTexture(0, NULL);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
m_pD3DDev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
m_pD3DDev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
m_pD3DDev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
m_pD3DDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
m_pD3DDev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
// going to set real fog color in Tick()
m_pD3DDev->SetRenderState( D3DRS_FOGCOLOR, D3DCOLOR_RGBA(0, 0, 0, 0));
m_pD3DDev->SetRenderState( D3DRS_FOGENABLE, TRUE );
m_pD3DDev->SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_NONE );
m_pD3DDev->SetRenderState( D3DRS_FOGVERTEXMODE, D3DFOG_NONE );
m_pD3DDev->SetRenderState( D3DRS_RANGEFOGENABLE, FALSE );
m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
// add alpha's straight to achieve a "burn-out" effect
m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
m_pD3DDev->SetRenderState(D3DRS_ZWRITEENABLE, true);
// we actually override point-size in the vertex shader
float const kMinPointSize = 0.1f;
float const kMaxPointSize = 25.0f;
float const kPointSize = 4.0f;
m_pD3DDev->SetRenderState(D3DRS_POINTSIZE_MIN, *reinterpret_cast<DWORD const *>(&kMinPointSize) );
m_pD3DDev->SetRenderState(D3DRS_POINTSIZE_MAX, *reinterpret_cast<DWORD const *>(&kMaxPointSize) );
m_pD3DDev->SetRenderState(D3DRS_POINTSIZE, *reinterpret_cast<DWORD const *>(&kPointSize) );
m_pD3DDev->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
m_pD3DDev->SetRenderState(D3DRS_POINTSCALEENABLE, false);
// write the non-changing vertex shader constants
WriteVertexShaderConstants();
// initialize the camera controls
mpMouseUI->Reset();
return S_OK;
}
void CShaderPSystem::WriteVertexShaderConstants() const
{
// All of the following are write-once!
D3DXVECTOR4 constants(0.0f, 2.0f, D3DX_PI, 1.0f/3.0f);
m_pD3DDev->SetVertexShaderConstant(VSC_CONSTANTS, &constants, 1);
D3DXVECTOR4 constants2(1.0f/2.0f, 0.25f, 80.0f, 1.0f / (2.0f * D3DX_PI));
m_pD3DDev->SetVertexShaderConstant(VSC_CONSTANTS2, &constants2, 1);
D3DXVECTOR4 cosine(1.0f, -1.0f / 2.0f, 1.0f / 24.0f, -1.0f / 720.0f);
m_pD3DDev->SetVertexShaderConstant(VSC_COSINE, &cosine, 1);
D3DXVECTOR4 sine(1.0f, -1.0f / 6.0f, 1.0f / 120.0f, -1.0f / 5040.0f);
m_pD3DDev->SetVertexShaderConstant(VSC_SINE, &sine, 1);
D3DXVECTOR4 rndVariance(1.0f, 1.0f, 2.0f, 0.3f);
m_pD3DDev->SetVertexShaderConstant(VSC_RND_VARIANCE, &rndVariance, 1);
float const kNumRnds = static_cast<float>(kNumRndVectors);
D3DXVECTOR4 rndNumVectors(kNumRnds, 1.0f/kNumRnds, 0.0f, 0.0f);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -