OpenGL--粒子系统

2023-05-16

  • 理论基础
    1,粒子系统的基本思想是用许多形状简单且赋予生命的微小粒子作为基本元素来表示物体(一般由点或很小的多边形通过纹理贴图表示),侧重于物体的总体形态和特征的动态变化。把物体定义为许多不规则,随机分布的粒子,且每个粒子均有一定的生命周期。随着时间的推移,旧的粒子不断消失(死亡),新的粒子不断加入(生长)。粒子的这种出生,成长,衰老和死亡的过程,能够较好地反映模糊物体的动态特性。因此它比起传统的帧动画,效果要更加逼真而且节省资源。但其计算量较大,不适合大范围的特效(卡),一般用于较小场景。
    2,粒子系统实现的一般步骤:一,初始化,即创建很多粒子对象同时赋予初始属性。二,循环运行,渲染粒子<–>更新粒子(如果有死亡就把其初始化为起始属性)。总的原理就是随机改变粒子的属性,然后渲染,这样循环。所谓的粒子编辑器无非就是在操作改变粒子属性罢了。

  • 实例代码
    1,雪花粒子
    资源:
    这里写图片描述snowball.bmp这里写图片描述wall.bmp

粒子类

//
//  Particle.h
//  opengl
//
//  Created by app05 on 15-5-20.
//  Copyright (c) 2015年 app05. All rights reserved.

//说明:就是根据粒子结构给其设置与得到对应属性的值(这个类只是给粒子设置属性)

#ifndef __opengl__Particle__
#define __opengl__Particle__

#include "GLTools.h"

/** 粒子结构 */
struct Particle
{
    float x,y,z;            /**< 粒子的位置 */
    unsigned int  r,g,b;    /**< 粒子的颜色 */
    float vx,vy,vz;         /**< 粒子的速度(x,y,z方向) */
    float ax,ay,az;         /**< 粒子在x,y,z上的加速度 */
    float lifetime;         /**< 粒子生命值 */
    float size;             /**< 粒子尺寸 */
    float dec;              /**< 粒子消失的速度 */
};

/** 粒子类 */
class CParticle
{
private:
    Particle*   data;               /**< 粒子指针 */
    int         numparticle;        /**< 粒子数目 */

public:
    CParticle();          /**< 构造函数 */
    ~CParticle();         /**< 析构函数 */

    /** 创建粒子数组 */
    int Create(long num);

    /** 设置和获取颜色属性 */
    int SetColor(GLint r,GLint g,GLint b);
    int SetColor(GLint index,GLint r,GLint g,GLint b);
    int GetColor(GLint index,GLint &r,GLint &g,GLint &b);

    /** 设置和获取速度属性 */
    int SetVelocity(GLfloat vx,GLfloat vy,GLfloat vz);
    int SetVelocity(GLint index,GLfloat vx,GLfloat vy,GLfloat vz);
    int GetVelocity(GLint index,GLfloat &vx,GLfloat &vy,GLfloat &vz);

    /** 设置和获取位置属性 */
    int SetPosition(GLfloat x,GLfloat y,GLfloat z);
    int SetPosition(GLint index,GLfloat x,GLfloat y,GLfloat z);
    int GetPosition(GLint index,GLfloat &x,GLfloat &y,GLfloat &z);

    /** 设置和获取加速度属性 */
    int SetAcceleration(GLfloat ax,GLfloat ay,GLfloat az);
    int SetAcceleration(GLint index,GLfloat ax,GLfloat ay,GLfloat az);
    int GetAcceletation(GLint index,GLfloat &ax,GLfloat &ay,GLfloat &az);

    /** 设置和获取尺寸属性 */
    int SetSize(GLfloat size);
    int SetSize(GLint index,GLfloat size);
    int GetSize(GLint index,GLfloat &size);

    /** 设置和获取消失速度属性 */
    int SetDec(GLfloat dec);
    int SetDec(GLint index,GLfloat dec);
    int GetDec(GLint index,GLfloat &dec);

