分享

OpenGL进阶(六) 粒子系统...

 oskycar 2021-07-06

http://blog.csdn.net/qp120291570/article/details/8373896

一、提要

       有一款例子特效软件叫做particle illution,在影视后期和游戏制作领域都可以用到,相信很多人都接触过,今天我们用SDL+OpenGL来实现例子效果。

确保你搞定了物理模拟的代码!

   代码下载

二、原理简介

     所谓的例子系统,就是同时控制一大堆类似的对象,这些对象可能是形体,可能是图片,有着不同的特征(寿命,速度,位置)。有了之前的基础,我们可以很轻易地搞定今天的东西。

三、代码清单

首先是粒子的头文件,我直接写成结构体了,里面有一些基本的属性。

  1. /***************************************************************************** 
  2. Copyright: 2012, ustc All rights reserved. 
  3. contact:k283228391@126.com 
  4. File name: particle.h 
  5. Description:Partical in opengl. 
  6. Author:Silang Quan 
  7. Version: 1.0 
  8. Date: 2012.12.20 
  9.  *****************************************************************************/  
  10. #ifndef PARTICLE_H  
  11. #define PARTICLE_H  
  12. #include "vector3d.h"  
  13. typedef struct  
  14. {  
  15.     float r;  
  16.     float g;  
  17.     float b;  
  18.     float alpha;  
  19. }Color;  
  20.   
  21. typedef struct  
  22. {  
  23.     Vector3D position;  
  24.     Vector3D velocity;  
  25.     Vector3D acceleration;  
  26.     Color color;  
  27.     float age;  
  28.     float life;  
  29.     float size;  
  30. }Particle;  
  31.   
  32. #endif // PARTICLE_H  
  1. /*****************************************************************************
  2. Copyright: 2012, ustc All rights reserved.
  3. contact:k283228391@126.com
  4. File name: particle.h
  5. Description:Partical in opengl.
  6. Author:Silang Quan
  7. Version: 1.0
  8. Date: 2012.12.20
  9. *****************************************************************************/
  10. #ifndef PARTICLE_H
  11. #define PARTICLE_H
  12. #include "vector3d.h"
  13. typedef struct
  14. {
  15. float r;
  16. float g;
  17. float b;
  18. float alpha;
  19. }Color;
  20. typedef struct
  21. {
  22. Vector3D position;
  23. Vector3D velocity;
  24. Vector3D acceleration;
  25. Color color;
  26. float age;
  27. float life;
  28. float size;
  29. }Particle;
  30. #endif // PARTICLE_H

我们用球体来模拟例子,所以size表示的就是球体的半径。

