OpenGL入门教程19:粒子系统

系列教程索引:OpenGL入门教程索引

首先函数基本的架构是:

flow

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

重要的是四个回调函数:

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

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

一般特效里的粒子系统在入门教程里面是说不清楚的,本文只是介绍最简单的粒子效果。

粒子效果一般要处理:

  • 粒子个数,几百上千个就差不多了,像那些海洋特效都是几百亿个粒子。
  • 粒子颜色,没有规定,RGB混合就可以了
  • 运动方向,不同的粒子向不同的方向运动,一定距离后消失

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//设置粒子
for (loop = 0; loop < MAX_PARTICLES; loop++) // Initials All The Textures
{
particle[loop].active = true; // Make All The Particles Active
particle[loop].life = 1.0f; // Give All The Particles Full Life
particle[loop].fade = float(rand() % 100) / 1000.0f + 0.003f; // Random Fade Speed
particle[loop].r = colors[(loop + 1) / (MAX_PARTICLES / 12)][0]; // Select Red Rainbow Color
particle[loop].g = colors[(loop + 1) / (MAX_PARTICLES / 12)][1]; // Select Green Rainbow Color
particle[loop].b = colors[(loop + 1) / (MAX_PARTICLES / 12)][2]; // Select Blue Rainbow Color
particle[loop].xi = float((rand() % 50) - 26.0f) * 10.0f; // Random Speed On X Axis
particle[loop].yi = float((rand() % 50) - 25.0f) * 10.0f; // Random Speed On Y Axis
particle[loop].zi = float((rand() % 50) - 25.0f) * 10.0f; // Random Speed On Z Axis
particle[loop].xg = 0.0f; // Set Horizontal Pull To Zero
particle[loop].yg = -0.8f; // Set Vertical Pull Downward
particle[loop].zg = 0.0f; // Set Pull On Z Axis To Zero
}

使用1000个粒子。

对每一个粒子设置颜色,运动方向(x,y,z)。

绘图部分

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
//OpenGL的主要绘图函数,绘制什么显示什么。
void displayGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清空界面和depth缓冲区
glLoadIdentity();

for (loop = 0; loop < MAX_PARTICLES; loop++) // Loop Through All The Particles
{
if (particle[loop].active) // If The Particle Is Active
{
float x = particle[loop].x; // Grab Our Particle X Position
float y = particle[loop].y; // Grab Our Particle Y Position
float z = particle[loop].z + zoom; // Particle Z Pos + Zoom

// Draw The Particle Using Our RGB Values, Fade The Particle Based On It's Life
glColor4f(particle[loop].r, particle[loop].g, particle[loop].b, particle[loop].life);

glBegin(GL_TRIANGLE_STRIP); // Build Quad From A Triangle Strip
glTexCoord2d(1, 1);
glVertex3f(x + 0.5f, y + 0.5f, z); // Top Right
glTexCoord2d(0, 1);
glVertex3f(x - 0.5f, y + 0.5f, z); // Top Left
glTexCoord2d(1, 0);
glVertex3f(x + 0.5f, y - 0.5f, z); // Bottom Right
glTexCoord2d(0, 0);
glVertex3f(x - 0.5f, y - 0.5f, z); // Bottom Left
glEnd(); // Done Building Triangle Strip

particle[loop].x += particle[loop].xi / (slowdown * 1000); // Move On The X Axis By X Speed
particle[loop].y += particle[loop].yi / (slowdown * 1000); // Move On The Y Axis By Y Speed
particle[loop].z += particle[loop].zi / (slowdown * 1000); // Move On The Z Axis By Z Speed

particle[loop].xi += particle[loop].xg; // Take Pull On X Axis Into Account
particle[loop].yi += particle[loop].yg; // Take Pull On Y Axis Into Account
particle[loop].zi += particle[loop].zg; // Take Pull On Z Axis Into Account
particle[loop].life -= particle[loop].fade; // Reduce Particles Life By 'Fade'

if (particle[loop].life < 0.0f) // If Particle Is Burned Out
{
particle[loop].life = 1.0f; // Give It New Life
particle[loop].fade = float(rand() % 100) / 1000.0f + 0.003f; // Random Fade Value
particle[loop].x = 0.0f; // Center On X Axis
particle[loop].y = 0.0f; // Center On Y Axis
particle[loop].z = 0.0f; // Center On Z Axis
particle[loop].xi = xspeed + float((rand() % 60) - 32.0f); // X Axis Speed And Direction
particle[loop].yi = yspeed + float((rand() % 60) - 30.0f); // Y Axis Speed And Direction
particle[loop].zi = float((rand() % 60) - 30.0f); // Z Axis Speed And Direction
particle[loop].r = colors[col][0]; // Select Red From Color Table
particle[loop].g = colors[col][1]; // Select Green From Color Table
particle[loop].b = colors[col][2]; // Select Blue From Color Table
}
}
}

//双缓冲技术,交换缓冲区以显示刚刚绘制的图像
glutSwapBuffers();
}

捕获键盘

要想捕获键盘输入,就得知道键盘输入是什么。

ascii

想要捕获什么就在keyboard函数中处理什么。

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//如果有按键按下调用此函数
void keyboard(unsigned char key, int x, int y)
{
usleep(100); //稍微延时以免干扰

switch (key)
{
case ESCAPE:
glutDestroyWindow(window); //销毁窗口
exit(0); //正常退出程序
break;
case UP_ARROW: //zoom in
zoom += 0.1f;
if (yspeed < 200){
yspeed += 1.0f;
}
break;
case DOWN_ARROW: //zoom out
zoom -= 0.1f;
if (yspeed > -200){
yspeed -= 1.0f;
}
break;
case LEFT_ARROW: //
if (xspeed > -200){
xspeed -= 1.0f;
}
break;
case RIGHT_ARROW:
if (xspeed < 200){
xspeed += 1.0f;
}
break;
case PLUS:
if (slowdown > 0.0f){
slowdown -= 0.01f;
}
break;
case MINUS:
if (slowdown < 4.0f){
slowdown += 0.01f;
}
break;
case SPACE:
col++;
if (col > 11)
col = 0;
break;
case TAB:
particle[loop].x = 0.0f; // Center On X Axis
particle[loop].y = 0.0f; // Center On Y Axis
particle[loop].z = 0.0f; // Center On Z Axis
particle[loop].xi = float((rand() % 50) - 26.0f) * 10.0f; // Random Speed On X Axis
particle[loop].yi = float((rand() % 50) - 25.0f) * 10.0f; // Random Speed On Y Axis
particle[loop].zi = float((rand() % 50) - 25.0f) * 10.0f; // Random Speed On Z Axis
break;
case N2: //6
if (particle[loop].yg > -1.5f){
particle[loop].yg -= 0.01f;
}
break;
case N4:
if (particle[loop].xg > -1.5f){
particle[loop].xg -= 0.01f;
}
break;
case N6:
if (particle[loop].xg < 1.5f){
particle[loop].xg += 0.01f;
}
break;
case N8:
if (particle[loop].yg < 1.5f){
particle[loop].yg += 0.01f;
}
break;
default:
break;
}
}

默认效果

默认

切换颜色

颜色

移动速度

速度

完整源码在OpenGL下的OpenGLut的8中。


OpenGL入门教程19:粒子系统
https://feater.top/opengl/opengl-particle/
作者
JackeyLea
发布于
2020年11月18日
许可协议