📄 particleemitter.cpp
字号:
#include "StdAfx.h"
#include ".\particleemitter.h"
void CParticleEmitter::InitEmitIB()
{
WORD Indices[MAX_EMIT_NUMBER*6];
for ( USHORT i = 0 ; i < MAX_EMIT_NUMBER ; i++ )
{
// 左上
Indices[i*6] = i * 4;
Indices[i*6+1] = i * 4 + 1;
Indices[i*6+2] = i * 4 + 2;
// 右下
Indices[i*6+3] = i * 4 + 2;
Indices[i*6+4] = i * 4 + 1;
Indices[i*6+5] = i * 4 + 3;
}
if(SUCCEEDED(m_pDevice->CreateIndexBuffer(
sizeof(Indices),
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&m_ib,
NULL
))){
VOID* pIndices;
if( FAILED( m_ib->Lock( 0, sizeof(Indices), (void**)&pIndices, 0 ) ) )
return ;
memcpy( pIndices, Indices, sizeof(Indices) );
m_ib->Unlock();
}
}
CParticleEmitter::CParticleEmitter(LPDIRECT3DDEVICE9 device,CParticleSystem* sys , const string& name , long maxparticle , long emit_ps , float spd , float size , D3DCOLOR clr )
: m_pParentSystem(sys) , m_bActive(false) , m_strName(name)
{
m_pDevice=device;
if(FAILED(m_pDevice->CreateVertexBuffer(
4*MAX_EMIT_NUMBER*sizeof(Vert_PDT1),
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC,
Vert_PDT1::fvf,
D3DPOOL_DEFAULT,
&m_vb,0))){
MessageBox(NULL,"创建顶点缓冲区失败","",MB_OK);
return;
}
InitEmitIB();
m_vecRelPos = sys->GetPosition();
m_ActiveList.clear();
m_DisableList.clear();
m_ParticlePool.clear();
m_un32MaxParticleNum = maxparticle;
m_fMaxEmitTime = 0.0f;
m_fMaxEmitTimeMin = 0;
m_fMaxEmitTimeVar = 0;
m_fRepeatDelay = 0.0f;
m_fRepeatDelayMin = 0;
m_fRepeatDelayVar = 0;
m_un32EmitNumPerSec = emit_ps;
m_fEmitAccum = 0.0f;
m_bInterpolation = true;
m_vecLastPos = m_vecPos = D3DXVECTOR3(0,0,0);
m_fElapsedTime = 0.0f;
m_vecVelocityMin = m_vecVelocityVar = D3DXVECTOR3(0,0,0);
m_pTexture = NULL;
m_fInitSizeMin = size;
m_fInitSizeVar = 0;
m_fLifeSpanMin = 0;
m_fLifeSpanVar = 0;
m_clrInitClrMin = clr;
m_clrInitClrVar = 0;
m_AffectorVector.clear();
}
CParticleEmitter::~CParticleEmitter()
{
Destroy();
}
void CParticleEmitter::UpdateMatrix()
{
}
bool CParticleEmitter::Initialize()
{
// 生成Pool
SetPoolSize( m_un32MaxParticleNum );
// 将Pool影响到DisableList
m_DisableList.clear();
for ( int i = 0 ; i < (int)m_ParticlePool.size() ; i++ )
{ m_DisableList.push_back( m_ParticlePool[i] ); }
m_ActiveList.clear();
m_textureName=new char[100];
sprintf(m_textureName,"%s","");
m_bActive = true;
m_pTexture=NULL;
return true;
}
void CParticleEmitter::Generate( float fElapsed )
{
long inewpar = 0;
m_fElapsedTime += fElapsed;
// 是否可以开始生成
if ( m_bActive )
{
// 检测Elapsed和EmitRate的倍数关系(即计算与EmitPerSec的乘数关系),大于1的部分按照倍数生成,余数累积
m_fEmitAccum += fElapsed * m_un32EmitNumPerSec;
inewpar = (long)m_fEmitAccum;
m_fEmitAccum -= inewpar;
// 这时inewpar记录了新Particle的数量
// 看此次发射是否到了终结的时刻
if ( m_fMaxEmitTimeMin != 0.0f )
{
if ( m_fElapsedTime > m_fMaxEmitTime )
{
SetActive(false);
m_fElapsedTime = 0.0f;
}
}
}
// 否则看是否触发了Repeat条件
else
{
if ( m_fRepeatDelay != 0.0f )
{
if ( m_fElapsedTime > m_fRepeatDelay )
{
SetActive(true);
// 计算新的Emit和Repeat
m_fMaxEmitTime = m_fMaxEmitTimeMin + RangeRandom( 0.0f , m_fMaxEmitTimeVar );
m_fRepeatDelay = m_fRepeatDelayMin + RangeRandom( 0.0f , m_fRepeatDelayVar );
m_fElapsedTime = 0.0f;
}
}
inewpar = 0;
}
// 按照前面的粒子数量产生新粒子
D3DXVECTOR3 vec;
if ( inewpar ) { vec = m_vecPos - m_vecLastPos; vec /= (float)inewpar; }
for ( long i = 0 ; i < inewpar ; i++ )
{
if ( m_DisableList.size() == 0 )
{ break; }
CParticle* par = m_DisableList.front();
m_DisableList.pop_front();
// 计算插值点位置(如果需要),否则,插值点位置等同于当前位置
if ( m_bInterpolation )
{ m_vecInterpolatePos = m_vecPos - (float)i * vec; }
else
{ m_vecInterpolatePos = m_vecPos; }
// 先进行自动配置,最后通过Creator修正
// 使用插值点位置
par->m_vecPosition = m_vecInterpolatePos;
// 注册粒子的父Emitter和初始信息
par->m_pParentEmitter = this;
par->m_vecInitPosition = par->m_vecPosition;
// 生成新粒子的大小信息
GenerateSize( par );
// 生成新粒子的速度信息
GenerateVelocity( par );
// 生成新粒子的生命信息
GenerateLife( par );
// 生成新粒子的颜色信息
GenerateColor( par );
// Creator修正
for ( long j = 0 ; j < (long)m_AffectorVector.size() ; j++ )
{
m_AffectorVector[j]->Create( par );
}
m_ActiveList.push_back(par);
}
}
void CParticleEmitter::GenerateSize( CParticle* particle )
{
particle->m_fSize = m_fInitSizeMin + RangeRandom( 0.0f , m_fInitSizeVar );
}
void CParticleEmitter::GenerateVelocity( CParticle* particle )
{
particle->m_vecVelocity.x = m_vecVelocityMin.x + RangeRandom( 0.0f , m_vecVelocityVar.x );
particle->m_vecVelocity.y = m_vecVelocityMin.y + RangeRandom( 0.0f , m_vecVelocityVar.y );
particle->m_vecVelocity.z = m_vecVelocityMin.z + RangeRandom( 0.0f , m_vecVelocityVar.z );
}
void CParticleEmitter::GenerateLife( CParticle* particle )
{
particle->m_fElapsedLife = m_fLifeSpanMin + RangeRandom( 0.0f , m_fLifeSpanVar );
}
void CParticleEmitter::GenerateColor( CParticle* particle )
{
static USHORT a,r,g,b;
a = m_InitAMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitAVar );
r = m_InitRMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitRVar );
g = m_InitGMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitGVar );
b = m_InitBMin + (UCHAR)RangeRandom( 0.0f , (float)m_InitBVar );
if ( a > 255 ){ a = 255; }
if ( r > 255 ){ r = 255; }
if ( g > 255 ){ g = 255; }
if ( b > 255 ){ b = 255; }
particle->m_clrColor = D3DCOLOR_ARGB(a,r,g,b);
}
void CParticleEmitter::Update( float fElapsed )
{
// 记录上一次位置,供位置插值用
m_vecLastPos = m_vecPos;
// 父System位置是否变化,需要影响过来
m_vecPos = m_pParentSystem->GetPosition() + m_vecRelPos;
// 是否到了上限
if( (long)m_ActiveList.size() < m_un32MaxParticleNum )
{
// 没有到上限就可以处理生成粒子的逻辑
Generate( fElapsed );
}
if ( m_ActiveList.empty() )
{ return; }
// 对所有Active的粒子进行Update
ParticleList::iterator it = m_ActiveList.begin();
for ( ; it != m_ActiveList.end() ; )
{
if ( !UpdateParticle( fElapsed , *it ) )
{
// 如果失效就取消此粒子
m_DisableList.push_back( *it );
it = m_ActiveList.erase( it );
}
else
{
// 否则,步进下一个
++it;
}
}
}
bool CParticleEmitter::UpdateParticle( float fElapsed , CParticle* particle )
{
if( !m_AffectorVector.empty() )
{
for ( int i = 0 ; i < (int)m_AffectorVector.size() ; ++i )
{
m_AffectorVector[i]->Logic( particle , fElapsed );
}
}
// 位置
particle->m_vecPosition += particle->m_vecVelocity * fElapsed;
// 生命
particle->m_fElapsedLife -= fElapsed;
if ( particle->m_fElapsedLife <= 0.0f )
{ return false; }
return true;
}
void CParticleEmitter::Render(D3DXVECTOR3 camDir)
{
// 重设世界矩阵为0,0,0
D3DXMATRIX matWorld;
D3DXMatrixIdentity( &matWorld );
m_pDevice->SetTransform(D3DTS_WORLD,&matWorld);
////////////////////////////////////////////
//成billborad效果
D3DXVECTOR3 eddy;
D3DXVECTOR3 dir=D3DXVECTOR3(0,0,1);
D3DXVec3Cross(&eddy,&dir,&camDir);
float dot=D3DXVec3Dot(&dir,&camDir);
float angle=(180*acos(dot))/D3DX_PI;
if(D3DXVec3Length(&eddy)<=0)
angle=0;
D3DXMatrixRotationAxis(&matWorld,&eddy,angle);
m_pDevice->SetTransform(D3DTS_WORLD,&matWorld);
/////////////////////////////////////////////
// 关闭光照
m_pDevice->SetRenderState( D3DRS_LIGHTING , false );
// 纹理操作
if(m_pTexture!=NULL&&strlen(m_textureName)>0){
m_pDevice->SetTexture(0,m_pTexture);
}
m_pDevice->SetTextureStageState( 0 , D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pDevice->SetTextureStageState( 0 , D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pDevice->SetTextureStageState( 0 , D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pDevice->SetTextureStageState( 0 , D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pDevice->SetTextureStageState( 0 , D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE , true );
m_pDevice->SetRenderState( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );
m_pDevice->SetRenderState( D3DRS_DESTBLEND , D3DBLEND_ONE );
m_pDevice->SetRenderState( D3DRS_ZENABLE , false );
m_pDevice->SetRenderState( D3DRS_ZWRITEENABLE , false );
RenderGeometry();
m_pDevice->SetRenderState( D3DRS_ZENABLE , true );
m_pDevice->SetRenderState( D3DRS_ZWRITEENABLE , true );
m_pDevice->SetTexture(0,NULL);
}
void CParticleEmitter::RenderGeometry()
{
if ( m_ActiveList.empty() )
{ return; }
// Look与摄像机Look相同但Y=0
D3DXVECTOR3 B_look =m_pParentSystem->m_look;
D3DXVec3Normalize( &B_look , &B_look );
// Up为摄像机的Up
D3DXVECTOR3 B_up = m_pParentSystem->m_up;
D3DXVec3Normalize( &B_up , &B_up );
// Right由Up叉乘Look
D3DXVECTOR3 B_right ;
D3DXVec3Cross( &B_right , &B_up , &B_look );
D3DXVec3Normalize( &B_right , &B_right );
// 填入数据
long i = 0;
ParticleList::iterator it = m_ActiveList.begin();
for ( ; it != m_ActiveList.end() ; ++it )
{
float halfsize = (*it)->m_fSize*0.5f;
m_PartDatas[i].pos = (*it)->m_vecPosition + B_up * halfsize - B_right * halfsize;
m_PartDatas[i+1].pos = (*it)->m_vecPosition + B_up * halfsize + B_right * halfsize;
m_PartDatas[i+2].pos = (*it)->m_vecPosition - B_up * halfsize - B_right * halfsize;
m_PartDatas[i+3].pos = (*it)->m_vecPosition - B_up * halfsize + B_right * halfsize;
m_PartDatas[i].clr = (*it)->m_clrColor;
m_PartDatas[i].tex.u = 0.0f; m_PartDatas[i].tex.v = 0.0f;
m_PartDatas[i+1].clr = (*it)->m_clrColor;
m_PartDatas[i+1].tex.u = 1.0f; m_PartDatas[i+1].tex.v = 0.0f;
m_PartDatas[i+2].clr = (*it)->m_clrColor;
m_PartDatas[i+2].tex.u = 0.0f; m_PartDatas[i+2].tex.v = 1.0f;
m_PartDatas[i+3].clr = (*it)->m_clrColor;
m_PartDatas[i+3].tex.u = 1.0f; m_PartDatas[i+3].tex.v = 1.0f;
i += 4;
}
// 写VB
void* pDst ;
m_vb->Lock(0, sizeof(m_PartDatas) ,(void **)&pDst,0);
memcpy( pDst , m_PartDatas , sizeof(m_PartDatas) );
m_vb->Unlock();
m_pDevice->SetStreamSource( 0 , m_vb , 0 , sizeof(Vert_PDT1));
m_pDevice->SetFVF(Vert_PDT1::fvf);
m_pDevice->SetIndices( m_ib);
m_pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST , 0 , 0 ,(UINT)m_ActiveList.size()*4 , 0 , (UINT)m_ActiveList.size()*2 );
}
void CParticleEmitter::Destroy()
{
m_bActive = false;
m_fElapsedTime = 0.0f;
for ( long i = 0 ; i < (long)m_ParticlePool.size() ; i++ )
{ SAFE_DELETE(m_ParticlePool[i]); }
m_ParticlePool.clear();
m_ActiveList.clear();
m_DisableList.clear();
DestroyPlugs();
}
void CParticleEmitter::AddAffector( CParticleAffector* pAffector )
{
m_AffectorVector.push_back( pAffector );
}
void CParticleEmitter::DestroyPlugs()
{
for ( long i = 0 ; i < (long)m_AffectorVector.size() ; i++ )
{ SAFE_DELETE( m_AffectorVector[i] ); }
SAFE_RELEASE(m_pTexture);
SAFE_RELEASE(m_ib);
SAFE_RELEASE(m_vb);
}
void CParticleEmitter::SetParentSystem( CParticleSystem* sys )
{
m_pParentSystem = sys;
}
void CParticleEmitter::SetActive( bool setting)
{
if( setting && m_un32MaxParticleNum && m_un32EmitNumPerSec && m_fInitSizeMin )
{
m_bActive = setting;
}
else
{
m_bActive = false;
m_vecLastPos = m_vecPos = D3DXVECTOR3(0,0,0);
}
}
void CParticleEmitter::SetMaxParticleNumber( long num )
{
m_un32MaxParticleNum = num;
if ( m_un32MaxParticleNum > MAX_EMIT_NUMBER )
{ m_un32MaxParticleNum = MAX_EMIT_NUMBER; }
}
void CParticleEmitter::SetEmitRate( long num_ps )
{
m_un32EmitNumPerSec = num_ps;
}
void CParticleEmitter::SetEmitRepeat( float emitmin , float delaymin , float emitvar , float delayvar)
{
m_fMaxEmitTimeMin = emitmin;
m_fMaxEmitTimeVar = emitvar;
m_fRepeatDelayMin = delaymin;
m_fRepeatDelayVar = delayvar;
}
void CParticleEmitter::SetRelativePos( const D3DXVECTOR3& rel )
{
if ( m_pParentSystem )
{
m_vecRelPos = rel;
m_vecPos = m_vecRelPos + m_pParentSystem->GetPosition();
}
}
void CParticleEmitter::SetSpeed( const D3DXVECTOR3& spd , const D3DXVECTOR3& var)
{
m_vecVelocityMin = spd;
m_vecVelocityVar = var;
}
void CParticleEmitter::SetSize( float initmin , float initvar)
{
m_fInitSizeMin = initmin;
m_fInitSizeVar = initvar;
}
void CParticleEmitter::SetLifeSpan( float min , float var)
{
m_fLifeSpanMin = min;
m_fLifeSpanVar = var;
}
void CParticleEmitter::SetColor( const D3DCOLORVALUE& clr , const D3DCOLORVALUE& var )
{
m_clrInitClrMin = D3DCOLOR_COLORVALUE( clr.r , clr.g , clr.b , clr.a );
m_clrInitClrVar = D3DCOLOR_COLORVALUE( var.r , var.g , var.b , var.a );
}
void CParticleEmitter::SetColor( D3DCOLOR clr , D3DCOLOR var )
{
m_clrInitClrMin = clr;
m_clrInitClrVar = var;
}
bool CParticleEmitter::SetTexture( char *texName )
{
if(strlen(texName)<=0){
sprintf(m_textureName,"%s","");
if(m_pTexture){
SAFE_RELEASE(m_pTexture);
}
return false;
}
if(strcmp(m_textureName,texName)==0)
return true;
else{
sprintf(m_textureName,"%s",texName);
}
// 调用D3DX函数生成
if(m_pTexture){
SAFE_RELEASE(m_pTexture);
}
if( FAILED(D3DXCreateTextureFromFile( m_pDevice,texName,&m_pTexture)))
{
MessageBox(NULL,"加载纹理失败","失败",MB_OK);
return false;
}
return true;
}
void CParticleEmitter::SetPoolSize( unsigned int size )
{
long oldSize = (long)m_ParticlePool.size();
if ( size == oldSize ) { return; }
// 如果新的小于等于旧的,需要重生成整个Pool
else if( (long)size < oldSize )
{
long decr = oldSize - size;
for ( long i = 0 ; i < (long)m_ParticlePool.size() ; i++ )
{ SAFE_DELETE(m_ParticlePool[i]); }
oldSize = 0;
}
// 分配空间
m_ParticlePool.reserve(size);
m_ParticlePool.resize(size);
// Create new particles
for( size_t i = oldSize; i < size; i++ )
{
m_ParticlePool[i] = new CParticle;
}
}
void CParticleEmitter::SetName(string str){
m_strName=str;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -