| 
 | 
 
引擎的粒子系统我一直在考虑,以前也设计过,但是感觉以前做过的过于复杂,这里我本着让粒子系统的接口尽可能的简单,功能尽可能的强大,我把粒子系统设计成了这样的形式:  
 
typedef void(G_CALL *InitParticleFn)(Particle* p,float time); 
typedef void(G_CALL *UpdateParticleFn)(Particle* p,float time);   
     
//////////////////////////////////////////////////////////// 
/// 定义引擎粒子系统描述符  
//////////////////////////////////////////////////////////// 
struct ParticleSystemDesc 
{ 
    ParticleSystemDesc():texture_id(0), 
                         init_fn(NULL), 
                         update_fn(NULL), 
                         particle_number(2000), 
                         life_span(8.0f), 
                         birth_interval(life_span/(float)particle_number), 
                         batch_particles(1), 
                         particle_size(1.0f)        
    { 
    } 
~ParticleSystemDesc(){} 
     
    int              texture_id;   
    InitParticleFn   init_fn; 
    UpdateParticleFn update_fn;    
    int              particle_number;  
    float            life_span;  
    float            birth_interval; 
    int              batch_particles; 
float            particle_size; 
};   
   
//////////////////////////////////////////////////////////// 
/// 定义引擎粒子系统类 
////////////////////////////////////////////////////////////   
class  ParticleSystem : NonCopyable, public Renderable   
{ 
public: 
    //////////////////////////////////////////////////////// 
    /// 构造引擎粒子系统(传入的描述符必须要有粒子初始化和更新回调函数)  
    ////////////////////////////////////////////////////////      
ParticleSystem(const ParticleSystemDesc &desc):desc(desc){} 
~ParticleSystem(){} 
public:  
    void BeginRender(){} 
    void AfterRender(){}  
 
protected:  
ParticleSystemDesc           desc;  
};  
 
显示贴图如下: 
 
  
 
  
 
  
对应的代码为: 
#include <GEngine/Main.hpp> 
#define WIN_WIDTH  640 
#define WIN_HEIGHT 480 
//! 粒子纹理  
static const unsigned char particle_texture[] =  
{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00, 
    0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00, 
    0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00, 
    0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00, 
    0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00, 
    0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 
}; 
//! 粒子大小  
#define PARTICLE_SIZE   0.7f 
//! 粒子重力加速度  
#define GRAVITY         9.8f 
//! 粒子初始化速度  
#define VELOCITY        8.0f 
//! 粒子喷泉高度  
#define FOUNTAIN_HEIGHT 3.0f 
//! 粒子喷泉半径  
#define FOUNTAIN_RADIUS 1.6f 
//! 粒子纹理大小   
#define P_TEX_WIDTH  8     
#define P_TEX_HEIGHT 8 
//! 粒子弹性碰撞摩擦力系数(1为无摩擦,0为最大摩擦)  
#define FRICTION        0.75f 
#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) 
//////////////////////////////////////////////////////////// 
/// 给出一个初始化粒子的方法  
//////////////////////////////////////////////////////////// 
void G_CALL InitParticle(core: article* p,float t); 
//////////////////////////////////////////////////////////// 
/// 更新粒子函数  
//////////////////////////////////////////////////////////// 
void G_CALL UpdateParticle(core::Particle* p,float time); 
//////////////////////////////////////////////////////////// 
/// 场景旋转和偏移  
////////////////////////////////////////////////////////////  
float TransForm(double t); 
 
//////////////////////////////////////////////////////////// 
/// 构造纹理  
////////////////////////////////////////////////////////////   
void BuildTexture(GLuint& texture_id); 
//////////////////////////////////////////////////////////// 
/// 渲染场景  
////////////////////////////////////////////////////////////  
void RenderScene();  
core: evice* device = NULL;  
libmath::TriTable* table = NULL;   
 
int main(int argc, char **argv) 
{ 
    int        i; 
    double     t0, t; 
     
    core::VideoMode mode; 
    mode.width = WIN_WIDTH; 
mode.height = WIN_HEIGHT;  
     
    device = core::InitDevice("盖莫引擎粒子系统",false,mode);  
    table = device->GetTriTable(); 
 
    core::ParticleSystemDesc desc; 
     
    GLuint texture_id; 
    BuildTexture(texture_id); 
    desc.texture_id = texture_id;     
    desc.init_fn = &InitParticle; 
    desc.update_fn = &UpdateParticle; 
    desc.batch_particles = 80; 
    desc.particle_size = 0.6f; 
    desc.life_span = 8; 
     
    core::ParticleSystem* ps = device->GetParticleSystem(desc);  
 
    t0 = device->GetTime(); 
    BEGIN_LOOP(device) 
        t = device->GetTime() - t0; 
        RenderScene(); 
        float dt = TransForm(t); 
        ps->Render();  
    END_LOOP(device) 
     
    device->Close(); 
    device->Drop(); 
 
    return 0; 
} 
 