接下来是粒子系统类(类名拼写错了*-*)

  1. /***************************************************************************** 
  2. Copyright: 2012, ustc All rights reserved. 
  3. contact:k283228391@126.com 
  4. File name: particalsystem.h 
  5. Description:Partical in opengl. 
  6. Author:Silang Quan 
  7. Version: 1.0 
  8. Date: 2012.12.20 
  9.  *****************************************************************************/  
  10.   
  11. #ifndef PARTICALSYSTEM_H  
  12. #define PARTICALSYSTEM_H  
  13. #include <vector>  
  14. #include <math.h>  
  15. #include <time.h>  
  16. #include <stdlib.h>  
  17. #include <iostream>  
  18. #include <GL/gl.h>  
  19. #include <GL/glu.h>  
  20. #include "particle.h"  
  21. #define PI 3.1415926  
  22. using namespace std;  
  23. class ParticalSystem  
  24. {  
  25.     public:  
  26.         ParticalSystem();  
  27.         ParticalSystem(int _count,float _gravity){ptlCount=_count;gravity=_gravity;};  
  28.         void init();  
  29.         void simulate(float dt);  
  30.         void aging(float dt);  
  31.         void applyGravity();  
  32.         void kinematics(float dt);  
  33.         void render();  
  34.         virtual ~ParticalSystem();  
  35.     protected:  
  36.     private:  
  37.     int ptlCount;  
  38.     float gravity;  
  39.     GLUquadricObj *mySphere;  
  40.     vector<Particle> particles;  
  41. };  
  42.   
  43. #endif // PARTICALSYSTEM_H  
  1. /*****************************************************************************
  2. Copyright: 2012, ustc All rights reserved.
  3. contact:k283228391@126.com
  4. File name: particalsystem.h
  5. Description:Partical in opengl.
  6. Author:Silang Quan
  7. Version: 1.0
  8. Date: 2012.12.20
  9. *****************************************************************************/
  10. #ifndef PARTICALSYSTEM_H
  11. #define PARTICALSYSTEM_H
  12. #include <vector>
  13. #include <math.h>
  14. #include <time.h>
  15. #include <stdlib.h>
  16. #include <iostream>
  17. #include <GL/gl.h>
  18. #include <GL/glu.h>
  19. #include "particle.h"
  20. #define PI 3.1415926
  21. using namespace std;
  22. class ParticalSystem
  23. {
  24. public:
  25. ParticalSystem();
  26. ParticalSystem(int _count,float _gravity){ptlCount=_count;gravity=_gravity;};
  27. void init();
  28. void simulate(float dt);
  29. void aging(float dt);
  30. void applyGravity();
  31. void kinematics(float dt);
  32. void render();
  33. virtual ~ParticalSystem();
  34. protected:
  35. private:
  36. int ptlCount;
  37. float gravity;
  38. GLUquadricObj *mySphere;
  39. vector<Particle> particles;
  40. };
  41. #endif // PARTICALSYSTEM_H

解释一下几个重要函数:

init:做一些例子系统的初始化工作;

aging:计算粒子的年龄;

applyGravity:向粒子施加重力;

kinematics:这个单词的意思是运动学,所以就是负责管理粒子的加速,位移;

simulate:例子模拟的总负责函数;

render:渲染粒子;

