OpenGL之粒子爆炸特效

OpenGL之粒子爆炸特效

遊戲中最常見『爆炸』特效.最常見做法是使用粒子系統模擬『爆炸』.你大約需要:

  1. 黑底白圓位圖『bmp』如上圖
  2. 爆炸特效音頻『wav』
  3. 粒子系統
  4. 廣告牌

其實所有『爆炸』特效都是圓心紋理位圖.只是它使用『廣告牌』技術讓其正對著你即『相機』. 渲染為紅色並讓其隨時間『下墜』『變暗』『縮小』直至消亡.之前模擬『飄雪』特效時使用三級系統.這次我將粒子結構大大簡化.其代碼我都在模擬『爆炸』特效中實現.W

粒子結構體

typedef struct PARTICLE_TYP {

VECTOR3D pos;// 位置

VECTOR3D pos_prev;// 之前位置

VECTOR3D velocity;// 速度與方向

VECTOR3D acceleration;// 加速度

float    energy;// 生命週期(秒)

float size;// 尺寸

float size_delta;//增量

float weight;// 重量

float wdight_delta;// 重量增量

float color[4];// 顏色

float color_delta[4];// 顏色增量

}PARTICLE,*PARTICLE_PTR;

爆炸特效結構體

typedef struct EXPLOSION_TPY {

int          state;//  狀態

PARTICLE_PTR array;// 數組

int          count;// 粒子數量/爆炸量

VECTOR3D     origin;// 原點

VECTOR3D     velocity;// 速度與方向

VECTOR3D     variation;// 速度變量

VECTOR3D     acceleration;// 加速度

float        energy;// 生命週期(秒)

float        size;// 尺寸 5.0f

float        size_variation ;// 尺寸變量 2.0f

float        spread;// 爆炸傳播範圍

float        color[4];// 顏色

VECTOR2D     texture_coord[4];// 紋理座標

}EXPLOSION,*EXPLOSION_PTR;

生成『爆炸』特效函式

count:爆炸量大約1-10即可.

pos:位置

spread: 爆炸傳播範圍 0.1即可

void Build_Explosion(EXPLOSION_PTR explosion,int count,VECTOR3D_PTR pos,float spread){

explosion->state = MODEL3D_STATE_ACTIVE;

explosion->count = count; // 粒子數量

explosion->array = (PARTICLE_PTR)malloc(sizeof(PARTICLE)*count);// 分配空間

explosion->spread = spread;// 傳播

explosion->size           = 5.0f;// 尺寸

explosion->size_variation = 2.0f;// 尺寸變量

explosion->energy = 1.5f + FRAND_RANGE1() / 2.0f;// 生命週期(秒)

Init_VECTOR3D(&explosion->origin, pos->x, pos->y, pos->z);// 源點

Init_VECTOR3D(&explosion->velocity, 0.0f, 2.0f, 0.0f);// 速度

Init_VECTOR3D(&explosion->variation, 4.0f, 4.0f, 4.0f);// 變量

Init_VECTOR3D(&explosion->acceleration, 0.0f, -5.0f, 0.0f);// 加速度

PARTICLE_PTR particle;// 粒子

for (int i = 0; i < count; ++i){

particle = &explosion->array[i];// 粒子

Buid_Explosion(explosion, particle);//生成粒子『爆炸』特效

}

Set_Pos_DirectSound(&explosion_sound3D, pos->x, pos->y, pos->z);// 設置音源位置

Play_DirectSound(&explosion_sound3D, false);//播放音頻數據

}

生成爆炸粒子函式

void Buid_Explosion(EXPLOSION_PTR explosion, PARTICLE_PTR  particle){

// 在發射區隨機位置生成粒子

particle->pos.x = explosion->origin.x + FRAND_RANGE1() * explosion->spread;// 傳播

particle->pos.y = explosion->origin.y + FRAND_RANGE1() * explosion->spread;

particle->pos.z = explosion->origin.z + FRAND_RANGE1() * explosion->spread;

//給粒子隨機速度

particle->velocity.x += FRAND_RANGE1() * explosion->velocity.x;

particle->velocity.y += FRAND_RANGE1() * explosion->velocity.y;

particle->velocity.z += FRAND_RANGE1() * explosion->velocity.z;

// 加速度

particle->acceleration = explosion->acceleration;

// 生命週期

particle->energy = 1.5f + FRAND_RANGE1() / 2.0f;

// 顏色

particle->color[0] = 1.0f;

particle->color[1] = 0.5f + FRAND_RANGE1() * 0.5f;

particle->color[2] = 0.0f;

particle->color[3] = 1.0f;

// 顏色增量

particle->color_delta[0] = 0.0f;

particle->color_delta[1] = -(particle->color[1] / 2.0f) / particle->energy;

particle->color_delta[2] = 0.0f;

particle->color_delta[3] = -1.0f / particle->energy;

// 設置粒子的大小

particle->size = explosion->size + FRAND_RANGE1() * explosion->size_variation;

particle->size_delta = -particle->size / particle->energy;

}

釋放『爆炸』特效函式

void Free_Explosion(EXPLOSION_PTR explosion){

if (explosion->array != NULL)

free(explosion->array);

explosion->state = MODEL3D_STATE_NULL;

memset(explosion, 0, sizeof(EXPLOSION));// 清空

}

更新『爆炸』特效函式

deltaTime:時間間隔

void Update_Explosion(EXPLOSION_PTR explosion, float deltaTime){

PARTICLE_PTR particle;// 粒子

for (int i = 0; i < explosion->count; ){

particle = &explosion->array[i];// 粒子

// 基於時間和速度更新粒子的位置

particle->pos = particle->pos + particle->velocity * deltaTime;

particle->velocity = particle->velocity + particle->acceleration * deltaTime;

particle->energy = particle->energy – deltaTime;

particle->size += particle->size_delta * deltaTime;

particle->color[3] += particle->color_delta[3] * deltaTime;

particle->color[1] += particle->color_delta[1] * deltaTime;

// 將最後一個粒子移動到當前位置,並減少計數.

if (particle->energy <= 0.0)

explosion->array[i] = explosion->array[–explosion->count];

else

++i;

}

if (explosion->count == 0)

Free_Explosion(explosion); // 釋放

}

渲染『爆炸』特效紋理函式

void Render_Explosion2(EXPLOSION_PTR explosion, BILLBOARD_PTR billboard){

float viewMatrix[16];

VECTOR3D right, up, pos;

GLfloat size;

right = billboard->right;

up = billboard->up;

// 壓入當前屬性

glPushAttrib(GL_ALL_ATTRIB_BITS);

glDisable(GL_DEPTH_TEST);

glEnable(GL_BLEND);

glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);

glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D, explosion_texture.ID);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

glBegin(GL_QUADS);

for (int i = 0; i < explosion->count; ++i){

PARTICLE_PTR particle = &explosion->array[i];// 粒子

size = particle->size / 2;

pos = particle->pos;

glColor4fv(particle->color);

glTexCoord2f(0.0, 0.0); glVertex3fv((pos + (right + up) * -size).M);

glTexCoord2f(1.0, 0.0); glVertex3fv((pos + (right – up) * size).M);

glTexCoord2f(1.0, 1.0); glVertex3fv((pos + (right + up) * size).M);

glTexCoord2f(0.0, 1.0); glVertex3fv((pos + (up – right) * size).M);

}

glEnd();

glDisable(GL_TEXTURE_2D);

glDisable(GL_BLEND);

glEnable(GL_DEPTH_TEST);

glPopAttrib();// 彈出當前屬性

}

評論