glBufferSubData() and glBindArray()

Viewed 57

I have two methods:

  1. opengl_init()
  2. opengl_draw()

In the first one I initialize an empty GL_ARRAY_BUFFER because I want to update my point coordinates each frame.

Everything works if in opengl_draw() method I keep commented out //glBindBuffer(GL_ARRAY_BUFFER, 0)

Normally I use this function when I draw elements statically in the last line of the opengl_init() method.

Question:

Could you explain why commenting out glBindBuffer() function positions are updated every frame, and if I use glBindBuffer() function objects are draw statically (no change of y coordinate) even if I use glBufferSubData() in a while loop every frame?

I also do not understand why I need to write glBindVertexArray(0); in the last line of opengl_init() method. I used this line from learnopengl tutorials.

My working code:

    void opengl_init()
    {
        //vertex array
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);

        //vertex buffer
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        //-> keep this function NULL to dynamically draw vertices glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), &vertices[0], GL_STATIC_DRAW); // target | size | data (poinnting to first element e.g. glm::value_ptr(vertices[0])) | usage
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), NULL, GL_STATIC_DRAW);

        //set attributes that corresponds to layout id in the vertex shader
        // set the vertex attribute pointers
        // vertex Positions
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)0);
        // vertex normals
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)offsetof(vertex, color));

        //bind buffers vao | vbo | ibo
        glBindVertexArray(0);
        //glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    // render the mesh
    void opengl_draw(opengl_shaders::shader& shader)
    {
        for (auto& v : vertices)
            v.position.y += 0.001;
        glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(vertex), &vertices[0]);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glBindVertexArray(vao);
        glDrawArrays(GL_POINTS, 0, vertices.size());
        glBindVertexArray(0);
    }
1 Answers

glBufferSubData requires that GL_ARRAY_BUFFER is bound to a buffer. glBindBuffer(GL_ARRAY_BUFFER, 0); binds it to nothing.

Assuming nothing else in this code touches GL_ARRAY_BUFFER, commenting that line leaves it bound to vbo, which means that the glBufferSubData call knows which buffer to update.

It is best to be explicit and bind the correct buffer before you touch it. In this case, inside opengl_draw.

If you find all of this confusing, know that modern OpenGL also has direct state access, which does not require a separate glBindBuffer:

// Note we pass vbo directly instead of GL_ARRAY_BUFFER
glNamedBufferSubData(vbo, 0, vertices.size() * sizeof(vertex), &vertices[0]);
Related