将粒子发射器与Transformfeedback相结合

先前写了一个没有用到transformfeedback的粒子发射器,这次进行补全。

使用transformfeedback的好处:可以实时的对粒子进行控制,比如检测粒子与物体的碰撞。

更新后的粒子发射器类:

#ifndef PARTICLE_GENERATOR_H
#define PARTICLE_GENERATOR_H
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <GL\Shader.h>

using namespace glm;
using namespace std;

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, GLfloat scale);
    void Update(GLfloat dt, vec3 position, vec3 velocity, GLuint newParticles, vec3 offset);
    void Draw(mat4 projection, mat4 view, mat4 model, GLuint feedback,GLuint texbuffer);
private:
    vector<Particle> particles;
    GLuint amount;
    Shader shader;
    GLuint texture;
    vec3 acceleration;
    GLfloat scales;//改变粒子大小
    GLboolean zhuangji;//判断粒子是否发生撞击
    GLuint VAO;
    void init();
    GLuint firstUnusedParticle();
    void respawnParticle(Particle &particle, vec3 position,vec3 velocity, vec3 offset = vec3(0.0f, 0.0f, 0.0f));
};

#endif

粒子发射器类中各个函数的具体实现:
1、构造函数

ParticleGenerator::ParticleGenerator(Shader shader, GLuint texture, GLuint amount, vec3 gravity, GLfloat scale): shader(shader), texture(texture), amount(amount), acceleration(gravity)
{
    this->init();
    this->scales = scale;
    this->zhuangji = GL_FALSE;
}

2、update函数:将计算粒子速度的代码和计算粒子位置的代码删除,并交由shader进行计算

if (!this->zhuangji)
    {
        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 -= 0.01f; 

        if (p.Life > 0.0f)
        {   
            p.Color.a = p.Life;
        }
    }

3、draw函数

glBlendFunc(GL_SRC_ALPHA, GL_ONE);

    this->shader.Use();
    GLuint total = 0;
    for (vector<Particle>::iterator it = this->particles.begin(); it != this->particles.end(); it++)
    {
        if (it->Life > 0.0f)
        {   
            glUniform1i(glGetUniformLocation(this->shader.Program, "triangle_count"), 12);
            glUniform1f(glGetUniformLocation(this->shader.Program, "scales"), this->scales);
            glUniform4f(glGetUniformLocation(this->shader.Program, "color"), it->Color.x, it->Color.y, it->Color.z, it->Color.w);
            glUniform3f(glGetUniformLocation(this->shader.Program, "velocity"), it->Velocity.x, it->Velocity.y, it->Velocity.z);
            glUniform3f(glGetUniformLocation(this->shader.Program, "lastposition"), it->Position.x, it->Position.y, it->Position.z);
            glUniform3f(glGetUniformLocation(this->shader.Program, "acceleration"), this->acceleration.x, this->acceleration.y, this->acceleration.z);

            glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "view"), 1, GL_FALSE, value_ptr(view));
            glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "model"), 1, GL_FALSE, value_ptr(model));
            glUniformMatrix4fv(glGetUniformLocation(this->shader.Program, "projection"), 1, GL_FALSE, value_ptr(projection));
            glBindTexture(GL_TEXTURE_BUFFER, texbuffer);

            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, this->texture);

            //使用transformfeedback获取来自着色器的变量中的数据
            glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, feedback, total * 7 * sizeof(GLfloat), 21 * sizeof(GLfloat));//为什么是21的理由:因为绘制的是GL_TRIANGLES,有三个顶点要绘制,需要把这三个顶点的信息都保存下来(虽然我们只需要一个定点的信息就行)
            glBindVertexArray(this->VAO);
            glBeginTransformFeedback(GL_TRIANGLES);
            //glBeginTransformFeedback(GL_POINTS);
            glDrawArrays(GL_TRIANGLES, 0, 36);
            //glDrawArrays(GL_POINTS, 0, 36);
            glEndTransformFeedback();
            glBindVertexArray(0);

            total++;
        }
    }

    glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, feedback);
    glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, total * 7 * sizeof(GLfloat), datas);//将缓存对象中的数据读取到一个数组当中

    int nums = 0;
    //更新粒子的位置数据和速度数据
    for (vector<Particle>::iterator it = this->particles.begin(); it != this->particles.end(); it++)
    {
        if (it->Life > 0.0f)
        {
            it->Position.x = datas[nums * 7];
            it->Position.y = datas[nums * 7 + 1];
            it->Position.z = datas[nums * 7 + 2];
            it->Velocity.x = datas[nums * 7 + 3];
            it->Velocity.y = datas[nums * 7 + 4];
            it->Velocity.z = datas[nums * 7 + 5];
            if (datas[nums * 7 + 6] == 1.0f)
            {
                this->zhuangji = GL_TRUE;
                //cout << it->Position.x << " " << it->Position.y << " " << it->Position.z << " " << it->Velocity.x << " " << it->Velocity.y << " " << it->Velocity.z << endl;
            }
            nums++;
        }
    }

    glUseProgram(0);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

