其实是我的图形学作业。火焰生成的算法写的不太好,蔓延得也不算真实。唯一的优点大概就是速度比较快吧,因为算法较简单。

效果:

贴一下C++源代码。仅供参考,工程里的其他内容和图片都没有放上来。

#include <windows.h> #include <math.h> #include <time.h> #include <GL/glaux.h> #include <GL/glut.h> #include <stdio.h> float angle=0.0,deltaAngle = 0.0,ratio; float x=0.0f,y=1.2f,z=15.0f; float lx=0.0f,ly=-0.2f,lz=-1.0f; int deltaMove = 0; time_t time_now,time_last; float radius = 0.1; int aa = 0; #define NUM_TREE_TEXTURES 4 GLint tree_display_list[NUM_TREE_TEXTURES]; #define NUM_TEXTURES 10 int count = -1; GLuint tobjects[NUM_TEXTURES]; #define NUM_TREES 50 struct Tree{ double x, //x coordinate y; //y coordinate int type; //decide the type from tree_display_list }tree[NUM_TREES]; /***********************************粒子系统***********************************************************************************/ #define MAX_PARTICLES 100000 // 定义最大的粒子数 float slowdown=2.0f; // 减速粒子 float init_x,init_z; GLuint loop,now_particles = 50,tmp_particles; typedef struct // 创建粒子数据结构 { float life; // 粒子生命 float fade; // 衰减速度 float x; // X 位置 float y; // Y 位置 float z; // Z 位置 float xi; // X 方向 float yi; // Y 方向 float zi; // Z 方向 float xg; // X 方向重力加速度 float yg; // Y 方向重力加速度 float zg; // Z 方向重力加速度 } particles; // 粒子数据结构 particles particle[MAX_PARTICLES]; // 保存MAX_PARTICLES个粒子的数组 /********************************************************************************************************************************/ AUX_RGBImageRec *LoadBMP(const char *Filename) // 载入位图文件 { FILE *File=NULL; // 文件句柄 if (!Filename) // 确认已给出文件名 { return NULL; // 若无返回 NULL } File=fopen(Filename,"r"); // 检查文件是否存在 if (File) // 文件存在么? { fclose(File); // 关闭文件句柄 return auxDIBImageLoad(/*(LPCWSTR)*/Filename); // 载入位图并返回指针 } return NULL; // 如果载入失败返回 NULL } int LoadGLTextures(const char *Filename) // 载入位图并转换成纹理 { int Status=FALSE; // 状态指示器 BYTE texture[65536][4]; AUX_RGBImageRec *TextureImage[1]; // 为纹理分配存储空间 memset(TextureImage,0,sizeof(void *)*1); // 将指针设为 NULL // 载入位图,查错,如果未找到位图文件则退出 if (TextureImage[0]=LoadBMP(Filename)) { Status=TRUE; // 将 Status 设为TRUE if (count >= 0 && count <= 3) for (int i=0;i<TextureImage[0]->sizeX*TextureImage[0]->sizeY;i++) { texture[i][0]=TextureImage[0]->data[i*3]; texture[i][1]=TextureImage[0]->data[i*3+1]; texture[i][2]=TextureImage[0]->data[i*3+2]; if (!texture[i][0] && !texture[i][1] && !texture[i][2]) texture[i][3]=0; else texture[i][3]=255; } else if (count == 4) for (int i=0;i<TextureImage[0]->sizeX*TextureImage[0]->sizeY;i++) { texture[i][0]=TextureImage[0]->data[i*3]; texture[i][1]=TextureImage[0]->data[i*3+1]; texture[i][2]=TextureImage[0]->data[i*3+2]; texture[i][3]=texture[i][0]; } glGenTextures(1, &tobjects[++count]); // 创建一个纹理 // 创建一个线性滤波纹理 glBindTexture(GL_TEXTURE_2D, tobjects[count]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); if (count ==0 || count >5) glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); else glTexImage2D(GL_TEXTURE_2D, 0, 4, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture); } if (TextureImage[0]) // 如果纹理存在 { if (TextureImage[0]->data) // 如果纹理图像存在 { free(TextureImage[0]->data); // 释放纹理图像所占的内存 } free(TextureImage[0]); // 释放图像结构 } return Status; // 返回 Status的值 } void changeSize(int w, int h) { // Prevent a divide by zero, when window is too short if(h == 0) h = 1; ratio = 1.0f * w / h; // Reset the coordinate system before modifying glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Set the viewport to be the entire window glViewport(0, 0, w, h); // Set the clipping volume gluPerspective(45,ratio,1,1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(x, y, z, x + lx,y + ly,z + lz, 0.0f,1.0f,0.0f); } void drawTree(int i) { glColor3f(1.0f, 1.0f, 1.0f); // Load the tree texture switch (i) { case 0: LoadGLTextures("Tree1.BMP"); break; case 1: LoadGLTextures("Tree2.BMP"); break; case 2: LoadGLTextures("Tree3.BMP"); break; case 3: LoadGLTextures("Tree4.BMP"); break; default: break; } // Draw the Tree glBindTexture(GL_TEXTURE_2D, tobjects[i+1]); glBegin(GL_QUADS); glTexCoord2f(1.0f, 1.0f); glVertex3i(1, 2, 0); glTexCoord2f(1.0f, 0.0f); glVertex3i(1, 0, 0); glTexCoord2f(0.0f, 0.0f); glVertex3i(-1, 0, 0); glTexCoord2f(0.0f, 1.0f); glVertex3i(-1, 2, 0); glEnd(); } GLuint createDL(int i) { GLuint TreeDL; // Create the id for the list TreeDL = glGenLists(1); // start list glNewList(TreeDL,GL_COMPILE); // call the function that contains // the rendering commands drawTree(i); // endList glEndList(); return(TreeDL); } void initScene() { int i; glClearColor(0.53f, 0.808f, 0.921f, 1.0f); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glEnable(GL_POINT_SMOOTH); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //读取地面的图片 LoadGLTextures("Ground.BMP"); // Create the trees for (i = 0; i < 4; i ++) tree_display_list[i] = createDL(i); for (i = 0; i< NUM_TREES; i ++) { tree[i].x =double(rand() % 200) / 10 - 10; tree[i].y = double(rand() % 200) / 10 - 10; tree[i].type = rand() % NUM_TREE_TEXTURES; } init_x = double(rand() % 8000) / 1000 - 4; init_z = double(rand() % 8000) / 1000 - 4; LoadGLTextures("Particle.bmp"); for (loop = 0;loop < now_particles;loop ++) //初始化所有的粒子 { particle[loop].life=1.0f; // 所有的粒子生命值为最大 particle[loop].fade=float(rand()%90)/1000.0f+0.013f; // 随机生成衰减速率 particle[loop].x=init_x + float(rand() % (int(radius*1000))) / 1000; particle[loop].y=0.0f; particle[loop].z=init_z + float(rand() % (int(radius*1000))) / 1000; particle[loop].xi=float((rand()%70)-32.0f); // 随机生成粒子速度 particle[loop].yi=float((rand()%70)-30.0f); particle[loop].zi=float((rand()%70)-30.0f); particle[loop].xg=0.0f; // 设置X轴方向加速度为0 particle[loop].yg=1.2f; // 设置Y轴方向加速度为1.2 particle[loop].zg=0.0f; // 设置Z轴方向加速度为0 } /********************************************************************************************************************************/ // glDepthFunc(GL_LEQUAL); // 所作深度测试的类型 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉系统对透视进行修正 //读取天空的图片 LoadGLTextures("Front.bmp"); LoadGLTextures("Left.bmp"); LoadGLTextures("Back.bmp"); LoadGLTextures("Right.bmp"); } void orientMe(float ang) { lx = sin(ang); lz = -cos(ang); glLoadIdentity(); gluLookAt(x, y, z, x + lx,y + ly,z + lz, 0.0f,1.0f,0.0f); } void moveMeFlat(int i) { x = x + i*(lx)*0.1; z = z + i*(lz)*0.1; glLoadIdentity(); gluLookAt(x, y, z, x + lx,y + ly,z + lz, 0.0f,1.0f,0.0f); } void renderScene(void) { int i; if (deltaMove) moveMeFlat(deltaMove); if (deltaAngle) { angle += deltaAngle; orientMe(angle); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //画地面 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBindTexture(GL_TEXTURE_2D, tobjects[0]); glBegin(GL_QUADS); glNormal3i(0, 1, 0); glTexCoord2f(20.0f, 20.0f); glVertex3i(50, 0, -50); glTexCoord2f(20.0f, 0.0f); glVertex3i(-50,0,-50); glTexCoord2f(0.0f, 0.0f); glVertex3i(-50,0,50); glTexCoord2f(0.0f, 20.0f); glVertex3i(50, 0, 50); glEnd(); //画天空 glBindTexture(GL_TEXTURE_2D, tobjects[6]); glBegin(GL_QUADS); glNormal3i(0, 1, 0); glTexCoord2f(1.0f, 1.0f); glVertex3i(-100, 100, -100); glTexCoord2f(1.0f, 0.0f); glVertex3i(-100,-40,-100); glTexCoord2f(0.0f, 0.0f); glVertex3i(100,-40,-100); glTexCoord2f(0.0f, 1.0f); glVertex3i(100, 100, -100); glEnd(); glBindTexture(GL_TEXTURE_2D, tobjects[7]); glBegin(GL_QUADS); glNormal3i(0, 1, 0); glTexCoord2f(1.0f, 1.0f); glVertex3i(-100, 100, 100); glTexCoord2f(1.0f, 0.0f); glVertex3i(-100,-40,100); glTexCoord2f(0.0f, 0.0f); glVertex3i(-100,-40,-100); glTexCoord2f(0.0f, 1.0f); glVertex3i(-100, 100, -100); glEnd(); glBindTexture(GL_TEXTURE_2D, tobjects[8]); glBegin(GL_QUADS); glNormal3i(0, 1, 0); glTexCoord2f(1.0f, 1.0f); glVertex3i(100, 100, 100); glTexCoord2f(1.0f, 0.0f); glVertex3i(100,-40,100); glTexCoord2f(0.0f, 0.0f); glVertex3i(-100,-40, 100); glTexCoord2f(0.0f, 1.0f); glVertex3i(-100, 100, 100); glEnd(); glBindTexture(GL_TEXTURE_2D, tobjects[9]); glBegin(GL_QUADS); glNormal3i(0, 1, 0); glTexCoord2f(1.0f, 1.0f); glVertex3i(100, 100, -100); glTexCoord2f(1.0f, 0.0f); glVertex3i(100,-40,-100); glTexCoord2f(0.0f, 0.0f); glVertex3i(100,-40,100); glTexCoord2f(0.0f, 1.0f); glVertex3i(100, 100, 100); glEnd(); for(i = 0; i < NUM_TREES; i ++) { glPushMatrix(); glTranslatef(tree[i].x, 0, tree[i].y); glRotatef(360-angle*180/3.1415926, 0.0, 1.0, 0.0); glCallList(tree_display_list[tree[i].type]); glPopMatrix(); } time_now = time(0); if (time_now - time_last >= 2) { radius += 0.1; time_last = time_now; } glEnable(GL_BLEND); glDepthMask(GL_FALSE); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); glBindTexture(GL_TEXTURE_2D, tobjects[5]); tmp_particles = now_particles; for (loop=0;loop<now_particles;loop++) { float x=particle[loop].x; // 返回X轴的位置 float y=particle[loop].y; // 返回Y轴的位置 float z=particle[loop].z; // 返回Z轴的位置 // 设置粒子颜色 glColor4f(1.0f,0.5f,0.0f,particle[loop].life); glPushMatrix(); glTranslatef(x, y, z); glRotatef(360-angle*180/3.1415926, 0.0, 1.0, 0.0); glBegin(GL_TRIANGLE_STRIP); // 绘制三角形带 glTexCoord2d(1,1); glVertex3f(0.5f,0.5f,0); glTexCoord2d(0,1); glVertex3f(-0.5f,0.5f,0); glTexCoord2d(1,0); glVertex3f(0.5f,-0.5f,0); glTexCoord2d(0,0); glVertex3f(-0.5f,-0.5f,0); //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(); glPopMatrix(); //particle[loop].x+=particle[loop].xi/(slowdown*1000); // 更新X坐标的位置 particle[loop].y+=particle[loop].yi/(slowdown*1000); // 更新Y坐标的位置 //particle[loop].z+=particle[loop].zi/(slowdown*1000); // 更新Z坐标的位置 //particle[loop].xi+=particle[loop].xg; // 更新X轴方向速度大小 particle[loop].yi+=particle[loop].yg; // 更新Y轴方向速度大小 //particle[loop].zi+=particle[loop].zg; // 更新Z轴方向速度大小 particle[loop].life-=particle[loop].fade; // 减少粒子的生命值 if (particle[loop].life<0.0f) // 如果粒子生命值小于0 { particle[loop].life=1.0f; // 产生一个新的粒子 particle[loop].fade=float(rand()%90)/1000.0f+0.013f; // 随机生成衰减速率 particle[loop].x=init_x + float(rand() % (int(radius*1000))) / 1000; particle[loop].y=0.0f; particle[loop].z=init_z + float(rand() % (int(radius*1000))) / 1000; particle[loop].xi=float((rand()%70)-32.0f); // 随机生成粒子速度 particle[loop].yi=float((rand()%70)-30.0f); particle[loop].zi=float((rand()%70)-30.0f); int tmp = (rand() % 40); //每个死亡粒子有机会产生两个新的粒子,这样火焰可以蔓延 if (tmp == 1) { tmp_particles ++; particle[tmp_particles].life=1.0f; particle[tmp_particles].fade=float(rand()%90)/1000.0f+0.013f; particle[tmp_particles].x=init_x + float(rand() % (int(radius*1000))) / 1000; particle[tmp_particles].y=0.0f; particle[tmp_particles].z=init_z + float(rand() % (int(radius*1000))) / 1000; particle[tmp_particles].xi=float((rand()%70)-32.0f); particle[tmp_particles].yi=float((rand()%70)-30.0f); particle[tmp_particles].zi=float((rand()%70)-30.0f); } } } now_particles = tmp_particles; glDepthMask(GL_TRUE); glDisable(GL_BLEND); glFlush(); glutSwapBuffers(); } void pressKey(int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT : deltaAngle = -0.01f;break; case GLUT_KEY_RIGHT : deltaAngle = 0.01f;break; case GLUT_KEY_UP : deltaMove = 1;break; case GLUT_KEY_DOWN : deltaMove = -1;break; } } void releaseKey(int key, int x, int y) { switch (key) { case GLUT_KEY_LEFT : case GLUT_KEY_RIGHT : deltaAngle = 0.0f;break; case GLUT_KEY_UP : case GLUT_KEY_DOWN : deltaMove = 0;break; } } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(10,10); glutInitWindowSize(640,360); glutCreateWindow("Forrest Fire"); srand((unsigned)time(0)); time_now = time(0); time_last = time_now; initScene(); glutIgnoreKeyRepeat(1); glutSpecialFunc(pressKey); glutSpecialUpFunc(releaseKey); glutDisplayFunc(renderScene); glutIdleFunc(renderScene); glutReshapeFunc(changeSize); glutMainLoop(); return(0); }