然后来看函数是怎么实现的:

  1. /***************************************************************************** 
  2. Copyright: 2012, ustc All rights reserved. 
  3. contact:k283228391@126.com 
  4. File name: particalsystem.Cpp 
  5. Description:Partical in opengl. 
  6. Author:Silang Quan 
  7. Version: 1.0 
  8. Date: 2012.12.22 
  9.  *****************************************************************************/  
  10.   
  11. #include "particalsystem.h"  
  12.   
  13. ParticalSystem::ParticalSystem()  
  14. {  
  15.     //ctor  
  16. }  
  17.   
  18. ParticalSystem::~ParticalSystem()  
  19. {  
  20.     //dtor  
  21. }  
  22.   
  23. void ParticalSystem::init()  
  24. {  
  25.     int i;  
  26.     srand(unsigned(time(0)));  
  27.     Color colors[3]={{0,0,1,1},{1,0,1,1}};  
  28.     for(i=0;i<ptlCount;i++)  
  29.     {  
  30.         //theta =(rand()%361)/360.0* 2*PI;  
  31.         Particle tmp={Vector3D(0,0,0),Vector3D(((rand()%50)-26.0f),((rand()%50)-26.0f),((rand()%50)-26.0f)),Vector3D(0,0,0),colors[rand()%2],0.0f,0.5+0.05*(rand()%10),0.3f};  
  32.         particles.push_back(tmp);  
  33.     }  
  34.     mySphere=gluNewQuadric();  
  35. }  
  36. void ParticalSystem::simulate(float dt)  
  37. {  
  38.     aging(dt);  
  39.     applyGravity();  
  40.     kinematics(dt);  
  41. }  
  42. void ParticalSystem::aging(float dt)  
  43. {  
  44.     for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)  
  45.     {  
  46.         iter->age+=dt;  
  47.         if(iter->age>iter->life)  
  48.         {  
  49.             iter->position=Vector3D(0,0,0);  
  50.             iter->age=0.0;  
  51.             iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f));  
  52.         }  
  53.     }  
  54. }  
  55. void ParticalSystem::applyGravity()  
  56. {  
  57.     for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)  
  58.             iter->acceleration=Vector3D(0,gravity,0);  
  59. }  
  60.   
  61. void ParticalSystem::kinematics(float dt)  
  62. {  
  63.     for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)  
  64.     {  
  65.         iter->position = iter->position+iter->velocity*dt;  
  66.         iter->velocity = iter->velocity+iter->acceleration*dt;  
  67.     }  
  68. }  
  69. void ParticalSystem::render()  
  70. {  
  71.   
  72.     for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)  
  73.     {  
  74.         float alpha = 1 - iter->age / iter->life;//calculate the alpha value according to the age of particle.  
  75.         Vector3D tmp=iter->position;  
  76.         glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha);  
  77.         glPushMatrix();  
  78.         glTranslatef(tmp.x,tmp.y,tmp.z);  
  79.         gluSphere(mySphere,iter->size, 32, 16);  
  80.         glPopMatrix();  
  81.     }  
  82.   
  83. }  
  1. /*****************************************************************************
  2. Copyright: 2012, ustc All rights reserved.
  3. contact:k283228391@126.com
  4. File name: particalsystem.Cpp
  5. Description:Partical in opengl.
  6. Author:Silang Quan
  7. Version: 1.0
  8. Date: 2012.12.22
  9. *****************************************************************************/
  10. #include "particalsystem.h"
  11. ParticalSystem::ParticalSystem()
  12. {
  13. //ctor
  14. }
  15. ParticalSystem::~ParticalSystem()
  16. {
  17. //dtor
  18. }
  19. void ParticalSystem::init()
  20. {
  21. int i;
  22. srand(unsigned(time(0)));
  23. Color colors[3]={{0,0,1,1},{1,0,1,1}};
  24. for(i=0;i<ptlCount;i++)
  25. {
  26. //theta =(rand()%361)/360.0* 2*PI;
  27. Particle tmp={Vector3D(0,0,0),Vector3D(((rand()%50)-26.0f),((rand()%50)-26.0f),((rand()%50)-26.0f)),Vector3D(0,0,0),colors[rand()%2],0.0f,0.5+0.05*(rand()%10),0.3f};
  28. particles.push_back(tmp);
  29. }
  30. mySphere=gluNewQuadric();
  31. }
  32. void ParticalSystem::simulate(float dt)
  33. {
  34. aging(dt);
  35. applyGravity();
  36. kinematics(dt);
  37. }
  38. void ParticalSystem::aging(float dt)
  39. {
  40. for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
  41. {
  42. iter->age+=dt;
  43. if(iter->age>iter->life)
  44. {
  45. iter->position=Vector3D(0,0,0);
  46. iter->age=0.0;
  47. iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f));
  48. }
  49. }
  50. }
  51. void ParticalSystem::applyGravity()
  52. {
  53. for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
  54. iter->acceleration=Vector3D(0,gravity,0);
  55. }
  56. void ParticalSystem::kinematics(float dt)
  57. {
  58. for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
  59. {
  60. iter->position = iter->position+iter->velocity*dt;
  61. iter->velocity = iter->velocity+iter->acceleration*dt;
  62. }
  63. }
  64. void ParticalSystem::render()
  65. {
  66. for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
  67. {
  68. float alpha = 1 - iter->age / iter->life;//calculate the alpha value according to the age of particle.
  69. Vector3D tmp=iter->position;
  70. glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha);
  71. glPushMatrix();
  72. glTranslatef(tmp.x,tmp.y,tmp.z);
  73. gluSphere(mySphere,iter->size, 32, 16);
  74. glPopMatrix();
  75. }
  76. }

实现还是比较简单的,下面渲染看一下^^.

首先要在initGL函数中添加两句话:

  1. glEnable(GL_BLEND);  
  2. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  
  1. glEnable(GL_BLEND);
  2. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

这样透明度才会有效。

接着初始化一个例子系统,并对例子进行初始化:

  1. ParticalSystem ps;  
