ParticleSystem.cpp
上传用户:henghua
上传日期:2007-11-14
资源大小:7655k
文件大小:12k
- #include "ParticleSystem.h"
- // 功能: 构造函数,初始化数据成员
- CParticleSystem::CParticleSystem( LPDIRECT3DDEVICE9 dev , cparticleconfig * config )
- {
- device = dev;
- m_fRadius = config->fRadius;
- m_dwBase = config->dwDiscard;
- m_dwFlush = config->dwFlush;
- m_dwDiscard = config->dwDiscard;
- m_dwParticles = 0;
- m_dwParticlesLim = 2048;
- m_pParticles = NULL;
- m_pParticlesFree = NULL;
- m_pVB = NULL;
- HRESULT hr;
- hr = D3DXCreateTextureFromFile( device, config->tex_file_name, &(this->m_pParticleTexture));
- this->src_pos1 = config->src_pos1;
- this->src_pos2 = config->src_pos2;
- this->src_dir = config->src_dir;
- this->src_vec = config->src_vec;
- }
- // 功能: 逐粒子释放粒子链和空闲粒子链
- CParticleSystem::~CParticleSystem()
- {
- while( m_pParticles )
- {
- PARTICLE* pSpark = m_pParticles;
- m_pParticles = pSpark->m_pNext;
- delete pSpark;
- }
- while( m_pParticlesFree )
- {
- PARTICLE *pSpark = m_pParticlesFree;
- m_pParticlesFree = pSpark->m_pNext;
- delete pSpark;
- }
- }
- //-----------------------------------------------------------------------------
- // 功能:更新粒子系统中的各个参量
- // 传入参量:每桢的时刻值,新粒子数上限,初始颜色,淡出颜色,初始速度,粒子源位置
- //-----------------------------------------------------------------------------
- HRESULT CParticleSystem::Update( FLOAT fSecsPerFrame, DWORD dwNumParticlesToEmit,
- const D3DXCOLOR &clrEmitColor,
- const D3DXCOLOR &clrFadeColor, float fEmitVel,
- D3DXVECTOR3 vPosition )
- {
- PARTICLE *pParticle, **ppParticle;
- // 记录时间,每桢叠加
- static float fTime = 0.0f;
- fTime += fSecsPerFrame;
- ppParticle = &m_pParticles;
- // 当链表不为空时,遍历粒子对象链表:更新每个粒子的信息,以及添加飞溅效果
- while( *ppParticle )
- {
- pParticle = *ppParticle;
- // 计算新点的位置
- float fT = fTime - pParticle->m_fTime0; // 与起始时间之差
- float fGravity; // 重力
- if( pParticle->m_bSpark ) // 如果是溅出的火星
- {
- fGravity = -5.0f;
- pParticle->m_fFade -= fSecsPerFrame * 2.25f;
- }
- else // 如果不是溅出的火星
- {
- fGravity = -9.8f;
- pParticle->m_fFade -= fSecsPerFrame * 0.99f;
- }
- // 物理学重力模型(计算下一桢的位置和速度)
- pParticle->m_vPos = pParticle->m_vVel0 * fT + pParticle->m_vPos0; // s1 = v * t + s0
- pParticle->m_vPos.y += (0.5f * fGravity) * (fT * fT); // y1 = y0 + 1/2*g*t^2
- pParticle->m_vVel.y = pParticle->m_vVel0.y + fGravity * fT; // v1.y = v0.y + g*t
- if( pParticle->m_fFade < 0.0f )
- pParticle->m_fFade = 0.0f;
- // 如果粒子撞击到地面,包括火花撞击到地面(位置小于某个值 或者 粒子处于飞溅状态且淡出系数已为负)
- if( pParticle->m_vPos.y < m_fRadius ||
- pParticle->m_bSpark && pParticle->m_fFade <= 0.0f )
- {
- // 如果不是火花,则产生火花;火花不可以产生火花
- if( !pParticle->m_bSpark )
- {
- // 产生四个火花
- for( int i=0; i<4; i++ )
- {
- PARTICLE *pSpark;
- // 增加新粒子结点的方式:由空闲链表给 或者 new一个
- if( m_pParticlesFree )
- {
- pSpark = m_pParticlesFree;
- m_pParticlesFree = pSpark->m_pNext;
- }
- else
- {
- if( NULL == ( pSpark = new PARTICLE ) )
- return E_OUTOFMEMORY;
- }
- // 插入新粒子
- pSpark->m_pNext = pParticle->m_pNext;
- pParticle->m_pNext = pSpark;
- // 为飞溅状态,更新初始位置x,z保留,y为触地面的高度
- pSpark->m_bSpark = TRUE; // 火花标示为真
- pSpark->m_vPos0 = pParticle->m_vPos; // 继承产生它的粒子的位置
- pSpark->m_vPos0.y = m_fRadius; // 高度设为固定溅射高度
- // fRand1=[0,2*pi], fRand2=[0,1/4*pi],产生限定范围的随机数
- FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.00f;
- FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
- // 撞地后的速度变化--〉作为新的初始速度
- pSpark->m_vVel0.x = pParticle->m_vVel.x * 0.25f + cosf(fRand1) * sinf(fRand2);
- pSpark->m_vVel0.z = pParticle->m_vVel.z * 0.25f + sinf(fRand1) * sinf(fRand2);
- pSpark->m_vVel0.y = cosf(fRand2);
- pSpark->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * 1.5f;
-
- // 更新当前位置和速度
- pSpark->m_vPos = pSpark->m_vPos0;
- pSpark->m_vVel = pSpark->m_vVel0;
-
- // 更新当前颜色值(根据淡出系数插值出最终颜色)
- D3DXColorLerp( &pSpark->m_clrDiffuse, &pParticle->m_clrFade,
- &pParticle->m_clrDiffuse, pParticle->m_fFade );
- pSpark->m_clrFade = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
- pSpark->m_fFade = 1.0f; // 初始m_fFade为1,颜色值为m_clrDiffuse
- pSpark->m_fTime0 = fTime;
- }
- }
- // 当前粒子对象接触到地面,“释放”(实际上将待销毁的粒子转给空闲链表,对象池性能优化技术)
- *ppParticle = pParticle->m_pNext;
- pParticle->m_pNext = m_pParticlesFree;
- m_pParticlesFree = pParticle;
- // 对象数减一
- if(!pParticle->m_bSpark)
- m_dwParticles--;
- }
- else
- {
- ppParticle = &pParticle->m_pNext;
- }
- }
- // 产生新粒子
- DWORD dwParticlesEmit = m_dwParticles + dwNumParticlesToEmit;
- while( m_dwParticles < m_dwParticlesLim && m_dwParticles < dwParticlesEmit )
- {
- // 对象池性能优化技术
- if( m_pParticlesFree )
- {
- pParticle = m_pParticlesFree;
- m_pParticlesFree = pParticle->m_pNext;
- }
- else
- {
- if( NULL == ( pParticle = new PARTICLE ) )
- return E_OUTOFMEMORY;
- }
- // 插入链表头部
- pParticle->m_pNext = m_pParticles;
- m_pParticles = pParticle;
- m_dwParticles++;
- // 设定新粒子的参量
- FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.0f;
- FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
- FLOAT fRand3 = ((FLOAT)rand()/(FLOAT)RAND_MAX);
- pParticle->m_bSpark = FALSE;
- D3DXVec3Lerp( &(pParticle->m_vPos0), &(this->src_pos1),&(this->src_pos2), fRand3);
- pParticle->m_vVel0.x = cosf(fRand1) * sinf(fRand2) * 0.1 + this->src_dir.x;
- pParticle->m_vVel0.z = sinf(fRand1) * sinf(fRand2) * 0.1 + this->src_dir.z;
- pParticle->m_vVel0.y = cosf(fRand2) * 0.1 + this->src_dir.y;
- pParticle->m_vVel0 *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * this->src_vec;
- pParticle->m_vPos = pParticle->m_vPos0;
- pParticle->m_vVel = pParticle->m_vVel0;
- pParticle->m_clrDiffuse = clrEmitColor;
- pParticle->m_clrFade = clrFadeColor;
- pParticle->m_fFade = 1.0f;
- pParticle->m_fTime0 = fTime;
- }
- return S_OK;
- }
- //-----------------------------------------------------------------------------
- // 功能:渲染
- //-----------------------------------------------------------------------------
- HRESULT CParticleSystem::DrawParticles( )
- {
- HRESULT hr;
- // 设置渲染状态为点精灵绘制
- device->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );
- device->SetRenderState( D3DRS_POINTSCALEENABLE, TRUE );
- device->SetRenderState( D3DRS_POINTSIZE, FtoDW(0.08f) );
- device->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(0.00f) );
- device->SetRenderState( D3DRS_POINTSCALE_A, FtoDW(0.5f) );
- device->SetRenderState( D3DRS_POINTSCALE_B, FtoDW(0.1f) );
- device->SetRenderState( D3DRS_POINTSCALE_C, FtoDW(1.00f) );
- // 设置顶缓流
- device->SetStreamSource( 0, m_pVB, 0, sizeof(POINTVERTEX) );
- device->SetFVF( D3DFVF_POINTVERTEX );
- PARTICLE* pParticle = m_pParticles;
- POINTVERTEX* pVertices;
- DWORD dwNumParticlesToRender = 0;
- // 采用顶点缓冲区部分锁定分块绘制的方法
- m_dwBase += m_dwFlush;
- if(m_dwBase >= m_dwDiscard)
- m_dwBase = 0;
- // 只锁定一个分块,如果m_dwBase为0,则丢弃重心返回一个新区域
- if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
- (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
- {
- return hr;
- }
-
- // 渲染每一个粒子对象
- while( pParticle )
- {
- D3DXVECTOR3 vPos(pParticle->m_vPos);
- D3DXVECTOR3 vVel(pParticle->m_vVel);
- // 计算速度大小
- FLOAT fLengthSq = D3DXVec3LengthSq(&vVel);
- UINT dwSteps;
- // 根据速度大小决定模糊绘制的次数
- if( fLengthSq < 1.0f ) dwSteps = 2;
- else if( fLengthSq < 4.00f ) dwSteps = 3;
- else if( fLengthSq < 9.00f ) dwSteps = 4;
- else if( fLengthSq < 12.25f ) dwSteps = 5;
- else if( fLengthSq < 16.00f ) dwSteps = 6;
- else if( fLengthSq < 20.25f ) dwSteps = 7;
- else dwSteps = 8;
- // 该速度用于计算模糊绘制的位移偏移,所以控制为微量
- vVel *= -0.04f / (FLOAT)dwSteps;
- // 颜色插值
- D3DXCOLOR clrDiffuse;
- D3DXColorLerp(&clrDiffuse, &pParticle->m_clrFade, &pParticle->m_clrDiffuse, pParticle->m_fFade);
- DWORD dwDiffuse = (DWORD) clrDiffuse;
- // 产生每个粒子对象的模糊绘制
- for( DWORD i = 0; i < dwSteps; i++ )
- {
- pVertices->v = vPos;
- pVertices->color = dwDiffuse;
- pVertices++;
- // 当填满顶缓区的一整块时,才解锁,然后绘制
- if( ++dwNumParticlesToRender == m_dwFlush )
- {
- m_pVB->Unlock();
- if(FAILED(hr = device->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender)))
- return hr;
- // 进入下一块的填充,此时显卡和CPU可同时工作
- m_dwBase += m_dwFlush;
- // 超过顶缓区的大小,则置零
- if(m_dwBase >= m_dwDiscard)
- m_dwBase = 0;
- // 锁定下一块
- if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
- (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
- {
- return hr;
- }
- // 绘制后计数器清零
- dwNumParticlesToRender = 0;
- }
- // 模糊绘制位移偏移
- vPos += vVel;
- }
- // 下一个粒子
- pParticle = pParticle->m_pNext;
- }
- // 解锁
- m_pVB->Unlock();
- // 绘制剩下不满块的区域
- if( dwNumParticlesToRender )
- {
- if(FAILED(hr = device->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender )))
- return hr;
- }
- // 还原最初的渲染状态
- device->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
- device->SetRenderState( D3DRS_POINTSCALEENABLE, FALSE );
- return S_OK;
- }
- // 画粒子实体
- void CParticleSystem::Render()
- {
- // 更新部分
- Update( 0.05, 10, D3DXCOLOR( 0.0f, 0.0f, 1.0f, 1.0f ) , D3DXCOLOR( 0.0f, 0.0f, 0.5f, 1.0f ),
- 60, D3DXVECTOR3(0,0,0) );
- // 渲染部分
- device->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
- device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
- device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
- device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
- device->SetTexture(0, m_pParticleTexture );
- this->DrawParticles( );
- device->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
- device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
- }
- HRESULT CParticleSystem::Init()
- {
- HRESULT hr;
- if(FAILED(hr = device->CreateVertexBuffer( m_dwDiscard * sizeof(POINTVERTEX),
- D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS,
- D3DFVF_POINTVERTEX, D3DPOOL_DEFAULT, &m_pVB, NULL )))
- {
- return E_FAIL;
- }
- return S_OK;
- }