动画内容
本动画模拟烟花的燃放过程。烟花燃放从地面升起,升到空中爆炸并产生无数小烟花围成圆形并落下,下落过程中伴随这能量的衰减直到消失。此动画的视角为仰视大致为30°。
名词解释
VC++6.0:一种开发环境;
OpenGL:是个专业的开放的3D程序接口,是一个功能强大,调用方便的底层3D图形库;
glut :OpenGL Utility Toolkit;
粒子系统:是许多粒子的集合。在图像学领域里,人们利用粒子系统模拟各种各样的现象,如火花、飞行的鸟群、波浪等。在这些应用中,粒子系统的动力学规律确定了粒子的位置,在每个位置上,我们放置了一个图形对象,而不是一个点。
[1]
运行环境
硬件要求
|
奔腾4 2.0GHZ以上,显卡X550(128bit位宽,128MB显存)以上。 |
软件要求
|
Windows2K/XP操作系统、VC++6.0 、并支持OpenGL glut工具包。 |
详细设计
粒子的数据结构定义
typedef struct
{
float x,y,z; // 粒子位置
float xSpeed, ySpeed, zSpeed; // 粒子的速度
float xg, yg, zg;// 粒子的运动加速度
float r,g,b; // 粒子的颜色
int style; // 粒子是上升还是下降
}PARTICLES;
烟花的数据结构定义
#define MAX_PARTICLES 24 //小烟花的个数
#define MAX_TAIL 30 //烟花尾部长度
#define MAX_FIRE 5 //烟花的个数
struct
{
PARTICLES particle[MAX_PARTICLES][MAX_TAIL]; //烟花系统数组
GLfloat life, fade, rad; //烟花的生命,衰减速度、和x-z平面上的运动速度
} Fire[MAX_FIRE];
烟花燃放过程建模及实现
烟花从地面的某一点生成并向上(y轴方向)作减速运动,在x,z轴方向速度为0。当y方向速度为0时烟花爆炸生成小烟花。此时给烟花的x-z平面上的速度rad赋初值,并将其分解到x,z方向上(与坐标轴的夹角根据下标确定),y轴的加速度不变至此小烟花运动轨迹为抛物线。爆炸后位置坐标变化的数学模型为:
X = rad*cos(a);
Y = yspeed + gt;
Z = rad*sin(a);
下面是烟花系统赋初始值(init()函数主要源代码)
for(loop2=0; loop2
{
//初始位置
xtemp = rand()%30 -15;
ytemp = (-1)*rand()%5-8;
ztemp = (-1)*rand()%5 -100;
speed = rand()%5+10; //x-z平面上的运动速度
Fire[loop2].life = 1.0f;
Fire[loop2].fade = (float)(rand()%100)/20000+0.002f;
Fire[loop2].rad = rand()%3+4;
for (loop=0; loop
{
Fire[loop2].particle[loop][0].style = 0;
//初始位置
Fire[loop2].particle[loop][0].x = xtemp;
Fire[loop2].particle[loop][0].y = ytemp;
Fire[loop2].particle[loop][0].z = ztemp;
//初始速度
Fire[loop2].particle[loop][0].xSpeed =0.0f;
Fire[loop2].particle[loop][0].ySpeed =speed;
Fire[loop2].particle[loop][0].zSpeed =0.0f;
//初始加速度
Fire[loop2].particle[loop][0].xg =0.0f;
Fire[loop2].particle[loop][0].yg =-2.0f;
Fire[loop2].particle[loop][0].zg =0.0f;
//初始颜色
Fire[loop2].particle[loop][0].r =1.0f;
Fire[loop2].particle[loop][0].g =1.0f;
Fire[loop2].particle[loop][0].b =1.0f;
//尾部初始化
for(loop1=1;loop1
{
Fire[loop2].particle[loop][loop1].x=Fire[loop2].particle[loop][0].x;
Fire[loop2].particle[loop][loop1].y=Fire[loop2].particle[loop][0].y;
Fire[loop2].particle[loop][loop1].z=Fire[loop2].particle[loop][0].z;
} //for1 end
}//for2 end
}// for3 end
粒子的运动位置变化(idle()函数主要源代码)
for(loop=0;loop
{
// 粒子位置更新
Fire[loop2].particle[loop][0].x += Fire[loop2].particle[loop][0].xSpeed/(speedFator*1000.0f);
Fire[loop2].particle[loop][0].y += Fire[loop2].particle[loop][0].ySpeed/(speedFator*1000.0f);
Fire[loop2].particle[loop][0].z += Fire[loop2].particle[loop][0].zSpeed/(speedFator*1000.0f);
// 粒子速度更新
Fire[loop2].particle[loop][0].ySpeed +=Fire[loop2].particle[loop][0].yg/(speedFator*1000.0f);
if(Fire[loop2].particle[loop][0].style==0 && Fire[loop2].particle[loop][0].ySpeed <2.0)
{
Fire[loop2].particle[loop][0].style = 1;
Fire[loop2].particle[loop][0].r = colors[color][0];
Fire[loop2].particle[loop][0].g = colors[color][1];
Fire[loop2].particle[loop][0].b = colors[color][2];
//速度分解
Fire[loop2].particle[loop][0].xSpeed = Fire[loop2].rad*sin(loop*15.0/(2*3.14159));
Fire[loop2].particle[loop][0].zSpeed = Fire[loop2].rad*cos(loop*15.0/(2*3.14159));
}
}
Fire[loop2].life -= Fire[loop2].fade; //生命衰减
粒子的死亡与再生
当粒子的生命减到小于0时,粒子死亡(显示过程中用生命值作为显示颜色的第四个参数,即alpha值)。然后给粒子重新生成,代码与初始化的代码类似。
后期制作
给动画添加背景图片,背景使用东方明珠夜景。为了体现烟花的真实性,在画完背景图片以后开启混合,使得背景的颜色也随烟花的颜色变化。
glCallList(1); //绘制背景
glEnable(GL_BLEND); //开启混合
改变视角,使得照相机仰视大致30°,给人以身临其境的感觉。
gluLookAt(0.0,-10.-30,0.0,0.0,10.0,-100.0,0.0,1.0,0.0);
[1]吴文国译.交互式计算机图形学--基于OpenGL的自顶向下方法(第3版)