OpenGL粒子系统详解及编程实现

标签: opengl编程
2016-08-23 14:23  1114人阅读  评论(0)  收藏  举报
  分类:
OSG(6) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

粒子系统的基本思想是:采用许多形状简单的微小粒子作为基本元素,用它们来表示不规则模糊物体。这些粒子都有各自的生命周期,在系统中都要经历“产生” 、 “运动和生长”及“消亡”三个阶段。粒子系统是一个有“生命”的系统,因此不象传统方法那样只能生成瞬时静态的景物画面,而是可以产生一系列运动进化的画面,这使得模拟动态的自然景物成为可能。

这篇文章讲解不用GPU加速的一个粒子系统实例。

利用粒子系统生成画面的基本步骤:  
1、产生新的粒子;  
2、赋予每一新粒子一定的属性;  
3、删去那些已经超过生存期的粒子;  
4、根据粒子的动态属性对粒子进行移动和变换;  
5、显示由有生命的粒子组成的图像。

粒子系统采用随机过程来控制粒子的产生数量,确定新产生粒子的一些初始随机属性,如初始运动方向、初始大小、初始颜色、初始透明度、初始形状以及生存期等,并在粒子的运动和生长过程中随机地改变这些属性。粒子系统的随机性使模拟不规则模糊物体变得十分简便。  
粒子系统应用的关键在于如何描述粒子的运动轨迹,也就是构造粒子的运动函数。函数选择的恰当与否,决定效果的逼真程度。其次,坐标系的选定(即视角)也有一定的关系,视角不同,看到的效果自然不一样了。

我们需要定义一个数据结构来描述粒子。这里定义一个struct类型,包含一些描述粒子特性的数据成员:

typedef struct//structrue for particle
{
  bool active;//active or not
  float life;//last time
  float fade;//describe the decreasing of life
  float r,g,b;//color
  float x,y,z;//the position
  float xi,yi,zi;//what direction to move
  float xg,yg,zg;//gravity
}particles;

其数据成员的意义:

active:粒子是否激活,没有激活的粒子将不会显示在屏幕上;

life:粒子的生命时间,也就是持续显示的时间。后面会被用在粒子的颜色的a值上。当它为0时,粒子完全透明,也就看不见了。所以其值应该不大于1.0f。

fade;描述life的衰减程度;

r、g、b:粒子的颜色

xi、yi、zi描述粒子的运动方向;

xg、yg、zg:描述粒子运动受到的阻力的方向。

接着我们要定义一个粒子集合,包含很多个粒子:

#define MAX_PARTICLES 1000
particles paticle[MAX_PARTICLES];

对粒子系统进行初始化:

for (loop = 0;loop < MAX_PARTICLES;++loop)
  {
    paticle[loop].active = true;
    paticle[loop].life = 1.0f;
    paticle[loop].fade = float(rand() % 100) / 1000.0f + 0.003f;
    paticle[loop].r = colors[loop * (12 / MAX_PARTICLES)][0];
    paticle[loop].g = colors[loop * (12 / MAX_PARTICLES)][1];
    paticle[loop].b = colors[loop * (12 / MAX_PARTICLES)][2];    paticle[loop].xi = float((rand() % 50) - 26.0f) * 10.0f;
    paticle[loop].yi = float((rand() % 50) - 25.0f) * 10.0f;
    paticle[loop].zi = float((rand() % 50) - 25.0f) * 10.0f;    paticle[loop].xg=0.8f;
    paticle[loop].yg=0.8f;
    paticle[loop].zg=0.8f;
  }

colors是预定义的以供使用的颜色数组:

static GLfloat colors[12][3]=     // Rainbow Of Colors
{
  {1.0f,0.5f,0.5f},{1.0f,0.75f,0.5f},{1.0f,1.0f,0.5f},{0.75f,1.0f,0.5f},
  {0.5f,1.0f,0.5f},{0.5f,1.0f,0.75f},{0.5f,1.0f,1.0f},{0.5f,0.75f,1.0f},
  {0.5f,0.5f,1.0f},{0.75f,0.5f,1.0f},{1.0f,0.5f,1.0f},{1.0f,0.5f,0.75f}
};

粒子系统的绘制: 
我们把每个粒子看成单独的一个对象来看待。在这里用由两个三角形组成的序列来表示,采用  GL_TRIANGLE_STRIP  方法绘制。

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

