火焰 粒子系统 OpenGL - 图文

更新时间:2023-11-14 15:44:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

课 程 设 计 报告

题 目 基于openGL的粒子系统——模拟火焰 系 (部) 专 业 班 级 学生姓名 学 号

起止时间:

指导教师(签字) 系 主 任(签字)

提交时间:

一、设计任务及要求: 设计任务:

要 求: 此次课程设计的课题为通过编程,实现火焰的绘制。实现交互控制火焰颜色、火焰燃烧方向、贴图形状,通过实验得到火焰贴图大小与火焰效果的关系,并给出代码和结果截图。 指导教师签名: 年 月 日 二、指导教师评语: 指导教师签名: 年 月 日 三、成绩

计算机图形学课程设计报告

1.课程设计目的

本学期系统学习了《计算机图形学》这门专业课,在学期期末按课程要求进行实验。粒子系统由Reeves于1983年首次提出,此后越来越受到重视,它的主要优点是可以利用非常简单的体素来构造复杂的物体,为自然现象(如火焰、雨、雪、树林等)的造型提供了强有力的技术手段。

该课程设计以培养我们算法设计与实现的能力为目标,通过实践,使我们了解、掌握计算机图形学的基本知识和关键技术、了解和熟悉计算机图形学的方法、工具和环境,同时培养我们的思维能力和团队合作能力。 2.课程设计描述及要求

粒子系统的基本思想是用许多形状简单且赋予生命的微小粒子作为基本元素来表示基本物体,侧重于物体的总体形态和特征的动态变化。把物体定义为许多不规则、随机分布的粒子,且每个粒子均有一定的生命周期。随着时间的推移,旧的粒子不断消失(死亡),新的粒子不断加入(生长)。粒子的这种出生、成长、衰老、死亡的过程,能够较好的反应模糊物体的动态特征。一个粒子系统是不断进化的,在生命周期的每一刻,都要完成以下四步:

初始化粒子 更新粒子 删除死粒子 绘制粒子 第一步产生5000个新粒子,他们的每个粒子都有生命周期为2; 第二步根据情况更新,递减一个随机的时间步;

第三步检查粒子的生命期,若为零,则将粒子从系统中删除; 第四步显示粒子系统中的粒子。 要求:

此次课程设计的课题为通过编程,实现火焰的绘制。实现交互控制火焰颜色、火焰燃烧方向、

贴图形状,通过实验得到火焰贴图大小与火焰效果的关系,并给出代码和结果截图。 3.系统开发环境 开发工具:VC 6.0

操作系统:Microsoft Windows 7 4、粒子系统(火焰)的算法原理

4.1 定义粒子的属性

宏定义粒子的最大数目5000,并定义结构体来设置粒子属性,代码如下: #define MAX_PARTICLES 5000 typedef struct { } particles;

bool float float float float float float float float float float float float float float

active; life; fade; r; g; b; x; y; z; xi; yi; zi; xg; yg; zg;

//

// 粒子数的数目

// 创建结构体

// 粒子生命周期

// 消失的速度 // 坐标 // 坐标 // 坐标

// X轴加速度 // Y轴加速度 // Z轴加速度

particles particle[MAX_PARTICLES]; // 创建粒子数组 4.2 初始化粒子