4、着色器代码

#version 330 core
layout (location = 0) in vec3 Position; 
layout (location = 1) in vec3 normal; 
layout (location = 2) in vec2 texcoords; 

out vec2 TexCoords;
out vec4 ParticleColor;

out float zhuangji;
out vec3 position_out;
out vec3 velocity_out;


uniform mat4 view;
uniform mat4 model;
uniform mat4 projection;

uniform vec4 color;

uniform vec3 velocity;
uniform vec3 lastposition;

uniform float scales;
uniform vec3 acceleration;
uniform int triangle_count;

uniform samplerBuffer cubeBuffer;

float time_step = 0.05f;


bool intersect(vec3 orign,vec3 direction,vec3 v0,vec3 v1,vec3 v2,out vec3 point)
{
    vec3 u, v, n;
    vec3 w0, w;
    float r, a, b;

    u = (v1 - v0);
    v = (v2 - v0);
    n = cross(u, v);

    w0 = orign - v0;
    a = -dot(n, w0);
    b = dot(n, direction);

    r = a / b;
    if (r < 0.0 || r > 1.0)
    {
        return false;
    }
    point = orign + r * direction;
    float uu, uv, vv, wu, wv, D;

    uu = dot(u, u);
    uv = dot(u, v);
    vv = dot(v, v);
    w = point - v0;
    wu = dot(w, u);
    wv = dot(w, v);
    D = uv * uv - uu * vv;

    float s, t;

    s = (uv * wv - vv * wu) / D;
    if (s < 0.0 || s > 1.0)
    {
        return false;
    }
    t = (uv * wu - uu * wv) / D;
    if (t < 0.0 || (s + t) > 1.0)
        return false;
    return true;
}

vec3 reflect_vector (vec3 v, vec3 n)
{
    return v - 2.0 * dot(v, n) * n;
}

void main()
{
    zhuangji = 0.0f;
    vec3 new_velocity = velocity + acceleration * time_step;//速度速率
    vec3 new_position = lastposition + new_velocity * time_step;//位置
    vec3 v0, v1, v2;
    vec3 point;

    ParticleColor = color;
    TexCoords = texcoords;

    for (int i = 0; i < triangle_count; i++)
    {
        v0 = texelFetch(cubeBuffer, i * 3).xyz;
        v1 = texelFetch(cubeBuffer, i * 3 + 1).xyz;
        v2 = texelFetch(cubeBuffer, i * 3 + 2).xyz;

        if (intersect(lastposition.xyz, lastposition.xyz - new_position.xyz, v0, v1, v2, point))
        {
            vec3 n = normalize(cross(v1 - v0, v2 - v0));
            new_position = point + reflect_vector(new_position.xyz - point, n);
            vec3 xx = reflect_vector(new_velocity, n);
            new_velocity = 0.8 * vec3(xx.x * 5.0f, xx.y/3.0f, xx.z * 5.0f);
            zhuangji = 1.0f;
        }
    }

    velocity_out = new_velocity;
    position_out = new_position;
    gl_Position = projection * view * model * vec4(Position * scales + lastposition, 1.0f);
}