这里不用绘制四边形的方法是因为绘制三角形速度要快很多,而且大多数图形卡本来就是把绘制i四边形的工作转化成为三角形实现。但是并不是所以的图形卡都这么做,所以我们手动实现。  GL_TRIANGLE_STRIP  的运作原理可以参考这里:  GL_TRIANGLE_STRIP

在本程序中,我们启用了混合。我们开启了混合功能,既为顶点绘制指定了颜色值,也使用了纹理贴图。

我们从硬盘上读取bmp图像,加载纹理。采用了GLAUX库实现。可以参考: GLAUX

程序完整代码:

#pragma comment(lib,"GLAUX.LIB")#include <iostream>
#include <GL/glut.h>
#include <GL/glaux.h>
using namespace std;#define MAX_PARTICLES 1000typedef struct//structrue for particle
{
  bool active;//active or not
  float life;//last time
  float fade;//describe the decreasing of life
  float r,g,b;//color
  float x,y,z;//the position
  float xi,yi,zi;//what direction to move
  float xg,yg,zg;//gravity
}particles;bool rainbow = true;
bool sp,rp;//space button and return button pressed or not?
float slowdown = 2.0f;
float xspeed,yspeed;
float zoom = -40.0f;
bool gkeys[256];GLuint loop,col,delay,texture[1];particles paticle[MAX_PARTICLES];static GLfloat colors[12][3]=     // Rainbow Of Colors
{
  {1.0f,0.5f,0.5f},{1.0f,0.75f,0.5f},{1.0f,1.0f,0.5f},{0.75f,1.0f,0.5f},
  {0.5f,1.0f,0.5f},{0.5f,1.0f,0.75f},{0.5f,1.0f,1.0f},{0.5f,0.75f,1.0f},
  {0.5f,0.5f,1.0f},{0.75f,0.5f,1.0f},{1.0f,0.5f,1.0f},{1.0f,0.5f,0.75f}
}; AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
  FILE *File=NULL;        // File Handle
  if (!Filename)        // Make Sure A Filename Was Given
  {
    return NULL;        // If Not Return NULL
  }
  File=fopen(Filename,"r");      // Check To See If The File Exists
  if (File)           // Does The File Exist?
  {
    fclose(File);         // Close The Handle
    return auxDIBImageLoad(Filename);   // Load The Bitmap And Return A Pointer
  }
  return NULL;          // If Load Failed Return NULL
} int LoadGLTextures()        // Load Bitmaps And Convert To Textures
{
  int Status=FALSE;        // Status Indicator
  AUX_RGBImageRec *TextureImage[1];    // Create Storage Space For The Texture   memset(TextureImage,0,sizeof(void *)*1); // Set The Pointer To NULL
  if (TextureImage[0]=LoadBMP("Data/Particle.bmp"))  // Load Particle Texture
  {
    Status=TRUE;          // Set The Status To TRUE
    glGenTextures(1, &texture[0]);    // Create One Textures     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, TextureImage[0]->sizeY,
      0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  }   if (TextureImage[0])        // If Texture Exists
  {
    if (TextureImage[0]->data)      // If Texture Image Exists
    {
      free(TextureImage[0]->data);    // Free The Texture Image Memory
    }
    free(TextureImage[0]);       // Free The Image Structure
  }
  return Status;          // Return The Status
} void reshape(int w,int h)
{
  if(0 == h)
    h = 1;
  glViewport(0,0,(GLsizei)w,(GLsizei)h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0f,(GLfloat)w / (GLfloat)h,0.1f,200.0f);  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}int init()
{
  if (!LoadGLTextures())
  {
    return false;
  }
  glShadeModel(GL_SMOOTH);
  glClearColor(0.0f,0.0f,0.0f,0.0f);
  glClearDepth(1.0f);
  glDisable(GL_DEPTH_TEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE);
  //really nice perspective calculations
  glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
  glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D,texture[0]);  for (loop = 0;loop < MAX_PARTICLES;++loop)
  {
    paticle[loop].active = true;
    paticle[loop].life = 1.0f;//full life is 1.0f
    //life decrease rate(a random value add 0.003f : never equals 0)
    paticle[loop].fade = float(rand() % 100) / 1000.0f + 0.003f;
    paticle[loop].r = colors[loop * (12 / MAX_PARTICLES)][0];
    paticle[loop].g = colors[loop * (12 / MAX_PARTICLES)][1];
    paticle[loop].b = colors[loop * (12 / MAX_PARTICLES)][2];    paticle[loop].xi = float((rand() % 50) - 26.0f) * 10.0f;
    paticle[loop].yi = float((rand() % 50) - 25.0f) * 10.0f;
    paticle[loop].zi = float((rand() % 50) - 25.0f) * 10.0f;    paticle[loop].xg=0.0f;
    paticle[loop].yg=-0.8f;
    paticle[loop].zg=0.8f;
  }
  return true;
}void display()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity();
  for (loop = 0;loop < MAX_PARTICLES;++loop)
  {
    if (paticle[loop].active)//the particle is alive
    {
      float x = paticle[loop].x;
      float y = paticle[loop].y;
      //our scene is moved into the screen
      float z = paticle[loop].z + zoom;      glColor4f(paticle[loop].r,
        paticle[loop].g,
        paticle[loop].r,
        //use life as alpha value:
        //as particle dies,it becomes more and more transparent
        paticle[loop].life);      //draw particles : use triangle strip instead of quad to speed
      glBegin(GL_TRIANGLE_STRIP);
        //top right
        glTexCoord2d(1,1);
        glVertex3f(x + 0.5f,y + 0.5f,z);
        //top left
        glTexCoord2d(0,1);
        glVertex3f(x - 0.5f,y + 0.5f,z);
        //bottom right
        glTexCoord2d(1,0);
        glVertex3f(x + 0.5f,y - 0.5f,z);
        //bottom left
        glTexCoord2d(0,0);
        glVertex3f(x - 0.5f,y - 0.5f,z);
      glEnd();      //Move On The X Axis By X Speed
      paticle[loop].x+=paticle[loop].xi/(slowdown*1000);
      //Move On The Y Axis By Y Speed
      paticle[loop].y+=paticle[loop].yi/(slowdown*1000);
      //Move On The Z Axis By Z Speed
      paticle[loop].z+=paticle[loop].zi/(slowdown*1000);       //add gravity or resistance : acceleration
      paticle[loop].xi += paticle[loop].xg;
      paticle[loop].yi += paticle[loop].yg;
      paticle[loop].zi += paticle[loop].zg;      //decrease particles' life
      paticle[loop].life -= paticle[loop].fade;      //if particle is dead,rejuvenate it
      if (paticle[loop].life < 0.0f)
      {
        paticle[loop].life = 1.0f;//alive again
        paticle[loop].fade = float(rand() % 100) / 1000.0f + 0.003f;        //reset its position
        paticle[loop].x = 0.0f;
        paticle[loop].y = 0.0f;
        paticle[loop].z = 0.0f;        //X Axis Speed And Direction
        paticle[loop].xi=xspeed+float((rand()%60)-32.0f);
        // Y Axis Speed And Direction
        paticle[loop].yi=yspeed+float((rand()%60)-30.0f);
        // Z Axis Speed And Direction
        paticle[loop].zi=float((rand()%60)-30.0f);         paticle[loop].r=colors[col][0];            // Select Red From Color Table
        paticle[loop].g=colors[col][1];            // Select Green From Color Table
        paticle[loop].b=colors[col][2];            // Select Blue From Color Table
      }
    }
  }  glutSwapBuffers();
}void keyboard(unsigned char key,int x,int y)
{
  switch(key)
  {
  case 'y':
    gkeys['y'] = true;
    break;
  case 'c':
    ++col;
    if (col >= 12)
    {
      col -= 12;
    }
    glutPostRedisplay();
    break;
  case 'l':
    slowdown += 0.3;
    glutPostRedisplay();
    break;
  case 'h':
    slowdown += 0.3;
    glutPostRedisplay();
    break;
  default:
    break;
  }
}int main(int argc,char** argv)
{
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(400,400);
  glutInitWindowPosition(100,100);
  glutCreateWindow("Particle");
  init();
  glutDisplayFunc(display);
  glutIdleFunc(display);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(keyboard);
  glutMainLoop();
  return 0;
}

