渲染不同的模型(使用它们自己的元素_数组_缓冲区),而不更改使用哪个VAO

yx2lnoni  于 2022-10-18  发布在  其他
关注(0)|答案(1)|浏览(144)

我正在尝试渲染多个共享相同vao和顶点格式的模型(遵循这篇文章Render one VAO containing two VBOs上的顶部答案),但我无法使其与GL_ELEMENT_ARRAY_BUFFER一起工作,也找不到任何资源/示例来帮助我。是否有可能做到这一点,或者元素数组缓冲区的工作方式是否与glVertexAttribFormat/glBindVertexBuffer和共享VAOS不兼容?或者我错过了相当于glBindVertexBufferELEMENT_ARRAY_BUFFER
My 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,它确实可以工作。
这个C++ GLSL Multiple IBO in VAO可能很有价值,但仍然不确定它对共享多个型号的Vao格式意味着什么……(我也意识到,将其称为IBO比EBO能给我带来更多的结果……)
编辑:这个问题最初被认为是Rendering meshes with multiple indices的副本,但它不是。与这个问题不同,我不是在谈论对不同数据有不同的索引(例如:位置的索引、法线的索引、纹理坐标的索引等)。但是每次绘制调用都有不同的索引,同时仍然使用相同的Vao格式(与使用Render one VAO containing two VBOs中的VBO和glBindVertexBuffer相同的方式)。

sf6xfgos

sf6xfgos1#

共享顶点数组对象的多个绘制调用

这种方法的目的是通过共享Vao并只为每次抽奖重新绑定缓冲区来避免更改Vao格式(参见glVertexAttribPointer and glVertexAttribFormat: What's the difference?https://www.youtube.com/watch?v=-bCeNzgiJ8I&t=1860)的成本。
下面是一个不使用元素缓冲区数组的明显示例:Render one VAO containing two VBOs
创建共享视频(每个程序只能创建一次):

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

相关问题