Do I have to call glVertexAttribPointer() each frame, for each rendered mesh?
Asked Answered
C

1

8

I have seen other people's code where they only called glVertexAttribPointer() when they initialized the vao. When I do that, only the first object in my scene gets rendered, but if I call it each frame * each object, everything renders fine... so does this mean I have to set glVertexAttribPointer() for each object before drawing? Or am I missing something?!

        glBindVertexArray(mesh->getVao());
        glBindBuffer(GL_ARRAY_BUFFER, mesh->getVbo());

        for(int i = 0; i < 5; i++)
            glEnableVertexAttribArray(i);

        // Vertex Positions
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
        offset++;
        // Vertex UVs
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
        offset++;
        // Vertex Normals
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
        offset++;
        // Vertex Tangents
        glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
        offset++;
        // Vertex Binormals
        glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);

        // Draw
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getVbo());
        glDrawElements(GL_TRIANGLES, mesh->getNumberOfIndices(), GL_UNSIGNED_SHORT, (void*)0);

        for (int i = 0; i < 5; i++)
            glDisableVertexAttribArray(i);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);

This is 1 draw call per object. It works perfect, but do I really need to call glVertecAttribPointer() each frame for each object as such?

Courage answered 23/2, 2017 at 9:9 Comment(0)
C
10

Vertex attribute pointers and index buffers are part of the VAO state, so they only have to be called once in the beginning.

Init:

glGenVertexArray(1, &vao);
glBindVertexArray(vao);

for(int i = 0; i < 5; i++)
    glEnableVertexAttribArray(i);

// Vertex Positions
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex UVs
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Normals
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Tangents
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);
offset++;
// Vertex Binormals
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (void*)*offset);

// Index Buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getVbo());

//Unbind VAO
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //Unbind the index buffer AFTER the vao has been unbinded

In each frame call

glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, mesh->getNumberOfIndices(), GL_UNSIGNED_SHORT, (void*)0);
glBindVertexArray(0);
Cocks answered 23/2, 2017 at 9:35 Comment(7)
This is absolutely fabulous! Thank you very much! I couldn't figure out just looking at other people's code but I could tell I didn't need to call it a million times, you have helped me out greatly, thank you :)Courage
Just one last thing: Do I not need to disable the VertexAttribArray at any point? (if I do, nothing is rendered) thank youCourage
No, unless you want to remove this attribute from the VAO.Cocks
@Cocks Do I need to call it every frame, if I don't use VAO's?Nostalgia
@JerryLundegaard: In OpenGL 3.3+ (Core Profile) using a VAO is mandatory. In earlier versions, yes, you have to call the vertex setup before every draw call. I wouldn't recommend using a pre Core Profile version.Cocks
@Cocks Is there any reason for it? Why doesn't openGL just remember it?Nostalgia
@JerryLundegaard: As long as you don't change it, it will remember it. But usually when you have a non-trivial application, you will render more than just one shape. If you need a more detailed answer, I suggest you ask a new question.Cocks

© 2022 - 2024 — McMap. All rights reserved.