ParticalSystem ps;


  1. int main( int argc, char* argv[] )  
  2. {  
  3.     // Color depth in bits of our window.  
  4.     int flags= SDL_OPENGL|SDL_RESIZABLE;  
  5.     //Set the SDL  
  6.     initSDL(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,flags);  
  7.     //Set the OpenGL  
  8.     initGL(SCREEN_WIDTH, SCREEN_HEIGHT );  
  9.     ps=ParticalSystem(100,-15.0);  
  10.     ps.init();  
  11.     //main loop  
  12.     while(true)  
  13.     {  
  14.         /* Process incoming events. */  
  15.         handleEvents( );  
  16.         ps.simulate(0.01);  
  17.         /* Draw the screen. */  
  18.         renderGL( );  
  19.     }  
  20.     return 0;  
  21. }  
int main( int argc, char* argv[] )
{
// Color depth in bits of our window.
int flags= SDL_OPENGL|SDL_RESIZABLE;
//Set the SDL
initSDL(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,flags);
//Set the OpenGL
initGL(SCREEN_WIDTH, SCREEN_HEIGHT );
    ps=ParticalSystem(100,-15.0);
    ps.init();
//main loop
while(true)
{
/* Process incoming events. */
handleEvents( );
ps.simulate(0.01);
/* Draw the screen. */
renderGL( );
}
return 0;
}


然后是渲染函数:

  1. void renderGL()  
  2. {  
  3.     // Clear the color and depth buffers.  
  4.     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );  
  5.     // We don't want to modify the projection matrix. */  
  6.     glMatrixMode( GL_MODELVIEW );  
  7.     glLoadIdentity( );  
  8.     // Move down the z-axis.  
  9.     glTranslatef(0.0f,0.0f,-35.0f);  
  10.     ps.render();  
  11.     SDL_GL_SwapBuffers( );  
  12. }  
  1. void renderGL()
  2. {
  3. // Clear the color and depth buffers.
  4. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
  5. // We don't want to modify the projection matrix. */
  6. glMatrixMode( GL_MODELVIEW );
  7. glLoadIdentity( );
  8. // Move down the z-axis.
  9. glTranslatef(0.0f,0.0f,-35.0f);
  10. ps.render();
  11. SDL_GL_SwapBuffers( );
  12. }

跑一下:


效果还是不错的~下面我们来实现一些更棒的效果!

四、动态模糊和碰撞检测

动态模糊的实现比较简单,主循环不再每次把整个画面清空,而是每帧画一个半透明的黑色长方形,就可以模拟动态模糊(motion blur)的效果。

将之前的

  1. // Clear the color and depth buffers.  
  2. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );  
  1. // Clear the color and depth buffers.
  2. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );

改成
  1. // Clear the depth buffers.  
  2. glClear(GL_DEPTH_BUFFER_BIT );  
  1. // Clear the depth buffers.
  2. glClear(GL_DEPTH_BUFFER_BIT );

然后在例子系统的render函数中添加画矩形的代码:
  1. void ParticalSystem::render()  
  2. {  
  3.   
  4.     for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)  
  5.     {  
  6.         float alpha = 1 - iter->age / iter->life;  
  7.         Vector3D tmp=iter->position;  
  8.         glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha);  
  9.         //glColor4f(1.0f, 1.0f, 1.0f, 0.1);  
  10.         glPushMatrix();  
  11.         glTranslatef(tmp.x,tmp.y,tmp.z);  
  12.         gluSphere(mySphere,iter->size, 32, 16);  
  13.         glPopMatrix();  
  14.     }  
  15.       
  16.     //Motion blue  
  17.     glColor4f(0.0f,0.0f,0.0f,0.1);  
  18.     glBegin(GL_QUADS);  
  19.     glVertex3f(-20.0f  , -20.0f  ,  20.0f  );  
  20.     glVertex3f( 20.0f  , -20.0f  ,  20.0f  );  
  21.     glVertex3f( 20.0f  ,  20.0f  ,  20.0f  );  
  22.     glVertex3f(-20.0f  ,  20.0f  ,  20.0f  );  
  23.     glEnd();  
  24.       
  25. }  
  1. void ParticalSystem::render()
  2. {
  3. for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
  4. {
  5. float alpha = 1 - iter->age / iter->life;
  6. Vector3D tmp=iter->position;
  7. glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha);
  8. //glColor4f(1.0f, 1.0f, 1.0f, 0.1);
  9. glPushMatrix();
  10. glTranslatef(tmp.x,tmp.y,tmp.z);
  11. gluSphere(mySphere,iter->size, 32, 16);
  12. glPopMatrix();
  13. }
  14. //Motion blue
  15. glColor4f(0.0f,0.0f,0.0f,0.1);
  16. glBegin(GL_QUADS);
  17. glVertex3f(-20.0f , -20.0f , 20.0f );
  18. glVertex3f( 20.0f , -20.0f , 20.0f );
  19. glVertex3f( 20.0f , 20.0f , 20.0f );
  20. glVertex3f(-20.0f , 20.0f , 20.0f );
  21. glEnd();
  22. }