利用循环变量loop,loop小于等于最大粒子数目时,则初始化每一个粒子,代码如下: for (loop=0;loop

{

particle[loop].active=true; particle[loop].life=2.0f;

//生命期

particle[loop].fade=float(rand()0)/1500.0f+0.002f; //消失速度(随机) particle[loop].r=colors[loop*(4/MAX_PARTICLES)][0];

}

particle[loop].g=colors[loop*(4/MAX_PARTICLES)][1]; particle[loop].b=colors[loop*(4/MAX_PARTICLES)][2];

particle[loop].xg=0.0f; particle[loop].yg=0.3f; particle[loop].zg=0.0f;

4.3 粒子消失的过程

(1)定义消失变量,使粒子的生命期递减一个随机的生命步,代码如下:

particle[loop].fade=float(rand()0)/1500.0f+0.002f;

(2)粒子的颜色透明度随着生命期的减少而降低,最终消失,代码如下:

glColor4f(particle[loop].r,particle[loop].g,particle[loop].b,particle[loop].life);

4.4 绘制及更新粒子

(1)设置粒子的运动状态,代码如下:

particle[loop].x+=particle[loop].xi/(slowdown*1050); //X的坐标随X轴速度变化 particle[loop].y+=particle[loop].yi/(slowdown*1050); particle[loop].z+=particle[loop].zi/(slowdown*1050);

particle[loop].xi+=particle[loop].xg; // X轴的速度随X轴的加速度变化 particle[loop].yi+=particle[loop].yg; particle[loop].zi+=particle[loop].zg;

// 周期衰减

particle[loop].life-=particle[loop].fade;

(2)当粒子生命期衰减为0时,更新粒子,代码如下: if (particle[loop].life<0.0f) { particle[loop].life=2.0f; particle[loop].fade=float(rand()0)/1500.0f+0.002f; particle[loop].x=0.0f; particle[loop].y=0.0f; particle[loop].z=0.0f; particle[loop].xi=float((rand()`)-30.0f); particle[loop].yi=float((rand()`)-30.0f); particle[loop].zi=float((rand()`)-30.0f); particle[loop].r=colors[col][0]; //渲染 particle[loop].g=colors[col][1]; //渲染 particle[loop].b=colors[col][2]; //渲染 particle[loop].xg=xg1; particle[loop].yg=yg1;

}

particle[loop].zg=0.0f;

5、实现交互的原理

5.1 键盘和鼠标主菜单控制火焰颜色 (1)定义颜色数组及设置火焰颜色:

static GLfloat colors[8][3]= // 颜色数组 { {0.0f,0.0f,0.0f},{0.5f,0.75f,1.0f},{1.0f,0.75f,0.5f},{0.75f,1.0f,0.5f}, {1.0f,0.5f,0.75f}, {0.35f,0.8f,0.5f}, {0.55f,0.25f,0.75f},{0.5f,0.5f,0.75f}, };

particle[loop].r=colors[col][0]; particle[loop].g=colors[col][1]; particle[loop].b=colors[col][2];

//渲染 //渲染 //渲染

(2)用键盘的“q”“w”“a”“s”“z”键和主菜单选择数组中相应行的RGB值来改变火焰颜色,代码如下:

void keyboard(unsigned char key,int x,int y) //定义键盘功能 {

switch(key) {

case 'q':

{

col=3;

xg1+=0.05;

glutPostRedisplay(); //重绘函数

} break;

case 'w':

{

col=4;

yg1+=0.05; glutPostRedisplay();

}

break; case 'a':

{

col=5;

xg1-=0.05; glutPostRedisplay();

}break;

case 's': {

col=6;

yg1-=0.05;

glutPostRedisplay(); } break; case 'z': {

col=7;

glutPostRedisplay();

}

break; default: break; } }

void MainMenuHandler(int option) //{

switch(option) { case 0: {

exit(0);

LoadGLTextures(); } break; case 1:

{

col=1;

定义主菜单功能

} break;

case 2:

}break; {

col=2;

default: break; }

glutPostRedisplay(); }

void MenuHandler() // 主菜单 {

int mainMenu;

mainMenu = glutCreateMenu(MainMenuHandler);

glutSetMenu(mainMenu); glutAddMenuEntry(\ glutAddMenuEntry(\ glutAddMenuEntry(\

glutAttachMenu(GLUT_RIGHT_BUTTON); }

5.2 键盘控制火焰燃烧方向 (代码可参照键盘控制火焰颜色) 5.3 选择贴图纹理

用键盘输入选择纹理所对应的编号,代码可参照附录源代码中int LoadGLTextures()函数。 6、程序运行结果

图6.1 图6.2

例如:选择2号:五角星火焰(图6.1) 贴图纹理:五角星(图6.2)

图6.3.1 图6.3.2

例如:选择4号:火焰(图6.3.1) 贴图纹理:火焰(图6.3.2)

图6.4.1 图6.4.2 图6.4.3 按键改变的火焰颜色(图6.4.1 图6.4.2 图6.4.3 )

图6.5.1 图6.5.2

鼠标主菜单,改变火焰颜色,和退出。例如选择“bright blue”,结果如图6.5.1 与图6.5.2

图6.6.1 图6.6.2

通过改变粒子X与Y轴的初速度和加速度,来改变火焰的燃烧方向,如图6.6.1与图6.6.2 7、总结

在完成基于粒子系统的火焰模拟实验的过程中,我们小组各成员通过分工与合作多种形式,查阅和检索相关文献及资料,最终通过学习基本原理、讨论实验方案、研究重点难点及验证预期结果等过程完成了本次实验。我们实验的特色在于使用键盘和鼠标控制火焰颜色的交互变化,以及使用

键盘控制火焰加速度的变化。在本次实验中我们学习并掌握了相关知识,同时也深刻的体会到了合作的重要性。今后,我们一定会更加认真学习。 8、参考资料:

《计算机图形学基础(第2版)》 陆枫 何云峰 编著 太原工业学院精品课程 9、附录:源程序代码清单 #include \#include #include #include #include #include #include #include \#define MAX_PARTICLES 5000

float slowdown=3.0f; float xspeed; float yspeed;

float zoom=-40.0f;

int a; float xg1; float yg1=0.2f; GLuint loop;

GLuint col=5; GLuint texture[1];

typedef struct

{ bool active; float life;

float fade;

// 粒子数的数目

// X轴速度 // Y轴速度

// 循环变量

// 初始颜色

// 创建数组存储纹理

// 创建结构体

//

// 粒子生命周期 // 消失的速度

}

float r; float g; float b; float x; float y; float z; float xi; float yi; float zi; float xg; float yg; float zg;

// 坐标 // 坐标 // 坐标

// X轴加速度 // Y轴加速度 // Z轴加速度

particles;

particles particle[MAX_PARTICLES]; // 创建粒子数组 static GLfloat colors[8][3]= { };

AUX_RGBImageRec *LoadBMP(char *Filename) {

FILE *File=NULL; if (!Filename) {

return NULL;

// 载入位图图像

{0.0f,0.0f,0.0f},{0.5f,0.75f,1.0f},{1.0f,0.75f,0.5f},{0.75f,1.0f,0.5f},

{1.0f,0.5f,0.75f}, {0.35f,0.8f,0.5f}, {0.55f,0.25f,0.75f},{0.5f,0.5f,0.75f},

// 颜色数组

}

File=fopen(Filename,\ if (File) {

fclose(File);

return auxDIBImageLoad(Filename);

}

return NULL; }

int LoadGLTextures() 成纹理 {

int Status=FALSE;

// 载入位图(调用上面的代码)并转换

AUX_RGBImageRec *TextureImage[1];

memset(TextureImage,0,sizeof(void *)*1);

printf(\键 xg1+=0.05;(X轴加速度) 荧光黄色\\n\printf(\键 yg1+=0.05;(X轴加速度) 玫瑰粉\\n\printf(\键 xg1-=0.05;(X轴加速度) 荧光绿\\n\printf(\键 yg1-=0.05;(X轴加速度) 亮紫\\n\

printf(\键 yg1-=0.05;(X轴加速度) 藕荷色\\n\

printf(\

printf(\选择纹理

printf(\

Triangle---\\n\\n\

Hexagon---\\n\\n\

printf(\scanf(\

if(a>6)

{

printf(\exit(0); }

switch(a) {

case 1: {

if (TextureImage[0]=LoadBMP(\ {

glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexImage2D(GL_TEXTURE_2D,

0,

3,

TextureImage[0]->sizeX,

Status=TRUE;

glGenTextures(1, &texture[0]);

TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); }

} break;

case 2:

{

if (TextureImage[0]=LoadBMP(\

{

glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

Status=TRUE;

glGenTextures(1, &texture[0]);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX,

TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

}

}break;

case 3: {

if (TextureImage[0]=LoadBMP(\

{

glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

0,

3,

TextureImage[0]->sizeX,

Status=TRUE;

glGenTextures(1, &texture[0]);

glTexImage2D(GL_TEXTURE_2D,

TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

}

}break;

case 4:

{

if (TextureImage[0]=LoadBMP(\

{

glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

0,

3,

TextureImage[0]->sizeX,

Status=TRUE;

glGenTextures(1, &texture[0]);

glTexImage2D(GL_TEXTURE_2D,

TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

}

}break;

case 5: {

if (TextureImage[0]=LoadBMP(\

{

glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

0,

3,

TextureImage[0]->sizeX,

Status=TRUE;

glGenTextures(1, &texture[0]);

glTexImage2D(GL_TEXTURE_2D,

TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

case 6: {

if (TextureImage[0]=LoadBMP(\

}

}break;

{

glBindTexture(GL_TEXTURE_2D, texture[0]);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

0,

3,

TextureImage[0]->sizeX,

Status=TRUE;

glGenTextures(1, &texture[0]);

glTexImage2D(GL_TEXTURE_2D,

TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

}

}break;

}

if (TextureImage[0]) { }

if (TextureImage[0]->data) { }

free(TextureImage[0]);

free(TextureImage[0]->data);

return Status; }

void ReSizeGLScene(GLsizei width, GLsizei height) { }

void InitGL(GLvoid) {

glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity();

// 调整并初始化GL窗口

gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,200.0f);

// OpenGL的设置

}

glClearColor(0.0f,0.0f,0.0f,0.0f); glShadeModel(GL_SMOOTH); glClearDepth(1.0f);

glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND);

glBlendFunc(GL_SRC_ALPHA,GL_ONE);

glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); glHint(GL_POINT_SMOOTH_HINT,GL_NICEST); glEnable(GL_TEXTURE_2D); LoadGLTextures();

glBindTexture(GL_TEXTURE_2D,texture[0]);

for (loop=0;loop

particle[loop].xg=0.0f; particle[loop].yg=0.3f; particle[loop].zg=0.0f;

particle[loop].active=true; particle[loop].life=2.0f;

particle[loop].fade=float(rand()0)/1500.0f+0.002f; particle[loop].r=colors[loop*(4/MAX_PARTICLES)][0]; particle[loop].g=colors[loop*(4/MAX_PARTICLES)][1]; particle[loop].b=colors[loop*(4/MAX_PARTICLES)][2];

void DrawGLScene(GLvoid) // 绘制

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0,0,5,

for (loop=0;loop

if (particle[loop].active) {

float x=particle[loop].x; float y=particle[loop].y;

0,1.5,0, 0,1,0);

float z=particle[loop].z+zoom;

);

particle[loop].x+=particle[loop].xi/(slowdown*1050); //X的坐标随X轴速度

glBegin(GL_TRIANGLE_STRIP);

glColor4f(particle[loop].r,particle[loop].g,particle[loop].b,particle[loop].life

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();

变化

particle[loop].y+=particle[loop].yi/(slowdown*1050);

particle[loop].z+=particle[loop].zi/(slowdown*1050);

}

{ }

particle[loop].life=2.0f;

if (particle[loop].life<0.0f)

particle[loop].yi+=particle[loop].yg; particle[loop].zi+=particle[loop].zg;

// 周期衰减

particle[loop].xi+=particle[loop].xg;

// X轴的速度随X轴的加速度变

particle[loop].life-=particle[loop].fade;

particle[loop].fade=float(rand()0)/1500.0f+0.002f; particle[loop].x=0.0f; particle[loop].y=0.0f; particle[loop].z=0.0f;

particle[loop].xi=float((rand()`)-30.0f); particle[loop].yi=float((rand()`)-30.0f); particle[loop].zi=float((rand()`)-30.0f);

particle[loop].r=colors[col][0]; particle[loop].g=colors[col][1]; particle[loop].b=colors[col][2]; particle[loop].xg=xg1; particle[loop].yg=yg1; particle[loop].zg=0.0f;

//渲染 //渲染 //渲染

} }

