烟花OpenGL初步实现demo

在NeHe程序框架基础上初步实现了这个烟花的demo。

烟花的弹片生存期由life和fade两个值决定。

烟花的弹片速度由speed和a两个值决定。

生命值和速度值变换在每次循环中加减运算实现,所以有必要添加一个参数来根据每台电脑的运算速度加以调整优化。

实现代码如下。所需BMP图片在这里

//vs2008 & windows7
#include<windows.h>
#include<tchar.h>
#include <gl\gl.h>
#include <gl\glu.h>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")

#define MAX_NUM_PARTICLES 20 //粒子数
#define MAX_NUM_SHELLS 40 //弹片数

HGLRC hRC=NULL; //OpenGL图形操作描述表
HDC hDC=NULL; //设备描述表
HWND hWnd=NULL; //窗口句柄
HINSTANCE hInstance; //应用程序实例

bool keys[256]; //键盘按键参数阵列
bool active=TRUE; //窗口是否活动
bool fullscreen=TRUE; //是否全屏

bool rainbow=false; //彩虹模式,改变颜色
bool sp; //空格键击键标志
bool rp; //回车键击键标志

float slowdown=1.0f; //粒子减速控制
float zoom=-55.0f; //视野变焦

GLuint loop,loop2,color,delay; //循环参数、当前颜色、延迟
GLuint texture[1]; //粒子贴图

float shell_life=5.0f; //弹片高度
float shell_fade=0.05f;
float shell_life1=4.0f; //弹片高度
float shell_fade1=0.05f;
float sxspeed=0.0f; //弹片速度
float szspeed=0.0f;
float syspeed=850.0f;
float shell_yg=-4.8f;

float particle_life=2.0f; //粒子高度
float particle_fade;
float xspeed; //粒子速度
float yspeed;
float zspeed;
float particle_yg=-2.8f;

float par_times=2.0f; //速度倍数
float par_times1=10.0f;

float x,y,z;
float x1,y1,z1;

typedef struct
{
bool active; //状态,生存or湮灭
float life; //粒子生命
float fade; //衰减速度
float r,g,b; //颜色
float x,y,z; //当前位置
float xd,yd,zd; //速度
float xg,yg,zg; //加速度 a=1-p[空气]/p[物质]
}particle; //粒子结构

typedef struct
{
bool active; //状态,生存or湮灭
float life; //粒子生命
float fade; //衰减速度
unsigned int status; //阶段
float x,y,z; //当前位置
float xd,yd,zd; //速度
float xg,yg,zg; //加速度 a=1-p[空气]/p[物质]
particle particles[MAX_NUM_PARTICLES]; //颗粒
}shell; //弹片

shell shells[MAX_NUM_SHELLS]; //弹体

static GLfloat colors[4][3]= // 颜色值
{
{1.0f,1.0f,1.0f},{1.0f,0.0f,0.0f},{1.0f,1.0f,0.0f},{1.0f,0.0f,1.0f}
};
//
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息处理函数
bool NeHeLoadBitmap(LPTSTR szFileName, GLuint *texid); //贴图图像载入
GLvoid ReSizeGLScene(GLsizei width, GLsizei height); //重新绘制窗口
int InitGL(GLvoid); //初始化OpenGL
int DrawGLScene(GLvoid); //画图
GLvoid KillGLWindow(GLvoid) ; //关闭窗口
//
bool NeHeLoadBitmap(LPTSTR szFileName, GLuint *texid) //从一个bmp文件创建贴图
{
HBITMAP hBMP; //bmp文件句柄
BITMAP BMP; // Bitmap数据结构
glGenTextures(1, texid); // 创建贴图
hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );
if (!hBMP)
return FALSE;
GetObject(hBMP, sizeof(BMP), &BMP); //获得目标
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // Pixel Storage Mode (Word Alignment / 4 Bytes)
//创建贴图
glBindTexture(GL_TEXTURE_2D, *texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
DeleteObject(hBMP);
return TRUE;
}//end of NeHeLoadBitmap