渲染一下:


效果还不错!

碰撞检测之前也实现过,在粒子系统里面加检测函数就Ok了.

  1. void ParticalSystem::checkBump(float x1,float x2,float y1,float y2)  
  2. {  
  3.     for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)  
  4.         {  
  5.             if (iter->position.x - iter->size < x1 || iter->position.x +iter->size > x2) iter->velocity.x = -iter->velocity.x;  
  6.             if (iter->position.y - iter->size < y1 || iter->position.y + iter->size > y2) iter->velocity.y = -iter->velocity.y;  
  7.         }  
  8. }  
  1. void ParticalSystem::checkBump(float x1,float x2,float y1,float y2)
  2. {
  3. for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
  4. {
  5. if (iter->position.x - iter->size < x1 || iter->position.x +iter->size > x2) iter->velocity.x = -iter->velocity.x;
  6. if (iter->position.y - iter->size < y1 || iter->position.y + iter->size > y2) iter->velocity.y = -iter->velocity.y;
  7. }
  8. }

由于我们的粒子是在空间运动,运行之后我们就可以看到粒子沿着空间的各个方向运动,我们在沿Z轴方向添加了一个“盒子”,撞到盒子则速度做相应的变化。



五、交互发射

这个其实是opengl之外的东西了。我们要用的是SDL的获取鼠标信息函数:SDL_GetMouseState(&posX, &posY);

作用就是获取当前鼠标的位置。

接下来还要做的一件事是写坐标变换函数。因为opengl的坐标个SDL窗口的坐标并不是重合的,我们要将鼠标的当前坐标映射到OpenGL的坐标上去。

  1. float posTransX(int posX)  
  2. {  
  3.     return (posX-400)/20.0;  
  4.   
  5. }  
  6. float posTransY(int posY)  
  7. {  
  8.     return (400-posY)/20.0;  
  9. }  
  1. float posTransX(int posX)
  2. {
  3. return (posX-400)/20.0;
  4. }
  5. float posTransY(int posY)
  6. {
  7. return (400-posY)/20.0;
  8. }

因为我的窗口是800*800的,然后根据当前视口的位置,转换函数就想上面那样。

坐后要修改一下粒子的simulate函数。当粒子死亡的时候,他的初始位置设置为鼠标当前的位置。

  1. void ParticalSystem::aging(float dt,float posX,float posY)  
  2. {  
  3.     for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)  
  4.     {  
  5.         iter->age+=dt;  
  6.         if(iter->age>iter->life)  
  7.         {  
  8.             iter->position=Vector3D(posX,posY,0);  
  9.             iter->age=0.0;  
  10.             iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f));  
  11.         }  
  12.     }  
  13. }  
  1. void ParticalSystem::aging(float dt,float posX,float posY)
  2. {
  3. for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
  4. {
  5. iter->age+=dt;
  6. if(iter->age>iter->life)
  7. {
  8. iter->position=Vector3D(posX,posY,0);
  9. iter->age=0.0;
  10. iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f));
  11. }
  12. }
  13. }

效果就像这样:



六、参考

nehe的opengl教程

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多