OpenGL粒子系统详解及编程实现相关推荐

  1. Android openGl开发详解(二)

    https://zhuanlan.zhihu.com/p/35192609 Android openGl开发详解(二)--通过SurfaceView,TextureView,GlSurfaceView ...

  2. [转]Hadoop集群_WordCount运行详解--MapReduce编程模型

    Hadoop集群_WordCount运行详解--MapReduce编程模型 下面这篇文章写得非常好,有利于初学mapreduce的入门 http://www.nosqldb.cn/1369099810 ...

  3. OpenGL纹理详解

    OpenGL纹理详解 现实生活中,纹理最通常的作用是装饰我们的物体模型,它就像是贴纸一样贴在物体表面,使得物体表面拥有图案.但实际上在OpenGL中,纹理的作用不仅限于此,它可以用来存储大量的数据,一 ...

  4. Android openGl开发详解(二)——通过SurfaceView,TextureView,GlSurfaceView显示相机预览(附Demo)

    最近公司在做自定义相机这一块,之前使用的是第三方,后来需求变更,第三方不支持添加动态贴纸,所以只能自己扩展.当然网上有很多例子,但是关于添加动态贴纸的例子几乎找不到,反正我是没找到(欲哭无泪).当然, ...

  5. 90分钟详解网络编程相关的细节处理丨 reactor丨网络io丨epoll丨C/C++丨Linux服务器开发丨后端开发丨Linux后台开发

    90分钟搞懂网络编程相关细节处理 1. 网络编程四要素 2. io多路复用 3. reactor三种基础封装方式 视频讲解如下,点击观看: 90分钟详解网络编程相关的细节处理丨 reactor丨网络i ...

  6. python神经网络算法pdf_Python与机器学习实战 决策树、集成学习、支持向量机与神经网络算法详解及编程实现.pdf...

    作 者 :何宇健 出版发行 : 北京:电子工业出版社 , 2017.06 ISBN号 :978-7-121-31720-0 页 数 : 315 原书定价 : 69.00 主题词 : 软件工具-程序设计 ...

  7. opengl 深度详解_一步步学OpenGL(1) -《打开一个窗口》

    注意本教程中需要使用的是freeGLUT(GLUT太老会有潜在危险)窗口库和GLEW扩展库. vs2013配置freeGLUT3.0:vs2013 配置 freeglut3.0(opengl的窗口系统 ...

  8. 【OpenGL】详解第一个OpenGL程序

    写在前面 OpenGL能做的事情太多了!很多程序也看起来很复杂.很多人感觉OpenGL晦涩难懂,原因大多是被OpenGL里面各种语句搞得头大,一会gen一下,一会bind一下,一会又active一下. ...

  9. opengl 深度详解_一步步学OpenGL(23) -《阴影贴图1》

    教程 23 阴影贴图1 原文: http://ogldev.atspace.co.uk/www/tutorial23/tutorial23.html CSDN完整版专栏: https://blog.c ...

最新文章

  1. Eclipse下配置主题颜色
  2. libevent简介和使用【转】
  3. bzoj千题计划161:bzoj1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果
  4. Django框架(3.django设计模型类、模型类生成表、ORM框架简介)
  5. linux vim verilog,vim下好用的verilog插件:)( 更新) - [IC]
  6. 基于 HTML5 Canvas 绘制的电信网络拓扑图
  7. leetcode 53. 最大子序和 动态规划解法、贪心法以及二分法
  8. 前端学习(705):do-while
  9. (二)原生JS实现 - 事件类方法
  10. 南洋oj 题目144小珂的苦恼
  11. 安卓nfs网络文件服务器,Linux网络文件服务器 NFS
  12. 经过多次试验后第一个成功地实现 HTTPService 与 MXML 之间传递数据,ArrayCollection 与DataGrid 之间成功绑定...
  13. 时序轮转的意思_《九州仙魔志》-烛龙:凡人的昼夜轮转,都在它眼睛开合之间...
  14. A_A03_001 stc-isp 单片机烧录软件安装与使用
  15. arccatalog点要素显示不完_改变人际关系核心要素,不讨好不献媚,牢记这3点,受益一生...
  16. discuz发帖流程_C#代码、流程discuz论坛批量或自动发帖
  17. ios 振动棒软件_iOS 14很棒
  18. 好书分享--生命3.0 人工智能时代人类的进化与重生
  19. 【论文泛读76】将来自bert的提取信息和多种嵌入方法与深度神经网络集成在一起,以进行幽默检测
  20. Makefile的常见错误信息

热门文章

  1. springboot毕设项目电子导游系统7rj3e(java+VUE+Mybatis+Maven+Mysql)
  2. 想你是一种说不出的痛
  3. RabbitMQ问题系列:(一)
  4. 微语录(2011-02-21---2011-02-27)
  5. Nodejs AES加密
  6. 前端:你要懂的单页面应用和多页面应用
  7. ChatGPT 余额查询接口
  8. 金马赛记 | 畅跑一场马拉松,纪念一段青葱岁月
  9. win7计算机属性资源管理器停止工作,win7资源管理器停止工作,手把手教你Win7资源管理器已停止工作怎么解决...
  10. PDU配电单元推荐——同为科技(TOWE)自接线工程安全机柜PDU