void BuildTexture(GLuint& texture_id) 
{ 
    glGenTextures( 1, &texture_id ); 
    glBindTexture( GL_TEXTURE_2D, texture_id); 
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT, 
                 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture);   
} 
//////////////////////////////////////////////////////////// 
/// 场景旋转和偏移  
////////////////////////////////////////////////////////////  
float TransForm(double t) 
{ 
    double xpos, ypos, zpos, angle_x, angle_y, angle_z; 
    static double t_old = 0.0; 
    float  dt = (float)(t-t_old); 
    t_old = t; 
 
    angle_x = 90.0 - 10.0; 
    angle_y = 10.0 * sin( 0.3 * t ); 
    angle_z = 10.0 * t; 
    glRotated( -angle_x, 1.0, 0.0, 0.0 ); 
    glRotated( -angle_y, 0.0, 1.0, 0.0 ); 
    glRotated( -angle_z, 0.0, 0.0, 1.0 ); 
 
    xpos =  15.0 * sin( (M_PI/180.0) * angle_z ) + 
             2.0 * sin( (M_PI/180.0) * 3.1 * t ); 
    ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) + 
             2.0 * cos( (M_PI/180.0) * 2.9 * t ); 
    zpos = 4.0 + 2.0 * cos( (M_PI/180.0) * 4.9 * t ); 
    glTranslated( -xpos, -ypos, -zpos ); 
    return dt;  
} 
void RenderScene() 
{ 
    glViewport( 0, 0, WIN_WIDTH,WIN_HEIGHT); 
    glClearColor( 0.1f, 0.1f, 0.1f, 1.0f ); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
    glMatrixMode( GL_PROJECTION ); 
    glLoadIdentity(); 
    gluPerspective(65.0, 640.0/480.0, 1.0, 60.0 ); 
    glMatrixMode( GL_MODELVIEW ); 
    glLoadIdentity(); 
} 
//////////////////////////////////////////////////////////// 
/// 给出一个初始化粒子的方法(t为粒子系统启动时间(单位:秒))  
//////////////////////////////////////////////////////////// 
void G_CALL InitParticle(core::Particle* p,float t) 
{ 
    //! 初始化粒子位置 
    p->position = Vector3f(0,0,FOUNTAIN_HEIGHT);  
 
    //! 设定粒子初始z轴速度  
    p->velocity.z = 0.7f + (0.3/4096.0) * (float) (rand() & 4095); 
    //! 获取随机xy平面旋转角度  
    float xy_angle = (2.0*M_PI/4096.0) * (float) (rand() & 4095); 
    p->velocity.x = 0.45f * table->CosTable(xy_angle);  
    p->velocity.y = 0.45f * table->SinTable(xy_angle);  
    //! 根据时间调整粒子初始速度  
    float velocity = VELOCITY*(0.8f + 0.1f*(float)(table->SinTable(0.5*t)+table->SinTable(0.31*t))); 
    p->velocity.x *= velocity; 
    p->velocity.y *= velocity; 
    p->velocity.z *= velocity; 
    //! 设定粒子初始颜色  
    p->color.red   = 0.7f + 0.3f * table->SinTable(0.34*t + 0.1);  
    p->color.green = 0.6f + 0.4f * table->SinTable(0.63*t + 1.1);  
    p->color.blue  = 0.6f + 0.4f * table->SinTable(0.91*t + 2.1);  
} 
//////////////////////////////////////////////////////////// 
/// 更新粒子函数  
//////////////////////////////////////////////////////////// 
void G_CALL UpdateParticle(core::Particle* p,float time) 
{ 
    float dt = time;  
    //! 修正粒子生命  
    p->life = p->life - dt * (1.0f / 8.0f); 
    //! 修正粒子速度  
    p->velocity.z = p->velocity.z - GRAVITY  *dt; 
    p->position  += p->velocity * dt; 
 
    //! 处理简单的碰撞  
    if( p->velocity.z < 0.0f ) 
    { 
        if((p->position.x*p->position.x + p->position.y*p->position.y) < FOUNTAIN_R2 && 
            p->position.z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) ) 
        { 
            p->velocity.z = -FRICTION * p->velocity.z; 
            p->position.z  = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 + 
                        FRICTION * (FOUNTAIN_HEIGHT + 
                        PARTICLE_SIZE/2 - p->position.z); 
        } 
        //! 当粒子碰撞到地面应该跳起来  
        else if( p->position.z < PARTICLE_SIZE/2 ) 
        { 
            p->velocity.z = -FRICTION * p->velocity.z; 
            p->position.z  = PARTICLE_SIZE/2 + FRICTION * (PARTICLE_SIZE/2 - p->position.z); 
        } 
    } 
}  
 
 |   
 
 
 
 |