摘 要: 对烟花粒子系统模型和燃放原理进行了详细的分析,在VC++和OpenGL开发工具基础上,利用纹理映射、色彩混合等技术对动态烟花进行仿真模拟。加入了音频技术,并通过鼠标注册回调函数对烟花燃放的位置加以控制。实验结果表明,烟花模型的实时性逼真性、可控性和灵活性得以加强。
关键词: 粒子系统;位置可控;音频效果
1983年,由REEVES W T等人提出的粒子系统绘制算法被认为是迄今为止模拟不规则模糊物体最为成功的算法[1],使得具有不规则几何形状、内在不确定性且运动具有随机性的模糊物体的虚拟仿真模拟上了一个新的台阶。目前,国内已经有很多研究者采用粒子系统对自然景物进行成功模拟,如王晓娟对礼花进行了模拟[2],肖何等人成功地进行了喷泉仿真[3]。本文在以上理论的基础上,通过VC++和OpenGL开发工具,利用鼠标注册回调等函数[4]对烟花燃放的位置加以控制,并加入了音频技术,从视觉和听觉两个方面上进一步增强了烟花爆炸模拟的灵活性、逼真性和沉浸感。
1 粒子系统基本原理
粒子系统不是一个简单的静态模型,而是一种过程计算模型。粒子系统是由许多简单形状的微小粒子(如球体、椭球、立方体、点、线等)作为基本元素聚集起来形成一个不规则的模糊物体,并以这些粒子充满物体,使其呈现各式各样的形状,从而构成的一个封闭的系统。
组成粒子系统的每个粒子都有一组属性,包括位置、运动速度、运动加速度、形状、大小、颜色、透明度、运动方向和生命周期等,这些属性随着时间的推移在不断地变化。一个粒子究竟有什么样的属性主要取决于其实现的具体应用。
一般情况下,系统中的每个粒子都会随着虚拟世界时间的流逝经历一个产生—活动—消亡3个阶段的流程[5],如图1所示。
2 烟花粒子系统建模
2.1 建立坐标系
本文建立的坐标系以屏幕的中心为坐标原点,从左到右的方向为X轴的正方向,从下到上为Y轴的正方向,从屏幕里面指向外面的方向为Z轴正方向[6]。
2.2 烟花及粒子的数据结构
烟花粒子的数据结构如下:
typedef struct
{
GLfloat x,y,z; //粒子位置
GLfloat xSpeed,ySpeed,zSpeed; //粒子的速度
GLfloat xg,yg,zg;//粒子的运动加速度
GLfloat r,g,b; //粒子的颜色
}PARTICLES;//粒子
烟花则是由一组具有相似性质的烟花粒子组成的,其数据结构如下:
typedef struct
{
PARTICLES particle[MAX_PARTICLES][MAX_TAIL];
GLfloat life,fade,rad;
}Fire;//烟花
2.3 烟花粒子系统的初始化
烟花粒子系统的初始化就是赋予烟花粒子属性初始状态。在烟花系统中,每个烟花由一组具有相似性质的烟花粒子组成,每一帧烟花的更新就是这组烟花粒子的更新。这里把每组粒子数定义为一个常数MAX_PARTICLES,这个常数的选择很重要[7],如果过大,会影响系统的实时性;如果过小,则会影响烟花模拟的真实性。
#define MAX_PARTICLES 96 //烟花小粒子个数
#define MAX_TAIL 30 //烟花尾部的长度
通过随机函数rand()和参数控制烟花的初始位置、初始颜色、速度、加速度、生命周期及衰减速率。其中, 颜色的初始化可以在模型中定义各种颜色到一个颜色数组中,然后通过随机函数rand()调用。粒子的运动受到各种外力的影响,包括重力和空气阻力等,在本实验中,只考虑垂直方向重力所产生的加速度。
fire.life=1.0f;
fire.rad=rand()%K1+P1; //K1、P1为参数
fire.fade=(float)(rand()%K2)/K3+P2;
//K2、K3、P1为参数
2.4 烟花粒子的运动更新
烟花粒子运动更新是整个烟花系统中最重要的组成部分,就是确定每一时刻当前粒子的运动状态,包括该时刻粒子的位置、速度和生命值等各种属性值。而这些属性又是由上一帧属性状态和运动的规律决定的。粒子下一帧的位置为:
3 位置可控烟花模拟
OpenGL应用工具包GLUT中封装有鼠标消息注册回调函数,利用此函数可以很好地控制烟花的位置,从而进一步增强烟花模拟的可控性和灵活性。
鼠标的按下、松开或移动等操作都可以产生相应的鼠标消息,这些消息在应用程序开发中出现,常常需要处理。GLUT对这几种常用的鼠标消息进行了封装,glutMontionFunc(void(*func)(int button,int state,int x,int y))可以实现对鼠标左键、右键或中键的按下、松开等操作的消息响应。其中,button是左键、右键和中键的标志,state是按下、松开的标志。
用鼠标单击屏幕,系统把单击的位置传送给鼠标消息注册回调函数glutMontionFunc(mouseFunc),通过一系列的坐标转换生成最终需要的OpenGL坐标,然后烟花在此位置上发生爆炸。主要实现的代码如下:
GLdouble w [3]={0};//最终的OpenGL坐标
GLint viewport[4];
GLdouble mv[16],proj[16];
GLfloat winX,winY,winZ;//视景体坐标及深度坐标
glPushMatrix();
glGetIntegerv(GL_VIEWPORT,viewport);
//取得当前视口的状态值
glGetDoublev(GL_MODELVIEW_MATRIX,mv);
//取得当前模型视点的最大值
glGetDoublev(GL_PROJECTION_MATRIX,proj);
//取得当前投影的最大值
glPopMatrix();
winX=x;
winY=viewport[3]-y;
glReadPixels(winX,winY,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&winZ);
gluUnProject(winX,winY,winZ,mv,proj,viewport,w,w+1,w+2);//取得最终的OpenGL坐标
4 音频与烟花爆炸同步
OpenGL本身不支持音频,本文使用了Win32的API函数库中的PlaySound(LPCSTR pszSound,HMODULE hmod,DWORD fdwSound)函数实现音频与烟花爆炸的同步。引入windows.h头文件(#include<windows.h>),后面加上如下代码:
#include<mmsystem.h>
#pragma comment(lib,"WINMM.LIB")
PlaySound(LPCSTR pszSound,HMODULE hmod,DWORD fdwSound)只能实现WAV格式的文件,其他音频文件可以通过别的软件进行剪切并转化为WAV格式。参数pszSound是指定了要播放声音的字符串,本实验中设为WAVE文件的名字;参数fdwSound是标志的组合,为实现同步和引入音频文件,将其设为SND_FILENAME| SND_SYNC。主要实现的代码如下:
if(button==GLUT_LEFT_BUTTON&&action==GLUT_DOWN)
{
获取鼠标点击的位置
绘制烟花的代码
PlaySound("烟花声音.wav",NULL,SND_ASYNC|SND_FILENAME);
}
5 实验结果评估与分析
实验利用粒子系统对烟花生成的过程进行仿真,应用了OpenGL的纹理映射、色彩混合、显示列表、加入背景图片、插入音频和控制位置等技术,结果如图3所示。图3是运用可以截取鼠标位置的红蜻蜓截图工具截取的实验结果图片,从图中可以清晰地看见在鼠标的位置上烟花发生了爆炸。
运用粒子系统对不规则模糊物体进行模拟是一个有效的方法。本实验从系统的实时性、简单性、灵活性和逼真性角度出发实现了烟花模型模拟,采用了纹理映射和显示列表技术,提高了系统的实时性;采用了色彩融合技术,增强了系统的逼真性;加入了背景图,提高了模拟的真实感;通过提取鼠标位置,实现了对烟花爆炸位置的控制,增强了系统的灵活性;加入了音频技术,实现烟花爆炸和声音的同步,增强了系统的沉浸感。
参考文献
[1] REEVES W T. Particle systems-a technique for modeling a class of fuzzy objects[J]. Computer Graphics,1983,17(3):359-376.
[2] 王晓娟.基于粒子系统动态烟花的模拟[J].青海大学学报,2009(4):29-32.
[3] 肖何,何明耘,白忠建.OpenGL中基于粒子系统的喷泉模拟实现[J].计算机仿真,2007(12):201-204.
[4] SHREINER D.OpenGL编程指南[M].李军,徐波,译.北京:机械工业出版社,2010.
[5] 葛芳,张成,韦穗,等.基于粒子系统的烟花动画设计[J].计算机技术与发展,2010,20(8):180-183.
[6] 汪继文,胡文平,金余锋.基于粒子系统的8字动态烟花仿真[J].计算机仿真,2010,27(10):211-214.
[7] 丁纪云,陈利平,李思昆.基于OpenGL的烟花动态模拟方法的研究与实现[J].计算机工程,2002,20(4):233-250.