OpenGL进阶(六)-粒子系统

一、提要

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

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

   代码下载

二、原理简介

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

三、代码清单

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

/*****************************************************************************
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

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


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

/*****************************************************************************
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

解释一下几个重要函数:

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

aging:计算粒子的年龄;

applyGravity:向粒子施加重力;

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

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

render:渲染粒子;

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

/*****************************************************************************
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();
    }

}

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

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

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

这样透明度才会有效。

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

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;
}


然后是渲染函数:

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

跑一下:


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


四、动态模糊和碰撞检测

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

将之前的

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

改成

// Clear the depth buffers.
glClear(GL_DEPTH_BUFFER_BIT );

然后在例子系统的render函数中添加画矩形的代码:

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

渲染一下:


效果还不错!

碰撞检测之前也实现过,在粒子系统里面加检测函数就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;
        }
}

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




五、交互发射

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

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

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

float posTransX(int posX)
{
    return (posX-400)/20.0;

}
float posTransY(int posY)
{
    return (400-posY)/20.0;
}

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

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

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

效果就像这样:






六、参考
nehe的opengl教程
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值