5、主程序更改

Shader cubeshader("ball.vs", "ball.frag");
    GLchar* cubevaryings[] = { "world_space_position" };
    glTransformFeedbackVaryings(cubeshader.Program, 1, cubevaryings, GL_INTERLEAVED_ATTRIBS);
    glLinkProgram(cubeshader.Program);

    glUseProgram(cubeshader.Program);
    glUniform1i(glGetUniformLocation(cubeshader.Program, "diffuseMap"), 0);
    glUseProgram(0);


    Shader particleshader("particles.vs", "particles.frag");
    GLchar* particlevaryings[] = {"position_out","velocity_out","zhuangji"};
    glTransformFeedbackVaryings(particleshader.Program, 3, particlevaryings, GL_INTERLEAVED_ATTRIBS);
    glLinkProgram(particleshader.Program);
    glUseProgram(particleshader.Program);
    glUniform1i(glGetUniformLocation(particleshader.Program, "sprite"), 0);
    glUseProgram(0);


GLuint cubefeedback, cubeTEX;
    glUseProgram(cubeshader.Program);
    glGenBuffers(1, &cubefeedback);
    glBindBuffer(GL_TEXTURE_BUFFER, cubefeedback);
    glBufferData(GL_TEXTURE_BUFFER, 160 * sizeof(GLfloat), NULL, GL_DYNAMIC_COPY);
    glGenTextures(1, &cubeTEX);
    glBindTexture(GL_TEXTURE_BUFFER, cubeTEX);
    glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, cubefeedback);
    glUseProgram(0);

    GLuint particlefeedback;
    glGenBuffers(1, &particlefeedback);
    glBindBuffer(GL_ARRAY_BUFFER, particlefeedback);
    glBufferData(GL_ARRAY_BUFFER, 5000 * 36 * 6 * sizeof(GLfloat), NULL, GL_DYNAMIC_COPY);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    while (!glfwWindowShouldClose(window))
    {
        GLfloat currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        glfwPollEvents();
        Do_Movement();

        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        mat4 projection = perspective(radians(camera.Zoom), (GLfloat)screenWidth / (GLfloat)screenHeight, 0.1f, 100.0f);
        mat4 model = mat4();
        model = translate(model, vec3(0.0f, -2.5f, 0.0f));
        mat4 view = camera.GetViewMatrix();

        cubeshader.Use();
        glUniformMatrix4fv(glGetUniformLocation(cubeshader.Program, "model"), 1, GL_FALSE, value_ptr(model));
        glUniformMatrix4fv(glGetUniformLocation(cubeshader.Program, "view"), 1, GL_FALSE, value_ptr(view));
        glUniformMatrix4fv(glGetUniformLocation(cubeshader.Program, "projection"), 1, GL_FALSE, value_ptr(projection));
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, cubefeedback);
        glBeginTransformFeedback(GL_TRIANGLES);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, woodtexture);
        RenderCube();
        glEndTransformFeedback();
        glUseProgram(0);




        model = mat4();
        //model = scale(model, vec3(0.1f, 0.1f, 0.1f));//bug~~~~~~~~~~~~~~~~~!!!!!!!!!!!!逻辑错误!!!!!!
        particle->Draw(projection, view, model, particlefeedback, cubeTEX);
        particle->Update(deltaTime, vec3(0.0f, 100.0f - currentFrame * 10.0f, 0.0f), vec3(0.0f, -150.0f, 0.0f), 15, vec3(0.0f));




        glfwSwapBuffers(window);
    }

效果:
这里写图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值