    /** 设置和获取生命值属性 */
    int SetLifeTime(GLfloat lifetime);
    int SetLifeTime(GLint index,GLfloat lifetime);
    int GetLifeTime(GLint index,GLfloat &lifetime);

    /** 获取粒子数组地址 */
    Particle *GetParticle() {   return data;        }

    /** 获得粒子的数目 */
    int GetNumOfParticle()  {   return numparticle; }

    /** 获得粒子所有的属性 */
    int GetAll(int index,                               /**< 索引 */
               GLint &r,GLint &g,GLint &b,              /**< 粒子的颜色 */
               GLfloat &x,GLfloat &y,GLfloat &z,        /**< 位置 */
               GLfloat &vx,GLfloat &vy,GLfloat &vz, /**< 速度 */
               GLfloat &ax,GLfloat &ay,GLfloat &az, /**< 加速度 */
               GLfloat &size,                           /**< 大小 */
               GLfloat &lifetime,                       /**< 生命时间 */
               GLfloat &dec                         /**< 消失速度 */
                );

    /** 设置粒子的所有属性 */
    int SetAll(int index,                           /**< 索引 */
               GLint r,GLint g,GLint b,         /**< 粒子的颜色 */
               GLfloat x,GLfloat y,GLfloat z,       /**< 位置 */  
               GLfloat vx,GLfloat vy,GLfloat vz,    /**< 速度 */
               GLfloat ax,GLfloat ay,GLfloat az,    /**< 加速度 */
               GLfloat size,                        /**< 大小 */
               GLfloat lifetime,                    /**< 生命时间 */
               GLfloat dec                          /**< 消失速度 */
                );
};

#endif /* defined(__opengl__Particle__) */
//
//  Particle.cpp
//  opengl
//
//  Created by app05 on 15-5-20.
//  Copyright (c) 2015年 app05. All rights reserved.
//

#include "Particle.h"

/** 构造函数 */
CParticle::CParticle()
{
    data = NULL;
    numparticle = 0;

}

/** 析构函数 */
CParticle::~CParticle()
{
    delete []data;
    data = NULL;
}

/** 创建一个包含num个元素的粒子数组 */
int CParticle::Create(long num)
{
    /** 删除粒子数组 */
    if (data)
        delete []data;

    /** 创建数组 */
    if(data = new Particle[num])
    {
        memset(data,0,sizeof(Particle)*numparticle);
        numparticle = num;

        /** 返回粒子个数 */
        return numparticle;
    }
    return 0;
}


/** 设置和获取颜色Color的函数实现 */
int CParticle::SetColor(GLint r,GLint g,GLint b)
{
    for (int index=0;index<numparticle;++index)
    {
        data[index].r=r;
        data[index].g=g;
        data[index].b=b;
    }
    return true;
}

int CParticle::SetColor(GLint index,GLint r,GLint g,GLint b)
{
    if(index>=0 && index<numparticle)
    {
        data[index].r=r;
        data[index].g=g;
        data[index].b=b;
        return true;
    }
    return false;
}

int CParticle::GetColor(GLint index,GLint &r,GLint &g,GLint &b)
{
    if(index>=0 && index<numparticle)
    {
        r=data[index].r;
        g=data[index].g;
        b=data[index].b;
        return true;
    }
    return false;
}

/** 设置和获取位置Position的函数实现 */
int CParticle::SetPosition(GLfloat x,GLfloat y,GLfloat z)
{
    for(int index=0;index<numparticle;++index)
    {
        data[index].x=x;
        data[index].y=y;
        data[index].z=z;
    }
    return true;
}

int CParticle::SetPosition(GLint index,GLfloat x,GLfloat y,GLfloat z)
{
    if(index>=0 && index<numparticle)
    {
        data[index].x=x;
        data[index].y=y;
        data[index].z=z;
        return true;
    }
    return false;
}

