版本 4.3

Version >= 4.3

OpenGL 4.3(或 ARB_separate_attrib_format)添加了一种指定顶点数据的替代方法,它在属性绑定的数据格式和提供数据的缓冲区对象源之间创建了分隔。因此,不是每个网格都有 VAO,而是每个顶点格式都有一个 VAO。

每个属性都与顶点格式和绑定点相关联。顶点格式由类型,组件计数,是否规范化以及从数据起点到该特定顶点的相对偏移量组成。绑定点指定属性从哪个缓冲区获取其数据。通过分离两者,你可以绑定缓冲区而无需重新指定任何顶点格式。你还可以使用单个绑定调用将用于提供数据的缓冲区更改为多个属性。

//accessible constant declarations
constexpr int vertexBindingPoint = 0;
constexpr int texBindingPoint = 1;// free to choose, must be less than the GL_MAX_VERTEX_ATTRIB_BINDINGS limit

//during initialization
glBindVertexArray(vao);

glVertexAttribFormat(posAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, pos));
// set the details of a single attribute
glVertexAttribBinding(posAttrLoc, vertexBindingPoint);
// which buffer binding point it is attached to
glEnableVertexAttribArray(posAttrLoc);

glVertexAttribFormat(normalAttrLoc, 3, GL_FLOAT, false, offsetof(Vertex, normal));
glVertexAttribBinding(normalAttrLoc, vertexBindingPoint);
glEnableVertexAttribArray(normalAttrLoc);

glVertexAttribFormat(texAttrLoc, 2, GL_FLOAT, false, offsetof(Texture, tex));
glVertexAttribBinding(texAttrLoc, texBindingPoint);
glEnableVertexAttribArray(texAttrLoc);

然后在绘制期间保持 vao 绑定并仅更改缓冲区绑定。

void drawMesh(Mesh[] mesh){
    glBindVertexArray(vao);

    foreach(mesh in meshes){
        glBindVertexBuffer(vertexBindingPoint, mesh.vbo, mesh.vboOffset, sizeof(Vertex));
        glBindVertexBuffer(texBindingPoint, mesh.texVbo, mesh.texVboOffset, sizeof(Texture));
        // bind the buffers to the binding point

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ebo);

        glDrawElements(GL_TRIANGLES, mesh.vertexCount, GL_UNSIGNED_INT, mesh.indexOffset);
        //draw
    }
}