在移动对象中使用OpenGL实例绘图

时间:2017-05-13 19:15:43

标签: c++ opengl drawing rendering shader

对于每个不熟悉的人来说,OpenGL实例化绘图是使用一个着色器调用绘制许多对象的地方,因此glDrawArrays仅在屏幕上为一千个对象调用一次而不是为每个对象调用一次。

现在的问题是:如何在OpenGL 3中为不断变化的顶点的对象实现实例化渲染?创建一个数组或在顶点着色器上指定一个专门用于对象在哪里工作的位置,因为我正在处理不断变化的对象向量,每帧移动坐标的速度不同。

我使用的对象类的标题和我的顶点着色器将在下面描述以供参考。

//CLASS
class Laser {

public:

    GLfloat x, y, xVelocity, yVelocity;
    GLuint texture;
    GLfloat angle;
    GLfloat velocity;
    GLfloat width, height;
    GLfloat drawWidth = 16;
    GLfloat drawHeight = 16;
    GLfloat damage;
    GLint actsToDissapear = -1;
    GLint actsExisting = 0;
    GLboolean expired = false;
    GLboolean isRotated = false;
    GLboolean variableColor = false;
    glm::vec3 color;
    std::string type = "Laser";

    Laser(GLfloat damage, GLfloat width, GLfloat height, GLuint texture, GLfloat x, GLfloat y, GLfloat xVelocity, GLfloat yVelocity, GLfloat drawWidth, GLfloat drawHeight, GLfloat actsToDissapear, GLboolean isRotated, GLfloat angle, GLboolean variableColor, glm::vec3 color);
    virtual void draw(SpriteRenderer* s);
    virtual void move(Rachel* player);
};

//VERTEX SHADER
#version 330 core
layout (location = 0) in vec4 vertex;

uniform mat4 model;
uniform mat4 projection;
out vec2 TexCoords;

void main() {
    TexCoords = vec2(vertex.z, vertex.w);
    gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
}

2 个答案:

答案 0 :(得分:0)

您寻找的概念是属性除数。请参阅glVertexAttribDivisor

简而言之:您将模型矩阵从uniform更改为从缓冲区读取的实例属性。每个帧都使用每个实例的新位置更新该缓冲区。实现这一点时要考虑的一件事是对模型矩阵使用(vec3偏移,quat4方向)表示,以便将消耗属性的数量减少一半。此外,根据您手头的确切问题,您可以使用计算着色器直接在GPU上更新该缓冲区。

答案 1 :(得分:0)