int CParticle::GetPosition(GLint index,GLfloat &x,GLfloat &y,GLfloat &z)
{
    if(index>=0 && index<numparticle)
    {
        x=data[index].x;
        y=data[index].y;
        z=data[index].z;
        return true;
    }
    return false;
}
/** 设置和获取加速度Acceleration的函数实现 */
int CParticle::SetAcceleration(GLfloat ax,GLfloat ay,GLfloat az)
{
    for (int index=0;index<numparticle;++index)
    {
        data[index].ax=ax;
        data[index].ay=ay;
        data[index].az=az;
    }
    return true;
}

int CParticle::SetAcceleration(GLint index,GLfloat ax,GLfloat ay,GLfloat az)
{
    if(index>=0 && index<numparticle)
    {
        data[index].ax=ax;
        data[index].ay=ay;
        data[index].az=az;
        return true;
    }
    return false;
}


int CParticle::GetAcceletation(GLint index,GLfloat &ax,GLfloat &ay,GLfloat &az)
{
    if(index>=0 && index<numparticle)
    {
        ax=data[index].ax;
        ay=data[index].ay;
        az=data[index].az;
        return true;
    }
    return false;
}



/** Velocity函数的实现 */
int CParticle::SetVelocity(GLfloat vx,GLfloat vy,GLfloat vz)
{
    for (int index=0;index<numparticle;++index)
    {
        data[index].vx=vx;
        data[index].vy=vy;
        data[index].vz=vz;
    }
    return true;
}

int CParticle::SetVelocity(GLint index,GLfloat vx,GLfloat vy,GLfloat vz)
{
    if(index>=0 && index<numparticle)
    {
        data[index].vx=vx;
        data[index].vy=vy;
        data[index].vz=vz;
        return true;
    }
    return false;
}

int CParticle::GetVelocity(GLint index,GLfloat &vx,GLfloat &vy,GLfloat &vz)
{
    if(index>=0 && index<numparticle)
    {
        vx=data[index].vx;
        vy=data[index].vy;
        vz=data[index].vz;
        return true;
    }
    return false;
}


/** Size函数的实现 */
int CParticle::SetSize(GLfloat size)
{
    for (int index=0;index<numparticle;++index)
    {
        data[index].size=size;
    }
    return true;
}

int CParticle::SetSize(GLint index,GLfloat size)
{
    if (index>=0 && index<numparticle)
    {
        data[index].size=size;
        return true;
    }
    return false;
}

int CParticle::GetSize(GLint index,GLfloat &size)
{
    if(index >= 0 && index < numparticle)
    {
        size=data[index].size;
        return true;
    }
    return false;
}

/** 消失速度Dec函数 */
int CParticle::SetDec(GLfloat dec)
{
    for (int index=0;index<numparticle;++index)
    {
        data[index].dec=dec;
    }
    return true;
}

int CParticle::SetDec(GLint index,GLfloat dec)
{
    if(index >= 0 && index < numparticle)
    {
        data[index].dec=dec;
        return true;
    }
    return false;
}

int CParticle::GetDec(GLint index,GLfloat &dec)
{
    if(index >= 0 && index < numparticle)
    {
        dec=data[index].dec;
        return true;
    }
    return false;
}

/** 设置粒子的lifetime 属性 */
int CParticle::SetLifeTime(GLfloat lifetime)
{
    for (int index=0;index<numparticle;++index)
    {
        data[index].lifetime=lifetime;
    }
    return true;
}

int CParticle::SetLifeTime(GLint index,GLfloat lifetime)
{
    if(index >= 0 && index < numparticle)
    {
        data[index].lifetime=lifetime;
        return true;
    }
    return false;
}

/** 获得粒子的lifetime属性 */
int CParticle::GetLifeTime(GLint index,GLfloat &lifetime)
{
    if(index >= 0 && index < numparticle)
    {
        lifetime=data[index].lifetime;
        return true;
    }
    return false;
}

