OpenGLut开发入门系列教程11:烟火晚会

系列教程索引:OpenGLut开发入门系列教程索引

上一篇:OpenGLut开发入门系列教程10:混合

本文介绍纹理在三维空间中移动,做出类似与烟花的效果。

opengl三维世界坐标系为:

3d

  • OpenGL坐标系(物体、世界、照相机坐标系)属于右手坐标系
  • 设备坐标系使用的是左手坐标系

我们之前开发的代码中一般z轴部分为负值,也就是说,我们看的视角是从z轴的+方向看向-方法。迷雾按照我们看的方向投射在我们绘制的物体上。

首先函数基本的架构是:

flow

在main函数中glut*Func()的参数为回调函数,需要在main函数外独立实现。

重要的是四个回调函数:

  • initGL,初始化函数
  • reshapeGL,尺寸调整函数,当窗口的尺寸发生变化时调用此函数重新绘图
  • keyboard,捕获键盘输入并处理
  • displayGL,将想要显示的图像绘制出来的函数

其他函数说明见OpenGL函数功能说明系列

加载纹理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
//加载纹理
void loadGLTexture(){
int w,h,c;//图片的宽度高度和通道数

unsigned char *data=stbi_load("crate.bmp",&w,&h,&c,0);

//创建纹理
glGenTextures(3,&texture[0]);

//纹理1-低质量缩放
glBindTexture(GL_TEXTURE_2D,texture[0]);//绑定纹理

//纹理过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);

//二位纹理,细节等级,RGB3组件,宽,高,边框,rgb数据,无符号整数,数据
if(c==3){
glTexImage2D(GL_TEXTURE_2D, 0, 3,w,h,0,GL_RGB,GL_UNSIGNED_BYTE,data);
}else if(c==4){
glTexImage2D(GL_TEXTURE_2D, 0, 3,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,data);
}

//纹理2-线性缩放
glBindTexture(GL_TEXTURE_2D,texture[1]);//绑定纹理

//纹理过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

//二位纹理,细节等级,RGB3组件,宽,高,边框,rgb数据,无符号整数,数据
if(c==3){
glTexImage2D(GL_TEXTURE_2D, 0, 3,w,h,0,GL_RGB,GL_UNSIGNED_BYTE,data);
}else if(c==4){
glTexImage2D(GL_TEXTURE_2D, 0, 3,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,data);
}

//纹理3-映射缩放
glBindTexture(GL_TEXTURE_2D,texture[2]);//绑定纹理

//纹理过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);

//二位纹理,细节等级,RGB3组件,宽,高,边框,rgb数据,无符号整数,数据
if(c==3){
glTexImage2D(GL_TEXTURE_2D, 0, 3,w,h,0,GL_RGB,GL_UNSIGNED_BYTE,data);
}else if(c==4){
glTexImage2D(GL_TEXTURE_2D, 0, 3,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,data);
}

//二位纹理,RGB3颜色,宽,高,Rgb边框值,rgb数据,无符号整数,数据
if(c==3){
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,w,h,GL_RGB,GL_UNSIGNED_BYTE,data);
}else if(c==4){
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,w,h,GL_RGBA,GL_UNSIGNED_BYTE,data);
}
}

和上一篇的一样,就是在上一篇的基础上改的。

流程上还是获取数据、创建纹理、绑定纹理、生成纹理。

烟花初始化

在前面的文章中提到彩色三角形四边形的写法。

1
2
3
4
5
6
glBegin(GL_TRIANGLES);//图像绘制部分
glColor3f(0.5f,0.5f,0.5f);
glVertex3f(0.0f,1.0f,0.0f);//点A(x,y,z)
glVertex3f(-1.0f,-1.0f,0.0f);//点B
glVertex3f(1.0f,-1.0f,0.0f);//点C
glEnd();

先绘制三角形,默认绘制的三角形为白色,在绘制前设置颜色,这样就会显示彩色的三角形。

本文的用法类似,绘制白色的烟花纹理,在绘制之前设置颜色。

显示的烟花粒子数据结构为:

1
2
3
4
5
6
typedef struct
{
int r, g, b; //粒子颜色
GLfloat dist; //粒子距中心距离
GLfloat angle; //粒子当前角度
} stars;

RGB就是颜色,dist表示纹理距离窗口中央的距离,距离越来越远知道从窗口消失。angle是纹理的旋转角度,实现动态效果。

1
2
3
//设置混合
glBlendFunc(GL_SRC_ALPHA,GL_ONE);//设置混合功能
glEnable(GL_BLEND);

设置粒子的初始值

1
2
3
4
5
6
7
8
9
10
//设置粒子
for (loop = 0; loop < STAR_NUM; loop++)
{
star[loop].angle = 0.0f; //初始时没有旋转

star[loop].dist = loop * 1.0f / STAR_NUM * 5.0f; //计算到中心的距离
star[loop].r = rand() % 256;
star[loop].g = rand() % 256;
star[loop].b = rand() % 256;
}

总计50个粒子,第二个粒子距离为0.004,第50个粒子的距离为0.196

绘制图像

绘制基本的粒子,并图上颜色。

1
2
3
4
5
6
7
8
9
10
11
12
// Assign A Color Using Bytes
glColor4ub(star[loop].r, star[loop].g, star[loop].b, 255);
glBegin(GL_QUADS); // Begin Drawing The Textured Quad
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 0.0f);
glEnd(); // Done Drawing The Textured Quad

还有实现动画效果

1
glRotatef(spin, 0.0f, 0.0f, 1.0f); // rotate the star on the z axis.

然后更新粒子的颜色、位置

1
2
3
4
5
6
7
8
9
10
11
spin += 0.01f;                                     // used to spin the stars.
star[loop].angle += loop * 1.0f / STAR_NUM * 1.0f; // change star angle.
star[loop].dist -= 0.01f; // bring back to center.

if (star[loop].dist < 0.0f)
{ // star hit the center
star[loop].dist += 5.0f; // move 5 units from the center.
star[loop].r = rand() % 256; // new red color.
star[loop].g = rand() % 256; // new green color.
star[loop].b = rand() % 256; // new blue color.
}

效果

未加载纹理效果

no texture

加载纹理后

texture

去掉颜色后

texture

开启闪烁后

texture

完整源码在OpenGL_Freshman下的OpenGLut的11中。

下一篇:OpenGLut开发入门系列教程12:雾化特效