下面是我认为你正在寻找的代码示例。我为我的粒子系统使用了实例渲染,它支持纹理,颜色和移动。适用于android opengl es和windows opengl。这段代码需要运行一些工作,但它应该很容易上手。

    #include "ParticleSystem.h"
    #include "Engine.h"
    #include "Transform.h"
    #include "Shader.h"
    #include "Texture.h"
    #include "Mesh.h"
    #include "ShaderHandler.h"

    ParticleSystem::ParticleSystem()
    {
    }

    ParticleSystem::~ParticleSystem()
    {
        shader = nullptr;
        texture = nullptr;
        glDeleteVertexArrays(1, &vertexArrayObject);
    }

    void ParticleSystem::init(Engine * engine, float size, Texture * texture, float maxVelocity, bool gravity)
    {
        this->maxVelocity = maxVelocity;
        this->gravity = gravity;

        this->size = size;
        vertex =
        {
            -size, -size, 0.0f,
            -size, size, 0.0f,
            size, size, 0.0f,
            size, -size, 0.0f
        };

        indices =
        {
            1, 0, 2, 3
        };

        this->shader = engine->getShaderHandler()->loadShader("res/shaders/texturedInstancedShader");
        this->texture = texture;

        glGenVertexArrays(1, &this->vertexArrayObject);
        glBindVertexArray(this->vertexArrayObject);

        glGenBuffers(ParticleSystem::NUM_BUFFERS, this->vertexArrayBuffer);

        glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->VERTEX_VB]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * this->vertex.size(), &this->vertex[0], GL_STATIC_DRAW); //send model to GPU

        glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->TEXTURE_VB]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * this->texCoords.size(), &this->texCoords[0], GL_STATIC_DRAW);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->vertexArrayBuffer[this->INDEX_VB]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), &this->indices[0], GL_STATIC_DRAW);

        glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->POSITION_VB]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * this->positions.size(), NULL, GL_STREAM_DRAW);    //NULL (empty) buffer

        glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->COLOR_VB]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * this->colors.size(), NULL, GL_STREAM_DRAW);   //NULL (empty) buffer

        glBindVertexArray(0);
    }


    void ParticleSystem::createPoint(float pps, float deltaTime, glm::vec3 position, float maxLife, glm::vec4 color, glm::vec3 velocity)
    {
        Particle particle;
        float amountPerSecond = pps * deltaTime;
        for (float i = 0; i < amountPerSecond; i++)
        {
            particle.life = (rand() % static_cast<int>(maxLife * 100)) / 100.f;
            particle.velocity = 
            {
                ((rand() % 200 / 100.f) - 1.f) * velocity.x,
                ((rand() % 200 / 100.f) - 1.f) * velocity.y,
                ((rand() % 200 / 100.f) - 1.f) * velocity.z
            };
            particles.emplace_back(particle);
            positions.emplace_back(position);
            colors.emplace_back(color);
        }
    }

    void ParticleSystem::draw(glm::mat4 view)
    {
        if (particles.size() > 0)
        {
            Transform transform;
            this->shader->bind();
            this->shader->loadTransform(transform, view);
            this->shader->loadInt(U_TEXTURE0, 0);
            this->texture->bind(0);

            glBindVertexArray(vertexArrayObject);

            glVertexAttribDivisor(0, 0);
            glVertexAttribDivisor(1, 1);
            glVertexAttribDivisor(2, 1);
            glVertexAttribDivisor(3, 0);

            glEnableVertexAttribArray(0);
            glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->VERTEX_VB]);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

            glEnableVertexAttribArray(1);
            glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->POSITION_VB]);
            glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * positions.size(), &positions[0], GL_STREAM_DRAW);
            glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

            glEnableVertexAttribArray(2);
            glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->COLOR_VB]);
            glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * colors.size(), &colors[0], GL_STREAM_DRAW);
            glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);

            glEnableVertexAttribArray(3);
            glBindBuffer(GL_ARRAY_BUFFER, this->vertexArrayBuffer[this->TEXTURE_VB]);
            glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

            glDrawElementsInstanced(GL_TRIANGLE_STRIP, indices.size(), GL_UNSIGNED_INT, 0, positions.size());

            glDisableVertexAttribArray(0);
            glDisableVertexAttribArray(1);
            glDisableVertexAttribArray(2);

            glBindVertexArray(0);
        }
    }

    void ParticleSystem::update(float deltaTime)
    {
        for (std::size_t i = 0; i < particles.size(); i++)
        {
            particles[i].life -= (1.f * deltaTime); //decrease life with 1 per second
            if (particles[i].life <= 0.f)   //dead
            {
                particles.erase(particles.begin() + i);
                colors.erase(colors.begin() + i);
                positions.erase(positions.begin() + i);
                continue;
            }

            if (this->gravity == true)
            {
                if (particles[i].velocity.y > -maxVelocity)
                {
                    particles[i].velocity.y -= maxVelocity * deltaTime; //1 second to reach maximum velocity
                }
                else
                {
                    particles[i].velocity.y = -maxVelocity;
                }
            }
            positions[i] += (particles[i].velocity * deltaTime);
        }
    }

着色器:

顶点着色器:

    #version 330 core

    layout(location = 0) in vec3 vertex;
    layout(location = 1) in vec3 positions;
    layout(location = 2) in vec4 colors;
    layout(location = 3) in vec2 texCoords;

    out vec2 texCoord;
    out vec4 color;

    uniform mat4 transform;

    void main()
    {
        color = colors;
        texCoord = texCoords;
        gl_Position = transform * vec4(vertex + positions, 1.0);
    }

片段着色器:

    #version 330 core

    in vec4 color;
    in vec2 texCoord;

    out vec4 colors;

    uniform sampler2D texture0;

    void main()
    {
        vec4 texel = texture2D(texture0, texCoord);
        if (texel.a <= 0.5)
        {
            discard;
        }
        colors = color * texel;
    }