http://blog.csdn.net/qp120291570/article/details/8373896
一、提要
有一款例子特效軟件叫做particle illution,在影視后期和游戲制作領(lǐng)域都可以用到,相信很多人都接觸過,今天我們用SDL+OpenGL來實現(xiàn)例子效果。
確保你搞定了物理模擬的代碼!
代碼下載
二、原理簡介
所謂的例子系統(tǒng),就是同時控制一大堆類似的對象,這些對象可能是形體,可能是圖片,有著不同的特征(壽命,速度,位置)。有了之前的基礎(chǔ),我們可以很輕易地搞定今天的東西。
三、代碼清單
首先是粒子的頭文件,我直接寫成結(jié)構(gòu)體了,里面有一些基本的屬性。
- /*****************************************************************************
- Copyright: 2012, ustc All rights reserved.
- contact:k283228391@126.com
- File name: particle.h
- Description:Partical in opengl.
- Author:Silang Quan
- Version: 1.0
- Date: 2012.12.20
- *****************************************************************************/
- #ifndef PARTICLE_H
- #define PARTICLE_H
- #include "vector3d.h"
- typedef struct
- {
- float r;
- float g;
- float b;
- float alpha;
- }Color;
-
- typedef struct
- {
- Vector3D position;
- Vector3D velocity;
- Vector3D acceleration;
- Color color;
- float age;
- float life;
- float size;
- }Particle;
-
- #endif // PARTICLE_H
/***************************************************************************** Copyright: 2012, ustc All rights reserved. contact:k283228391@126.com Description:Partical in opengl. *****************************************************************************/
我們用球體來模擬例子,所以size表示的就是球體的半徑。
接下來是粒子系統(tǒng)類(類名拼寫錯了*-*)
- /*****************************************************************************
- Copyright: 2012, ustc All rights reserved.
- contact:k283228391@126.com
- File name: particalsystem.h
- Description:Partical in opengl.
- Author:Silang Quan
- Version: 1.0
- Date: 2012.12.20
- *****************************************************************************/
-
- #ifndef PARTICALSYSTEM_H
- #define PARTICALSYSTEM_H
- #include <vector>
- #include <math.h>
- #include <time.h>
- #include <stdlib.h>
- #include <iostream>
- #include <GL/gl.h>
- #include <GL/glu.h>
- #include "particle.h"
- #define PI 3.1415926
- using namespace std;
- class ParticalSystem
- {
- public:
- ParticalSystem();
- ParticalSystem(int _count,float _gravity){ptlCount=_count;gravity=_gravity;};
- void init();
- void simulate(float dt);
- void aging(float dt);
- void applyGravity();
- void kinematics(float dt);
- void render();
- virtual ~ParticalSystem();
- protected:
- private:
- int ptlCount;
- float gravity;
- GLUquadricObj *mySphere;
- vector<Particle> particles;
- };
-
- #endif // PARTICALSYSTEM_H
/***************************************************************************** Copyright: 2012, ustc All rights reserved. contact:k283228391@126.com File name: particalsystem.h Description:Partical in opengl. *****************************************************************************/ ParticalSystem(int _count,float _gravity){ptlCount=_count;gravity=_gravity;}; void kinematics(float dt); virtual ~ParticalSystem(); vector<Particle> particles; #endif // PARTICALSYSTEM_H
解釋一下幾個重要函數(shù):
init:做一些例子系統(tǒng)的初始化工作;
aging:計算粒子的年齡;
applyGravity:向粒子施加重力;
kinematics:這個單詞的意思是運動學,所以就是負責管理粒子的加速,位移;
simulate:例子模擬的總負責函數(shù);
render:渲染粒子;
然后來看函數(shù)是怎么實現(xiàn)的:
- /*****************************************************************************
- Copyright: 2012, ustc All rights reserved.
- contact:k283228391@126.com
- File name: particalsystem.Cpp
- Description:Partical in opengl.
- Author:Silang Quan
- Version: 1.0
- Date: 2012.12.22
- *****************************************************************************/
-
- #include "particalsystem.h"
-
- ParticalSystem::ParticalSystem()
- {
- //ctor
- }
-
- ParticalSystem::~ParticalSystem()
- {
- //dtor
- }
-
- void ParticalSystem::init()
- {
- int i;
- srand(unsigned(time(0)));
- Color colors[3]={{0,0,1,1},{1,0,1,1}};
- for(i=0;i<ptlCount;i++)
- {
- //theta =(rand()%361)/360.0* 2*PI;
- 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};
- particles.push_back(tmp);
- }
- mySphere=gluNewQuadric();
- }
- void ParticalSystem::simulate(float dt)
- {
- aging(dt);
- applyGravity();
- kinematics(dt);
- }
- void ParticalSystem::aging(float dt)
- {
- for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
- {
- iter->age+=dt;
- if(iter->age>iter->life)
- {
- iter->position=Vector3D(0,0,0);
- iter->age=0.0;
- iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f));
- }
- }
- }
- void ParticalSystem::applyGravity()
- {
- for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
- iter->acceleration=Vector3D(0,gravity,0);
- }
-
- void ParticalSystem::kinematics(float dt)
- {
- for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
- {
- iter->position = iter->position+iter->velocity*dt;
- iter->velocity = iter->velocity+iter->acceleration*dt;
- }
- }
- void ParticalSystem::render()
- {
-
- for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
- {
- float alpha = 1 - iter->age / iter->life;//calculate the alpha value according to the age of particle.
- Vector3D tmp=iter->position;
- glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha);
- glPushMatrix();
- glTranslatef(tmp.x,tmp.y,tmp.z);
- gluSphere(mySphere,iter->size, 32, 16);
- glPopMatrix();
- }
-
- }
/***************************************************************************** Copyright: 2012, ustc All rights reserved. contact:k283228391@126.com File name: particalsystem.Cpp Description:Partical in opengl. *****************************************************************************/ #include "particalsystem.h" ParticalSystem::ParticalSystem() ParticalSystem::~ParticalSystem() void ParticalSystem::init() srand(unsigned(time(0))); Color colors[3]={{0,0,1,1},{1,0,1,1}}; //theta =(rand()%361)/360.0* 2*PI; 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}; particles.push_back(tmp); mySphere=gluNewQuadric(); void ParticalSystem::simulate(float dt) void ParticalSystem::aging(float dt) for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++) iter->position=Vector3D(0,0,0); iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f)); void ParticalSystem::applyGravity() for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++) iter->acceleration=Vector3D(0,gravity,0); void ParticalSystem::kinematics(float dt) for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++) iter->position = iter->position+iter->velocity*dt; iter->velocity = iter->velocity+iter->acceleration*dt; void ParticalSystem::render() for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++) float alpha = 1 - iter->age / iter->life;//calculate the alpha value according to the age of particle. Vector3D tmp=iter->position; glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha); glTranslatef(tmp.x,tmp.y,tmp.z); gluSphere(mySphere,iter->size, 32, 16);
實現(xiàn)還是比較簡單的,下面渲染看一下^^.
首先要在initGL函數(shù)中添加兩句話:
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
這樣透明度才會有效。
接著初始化一個例子系統(tǒng),并對例子進行初始化:
ParticalSystem ps;
- 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;
- }
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;
}
然后是渲染函數(shù):
- void renderGL()
- {
- // Clear the color and depth buffers.
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
- // We don't want to modify the projection matrix. */
- glMatrixMode( GL_MODELVIEW );
- glLoadIdentity( );
- // Move down the z-axis.
- glTranslatef(0.0f,0.0f,-35.0f);
- ps.render();
- SDL_GL_SwapBuffers( );
- }
// Clear the color and depth buffers. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); // We don't want to modify the projection matrix. */ glMatrixMode( GL_MODELVIEW ); glTranslatef(0.0f,0.0f,-35.0f);
跑一下:

效果還是不錯的~下面我們來實現(xiàn)一些更棒的效果!
四、動態(tài)模糊和碰撞檢測
動態(tài)模糊的實現(xiàn)比較簡單,主循環(huán)不再每次把整個畫面清空,而是每幀畫一個半透明的黑色長方形,就可以模擬動態(tài)模糊(motion blur)的效果。
將之前的
- // Clear the color and depth buffers.
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
// Clear the color and depth buffers. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
改成
- // Clear the depth buffers.
- glClear(GL_DEPTH_BUFFER_BIT );
// Clear the depth buffers. glClear(GL_DEPTH_BUFFER_BIT );
然后在例子系統(tǒng)的render函數(shù)中添加畫矩形的代碼:
- void ParticalSystem::render()
- {
-
- for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
- {
- float alpha = 1 - iter->age / iter->life;
- Vector3D tmp=iter->position;
- glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha);
- //glColor4f(1.0f, 1.0f, 1.0f, 0.1);
- glPushMatrix();
- glTranslatef(tmp.x,tmp.y,tmp.z);
- gluSphere(mySphere,iter->size, 32, 16);
- glPopMatrix();
- }
-
- //Motion blue
- glColor4f(0.0f,0.0f,0.0f,0.1);
- glBegin(GL_QUADS);
- glVertex3f(-20.0f , -20.0f , 20.0f );
- glVertex3f( 20.0f , -20.0f , 20.0f );
- glVertex3f( 20.0f , 20.0f , 20.0f );
- glVertex3f(-20.0f , 20.0f , 20.0f );
- glEnd();
-
- }
void ParticalSystem::render() for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++) float alpha = 1 - iter->age / iter->life; Vector3D tmp=iter->position; glColor4f(iter->color.r,iter->color.g,iter->color.b,alpha); //glColor4f(1.0f, 1.0f, 1.0f, 0.1); glTranslatef(tmp.x,tmp.y,tmp.z); gluSphere(mySphere,iter->size, 32, 16); glColor4f(0.0f,0.0f,0.0f,0.1); glVertex3f(-20.0f , -20.0f , 20.0f ); glVertex3f( 20.0f , -20.0f , 20.0f ); glVertex3f( 20.0f , 20.0f , 20.0f ); glVertex3f(-20.0f , 20.0f , 20.0f );
渲染一下:

