游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2097|回复: 0

盖莫引擎的粒子系统设计

[复制链接]

50

主题

69

帖子

69

积分

注册会员

Rank: 2

积分
69
发表于 2010-2-24 15:12:00 | 显示全部楼层 |阅读模式
引擎的粒子系统我一直在考虑,以前也设计过,但是感觉以前做过的过于复杂,这里我本着让粒子系统的接口尽可能的简单,功能尽可能的强大,我把粒子系统设计成了这样的形式:

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);
        }
    }
}

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2024-5-12 14:01

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表