Render one VAO containing two VBOs

有些话、适合烂在心里 提交于 2020-06-16 05:15:08

问题


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?


回答1:


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);


来源:https://stackoverflow.com/questions/40652905/render-one-vao-containing-two-vbos

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!