我正在尝试渲染共享相同VAO和顶点格式的多个模型(以下是本文中的顶部答案"渲染一个包含两个VBO的VAO"(,但我无法使其与GL_ELEMENT_ARRAY_BUFFER
一起使用,也找不到任何资源/示例来帮助我。是否有可能做到这一点,或者元素数组缓冲区的工作方式是否与glVertexAttribFormat
/glBindVertexBuffer
和共享VAO不兼容?还是我错过了相当于glBindVertexBuffer
的ELEMENT_ARRAY_BUFFER
?
我的VAO最初是这样创建的:
glCreateVertexArrays(1, &sharedVao);
glBindVertexArray(sharedVao);
glEnableVertexAttribArray(0);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(0, 0);
// (just 1 for the example but there is more)
glBindVertexArray(0);
然后我的模型缓冲区创建如下:
glBindVertexArray(sharedVao); // tried with and without binding vao first, no success
glCreateBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), vertices.data(), GL_STATIC_DRAW);
// (just 1 for the example but there is more)
glCreateBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangles.size() * sizeof(triangle), triangles.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
最后我呈现如下:
glBindVertexArray(sharedVao);
for (auto const& model : models)
{
glBindVertexBuffer(0, model.vbo, sizeof(vertex));
// (just 1 for the example but there is more)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.ebo);
// also tried glVertexArrayElementBuffer(sharedVao, model.ebo);
glDrawElements(GL_TRIANGLES, model.triangleCount * 3, GL_UNSIGNED_INT, nullptr);
}
请注意,如果我开始使用glDrawArray
渲染相同的VAO(因此没有元素数组缓冲区(,它确实有效。
VAO中的这个C++GLSL Multiple IBO可能有价值,但仍然不确定它对共享多个模型的VAO格式意味着什么。。。(也意识到称之为IBO比EBO能给我更多的结果…(
编辑:这个问题最初被认为是具有多个索引的渲染网格的副本,但事实并非如此。与其他问题不同的是,我不是在谈论对不同的数据使用不同的索引(例如:位置索引、法线索引、纹理坐标索引等(,而是在每次绘制调用时使用不同的指数,同时仍然使用相同的VAO格式(在渲染一个包含两个VBO的VAO时使用VBO和glBindVertexBuffer
的方法相同(。
使用共享顶点数组对象的多个绘制调用
此方法的目的是避免更改VAO格式的成本(请参阅glVertexAttribPointer和glVertexAttribFormat:';有什么区别?或者https://www.youtube.com/watch?v=-bCeNzgiJ8I&t=1860(,通过共享VAO并且仅针对每次绘制重新绑定缓冲器。
这里可以看到一个不使用元素缓冲区阵列的明显例子:渲染一个包含两个VBO的VAO
创建共享VAO(每个程序只能一次(:
GLuint sharedVao = 0;
glCreateVertexArray(1, &sharedVao);
glBindVertexArray(sharedVao);
glEnableVertexAttribArray(0);
glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
// binding each attribute from its own buffer so attrib_index == buffer_index
glVertexAttribBinding(0, 0);
glEnableVertexAttribArray(1);
glVertexAttribFormat(1, 2, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(1, 1);
创建网格缓冲区(每个网格只能创建一次(:
struct Mesh
{
GLuint m_ebo = 0;
std::array<GLuint, 2> m_vbos = 0;
GLuint m_triangleCount = 0;
};
// Binding shared VAO here is mandatory as operations accessing or modifying EBO's
// state are not guaranteed to succeed if it wasn't bound to a VAO.
// However, for every new model, binding the EBO will unbind the previous, and we
// will need to rebind EBO to shared VAO for every draw call.
glBindVertexArray(sharedVao);
glCreateBuffer(1, &mesh.m_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.m_ebo);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
triangles.size() * sizeof(Triangle),
triangles.data(),
GL_STATIC_DRAW);
glBindVertexArray(0);
mesh.m_triangleCount = triangles.size();
glCreateBuffers(2, mesh.m_vbos.data());
glBindBuffer(GL_ARRAY_BUFFER, mesh.m_vbos[0]);
glBufferData(
GL_ARRAY_BUFFER,
positions.size() * sizeof(glm::vec3),
positions.data(),
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, mesh.m_vbos[1]);
glBufferData(
GL_ARRAY_BUFFER,
textureCoords.size() * sizeof(glm::vec2),
textureCoords.data(),
GL_STATIC_DRAW);
渲染循环:
// Bind shared VAO only once
// If drawing with different set of vertex data bound, use glEnableVertexAttribArray
// or glDisableVertexAttribArray before draw calls
glBindVertexArray(sharedVao);
for (auto const& mesh : meshes)
{
glBindVertexBuffer(0, mesh.m_vbos[0], 0, sizeof(glm::vec3));
glBindVertexBuffer(1, mesh.m_vbos[1], 0, sizeof(glm::vec2));
// This is the key difference with existing example on sharing VAO:
// EBO must be rebound for every draw (unless 2 draws share the same primitive indices)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.m_ebo);
glDrawElements(GL_TRIANGLES, mesh.m_triangleCount * 3, GL_UNSIGNED_INT, nullptr);
}