glutSwapBuffers();

void MainMenuHandler(int option) //{

switch(option) { case 0: {

exit(0);

LoadGLTextures(); } break; case 1:

{

col=1;

} break;

case 2: {

col=2;

}break;

default: break; }

glutPostRedisplay(); }

定义主菜单功能

void MenuHandler() // 主菜单 {

int mainMenu;

mainMenu = glutCreateMenu(MainMenuHandler);

glutSetMenu(mainMenu); glutAddMenuEntry(\ glutAddMenuEntry(\ glutAddMenuEntry(\

glutAttachMenu(GLUT_RIGHT_BUTTON); }

void keyboard(unsigned char key,int x,int y) //{

定义键盘功能 switch(key) {

case 'q':

{

col=3;

//xg1+=0.05;

glutPostRedisplay(); //重绘函数

} break;

case 'w':

{

col=4;

// yg1+=0.05; glutPostRedisplay();

}

break; case 'a':

{

col=5;

// xg1-=0.05; glutPostRedisplay();

}break;

case 's':

{

col=6;

//yg1-=0.05;

glutPostRedisplay(); } break; case 'z':

{

col=7;

glutPostRedisplay();

}

break;

default: break; } }

int main(int argc, char* argv[]) {

InitGL();

glutReshapeFunc(ReSizeGLScene); glutInit(&argc,argv);

glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH); glutInitWindowSize(500,650); glutInitWindowPosition(800,50); glutCreateWindow(\

}

glutDisplayFunc(DrawGLScene); glutIdleFunc(DrawGLScene); MenuHandler();

glutKeyboardFunc(keyboard); glutMainLoop(); return 0;

本文来源:https://www.bwwdw.com/article/061v.html

Top