3

I'm trying to draw two triangles in a window in OpenGL 3.3. I'm using the GLFW library for the windowing system.

From what I understand, I should have two VBOs (one for each triangle) and one VAO containing these two VBOs. That's what I did.

However, I can't figure out what calls I should make to render these two VBOs. Indeed, whatever I do, only the first VBO (first triangle) gets drawn. The second one never shows up.

int main()
{
    GLFWwindow *window = setupWindow();
    GLfloat triangle1Vertices[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f
    };
    GLfloat triangle2Vertices[] = {
        0.f, -0.5f, 0.0f,
        0.8f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f
    };
    GLuint vao, vbo[2];

    glGenVertexArrays(1, &vao);
    glGenBuffers(2, vbo);

    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle1Vertices), triangle1Vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2Vertices), triangle2Vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    glEnableVertexAttribArray(1);

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

    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();

        glClearColor(0.3f, 0.3f, 0.5f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);


        glBindVertexArray(vao);

        glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        glBindVertexArray(0);


        glfwSwapBuffers(window);
    }

    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(2, vbo);

    glfwTerminate();

    return 0;
}

I'm clearly missing something, but what?

GuiTeK
  • 1,344
  • 5
  • 19
  • 36
  • The `glVertexAttribPointer` in the render loop look extremely suspicious. Part of the whole point of using VAOs is that you set up the inputs of the pipeline only once, then you do `bind vao; draw; bind another vao; draw;`. Why do you keep re-setting the attributes (to the same buffers/formats, nonetheless)? – peppe Nov 17 '16 at 12:16
  • Second, how does your vertex shader look like? At which location(s) is it expecting inputs? And how could the shader know (if that's all of your code) that it needs to process attributes coming from one location instead of another, depending on which triangle you want to draw? – peppe Nov 17 '16 at 12:16

1 Answers1

7

From what I understand, I should have two VBOs (one for each triangle) and one VAO containing these two VBOs.

Then your understanding is wrong.

If you want to have two different buffers with two different triangles, then you either need two different VAOs, or you need to swap which buffer the VAO uses between rendering each object.

Your rendering code is close to correct, but not quite:

    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    glDrawArrays(GL_TRIANGLES, 0, 3);

Notice that the second glVertexAttribPointer call uses attribute 0 as well. The attribute indices you pass to glVertexAttribPointer specify which shader input variable gets fed from that array. What you're trying to do is render a second object using the same shader, changing only where the vertex arrays come from. And that requires using the same attribute index.

However, if OpenGL 4.3/ARB_vertex_attrib_binding is available to you, I would highly encourage you to just use those APIs. It makes your code much more straightforward:

//vertex setup
glGenVertexArrays(1, &vao);

glBindVertexArray(vao);
//Sets up the format, *without* a buffer object.
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
//Sets up where the buffer object comes from
glVertexAttribBinding(0, 0);
//Enable VAO
glEnableVertexAttribArray(0);
//Done with VAO
glBindVertexArray(0);

//Set up buffer object data storage.
glGenBuffers(2, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle1Vertices), triangle1Vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangle2Vertices), triangle2Vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

Then, in your loop:

glBindVertexArray(vao);

//Use buffer 0 to render.
glBindVertexBuffer(0, vbo[0], 0, 3 * sizeof(float));
glDrawArrays(GL_TRIANGLES, 0, 3);
//Use buffer 1 to render.
glBindVertexBuffer(0, vbo[1], 0, 3 * sizeof(float));
glDrawArrays(GL_TRIANGLES, 0, 3);

glBindVertexArray(0);
Community
  • 1
  • 1
Nicol Bolas
  • 413,367
  • 61
  • 711
  • 904