GLvoid ReSizeGLScene(GLsizei width, GLsizei height) //重画窗口
{
if (height==0) height=1;
glViewport(0, 0, width, height); //重置当前窗口
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,200.0f); //视图
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}//end of ReSizeGLScene

int InitGL(GLvoid) //初始化gl
{
if (!NeHeLoadBitmap(_T("Data\\Particle.bmp"), &texture[0])) {return FALSE; }//载入贴图
glShadeModel(GL_SMOOTH); // Enables Smooth Shading
glClearColor(0.0f,0.0f,0.0f,0.0f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glDisable(GL_DEPTH_TEST); // Disables Depth Testing
glEnable(GL_BLEND); // Enable Blending
glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Type Of Blending To Perform
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // Really Nice Perspective Calculations
glHint(GL_POINT_SMOOTH_HINT,GL_NICEST); // Really Nice Point Smoothing
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glBindTexture(GL_TEXTURE_2D,texture[0]); // Select Our Texture

for(loop2=0;loop2<MAX_NUM_SHELLS;loop2++)
{
shells[loop2].active=true;
shells[loop2].status=0; //0-上升阶段
shells[loop2].life=shell_life1;
// shells[loop2].fade=float(rand()%100)/1000.0f+0.003f;
shells[loop2].fade=shell_fade1;
shells[loop2].xd=float((rand()%50)-25.0f)*par_times1;
shells[loop2].yd=float((rand()%50)-25.0f)*par_times1;
shells[loop2].zd=float((rand()%50)-25.0f)*par_times1;
shells[loop2].xg=0.0f;
shells[loop2].yg=shell_yg;
shells[loop2].zg=0.0f;
for (loop=0;loop<MAX_NUM_PARTICLES;loop++) // 初始化所有贴图
{
shells[loop2].particles[loop].active=true; // 使所有粒子为活动
shells[loop2].particles[loop].life=particle_life; // 所有粒子生命值
shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; // 随机生命递减速度
shells[loop2].particles[loop].r=colors[color][0]; //颜色
shells[loop2].particles[loop].g=colors[color][1];
shells[loop2].particles[loop].b=colors[color][2];
shells[loop2].particles[loop].xd=float((rand()%50)-25.0f)*par_times; //随机速度
shells[loop2].particles[loop].yd=float((rand()%50)-25.0f)*par_times;
shells[loop2].particles[loop].zd=float((rand()%50)-25.0f)*par_times;
shells[loop2].particles[loop].xg=0.0f; //加速度
shells[loop2].particles[loop].yg=particle_yg;
shells[loop2].particles[loop].zg=0.0f;
}
}
shells[0].life=shell_life;
shells[0].fade=shell_fade;
return TRUE;
}//end of InitGL

int DrawGLScene(GLvoid) //画图
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix

switch(shells[0].status)
{
case 0: //上升阶段
{
if(shells[0].life==shell_life)
{
shells[0].x=0.0f;
shells[0].y=-30.0f;
shells[0].z=zoom;
shells[0].xd=sxspeed; //获得初始速度
shells[0].yd=syspeed;
shells[0].zd=szspeed;
//
for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
{
shells[0].particles[loop].x=shells[0].x;
shells[0].particles[loop].y=shells[0].y;
shells[0].particles[loop].z=shells[0].z;
}
}//if life
shells[0].x+=shells[0].xd/(slowdown*1000); //新位置
shells[0].y+=shells[0].yd/(slowdown*1000);
shells[0].z+=shells[0].zd/(slowdown*1000);
shells[0].xd+=shells[0].xg; //速度增量
shells[0].yd+=shells[0].yg;
shells[0].zd+=shells[0].zg;
shells[0].life-=shells[0].fade; //生命递减
if(shells[0].life<0.0f)
{
shells[0].status=1; //转到下一个阶段
shells[0].active=false;
x1=shells[0].x;
y1=shells[0].y;
z1=shells[0].z;
break;
}

for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
{
if(shells[0].particles[loop].active)
{
shells[0].particles[loop].x+=shells[0].particles[loop].xd/(slowdown*1000); //位置改变
shells[0].particles[loop].y+=shells[0].particles[loop].yd/(slowdown*1000);
shells[0].particles[loop].z+=shells[0].particles[loop].zd/(slowdown*1000);
shells[0].particles[loop].xd+=shells[0].particles[loop].xg; //速度增量
shells[0].particles[loop].yd+=shells[0].particles[loop].yg;
shells[0].particles[loop].zd+=shells[0].particles[loop].zg;
shells[0].particles[loop].life-=shells[0].particles[loop].fade; //生命减少

x=shells[0].particles[loop].x; //获得位置坐标
y=shells[0].particles[loop].y;
z=shells[0].particles[loop].z+zoom;
glColor4f(shells[0].particles[loop].r,shells[0].particles[loop].g,shells[0].particles[loop].b,shells[0].particles[loop].life); //颜色
glBegin(GL_TRIANGLE_STRIP); //两个三角画一个矩形
glTexCoord2d(1,1);glVertex3f(x+0.5f,y+0.5f,z);
glTexCoord2d(0,1);glVertex3f(x-0.5f,y+0.5f,z);
glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);
glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);
glEnd();

if(shells[0].particles[loop].life<0.0f) //湮灭
{
shells[0].particles[loop].life=particle_life; //获得新生
shells[0].particles[loop].fade=float(rand()%100)/100.0f+0.03f; //生命递减速度
shells[0].particles[loop].x=shells[0].x; //新生粒子位置与弹片位置相同
shells[0].particles[loop].y=shells[0].y;
shells[0].particles[loop].z=shells[0].z;
shells[0].particles[loop].xd=xspeed+float((rand()%50)-25.0f)*par_times; //初始速度
shells[0].particles[loop].yd=yspeed+float((rand()%50)-25.0f)*par_times;
shells[0].particles[loop].zd=zspeed+float((rand()%50)-25.0f)*par_times;
shells[0].particles[loop].r=colors[color][0]; //粒子颜色,用参数color改变
shells[0].particles[loop].g=colors[color][1];
shells[0].particles[loop].b=colors[color][2];
}//end of if life

}//end of if active
}//end of for loop
break;
}//end of case 0:
case 1:
{
if(shells[0].active==false)
{
shells[0].active=true;
for(loop2=1;loop2<MAX_NUM_SHELLS;loop2++)
{
shells[loop2].x=x1;
shells[loop2].y=y1;
shells[loop2].z=z1;
}
}//if !
for(loop2=1;loop2<MAX_NUM_SHELLS;loop2++)
{
// if(shells[loop2].life>0.0f)
// {
for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
{
if(shells[loop2].life==shell_life1)
{
shells[loop2].particles[loop].x=shells[loop2].x;
shells[loop2].particles[loop].y=shells[loop2].y;
shells[loop2].particles[loop].z=shells[loop2].z;
}
shells[loop2].particles[loop].x+=shells[loop2].particles[loop].xd/(slowdown*1000); //位置改变
shells[loop2].particles[loop].y+=shells[loop2].particles[loop].yd/(slowdown*1000);
shells[loop2].particles[loop].z+=shells[loop2].particles[loop].zd/(slowdown*1000);
shells[loop2].particles[loop].xd+=shells[loop2].particles[loop].xg; //速度增量
shells[loop2].particles[loop].yd+=shells[loop2].particles[loop].yg;
shells[loop2].particles[loop].zd+=shells[loop2].particles[loop].zg;
shells[loop2].particles[loop].life-=shells[loop2].particles[loop].fade; //生命减少

x=shells[loop2].particles[loop].x; //获得位置坐标
y=shells[loop2].particles[loop].y;
z=shells[loop2].particles[loop].z+zoom;
glColor4f(shells[loop2].particles[loop].r,shells[loop2].particles[loop].g,shells[loop2].particles[loop].b,shells[loop2].particles[loop].life); //颜色
glBegin(GL_TRIANGLE_STRIP); //两个三角画一个矩形
glTexCoord2d(1,1);glVertex3f(x+0.5f,y+0.5f,z);
glTexCoord2d(0,1);glVertex3f(x-0.5f,y+0.5f,z);
glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);
glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);
glEnd();

if(shells[loop2].particles[loop].life<0.0f) //湮灭
{
shells[loop2].particles[loop].life=particle_life; //获得新生
shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; //生命递减速度
shells[loop2].particles[loop].x=shells[loop2].x;
shells[loop2].particles[loop].y=shells[loop2].y;
shells[loop2].particles[loop].z=shells[loop2].z;
shells[loop2].particles[loop].xd=xspeed+float((rand()%50)-25.0f)*par_times; //初始速度
shells[loop2].particles[loop].yd=yspeed+float((rand()%50)-25.0f)*par_times;
shells[loop2].particles[loop].zd=zspeed+float((rand()%50)-25.0f)*par_times;
shells[loop2].particles[loop].r=colors[color][0]; //粒子颜色,用参数color改变
shells[loop2].particles[loop].g=colors[color][1];
shells[loop2].particles[loop].b=colors[color][2];
}
}//for loop
// }//if life
shells[loop2].x+=shells[loop2].xd/(slowdown*1000); //新位置
shells[loop2].y+=shells[loop2].yd/(slowdown*1000);
shells[loop2].z+=shells[loop2].zd/(slowdown*1000);
shells[loop2].xd+=shells[loop2].xg; //速度增量
shells[loop2].yd+=shells[loop2].yg;
shells[loop2].zd+=shells[loop2].zg;
shells[loop2].life-=shells[loop2].fade; //生命递减
if(shells[1].life<0.0f){shells[1].status=1;}
}//for loop2
break;
}//end of case 1:
default:
break;
}//end of switch

