nauman
nauman

Reputation: 151

OpenGL - Buffer updates next rendering object

Okej, so i got a really odd case where i have three(or two, doesnt matter) objects and one of them is updating its buffer to "animate". In other words, one object is moving and the other(s) stands still. The odd part comes in when the moving object is moving but the object that is rendering after the moving object is accually animating. The moving object moves but does not animate. Hope it makes sense.

Now some code and since i have troubleshooting it to be buffer related i will those parts:

Object::Object() {
    ...
    glGenVertexArrays(1, &VAO_);
    glGenBuffers(2, VBO_); 
    glGenBuffers(1, &EBO_);

    glBindVertexArray(VAO_);

    glBindBuffer(GL_ARRAY_BUFFER, VBO_[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 3, vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glEnableVertexAttribArray(0);  

    glBindBuffer(GL_ARRAY_BUFFER, VBO_[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 2, tex_vert, GL_STREAM_DRAW);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * 6, indices, GL_STATIC_DRAW);

    glBindVertexArray(0);                       // unbind vertex
    glBindBuffer(GL_ARRAY_BUFFER, 0);           // unbind buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);   // unbind buffer
}
void Object::Update() {
    ...
    glBindBuffer(GL_ARRAY_BUFFER, VBO_[1]);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * 4 * 2, tex_vert);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Object::Render() {
    ...
    glUseProgram(Shader_.GetProgramID());
    glBindVertexArray(VAO_);
    glBindTexture(GL_TEXTURE_2D, Texture_);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

int Main() {
    Object m();
    Object m2();
    Object m3();
    while (!glfwWindowShouldClose(engine.window)) {
        ...
        m.Update();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        m.Render();
        m3.Render();
        m2.Render();
        glfwSwapBuffers(window);
        ...
    }
}

So m3 get anitmated but m is moving, and if a change place with m3 and m2, m2 will get animated. If i dont render m2/m3, m will get animation and moving. Worth mentioning, all non-animating objects get the texture but will stay in init state, so everything looks good at the beginning.

VAO, VBO and EBO got different values for each object but yet, "wrong" buffer(VBO_[1]) get updated.

Think i tried most of the wrong ways of solving this so it would be really appreciated if someone could point me in the right direction.

Edit:

Addition info regarding how the buffers are filled etc.

void Object::Update() {
    if (Keyboard::KeyPressed(GLFW_KEY_W)) {
        if (MovementY_ < 0) {
            MovementY_ = 0;
        }
        MovementY_ += MovementSpeed_ * Engine::GetDeltaTime();

        TextureTopLeft_      = glm::vec2((MALE_TEXTURE_SIZE_S * SpriteFrame_) - MALE_TEXTURE_SIZE_S,    MALE_UP_STAND_T - MALE_TEXTURE_SIZE_T);
        TextureTopRight_     = glm::vec2((MALE_TEXTURE_SIZE_S * SpriteFrame_),                          MALE_UP_STAND_T - MALE_TEXTURE_SIZE_T);
        TextureBottomLeft_   = glm::vec2((MALE_TEXTURE_SIZE_S * SpriteFrame_) - MALE_TEXTURE_SIZE_S,    MALE_UP_STAND_T);
        TextureBottomRight_  = glm::vec2((MALE_TEXTURE_SIZE_S * SpriteFrame_),                          MALE_UP_STAND_T);
    }
    float tex_vert[4][2] = {
        {TextureTopRight_.s,      TextureTopRight_.t},
        {TextureBottomRight_.s,   TextureBottomRight_.t},
        {TextureBottomLeft_.s,    TextureBottomLeft_.t},
        {TextureTopLeft_.s,       TextureTopLeft_.t},
    };
    glBindBuffer(GL_ARRAY_BUFFER, VBO_[1]);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * 4 * 2, tex_vert);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    PositionX_ += MovementX_;
    PositionY_ += MovementY_;
}
void Object::Render() {
    glm::mat4 Projection, Model;
    Projection = glm::orthoLH(0.0f, float(Engine::GetFrameBufferWidth()), 0.0f, float(Engine::GetFrameBufferHeight()), 0.0f, 1000.0f);

    Model = glm::translate(Model, glm::vec3(PositionX_, PositionY_, PositionY_));
    glm::mat4 mvp = Projection * Model;
    GLint MVP = glGetUniformLocation(Shader_.GetProgramID(), "MVP");
    glUniformMatrix4fv(MVP, 1, GL_FALSE, glm::value_ptr(mvp));

    glUseProgram(Shader_.GetProgramID());
    glBindVertexArray(VAO_);
    glBindTexture(GL_TEXTURE_2D, Texture_);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

# These two never change, assigned in object-creation.
float vertices[4][3] = {
    {+SpriteWidth_, +SpriteHeight_, 0.0f},
    {+SpriteWidth_, -SpriteHeight_, 0.0f},
    {-SpriteWidth_, -SpriteHeight_, 0.0f},
    {-SpriteWidth_, +SpriteHeight_, 0.0f},
};

unsigned int indices[] = {
    2, 1, 0,
    2, 0, 3,
};

Fragment shader:

out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;

void main() {
    FragColor = texture(ourTexture, TexCoord);
}

Vertex shader:

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 MVP;

void main() {
    gl_Position = MVP * vec4(aPos, 1.0);
    TexCoord = aTexCoord;
}

Upvotes: 0

Views: 111

Answers (1)

nauman
nauman

Reputation: 151

The problem was not regarding the update of VBO_[1], aka the texture position of which should be rendered.

# Correct
glBindBuffer(GL_ARRAY_BUFFER, VBO_[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * 4 * 2, tex_vert);
glBindBuffer(GL_ARRAY_BUFFER, 0);

The problem was that the movement/position, aka the MVP, did not update the correct object due to the missplacement of glUseProgram. First object get an empty MVP, second object get the first objects MVP, third object get the second objects MVP, first object get the third objects MVP etc. If glUseProgram(0) had been used in the end of the rendering function, none of the objects would have been placed correctly, since MVP never got a real value.

# Updated with correct position of glUseProgram()

glm::mat4 Projection, Model;
Projection = glm::orthoLH(0.0f, float(Engine::GetFrameBufferWidth()), 0.0f, float(Engine::GetFrameBufferHeight()), 0.0f, 1000.0f);

Model = glm::translate(Model, glm::vec3(PositionX_, PositionY_, PositionY_));
glm::mat4 mvp = Projection * Model;
GLint MVP = glGetUniformLocation(Shader_.GetProgramID(), "MVP");

glUseProgram(Shader_.GetProgramID()); // This must be loaded before UniformMatrix4fv
glUniformMatrix4fv(MVP, 1, GL_FALSE, glm::value_ptr(mvp));
glBindVertexArray(VAO_);
glBindTexture(GL_TEXTURE_2D, Texture_);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

So, notes to others who get confused:

glUseProgram() BEFORE glUniformMatrix4fv()

Thanks to Rabbid76 who found the solution!

Upvotes: 1

Related Questions