效果還不錯!
碰撞檢測之前也實現(xiàn)過,在粒子系統(tǒng)里面加檢測函數(shù)就Ok了.
- void ParticalSystem::checkBump(float x1,float x2,float y1,float y2)
- {
- for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
- {
- if (iter->position.x - iter->size < x1 || iter->position.x +iter->size > x2) iter->velocity.x = -iter->velocity.x;
- if (iter->position.y - iter->size < y1 || iter->position.y + iter->size > y2) iter->velocity.y = -iter->velocity.y;
- }
- }
void ParticalSystem::checkBump(float x1,float x2,float y1,float y2) for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++) if (iter->position.x - iter->size < x1 || iter->position.x +iter->size > x2) iter->velocity.x = -iter->velocity.x; if (iter->position.y - iter->size < y1 || iter->position.y + iter->size > y2) iter->velocity.y = -iter->velocity.y;
由于我們的粒子是在空間運動,運行之后我們就可以看到粒子沿著空間的各個方向運動,我們在沿Z軸方向添加了一個“盒子”,撞到盒子則速度做相應(yīng)的變化。


五、交互發(fā)射
這個其實是opengl之外的東西了。我們要用的是SDL的獲取鼠標信息函數(shù):SDL_GetMouseState(&posX, &posY);
作用就是獲取當前鼠標的位置。
接下來還要做的一件事是寫坐標變換函數(shù)。因為opengl的坐標個SDL窗口的坐標并不是重合的,我們要將鼠標的當前坐標映射到OpenGL的坐標上去。
- float posTransX(int posX)
- {
- return (posX-400)/20.0;
-
- }
- float posTransY(int posY)
- {
- return (400-posY)/20.0;
- }
float posTransX(int posX) float posTransY(int posY)
因為我的窗口是800*800的,然后根據(jù)當前視口的位置,轉(zhuǎn)換函數(shù)就想上面那樣。
坐后要修改一下粒子的simulate函數(shù)。當粒子死亡的時候,他的初始位置設(shè)置為鼠標當前的位置。
- void ParticalSystem::aging(float dt,float posX,float posY)
- {
- for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++)
- {
- iter->age+=dt;
- if(iter->age>iter->life)
- {
- iter->position=Vector3D(posX,posY,0);
- iter->age=0.0;
- iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f));
- }
- }
- }
void ParticalSystem::aging(float dt,float posX,float posY) for(vector<Particle>::iterator iter=particles.begin();iter!=particles.end();iter++) iter->position=Vector3D(posX,posY,0); iter->velocity=Vector3D(((rand()%30)-15.0f),((rand()%30)-11.0f),((rand()%30)-15.0f));
效果就像這樣:


六、參考
nehe的opengl教程
|