/** 获取粒子的所有属性 */
int CParticle::GetAll(int index,GLint &r,GLint &g,GLint &b,         /**< 粒子的颜色 */
                      GLfloat &x,GLfloat &y,GLfloat &z,     /**< 位置 */
                      GLfloat &vx,GLfloat &vy,GLfloat &vz,  /**< 速度 */
                      GLfloat &ax,GLfloat &ay,GLfloat &az,  /**< 加速度 */
                      GLfloat &size,                            /**< 大小 */
                      GLfloat &lifetime,                        /**< 生命时间 */
                      GLfloat &dec                          /**< 消失速度 */
)
{
    if (index>=0 && index<numparticle)
    {
        r=data[index].r;
        g=data[index].g;
        b=data[index].b;
        x=data[index].x;
        y=data[index].y;
        z=data[index].z;
        vx=data[index].vx;
        vy=data[index].vy;
        vz=data[index].vz;
        ax=data[index].ax;
        ay=data[index].ay;
        az=data[index].az;
        lifetime=data[index].lifetime;
        size=data[index].size;
        dec=data[index].dec;
        return true;
    }
    return false;
}

/** 设置粒子的所有属性 */
int CParticle::SetAll(int index,GLint r,GLint g,GLint b,        /**< 粒子的颜色 */
                      GLfloat x,GLfloat y,GLfloat z,        /**< 位置 */
                      GLfloat vx,GLfloat vy,GLfloat vz, /**< 速度 */
                      GLfloat ax,GLfloat ay,GLfloat az, /**< 加速度 */
                      GLfloat size,                     /**< 大小 */
                      GLfloat lifetime,                 /**< 生命时间 */
                      GLfloat dec                           /**< 消失速度 */
)
{
    if(index>=0 && index<numparticle)
    {
        data[index].r=r;
        data[index].g=g;
        data[index].b=b;
        data[index].x=x;
        data[index].y=y;
        data[index].z=z;
        data[index].vx=vx;
        data[index].vy=vy;
        data[index].vz=vz;
        data[index].ax=ax;
        data[index].ay=ay;
        data[index].az=az;
        data[index].lifetime=lifetime;
        data[index].size=size;
        data[index].dec=dec;
        return true;
    }
    return false;
}

实现

#include "GLTools.h"
#include "Particle.h"

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

/** 创建一个粒子类对象 */
CParticle Snow;

/** 用来设置粒子的属性值 */
float x,y,z,vx,vy,vz,ax,ay,az,size,lifetime,dec;
int r,g,b;

/** 载入纹理 */
GLuint  texName[2];
bool LoadTextures()
{
    GLbyte *pBits[2];
    int nWidth, nHeight;

    char* fileName[] = {"/Users/app05/Desktop/opengl/wall.bmp","/Users/app05/Desktop/opengl/snowball.bmp" };

    for(int i=0; i<2; i++)
    {
        pBits[i] = gltReadBMPBits(fileName[i], &nWidth, &nHeight );
        if(pBits[i] == NULL)
        {
            printf("bmp load failed");
            exit(-1);
        }

        glGenTextures(1,&texName[i]);

        /** 创建纹理对象 */
        glBindTexture(GL_TEXTURE_2D, texName[i]);

        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

        gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, nWidth, nHeight,
                          GL_RGB, GL_UNSIGNED_BYTE,pBits[i]);
    }
    return true;
}


/** 绘制地面 */
float angle = 0;
void DrawGround()
{
    glPushMatrix();
    glTranslatef(0.0f,0.0f,-6.0f);
    glRotatef(angle,0.0f,1.0f,0.0f);

    /** 指定纹理 */
    glBindTexture(GL_TEXTURE_2D,texName[0]);
    glColor4ub(255,255,255,255);
    glNormal3f(0.0f,1.0f,0.0f);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f,0.0f);glVertex3f(-2.5f,-1.0f,2.5f);
    glTexCoord2f(1.0f,0.0f);glVertex3f(-2.5f,-1.0f,-2.5f);
    glTexCoord2f(1.0f,1.0f);glVertex3f(2.5f,-1.0f,-2.5f);
    glTexCoord2f(0.0f,1.0f);glVertex3f(2.5f,-1.0f,2.5f);
    glEnd();
    glPopMatrix();

    /** 地面转动的角度 */
    angle += 0.02f;
}