虚拟森林火场生成及蔓延模拟相关推荐

  1. ADAS虚拟车道边界生成

    ADAS虚拟车道边界生成 Virtual Lane Boundary Generation for Human-Compatible Autonomous Driving: A Tight Coupl ...

  2. boost::mp11模块使用一些节点生成并行蒙特卡罗模拟的示例

    boost::mp11模块使用一些节点生成并行蒙特卡罗模拟的示例 实现功能 C++实现代码 实现功能 boost::mp11模块使用一些节点生成并行蒙特卡罗模拟的示例 C++实现代码 #include ...

  3. Python生成CSV文件模拟某小区用户手机通话记录

    好消息:"Python小屋"编程比赛正式开始 推荐图书: <Python程序设计(第3版)>,(ISBN:978-7-302-55083-9),董付国,清华大学出版社, ...

  4. 虚拟现实是利用计算机,虚拟现实技术就是利用计算机生成一种模拟环境

    虚拟现实(Virtual Reality,简称VR,)是利用电脑模拟产生一个三维空间的虚拟世界,提供使用者关于视觉.听觉.触觉等感官的模拟,让使用者如同身历其境一般,可以及时.没有限制地观察三度空间内 ...

  5. 腾讯发布 3D 虚拟场景自动生成解决方案,用 AIGC 助力游戏开发提效

    3月28日记者获悉,腾讯 AI Lab在2023游戏开发者大会(Game Developers Conference)上发布了自研的3D游戏场景自动生成解决方案,通过AIGC技术,帮助开发者在极短的时 ...

  6. 高校如何搭建虚拟实验室?如何通过数据手套模拟实验教学?

    虚拟实验室是由虚拟现实技术生成的一类适于进行虚拟实验的实验系统,包括相应实验室环境.有关的实验仪器设备.实验对象以及实验信息资源等.在虚拟实验室中,学生能够在计算机建立的三维的模拟实验场景中从不同的视 ...

  7. 【Pytorch神经网络实战案例】16 条件WGAN模型生成可控Fashon-MNST模拟数据

    1 条件GAN前置知识 条件GAN也可以使GAN所生成的数据可控,使模型变得实用, 1.1 实验描述 搭建条件GAN模型,实现向模型中输入标签,并使其生成与标签类别对应的模拟数据的功能,基于WGAN- ...

  8. 【Pytorch神经网络实战案例】14 构建条件变分自编码神经网络模型生成可控Fashon-MNST模拟数据

    1 条件变分自编码神经网络生成模拟数据案例说明 在实际应用中,条件变分自编码神经网络的应用会更为广泛一些,因为它使得模型输出的模拟数据可控,即可以指定模型输出鞋子或者上衣. 1.1 案例描述 在变分自 ...

  9. C# 城市路网地图生成与运动模拟(一)-数据的获取

    雪影工作室版权所有,转载请注明[http://blog.csdn.net/lina791211] 1.前言 这段时间一直在研究城市路网,某一天受不可告人的启发,决定把城市路网的地图做出来,然后模拟移动 ...

最新文章

  1. SpringBoot 【IDEA热部署+浏览器禁用缓存】迅速提升效率
  2. 2天训练出15亿参数大模型,国产开源项目力克英伟达Megatron-LM,来自LAMB作者团队...
  3. 【IT笔试面试题整理】连续子数组的最大和
  4. Java-protected的使用范围
  5. 模拟上帝之手的对抗博弈——GAN背后的数学原理
  6. 为什么说C语言是面向过程的?
  7. 你还会写这段C51程序吗?
  8. Windows批处理符号简介、常用Dos命令
  9. PyG图神经网络框架--构建信息传递网络(MPN)
  10. sql 逻辑运算符_SQL Like逻辑运算符介绍和概述
  11. @JsonView的简单使用
  12. quartus中与modelsim进行联合仿真出现错误error:(vopt-13130)failed to find design unit****
  13. BZOJ2109 [Noi2010]Plane 航空管制
  14. 基于Java的网上商城系统
  15. 【Socket网络编程进阶与实战】------ Socket网络编程快速入门
  16. allegro中design size无法修改
  17. 计算机网络里不显示共享打印机驱动,win10连接共享打印机时“找不到驱动程序”怎么回事...
  18. Java + lua = 王炸!!
  19. docsify学习笔记
  20. 接手别人的代码,死的心有吗?

热门文章

  1. 清北力压耶鲁,MIT蝉联第一,2023QS世界大学排名最新发布
  2. 触宝输入法 v6.9.8.7
  3. Fortran中go to语句的罕见用法
  4. 兔子繁衍问题(PTA)
  5. navicat mysql 存储过程_navicat怎么创建存储过程
  6. gmt转换北京时间 java_java GMT 日期转换 | 学步园
  7. 一文让你彻底了解多线程
  8. c++ 已知直线外一点,求对称点
  9. android开发 实现动态获得app的cpu占有率并导出文件的两种方法。
  10. [kpw] USBNetwork + WinSCP + PublicKey + PrivateKey