VAO和元素缓冲对象

Jef*_*rey 6 opengl

我一直在读一些关于VAO如何与VBO合作的内容.据我所知,当我们调用glVertexAttribPointer时,VAO只存储有关VBO的状态信息.我的问题是,它什么时候存储关于EBO的状态(对于索引绘图),它是否在调用glVertexAttribPointer时为两者保存状态?

//Vertices of the rectangle
std::vector<GLfloat> vertices
{
    0.5f,  0.5f, 0.0f,  // Top Right
    0.5f, -0.5f, 0.0f,  // Bottom Right
    -0.5f,  0.5f, 0.0f,  // Top Left 
    -0.5f, -0.5f, 0.0f,  // Bottom Left
};

//Indices of the triangle
std::vector<GLuint> indices
{
    0, 1, 3,
    0, 3, 2
};


GLuint VAO, VBO, EBO; 
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);

glBindVertexArray(VAO); //Bind the VAO

//Bind the buffers
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), &vertices[0], GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);

glBindVertexArray(0); //Unbind the VAO

//Supply Index Buffer information
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

//Custom shader class that stores the program to be used at render time
Shader shader("..path_to_shader\\shaders\\vertexshader.vert", "..path_to_shader\\shaders\\fragmentshader.frag");

while (!glfwWindowShouldClose(window))
{
    glUseProgram(shader.Program());
    glBindVertexArray(VAO); //Bind the VAO to draw.
    glClearBufferfv(GL_COLOR, 0, &color[0]);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

    glfwPollEvents();
    glfwSwapBuffers(window);

    glBindVertexArray(0);
    glUseProgram(0);
}
Run Code Online (Sandbox Code Playgroud)

Ret*_*adi 13

GL_ELEMENT_ARRAY_BUFFER绑定时,绑定成为VAO状态的一部分:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...);
Run Code Online (Sandbox Code Playgroud)

VAO受到约束.

请注意,在没有VAO绑定的情况下绑定元素数组缓冲区也是合法的.这对于用数据,使用glBufferData()或类似的调用填充它真的很有用.因为在Core Profile中你需要一个VAO绑定任何绘制调用,你需要在绑定VAO时绑定你想要用于渲染的元素数组缓冲区.

关于您的代码,您使用的调用顺序将无法提供所需的结果.以下是您的重要电话,其中的评论说明了结果:

glBindVertexArray(VAO);
// VAO is now bound. If this is the first time, it will have the default VAO state.

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// The element array buffer is bound, and this binding becomes part of the VAO state.

glBindVertexArray(0);
// The VAO is unbound. Since the element array buffer binding was part of the
// VAO state, the element array buffer is also unbound.

glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint),
             &indices[0], GL_STATIC_DRAW);
// This will not work, since you do not have an element array buffer bound.
Run Code Online (Sandbox Code Playgroud)

为了实现这一点,最简单的解决方案是更改最后两个调用的顺序:

glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint),
             &indices[0], GL_STATIC_DRAW);
// The currently bound element array buffer is filled with data.

glBindVertexArray(0);
// The VAO is unbound. Since the element array buffer binding was part of the
// VAO state, the element array buffer is also unbound.
Run Code Online (Sandbox Code Playgroud)

只是为了探索这个,下面的顺序也可以工作:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// The element array buffer is bound, Since no VAO is bound, the binding becomes
// part of the global state (or more precisely, of the default VAO 0).
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint),
             &indices[0], GL_STATIC_DRAW);
// The currently bound element array buffer is filled with data.

glBindVertexArray(VAO);
// VAO is now bound. If this is the first time, it will have the default VAO state.
// Since the element array binding is part of the VAO state, the previously bound
// element array buffer is not bound anymore.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// The element array buffer is bound, and this binding becomes part of the VAO state.
glBindVertexArray(0);
// The VAO is unbound. Since the element array buffer binding was part of the
// VAO state, the element array buffer binding is restored to the binding that
// was current before the VAO was bound.
Run Code Online (Sandbox Code Playgroud)

请注意,在此序列中,您必须在绑定VAO后再次绑定元素数组缓冲区,因为VAO状态中的元素数组缓冲区绑定将在绑定VAO后立即覆盖当前绑定.


pla*_*cel 8

来自opengl.org:

顶点数组对象(VAO)是一个OpenGL对象,它存储提供顶点数据所需的所有状态(下面有一个小例外).它存储顶点数据的格式以及提供顶点数据数组的缓冲区对象(见下文).

在下面,在Index Buffers

索引缓冲区绑定存储在VAO中.

因为GL_ARRAY_BUFFERVAO会在你打电话时保存绑定glVertexAttribPointer.这主要是因为GL_ARRAY_BUFFER绑定不是VAO状态的一部分.因此呼叫glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle)不会对VAO的状态做任何事情.

因为GL_ELEMENT_ARRAY_BUFFER情况并非如此:VAO(如果绑定)将在您调用时保存索引缓冲区绑定到它的状态glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle).

有很多关于OpenGL 索引缓冲的教程和opengl-tutorial.org上的另一些基础知识.