/** 初始化雪花粒子 */
bool InitSnow()
{
    for (int i=0; i < Snow.GetNumOfParticle(); ++i)
    {
        ///初始化颜色(白色)
        r = 255;
        g = 255;
        b = 255;
        Snow.SetColor(i,r,g,b);

        ///初始化坐标
        x = 0.1f * (rand() % 50) - 2.5f;
        y = 2 + 0.1f * (rand() % 2);
        if((int)x % 2 == 0)
            z = rand()%6;
        else
            x = -rand()%3;
        Snow.SetPosition(i,x,y,z);

        ///初始化速度
        vx = 0.00001 * (rand()%100);
        vy = 0.0000002 * (rand()%28000);
        vz = 0;
        Snow.SetVelocity(i,vx,vy,vz);

        ///初始化加速度
        ax = 0;
        ay = 0.000005f;
        az = 0;
        Snow.SetAcceleration(i,ax,ay,az);

        ///初始化生命周期
        lifetime = 100;
        Snow.SetLifeTime(i,lifetime);

        ///消失速度
        dec = 0.005 * (rand()%50);
        Snow.SetDec(i,dec);

        ///初始化大小
        Snow.SetSize(i,0.03f);
    }
    return true;
}

/** 更新粒子 */
void UpdateSnow()
{
    /** 更新位置 */
    x += (vx * 5);
    y -= vy;

    /** 更新速度 */
    vy += ay;

    /** 更新生存时间 */
    lifetime -= dec;

    if(x > 3)
        x = -2;

    /** 如果粒子消失或生命结束 */
    if (y <= -1 || lifetime <= 0)
    {
        /** 初始化位置 */
        x = 0.1f * (rand()%50) - 2.5f;
        y = 2 + 0.1f * (rand()%2);
        if((int)x%2 == 0)
            z = rand()%6;
        else
            z = -rand()%3;

        /** 初始化速度 */
        vx = (float)(0.00001 * (rand()%100));
        vy = (float)(0.0000002 * (rand()%28000));
        vz = 0;

        /** 初始化加速度 */
        ax = 0;
        ay = 0.000005f;
        az = 0;
        lifetime = 100;
        dec = 0.005*(rand()%50);
    }
}

/** 绘制粒子 */
void DrawParticle()
{
    /** 绑定纹理 */
    glBindTexture(GL_TEXTURE_2D,texName[1]);

    for(int i = 0; i<Snow.GetNumOfParticle(); ++i)
    {
        /** 获得粒子的所有属性 */
        Snow.GetAll(i,r,g,b,x,y,z,vx,vy,vz,ax,ay,az,size,lifetime,dec);
        glLoadIdentity();
        glTranslatef(0.0f,0.0f,-6.0f);
        glColor4ub(r,g,b,255);
        glNormal3f(0.0f,0.0f,1.0f);   /**< 定义法线方向 */
        /** 画出粒子 */
        glBegin(GL_QUADS);
        glTexCoord2f(0.0f,0.0f);glVertex3f(x-size,y-size,z);
        glTexCoord2f(1.0f,0.0f);glVertex3f(x-size,y+size,z);
        glTexCoord2f(1.0f,1.0f);glVertex3f(x+size,y+size,z);
        glTexCoord2f(0.0f,1.0f);glVertex3f(x+size,y-size,z);
        glEnd();

        /** 更新粒子属性 */
        UpdateSnow();
        Snow.SetAll(i,r,g,b,x,y,z,vx,vy,vz,ax,ay,az,size,lifetime,dec);
    }
    glutPostRedisplay();//发送渲染请求
}

