粒子系统的管理

      之前第一次学习的时候写过两次粒子系统,但都是只能用于特定的粒子效果,类的扩展性较差。刚刚又把粒子系统重新规划了一下。

      首先,粒子要有诸多属性,我们用一个结构体表示;然后在粒子系统类中创建一个粒子容器;最后通过对容器的访问实现粒子属性的更新和渲染以及销毁。写完这个基类,以后只需从该基类派生,然后实现一下基类中的纯虚函数InitParticle(Particle& _out)即可。

//粒子结构体

struct Particle
{
 D3DXVECTOR3 initPos;  //初始位置
 D3DXVECTOR3 initVel;   //初始速度
 float      initSize;            //初始尺寸
 float      initTime;           //初始时间
 float      lifeTime;           //粒子寿命
 float      mass;                //粒子质量
 D3DXCOLOR    initColor;  //初始颜色
 
 static IDirect3DVertexDeclaration9*    Decl;
};

//粒子系统类

class ParticleSystem
{
public:
 ParticleSystem(LPDIRECT3DDEVICE9  _pd3dDevice,const char* _fxName, const char* _techName, const char* _textureName,
       const D3DXVECTOR3& _acceleration,
       const AABB& _box,
       int _maxParticlesNum,
       float _timePerParticle);
 virtual ~ParticleSystem();
 
 void AddParticle();
 void SetPosition(const D3DXVECTOR3& _pos);
 void SetBox(const AABB& _box);
 void SetBoxVisiable(bool _visiable){m_BoundingBoxVisiable = _visiable;}
 int GetAliveNum(){return m_AliveParticles.size();}
 D3DXVECTOR3 GetBoxMin(){return m_BoxMin;}
 D3DXVECTOR3 GetBoxMax(){return m_BoxMax;}

 virtual void InitParticle( Particle& _out)=0;
 virtual void Update(float _deltaTime);
 virtual void Render();
 virtual void Lost();
 virtual void Reset();
 virtual void Destroy();
protected:
 virtual void RenderBoundingBox(const AABB& _box);

 LPDIRECT3DDEVICE9  m_pd3dDevice;
 ID3DXEffect* m_Effect;                                            //效果指针
 LPDIRECT3DTEXTURE9 m_Texture;                          //粒子纹理
 LPDIRECT3DVERTEXBUFFER9 m_VertexBuffer;         //顶点缓存
 LPDIRECT3DVERTEXBUFFER9  m_BoxVertexBuffer;  //包围盒顶点缓冲
 D3DXMATRIX m_World;                //世界矩阵
 D3DXMATRIX m_InvWorld;           //世界逆矩阵
 float    m_Time;                            //相对于第一个粒子出生的本地时间
 D3DXVECTOR3 m_Acceleration;   //粒子加速度
 AABB    m_Box;                            //整个粒子系统的包围盒
 int     m_MaxParticlesNum;           // 本粒子系统最大的粒子数
 float    m_TimePerParticle;            //每两个粒子出生的最小间隔时间
 vector<Particle> m_Particles;       //存放粒子对象实例的容器
 vector<Particle*> m_AliveParticles;  //存放有生命的粒子对象地址的容器
 vector<Particle*> m_DeadParticles;  //存放已死亡的粒子对象地址的容器

};

     一个粒子有两个状态:存活态,死亡态。 有人会想,当粒子死亡时就把这个particle从容器中pop弹出,粒子要重生时只需再声明一个变量然后push压入容器中即可。这样一来当有大量的粒子不断重生和死亡时,可向而知,内存会发生怎样的高频变化,其实这是完全没有必要的。

    换一种思路,一开始将粒子容器预留出最大限量的空间,此时列表中已经充满了粒子,每次刷新的时候我们遍历这个容器,通过粒子的年龄来判断是否死亡,如果死亡,则把该粒子的指针push到另外一个名叫 deadparticle 的容器中;如果粒子仍然处于存活态,则把其指针push到一个名叫 aliveparticle的容器中。  再看上面类的最后三个成员变量就是又来管理 两种不同态 的粒子的。

   注意AliveParticles和DeadParticles存放的是粒子指针,这样效率高。

 

 

   另一个需要优化的地方就是,在动态变化大量粒子的尺寸时,我们往往是根据粒子到眼睛的距离来变化的。这时我们就需要眼睛的位置和粒子的位置在同一个坐标空间中。当然是只需把眼睛位置转换到粒子的本地空间中最好。

   在一个需要优化的地方便是要对粒子系统进行视锥体剪裁。也许大量的雪花剪裁没有意义,因为雪花总是在摄像机的前方被渲染。如果是一堆火,好几堆火酒十分有必要进行剪裁。办法当然最简单的就是加 包围盒。然后来一个包围盒与视锥体的 相交检测。这个检测的代码我看了一些相关的图形知识才看懂了,现贴上来供大家参考:

//6代表了视锥体的六个面,4代表了每个面的四个信息,见下面注释

float m_Frustum[6][4];

enum PlaneData
{
 A = 0,    // The X value of the plane's normal
 B = 1,    // The Y value of the plane's normal
 C = 2,    // The Z value of the plane's normal
 D = 3    // The distance the plane is from the origin
};

//xyz为包围盒的最小点,x2y2z2为最大点

bool Frustum::BoxInFrustum( float x, float y, float z, float x2, float y2, float z2)
{
 // Go through all of the corners of the box and check then again each plane
 // in the frustum.  If all of them are behind one of the planes, then it most
 // like is not in the frustum.
 for(int i = 0; i < 6; i++ )
 {
  if(m_Frustum[i][A] * x  + m_Frustum[i][B] * y  + m_Frustum[i][C] * z  + m_Frustum[i][D] > 0)  continue;
  if(m_Frustum[i][A] * x2 + m_Frustum[i][B] * y  + m_Frustum[i][C] * z  + m_Frustum[i][D] > 0)  continue;
  if(m_Frustum[i][A] * x  + m_Frustum[i][B] * y2 + m_Frustum[i][C] * z  + m_Frustum[i][D] > 0)  continue;
  if(m_Frustum[i][A] * x2 + m_Frustum[i][B] * y2 + m_Frustum[i][C] * z  + m_Frustum[i][D] > 0)  continue;
  if(m_Frustum[i][A] * x  + m_Frustum[i][B] * y  + m_Frustum[i][C] * z2 + m_Frustum[i][D] > 0)  continue;
  if(m_Frustum[i][A] * x2 + m_Frustum[i][B] * y  + m_Frustum[i][C] * z2 + m_Frustum[i][D] > 0)  continue;
  if(m_Frustum[i][A] * x  + m_Frustum[i][B] * y2 + m_Frustum[i][C] * z2 + m_Frustum[i][D] > 0)  continue;
  if(m_Frustum[i][A] * x2 + m_Frustum[i][B] * y2 + m_Frustum[i][C] * z2 + m_Frustum[i][D] > 0)  continue;
  // If we get here, it isn't in the frustum
  return false;
 }

 // Return a true for the box being inside of the frustum
 return true;
}

最后贴上今天下午写的一个类似传送点的粒子系统(最大粒子数2500):

粒子系统的管理_第1张图片

 粒子系统的管理_第2张图片

你可能感兴趣的:(c,优化,struct,Class,float,distance)