ParticleSystem.cpp
上传用户:henghua
上传日期:2007-11-14
资源大小:7655k
文件大小:12k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. #include "ParticleSystem.h"
  2. // 功能: 构造函数,初始化数据成员
  3. CParticleSystem::CParticleSystem( LPDIRECT3DDEVICE9 dev , cparticleconfig * config )
  4. {
  5. device  = dev;
  6.     m_fRadius        = config->fRadius;
  7.     m_dwBase         = config->dwDiscard;
  8.     m_dwFlush        = config->dwFlush;
  9. m_dwDiscard      = config->dwDiscard;
  10.     m_dwParticles    = 0;
  11.     m_dwParticlesLim = 2048;
  12.     m_pParticles     = NULL;
  13.     m_pParticlesFree = NULL;
  14. m_pVB            = NULL;
  15. HRESULT hr;
  16. hr = D3DXCreateTextureFromFile( device, config->tex_file_name, &(this->m_pParticleTexture));
  17. this->src_pos1 = config->src_pos1;
  18. this->src_pos2 = config->src_pos2;
  19. this->src_dir = config->src_dir;
  20. this->src_vec = config->src_vec;
  21. }
  22. // 功能: 逐粒子释放粒子链和空闲粒子链
  23. CParticleSystem::~CParticleSystem()
  24. {
  25.     while( m_pParticles )
  26.     {
  27.         PARTICLE* pSpark = m_pParticles;
  28.         m_pParticles = pSpark->m_pNext;
  29.         delete pSpark;
  30.     }
  31.     while( m_pParticlesFree )
  32.     {
  33.         PARTICLE *pSpark = m_pParticlesFree;
  34.         m_pParticlesFree = pSpark->m_pNext;
  35.         delete pSpark;
  36.     }
  37. }
  38. //-----------------------------------------------------------------------------
  39. // 功能:更新粒子系统中的各个参量
  40. // 传入参量:每桢的时刻值,新粒子数上限,初始颜色,淡出颜色,初始速度,粒子源位置
  41. //-----------------------------------------------------------------------------
  42. HRESULT CParticleSystem::Update( FLOAT fSecsPerFrame, DWORD dwNumParticlesToEmit,
  43.                                  const D3DXCOLOR &clrEmitColor,
  44.                                  const D3DXCOLOR &clrFadeColor, float fEmitVel,
  45.                                  D3DXVECTOR3 vPosition )
  46. {
  47.     PARTICLE *pParticle, **ppParticle;
  48. // 记录时间,每桢叠加
  49.     static float fTime = 0.0f;
  50.     fTime += fSecsPerFrame;
  51.     ppParticle = &m_pParticles;
  52. // 当链表不为空时,遍历粒子对象链表:更新每个粒子的信息,以及添加飞溅效果
  53.     while( *ppParticle )
  54.     {
  55.         pParticle = *ppParticle;
  56.         // 计算新点的位置
  57.         float fT = fTime - pParticle->m_fTime0; // 与起始时间之差
  58.         float fGravity; // 重力
  59.         if( pParticle->m_bSpark ) // 如果是溅出的火星
  60.         {
  61.             fGravity = -5.0f;
  62.             pParticle->m_fFade -= fSecsPerFrame * 2.25f;
  63.         }
  64.         else // 如果不是溅出的火星
  65.         {
  66.             fGravity = -9.8f;
  67.             pParticle->m_fFade -= fSecsPerFrame * 0.99f;
  68.         }
  69. // 物理学重力模型(计算下一桢的位置和速度)
  70.         pParticle->m_vPos    = pParticle->m_vVel0 * fT + pParticle->m_vPos0; // s1 = v * t + s0
  71.         pParticle->m_vPos.y += (0.5f * fGravity) * (fT * fT); // y1 = y0 + 1/2*g*t^2
  72.         pParticle->m_vVel.y  = pParticle->m_vVel0.y + fGravity * fT; // v1.y = v0.y + g*t
  73.         if( pParticle->m_fFade < 0.0f )
  74.             pParticle->m_fFade = 0.0f;
  75.         // 如果粒子撞击到地面,包括火花撞击到地面(位置小于某个值 或者 粒子处于飞溅状态且淡出系数已为负)
  76.         if( pParticle->m_vPos.y < m_fRadius ||
  77.             pParticle->m_bSpark && pParticle->m_fFade <= 0.0f )
  78.         {
  79.             // 如果不是火花,则产生火花;火花不可以产生火花
  80.             if( !pParticle->m_bSpark )
  81.             {
  82. // 产生四个火花
  83.                 for( int i=0; i<4; i++ )
  84.                 {
  85.                     PARTICLE *pSpark;
  86. // 增加新粒子结点的方式:由空闲链表给 或者 new一个
  87.                     if( m_pParticlesFree )
  88.                     {
  89.                         pSpark = m_pParticlesFree;
  90.                         m_pParticlesFree = pSpark->m_pNext;
  91.                     }
  92.                     else
  93.                     {
  94.                         if( NULL == ( pSpark = new PARTICLE ) )
  95.                             return E_OUTOFMEMORY;
  96.                     }
  97. // 插入新粒子
  98.                     pSpark->m_pNext = pParticle->m_pNext;
  99.                     pParticle->m_pNext = pSpark;
  100. // 为飞溅状态,更新初始位置x,z保留,y为触地面的高度
  101.                     pSpark->m_bSpark  = TRUE; // 火花标示为真
  102.                     pSpark->m_vPos0   = pParticle->m_vPos; // 继承产生它的粒子的位置
  103.                     pSpark->m_vPos0.y = m_fRadius; // 高度设为固定溅射高度
  104. // fRand1=[0,2*pi], fRand2=[0,1/4*pi],产生限定范围的随机数
  105.                     FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.00f;
  106.                     FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
  107. // 撞地后的速度变化--〉作为新的初始速度
  108.                     pSpark->m_vVel0.x  = pParticle->m_vVel.x * 0.25f + cosf(fRand1) * sinf(fRand2);
  109.                     pSpark->m_vVel0.z  = pParticle->m_vVel.z * 0.25f + sinf(fRand1) * sinf(fRand2);
  110.                     pSpark->m_vVel0.y  = cosf(fRand2);
  111.                     pSpark->m_vVel0.y *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * 1.5f;
  112. // 更新当前位置和速度
  113.                     pSpark->m_vPos = pSpark->m_vPos0;
  114.                     pSpark->m_vVel = pSpark->m_vVel0;
  115. // 更新当前颜色值(根据淡出系数插值出最终颜色)
  116.                     D3DXColorLerp( &pSpark->m_clrDiffuse, &pParticle->m_clrFade,
  117.                                    &pParticle->m_clrDiffuse, pParticle->m_fFade );
  118.                     pSpark->m_clrFade = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
  119.                     pSpark->m_fFade   = 1.0f; // 初始m_fFade为1,颜色值为m_clrDiffuse
  120.                     pSpark->m_fTime0  = fTime;
  121.                 }
  122.             }
  123.             // 当前粒子对象接触到地面,“释放”(实际上将待销毁的粒子转给空闲链表,对象池性能优化技术)
  124.             *ppParticle = pParticle->m_pNext;
  125.             pParticle->m_pNext = m_pParticlesFree;
  126.             m_pParticlesFree = pParticle;
  127. // 对象数减一
  128.             if(!pParticle->m_bSpark)
  129.                 m_dwParticles--;
  130.         }
  131.         else
  132.         {
  133.             ppParticle = &pParticle->m_pNext;
  134.         }
  135.     }
  136.     // 产生新粒子
  137.     DWORD dwParticlesEmit = m_dwParticles + dwNumParticlesToEmit;
  138.     while( m_dwParticles < m_dwParticlesLim && m_dwParticles < dwParticlesEmit )
  139.     {
  140. // 对象池性能优化技术
  141.         if( m_pParticlesFree )
  142.         {
  143.             pParticle = m_pParticlesFree;
  144.             m_pParticlesFree = pParticle->m_pNext;
  145.         }
  146.         else
  147.         {
  148.             if( NULL == ( pParticle = new PARTICLE ) )
  149.                 return E_OUTOFMEMORY;
  150.         }
  151. // 插入链表头部
  152.         pParticle->m_pNext = m_pParticles;
  153.         m_pParticles = pParticle;
  154.         m_dwParticles++;
  155.         // 设定新粒子的参量
  156.         FLOAT fRand1 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 2.0f;
  157.         FLOAT fRand2 = ((FLOAT)rand()/(FLOAT)RAND_MAX) * D3DX_PI * 0.25f;
  158. FLOAT fRand3 = ((FLOAT)rand()/(FLOAT)RAND_MAX);
  159.         pParticle->m_bSpark = FALSE;
  160. D3DXVec3Lerp( &(pParticle->m_vPos0), &(this->src_pos1),&(this->src_pos2), fRand3);
  161. pParticle->m_vVel0.x  = cosf(fRand1) * sinf(fRand2) * 0.1  + this->src_dir.x;
  162.         pParticle->m_vVel0.z  = sinf(fRand1) * sinf(fRand2) * 0.1  + this->src_dir.z;
  163.         pParticle->m_vVel0.y  = cosf(fRand2) * 0.1 + this->src_dir.y;
  164. pParticle->m_vVel0 *= ((FLOAT)rand()/(FLOAT)RAND_MAX) * this->src_vec;
  165.         pParticle->m_vPos = pParticle->m_vPos0;
  166.         pParticle->m_vVel = pParticle->m_vVel0;
  167.         pParticle->m_clrDiffuse = clrEmitColor;
  168.         pParticle->m_clrFade    = clrFadeColor;
  169.         pParticle->m_fFade      = 1.0f;
  170.         pParticle->m_fTime0     = fTime;
  171.     }
  172.     return S_OK;
  173. }
  174. //-----------------------------------------------------------------------------
  175. // 功能:渲染
  176. //-----------------------------------------------------------------------------
  177. HRESULT CParticleSystem::DrawParticles(  )
  178. {
  179.     HRESULT hr;
  180.     // 设置渲染状态为点精灵绘制
  181.     device->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );
  182.     device->SetRenderState( D3DRS_POINTSCALEENABLE,  TRUE );
  183.     device->SetRenderState( D3DRS_POINTSIZE,     FtoDW(0.08f) );
  184.     device->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(0.00f) );
  185.     device->SetRenderState( D3DRS_POINTSCALE_A,  FtoDW(0.5f) );
  186.     device->SetRenderState( D3DRS_POINTSCALE_B,  FtoDW(0.1f) );
  187.     device->SetRenderState( D3DRS_POINTSCALE_C,  FtoDW(1.00f) );
  188.     // 设置顶缓流
  189.     device->SetStreamSource( 0, m_pVB, 0, sizeof(POINTVERTEX) );
  190.     device->SetFVF( D3DFVF_POINTVERTEX );
  191.     PARTICLE*    pParticle = m_pParticles;
  192.     POINTVERTEX* pVertices;
  193.     DWORD        dwNumParticlesToRender = 0;
  194. // 采用顶点缓冲区部分锁定分块绘制的方法
  195. m_dwBase += m_dwFlush;
  196. if(m_dwBase >= m_dwDiscard)
  197. m_dwBase = 0;
  198. // 只锁定一个分块,如果m_dwBase为0,则丢弃重心返回一个新区域
  199. if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
  200. (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
  201.     {
  202. return hr;
  203.     }
  204.     // 渲染每一个粒子对象
  205.     while( pParticle )
  206.     {
  207.         D3DXVECTOR3 vPos(pParticle->m_vPos);
  208.         D3DXVECTOR3 vVel(pParticle->m_vVel);
  209. // 计算速度大小
  210.         FLOAT       fLengthSq = D3DXVec3LengthSq(&vVel);
  211.         UINT        dwSteps;
  212. // 根据速度大小决定模糊绘制的次数
  213.         if( fLengthSq < 1.0f )        dwSteps = 2;
  214.         else if( fLengthSq <  4.00f ) dwSteps = 3;
  215.         else if( fLengthSq <  9.00f ) dwSteps = 4;
  216.         else if( fLengthSq < 12.25f ) dwSteps = 5;
  217.         else if( fLengthSq < 16.00f ) dwSteps = 6;
  218.         else if( fLengthSq < 20.25f ) dwSteps = 7;
  219.         else                          dwSteps = 8;
  220. // 该速度用于计算模糊绘制的位移偏移,所以控制为微量
  221.         vVel *= -0.04f / (FLOAT)dwSteps;
  222. // 颜色插值
  223.         D3DXCOLOR clrDiffuse;
  224.         D3DXColorLerp(&clrDiffuse, &pParticle->m_clrFade, &pParticle->m_clrDiffuse, pParticle->m_fFade);
  225.         DWORD dwDiffuse = (DWORD) clrDiffuse;
  226.         // 产生每个粒子对象的模糊绘制
  227.         for( DWORD i = 0; i < dwSteps; i++ )
  228.         {
  229.             pVertices->v     = vPos;
  230.             pVertices->color = dwDiffuse;
  231.             pVertices++;
  232. // 当填满顶缓区的一整块时,才解锁,然后绘制
  233.             if( ++dwNumParticlesToRender == m_dwFlush )
  234.             {
  235.                 m_pVB->Unlock();
  236.                 if(FAILED(hr = device->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender)))
  237. return hr;
  238. // 进入下一块的填充,此时显卡和CPU可同时工作
  239. m_dwBase += m_dwFlush;
  240. // 超过顶缓区的大小,则置零
  241. if(m_dwBase >= m_dwDiscard)
  242. m_dwBase = 0;
  243.  // 锁定下一块
  244. if( FAILED( hr = m_pVB->Lock( m_dwBase * sizeof(POINTVERTEX), m_dwFlush * sizeof(POINTVERTEX),
  245.             (void**) &pVertices, m_dwBase ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD ) ) )
  246.                 {
  247. return hr;
  248.                 }
  249. // 绘制后计数器清零
  250.                 dwNumParticlesToRender = 0;
  251.             }
  252. // 模糊绘制位移偏移
  253.             vPos += vVel;
  254.         }
  255. // 下一个粒子
  256.         pParticle = pParticle->m_pNext;
  257.     }
  258.     // 解锁
  259.     m_pVB->Unlock();
  260.     // 绘制剩下不满块的区域
  261.     if( dwNumParticlesToRender )
  262.     {
  263.         if(FAILED(hr = device->DrawPrimitive( D3DPT_POINTLIST, m_dwBase, dwNumParticlesToRender )))
  264. return hr;
  265.     }
  266.     // 还原最初的渲染状态
  267.     device->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
  268.     device->SetRenderState( D3DRS_POINTSCALEENABLE,  FALSE );
  269.     return S_OK;
  270. }
  271. // 画粒子实体
  272. void CParticleSystem::Render()
  273. {
  274. // 更新部分
  275. Update( 0.05, 10, D3DXCOLOR( 0.0f, 0.0f,  1.0f,   1.0f ) , D3DXCOLOR( 0.0f, 0.0f,   0.5f,   1.0f ), 
  276. 60, D3DXVECTOR3(0,0,0) );
  277. // 渲染部分
  278. device->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  279.     device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  280.     device->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
  281.     device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  282.     device->SetTexture(0, m_pParticleTexture );
  283.     this->DrawParticles( );
  284.     device->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  285.     device->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  286. }
  287. HRESULT CParticleSystem::Init()
  288. {
  289. HRESULT hr;
  290. if(FAILED(hr = device->CreateVertexBuffer( m_dwDiscard * sizeof(POINTVERTEX), 
  291. D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS, 
  292. D3DFVF_POINTVERTEX, D3DPOOL_DEFAULT, &m_pVB, NULL )))
  293. {
  294.         return E_FAIL;
  295. }
  296. return S_OK;
  297. }