/
/** 初始化 */
void init(void)
{
    /** 用户自定义的初始化过程 */
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
    glClearDepth(1.0f);//指定深度缓冲区的清除值(即将深度缓冲区里的值设置为1)
    glDepthFunc(GL_LEQUAL);//指定用于深度缓冲比较值(即新进像素深度值与原来的1比较,<=则通过,否则丢弃)
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    glEnable(GL_TEXTURE_2D);             /**< 开启纹理映射 */
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);    /**< 设置混合因子获得半透明效果 */
    glEnable(GL_BLEND);                  /**< 启用混和 */

    /**  载入纹理 */
    if(!LoadTextures())
    {
        printf("bmp load failed");
        exit(-1);
    }

    /** 创建500个粒子 */
    Snow.Create(500);

    /** 初始化粒子 */
    InitSnow();
}

/** 渲染 */
void display(void)
{
    /** 用户自定义的绘制过程 */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    /** 绘制地面 */
    DrawGround();

    /** 绘制粒子 */
    DrawParticle();

    glFlush(); /**<强制执行所有的OpenGL命令 */
}


void ChangeSize(int width, int height)
{
    glViewport(0, 0, width, height);    /**< 重新设置视口 */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 1700.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB );
    glutInitWindowSize (400, 400);
    glutInitWindowPosition (100, 100);
    glutCreateWindow("雪花粒子");
    init();
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

这里写图片描述


2,烟花粒子
资源
这里写图片描述flare.bmp

/** 初始化粒子 */
bool InitProtechny()
{
    for (int i=0; i < Protechny.GetNumOfParticle(); ++i)
    {
        ///初始化颜色
        //r = rand()%255;
        //g = rand()%255;
        //b = rand()%255;
        r = 50;
        g = 50;
        b = 100;

        Protechny.SetColor(i,r,g,b);

        ///初始化坐标
        x = 0.005f * (rand()%9);
        y = 0.005f * (rand()%9)-1;
        z = 0.005f * (rand()%6);
        Protechny.SetPosition(i,x,y,z);

        ///初始化速度
        vx = 0.0000007f * (rand()%9000-rand()%9000);
        vy = 0.0000042f * (rand()%9000);
        vz = 0.0000001f * (rand()%9000);

        Protechny.SetVelocity(i,vx,vy,vz);

        ///初始化加速度
        ax = 0;
        ay = -0.0002;
        az = 0;

        Protechny.SetAcceleration(i,ax,ay,az);
        ///初始化生命周期
        lifetime = 100;
        Protechny.SetLifeTime(i,lifetime);

        ///消失速度
        dec=0.05*(rand()%50);
        Protechny.SetDec(i,dec);

        ///初始化大小
        Protechny.SetSize(i,0.02f);
    }
    return true;
}
/** 更新粒子 */
void UpdateProtechny()
{
    /** 更新位置 */
    x += vx;
    y += vy;
    z += vz;

    /** 更新速度 */
    vy += ay;

    /** 更新生存时间 */
    lifetime -= dec;

    /** 如果粒子消失或生命结束 */
    if (y <= -1 || lifetime <= 0)
    {
        /** 初始化位置 */
        x = 0.005f * (rand()%9);
        y = 0.005f * (rand()%9)-1;
        z = 0.000001f * (rand()%9000);

        /** 初始化速度 */
        vx = 0.0000007f * (rand()%9000-rand()%9000);
        vy = 0.0000042f * (rand()%9000);
        vz = 0.0000001f * (rand()%90000);

        lifetime = 100;
        dec = 0.1 * (rand()%50);
    }
}

这里写图片描述


3,瀑布粒子(资源同上)

