没有使用transformfeedback的粒子系统

来源:互联网 发布:javascript事件委托 编辑:程序博客网 时间:2024/06/02 23:28

注意:这是一个十分基础的粒子系统,没有billboard没有几何着色器没有光照没有噪声处理,算是粒子系统的一个小基础

上周通过OpenGL编程指南用TransFormFeedback技术按照书上那不完全的代码补全了粒子碰撞效果,然后我本意是想做一个火球效果。。。。。结果我觉得我还是先一步步来做一个基础的粒子系统。

粒子系统的主要成分就是一个粒子发射器类,我们写好该类后,可以通过调整参数实现各种不同的效果。
首先是粒子结构体:

struct Particle {    vec3 Position, Velocity;//定义粒子的位置和速度    vec4 Color;//定义粒子颜色    GLfloat Life;//定义粒子生命周期    Particle() : Position(0.0f), Velocity(0.0f), Color(1.0f), Life(0.0f) { }};

然后是粒子发射器类:

class ParticleGenerator{public:    ParticleGenerator(Shader shader, GLuint texture, GLuint amount, vec3 gravity);    void Update(GLfloat dt, vec3 position, vec3 velocity, GLuint newParticles, vec3 offset = vec3(0.0f, 0.0f, 0.0f));//更新粒子状态    void Draw(mat4 projection, mat4 view, mat4 model);//绘制粒子private:    vector<Particle> particles;//粒子数组,保存每个粒子的信息    GLuint amount;    Shader shader;    GLuint texture;    vec3 gravity;    GLuint VAO;    void init();//将粒子进行初始化    GLuint firstUnusedParticle();//查询死亡的粒子    void respawnParticle(Particle &particle, vec3 position,vec3 velocity, vec3 offset = vec3(0.0f, 0.0f, 0.0f));//将死亡的粒子重新初始化};

定义完后,我们接下来就开始写各个函数:
1、粒子发射器的构造函数

ParticleGenerator::ParticleGenerator(Shader shader, GLuint texture, GLuint amount, vec3 gravity): shader(shader), texture(texture), amount(amount),gravity(gravity){    this->init();}

2、init函数,该函数用于具体设置粒子的形状

GLuint VBO;    GLfloat particle_quad[] =     {        -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,         0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,         0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,                 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,          -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,          -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,        -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,         0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,          0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,          0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,         -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,          -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,          -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,         -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,         -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,          -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,         -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,          -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,         0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,         0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,         0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,            0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,          0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,          0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,         -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,         0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,         0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,        0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,         -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,         -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,         -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,        0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,         0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,         0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,         -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,        -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f     };//小立方体的顶点数据    glGenVertexArrays(1, &this->VAO);    glGenBuffers(1, &VBO);    glBindVertexArray(this->VAO);    glBindBuffer(GL_ARRAY_BUFFER, VBO);    glBufferData(GL_ARRAY_BUFFER, sizeof(particle_quad), particle_quad, GL_STATIC_DRAW);    glEnableVertexAttribArray(0);    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);    glEnableVertexAttribArray(1);    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));    glEnableVertexAttribArray(2);    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));    glBindVertexArray(0);    for (GLuint i = 0; i < this->amount; ++i)    {        this->particles.push_back(Particle());    }

3、Update函数

void ParticleGenerator::Update(GLfloat dt, vec3 position, vec3 velocity, GLuint newParticles, vec3 offset){    //我当前想要生成newParticles个新粒子,我首先要查询是否有旧粒子死亡,为了防止生成大量数据    for (GLuint i = 0; i < newParticles; ++i)    {        int unusedParticle = this->firstUnusedParticle();//获取已经死亡的旧粒子的下标        if (unusedParticle != -1)        {            this->respawnParticle(this->particles[unusedParticle], position, velocity, offset);//重新生成该粒子        }    }    for (GLuint i = 0; i < this->amount; ++i)//更新每个粒子的状态    {        Particle &p = this->particles[i];        p.Life -= dt * 0.05; //减掉寿命        if (p.Life > 0.0f)//没死的话        {               p.Velocity = p.Velocity + dt * this->gravity;//更新速度            p.Position += p.Velocity * dt;//更新位置            p.Color.a = p.Life;//更新颜色        }    }}

4、Draw函数

void ParticleGenerator::Draw(mat4 projection, mat4 view, mat4 model){    glBlendFunc(GL_SRC_ALPHA, GL_ONE);//开启融混    this->shader.Use();    for (vector<Particle>::iterator it = this->particles.begin(); it != this->particles.end(); it++)    {        if (it->Life > 0.0f)        {            glUniform3f(glGetUniformLocation(this->shader.Program, "offset"), it->Position.x, it->Position.y, it->Position.z);            //传递坐标更改值,因为我暂时没用Transformfeedback,所以用了累计函数的形式进行更新            glUniform4f(glGetUniformLocation(this->shader.Program, "color"), it->Color.x, it->Color.y, it->Color.z, it->Color.w);            //传递颜色更改值            glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "projection"), 1, GL_FALSE, value_ptr(projection));            glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "view"), 1, GL_FALSE, value_ptr(view));            glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "model"), 1, GL_FALSE, value_ptr(model));            glActiveTexture(GL_TEXTURE0);            glBindTexture(GL_TEXTURE_2D, this->texture);            glBindVertexArray(this->VAO);            glDrawArrays(GL_TRIANGLES, 0, 36);            glBindVertexArray(0);        }    }    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//将融混模式调回默认状态}

5、firstUnusedParticle函数,获取最先死亡的粒子

GLuint ParticleGenerator::firstUnusedParticle(){    //因为粒子随着时间生成,所以我们可以用一个lastUsedParticle记录上一个死亡的粒子的下标,因为下一个死亡的粒子的下标往往在上一个死亡粒子的后面    for (GLuint i = lastUsedParticle; i < this->amount; ++i)     {        if (this->particles[i].Life <= 0.0f)         {            lastUsedParticle = i;            return i;        }    }    //如果没有找到的话,我们再找前面是否有粒子死亡    for (GLuint i = 0; i < lastUsedParticle; ++i)     {        if (this->particles[i].Life <= 0.0f)         {            lastUsedParticle = i;            return i;        }    }    lastUsedParticle = 0;    return -1;}

6、respawnParticle函数

void ParticleGenerator::respawnParticle(Particle &particle, vec3 position,vec3 velocity, vec3 offset){    GLfloat random1 = ((rand() % 100) - 50) / 10.0f;    GLfloat random2 = ((rand() % 100) - 50) / 10.0f;    GLfloat rColor = 0.5 + ((rand() % 100) / 100.0f);    particle.Position = position;//定义初始位置    particle.Color = vec4(rColor, rColor, rColor, 1.0f);//定义初始颜色    particle.Life = 1.0f;//定义生命值大小    vec3 direction = normalize(vec3(random1, 0.0f, random2));    particle.Velocity = (velocity + direction * 100.0f + offset) * 0.1f;//定义初始速度}

最后我们需要在main函数中调用:

ParticleGenerator *particle = new ParticleGenerator(particleshader, textureofparticle, 10000, vec3(0.0f, -9.8f, 0.0f));particle->Update(deltaTime, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 500.0f, 0.0f), 2, vec3(0.0f));//参数分别为距离绘制上一帧的时间差,发射器初始位置,粒子初始速度,更新粒子的数量,发射器范围大小(类比于枪械的口径)particle->Draw(projection, camera.GetViewMatrix(), model);

这里写图片描述

0 0
原创粉丝点击