while following the lighting chapter in the learnopengl series,作者在创建多个VAO
s(顶点数组对象)时提供了这种代码:
unsigned int VBO, cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(cubeVAO);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); //#this
glEnableVertexAttribArray(0);
// second, configure the light's VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube)
unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
// we only need to bind to the VBO (to link it with glVertexAttribPointer), no need to fill it; the VBO's data already contains all we need (it's already bound, but we do it again for educational purposes)
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); //#this
glEnableVertexAttribArray(0);
这里我们使用相同的VBO
和多个VAO
,但是对glVertexAttribPointer
的调用使用相同的参数进行了两次。他提到的Earlier in this lesson:
每个顶点属性从VBO管理的内存中获取数据,而从哪个VBO获取数据(您可以有多个VBO)由当前调用glVertexAttribPointer绑定到GL_ARRAY_BUFFER的VBO确定。由于先前定义的VBO在调用glVertexAttribPointer之前仍然绑定,所以现在将顶点属性0与它的顶点数据关联。
所以,这并不意味着这两个调用是多余的,还是这是必要的,如果不执行,将会引起问题吗?
所以,这并不意味着这两个调用是多余的,还是这是必要的,如果不执行,将会引起问题吗?
没有在这里查看操作顺序。
// the buffer bound to GL_ARRAY_BUFFER is VBO,
// from here, until the end of the code in this block
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// start modifying the cubeVAO
// cubeVAO currently knows NOTHING about which attributes are needed.
glBindVertexArray(cubeVAO);
// set up info about vertex attribute 0, within cubeVAO.
// cubeVAO now knows about 1 attribute, index == 0
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); //#this
glEnableVertexAttribArray(0);
// now start setting up the lightVAO.
// note that at this point, VBO is still bound to GL_ARRAY_BUFFER
glBindVertexArray(lightVAO);
// set up info about vertex attribute 0, within lightVAO.
// lightVAO now knows about 1 attribute, index == 0
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
如果省略对glVertexAttribPointer和glEnableVertexAttribArray的第二次调用,则lightVAO将包含完全为零顶点属性的绑定。这意味着顶点着色器中的任何属性都不会接收任何数据。
在您的原始代码中,不需要第二次调用glBindBuffer。还要说真的,因为cubeVAO和lightVAO仅具有一个属性,该属性是从同一缓冲区读取的。在这里只需使用一个VAO就可以了。
\ edit
最好是根据插槽而不是实例来考虑。 GPU将支持固定数量的顶点属性(对GL_MAX_VERTEX_ATTRIBS进行glGet可以找出多少个)。因此,唯一受支持的索引将是:0->(GL_MAX_VERTEX_ATTRIBS-1),因此说“创建了新实例”并不是很准确(因为这意味着动态分配)。该行为更类似于:
// struct to store info about a vertex attribute
struct VertexAttribute
{
bool enabled = false; //< on or off?
int size;
GLenum dataType;
bool normalise;
int stride;
size_t offset;
GLuint buffer; //< which buffer was bound to GL_ARRAY_BUFFER
};
// the VAO just stores the current state of the vertex bindings
struct VAO
{
VertexAttribute vertexAttribs[GL_MAX_VERTEX_ATTRIBS];
void glVertexAttribPointer(
int index, int size, GLenum type,
bool normalise, int stride, size_t offset)
{
vertexAttribs[index].size = size;
vertexAttribs[index].dataType = type;
vertexAttribs[index].normalise = normalise;
vertexAttribs[index].stride = stride;
vertexAttribs[index].offset = offset;
// grab buffer
vertexAttribs[index].buffer = glGet(GL_ARRAY_BUFFER_BINDING);
}
void glDisableVertexAttribArray(uint32_t index)
{
vertexAttribs[index].enabled = false;
}
void glEnableVertexAttribArray(uint32_t index)
{
vertexAttribs[index].enabled = true;
}
};