/** 初始化粒子 */
bool InitParticle()
{
    for (int i=0; i < Waterfall.GetNumOfParticle(); ++i)
    {
        ///初始化颜色
        //r = rand()%255;
        //g = rand()%255;
        //b = rand()%255;
        r = 50;
        g = 50;
        b = 100;

        Waterfall.SetColor(i,r,g,b);

        ///初始化坐标
        x = 0.005f * (rand()%9) - 1;
        y = 0.005f * (rand()%9) + 1.6;
        z = 0.0001f * (rand()%15000);

        Waterfall.SetPosition(i,x,y,z);

        ///初始化速度
        vz = 0;
        vx = 0.000001f*(rand()%9000);
        vy = -rand()%5400 * vx * vx;

        Waterfall.SetVelocity(i,vx,vy,vz);

        ///初始化加速度
        ax = 0;
        ay = -0.0001;
        az = 0;

        Waterfall.SetAcceleration(i,ax,ay,az);

        ///初始化生命周期
        lifetime = 100;
        Waterfall.SetLifeTime(i,lifetime);

        ///消失速度
        dec = 0.05 * (rand()%50);
        Waterfall.SetDec(i,dec);

        ///初始化大小
        Waterfall.SetSize(i,0.02f);
    }
    return true;
}
/** 更新粒子 */
void UpdateParticle()
{
    /** 更新位置 */
    x += vx;
    y += vy;

    /** 更新速度 */
    vy += ay;

    /** 更新生存时间 */
    lifetime -= dec;

    /** 如果粒子消失或生命结束 */
    if (y <= -1 || lifetime <= 0)
    {
        /** 初始化位置 */
        x = 0.005f * (rand()%9) - 1;
        y = 0.005f * (rand()%9) + 1.6;
        z = 0.0001f * (rand()%15000);

        /** 初始化速度 */
        vz = 0;
        vx = 0.000001f * (rand()%9000);
        vy = -rand()%500 * vx * vx;

        lifetime = 100;
        dec = 0.05 * (rand()%50);
    }
}