if (keys[VK_TAB]||shells[1].status==1) //TAB发射一颗新烟花弹
{
shells[0].life=shell_life;
shells[0].status=0;
for(loop2=0;loop2<MAX_NUM_SHELLS;loop2++)
{
shells[loop2].active=true;
shells[loop2].status=0; //0-上升阶段
shells[loop2].life=shell_life1;
// shells[loop2].fade=float(rand()%100)/1000.0f+0.003f;
shells[loop2].fade=shell_fade1;
shells[loop2].xd=float((rand()%50)-25.0f)*par_times1;
shells[loop2].yd=float((rand()%50)-25.0f)*par_times1;
shells[loop2].zd=float((rand()%50)-25.0f)*par_times1;
shells[loop2].xg=0.0f;
shells[loop2].yg=shell_yg;
shells[loop2].zg=0.0f;
for (loop=0;loop<MAX_NUM_PARTICLES;loop++) // 初始化所有贴图
{
shells[loop2].particles[loop].active=true; // 使所有粒子为活动
shells[loop2].particles[loop].life=particle_life; // 所有粒子生命值
shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; // 随机生命递减速度
shells[loop2].particles[loop].r=colors[color][0]; //颜色
shells[loop2].particles[loop].g=colors[color][1];
shells[loop2].particles[loop].b=colors[color][2];
shells[loop2].particles[loop].xd=float((rand()%50)-25.0f)*par_times; //随机速度
shells[loop2].particles[loop].yd=float((rand()%50)-25.0f)*par_times;
shells[loop2].particles[loop].zd=float((rand()%50)-25.0f)*par_times;
shells[loop2].particles[loop].xg=0.0f; //加速度
shells[loop2].particles[loop].yg=particle_yg;
shells[loop2].particles[loop].zg=0.0f;
}
}
shells[0].life=shell_life;
shells[0].fade=shell_fade;
}//if

return TRUE;
}//end of DrawGLScene

<完>

原文地址:https://www.cnblogs.com/afarmer/p/1611257.html