3
$\begingroup$

Let's say I have a have 10 different terrains. Each terrain have the same x and z coordinates, but they have different y coordinate, normals and colors. The indices used for element rendering is also the same.

The data looks like this:

std::vector<GLfloat> xzCoords;
std::vector<GLuint> indices;

std::vector<GLfloat> yCoords[10];
std::vector<GLfloat> normals[10];
std::vector<GLfloat> colors[10];

And the VBO and VAO IDs:

GLuint VAO_IDs[10];
GLuint VBO_xzCoord_IDs[10];
GLuint VBO_yCoord_IDs[10];
GLuint VBO_indices_IDs[10];
GLuint VBO_normals_IDs[10];
GLuint VBO_colors_IDs[10];

If I want one VAO for each of the terrain deffinitions, how would that look if the VBO for xz coordinates and indices are the same for each?

What I am doing now looks like this:

Setting up the buffers:

for (size_t i = 0; i < 10; i++){
        //VAO
        glGenVertexArrays(1, &VAO_IDs[i]);
        glBindVertexArray(VAO_IDs[i]);

        //VBO
        glGenBuffers(1, &VBO_xzCoord_IDs[i]);
        glGenBuffers(1, &VBO_yCoord_IDs[i]);
        glGenBuffers(1, &VBO_indices_IDs[i]);
        glGenBuffers(1, &VBO_normals_IDs[i]);
        glGenBuffers(1, &VBO_colors_IDs[i]);

        //xz coords
        glBindBuffer(GL_ARRAY_BUFFER, VBO_xzCoord_IDs[i]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*xzCoords.size(), &xzCoords[0], GL_STATIC_DRAW);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glEnableVertexAttribArray(0);
        //y coords
        glBindBuffer(GL_ARRAY_BUFFER, VBO_yCoord_IDs[i]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*yCoords[i].size(), &yCoords[i][0], GL_STREAM_DRAW);
        glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glEnableVertexAttribArray(1);
        //normals
        glBindBuffer(GL_ARRAY_BUFFER, VBO_normals_IDs[i]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VBO_normals_IDs[i].size(), &VBO_normals_IDs[i][0], GL_STREAM_DRAW);
        glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glEnableVertexAttribArray(2);
        //colors
        glBindBuffer(GL_ARRAY_BUFFER, VBO_colors_IDs[i]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*VBO_colors_IDs[i].size(), &VBO_colors_IDs[i][0], GL_STREAM_DRAW);
        glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glEnableVertexAttribArray(3);

//indices
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO_indices_IDs[i]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*indices.size(), &indices[0], GL_STATIC_DRAW);
    }

Rendering function:

for (size_t i = 0; i < 10; i++)
    {
        glBindVertexArray(VAO_IDs[i]);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO_indices_IDs[i]);
        glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void*)0);

    }

So as you can see, I create a new xz-coordinates and indices buffer for each VAO. I doubt this is the most effective way to do it. How should I do this?

$\endgroup$
  • $\begingroup$ Step 1: Stop confusing the act of creating a buffer with the act of using that buffer with a VAO. $\endgroup$ – Nicol Bolas Jan 29 '17 at 14:58
4
$\begingroup$

VAO can share VBO's because they do not store vertex data itself but references to Vertex Buffer Objects.

So you can first generate your buffers and upload your buffer data (vertex data and index data) to currently bound buffers.

glGenBuffers(1, &VBO_xzCoord_IDs[i]);
glGenBuffers(1, &VBO_yCoord_IDs[i]);
glGenBuffers(1, &VBO_indices_IDs[i]);
glGenBuffers(1, &VBO_normals_IDs[i]);
glGenBuffers(1, &VBO_colors_IDs[i]);

//xz coords
glBindBuffer(GL_ARRAY_BUFFER, VBO_xzCoord_IDs[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*xzCoords.size(), &xzCoords[0], GL_STATIC_DRAW);

...

//indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO_indices_IDs[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*indices.size(), &indices[0], GL_STATIC_DRAW);

And then generate your VAO's and connect vertex array object data index you provide in glVertexAttribPointer call with currently bound GL_ARRAY_BUFFER.

The GL_ELEMENT_ARRAY_BUFFER can be a little confusing because it doesn't require glVertexAttribPointer call. So how it is connected with VAO? It seems that binding the buffer ties it to the currently bound VAO.

//VAO
glGenVertexArrays(1, &VAO_IDs[i]);
glBindVertexArray(VAO_IDs[i]);

//xz coords
glBindBuffer(GL_ARRAY_BUFFER, VBO_xzCoord_IDs[i]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

...

//indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO_indices_IDs[i]);

glBindVertexArray(0);

And in your rendering call you don't need to bind GL_ELEMENT_ARRAY_BUFFER because it was already connected with VAO.

$\endgroup$
  • $\begingroup$ Thank you. I made it so that the "shared VBOs" are only calling glBufferData once, then they are rebounded and set to a vertex attribute for each VAO. So I don't need to call glBufferData for 10 time with the same data:) $\endgroup$ – remi000 Jan 29 '17 at 16:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.