这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenGL--粒子系统 的相关文章

  • 线程和进程的区别与联系以及单线程多进程与单进程多线程的区别

    线程和进程 概念 进程 xff08 process xff09 xff1a 是指具有已一定功能的独立程序 xff0c 是系统资源分配的基本单位 xff0c 在内存中有其完备的数据空间和代码空间 xff0c 拥有完整的虚拟空间地址 一个进程所
  • QgraphicsScene类

    概述 QgraphicsScene类为管理大量的2D图形item提供了一个管理界面 xff0c 做为item的容器 xff0c 它配合使用QgraphicsView使用来观察items 例如线 xff0c 矩形 xff0c 文本或者自定义的
  • 最好的 Curl 学习指南,强烈建议收藏!

    来自 xff1a 阮一峰的网络日志 链接 xff1a http www ruanyifeng com blog 2019 09 curl reference html 简介 curl 是常用的命令行工具 xff0c 用来请求 Web 服务器
  • TCP超时与重传

    1 TCP重传 A 基于时间信息 设置RTO xff1a tcp协议对超时报文的处理响应比较剧烈 xff0c 如 xff1a i 基于拥塞控制机制 xff0c 减小发送窗口大小 限窗 xff1b ii 当一个重传报文段被再次重传时 xff0
  • tcpdump参数用法详解

    一直在linux下开发的人一定会用到tcpdump xff0c 下面就是关于tcpdump的使用方法说明 1 tcpdump的选项 a 将网络地址和广播地址转变成名字 xff1b d 将匹配信息包的代码以人们能够理解的汇编格式给出 xff1
  • 学习图像处理知识---EmguCV3.4图像ArUco Marker Detection--DetectorParameters 结构体

    好久没有更新了图像处理 ArUco Marker Detection 种汉明 海明 码的格子图 用于相机 相机姿态估计之标记检测 在Emgu CV Aruco Namespace 命名空间中 重要的检测结构体DetectorParamete
  • 仿真导航中2d Nav Goal后小车不能到达目标点

    古月老师的课程我在进行仿真导航过程中 xff0c 遇到了小车不能到达我在rviz中指定的2d Nav Goal的目标点 xff0c 并且反复震荡的问题 解决方法如下 xff1a 模型参数里左右轮参数搞反了 xff0c 互换一下即可
  • 超声波传感器测距原理

    超声波 ultrasonic waves xff1a 人类耳朵能听到的声波频率为20HZ xff5e 20KHz 当声波的振动频率大于20KHz或小于20Hz时 xff0c 我们便听不见了 因此 xff0c 我们把频率高于20000赫兹的声
  • stm32串口中断收发数据环形缓冲区的设计

    cpp view plain copy Function Name USART2 IRQHandler Description This function handles USART2 global interrupt request In
  • CMake注意事项

    今天被target link libraries找不到库文件的问题给郁闷了好久 xff0c 后来才发现target link libraries第二个参数 xff08 即需要连接的库 xff09 居然一定要lib作为开头 xff0c 才能在
  • Web后端http请求(带用户名和密码防止401 Unauthorized)

    Java Java这方面的Jar包应该比较多 xff0c 比如HttpClient xff0c 我这里使用最基本的 xff1a java view plain copy 认证信息对象 xff0c 用于包含访问翻译服务的用户名和密码 Auth
  • 开关电源基础——TI电源在电赛中的应用

    开关电源基础 线性稳压器等效电路 如果输入是39V xff0c 输出是13V xff0c 那么效率为33 3 xff0c 过低的效率导致能量的浪费 如何提高线性稳压器的效率呢 xff1f 这是开关电源最原始的设计思想 xff0c 但是我们又
  • QGraphicsView类

    QGraphicsView提供一个显示QGraphicsScene内容的窗口 xff0c 该窗口可以滚动 xff0c 可以在构造时候把场景对象作为参数 xff0c 或者之后使用setScene 来设置view的场景 xff0c 然后调用了s
  • STM32 USART 接收任意长度字符

    近段时间学习到 STM32 USART 部分 xff0c 基本上在接收数据的时候都是采用定长 xff0c 所以一直想实现接收任意长度的字符串 这里的任意长度不是指的无限长 xff0c 而是在自己定义的缓冲区范围之类 比如说缓冲区的大小是 1
  • 关于RS485和RS422总线,一主多从回复信号被拉低收不到反馈数据的问题。

    芯片 xff1a MAX13487EESA xff08 RS485 xff09 这里这个三个电阻不接 AK管不接也行 如果你发现你在总线上挂接两个以上的RS485模块 xff0c 发现总线电压和只接一个时波形幅度降低了 xff0c 就是上面
  • ubuntu16.04 UNIX 网络编程卷一 源码使用

    参考源码目录 README文档 tar xvf unpv13e tar gz 解压 然后进入源码目录 a configure 这一步没有出现问题 b cd lib c make 这一步没有出错 d cd libfree e make 这一步
  • HTTP认证之摘要认证——Digest

    一 概述 Digest认证是为了修复基本认证协议的严重缺陷而设计的 xff0c 秉承 绝不通过明文在网络发送密码 的原则 xff0c 通过 密码摘要 进行认证 xff0c 大大提高了安全性 相对于基本认证 xff0c 主要有如下改进 xff
  • QFramework Pro 开发日志(六)一键生成类图功能介绍

    这个功能连续开发了三天 xff0c 现在完成了一个基本的雏形 先说说 xff0c 为啥做这个功能吧 作为 Unity 开发者 xff0c 不管是在做游戏还是在做工具 方案 学习源码的时候 xff0c 多多少少都会需要魔改一些其他插件 框架
  • HAL库教程9:串口接收不定长数据

    串口收到的两组数据之间 xff0c 往往会有一定的时间间隔 可以判断这个间隔 xff0c 来实现无需结束符 xff0c 无需指定长度 xff0c 串口可接收不定长数据的功能 如果串口在一定的时间内没有收到新的数据 xff0c 可以认为一组数
  • odroid平台——ASUS Xtion Pro Live + Openni + ROS搭建(Xu4升级版)

    之前的文章写了基于odroid xu3的Xtion 43 ROS搭建方法 xff0c 由于xu3停产了 xff0c 只能换用xu4 xff0c 但是换的过程中发现xu4没有usb2 0 xff0c 只有usb3 0 xff0c 但是很遗憾X

随机推荐