|
引擎的粒子系统我一直在考虑,以前也设计过,但是感觉以前做过的过于复杂,这里我本着让粒子系统的接口尽可能的简单,功能尽可能的强大,我把粒子系统设计成了这样的形式:
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);
}
}
}
|
|