VAO 中的 C++ GLSL 多个 IBO

Posted

技术标签:

【中文标题】VAO 中的 C++ GLSL 多个 IBO【英文标题】:C++ GLSL Multiple IBO in VAO 【发布时间】:2014-08-05 09:37:01 【问题描述】:

我正在开发一个小项目,我正在使用 VBO、IBO 和 VAO,我有一个顶点数组及其各自的数组索引,我对材料做同样的事情(因为相同的顶点可以有不同的材料另一面)但VAO中的此链接相同不显示任何内容。每一个 VAO 都必须是 IBO?

附上我的代码,分别发送数据到gpu和渲染!

感谢您的帮助,问候 :)

void Upload()
    GLuint ibo[2], vbo[3];

    glGenBuffers(3, vbo);
    glGenBuffers(2, ibo);
    glGenVertexArrays(1, vao);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); //Vertices
    glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vec3), vertices.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); //Normales
    glBufferData(GL_ARRAY_BUFFER, vertex_normal.size()*sizeof(vec3), vertex_normal.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, v_indices.size()*sizeof(GLuint), v_indices.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); //Material
    glBufferData(GL_ARRAY_BUFFER, materials.size()*sizeof(Material), materials.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size()*sizeof(GLuint), m_indices.data(), GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    glBindVertexArray(vao[0]);
    //Vertices:
    glEnableVertexAttribArray(attrib_vertex);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(attrib_vertex, 3, GL_FLOAT, GL_FALSE, 0, 0);
    //Normales:
    glEnableVertexAttribArray(attrib_normal);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glVertexAttribPointer(attrib_normal, 3, GL_FLOAT, GL_FALSE, 0, 0);
    //IBO:
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);

    //Materiales:
    for(int i=0; i<5; ++i)
        glEnableVertexAttribArray(attrib_material+i);
    glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
    glVertexAttribPointer(attrib_material, 4, GL_FLOAT, GL_FALSE, sizeof(Material), NULL);
    glVertexAttribPointer(attrib_material+1, 4, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, diffuse));
    glVertexAttribPointer(attrib_material+2, 4, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, specular));
    glVertexAttribPointer(attrib_material+3, 4, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, emission));
    glVertexAttribPointer(attrib_material+4, 1, GL_FLOAT, GL_FALSE, sizeof(Material), (void*)offsetof(Material, shininess));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[1]);

    //Desactivando todo:
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glDisableVertexAttribArray(attrib_vertex);
    glDisableVertexAttribArray(attrib_normal);
    for(int i=0; i<5; ++i)
        glDisableVertexAttribArray(attrib_material+i);

void Draw()
    glBindVertexArray(vao[0]);
    glDrawElements(GL_TRIANGLES, v_indices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

【问题讨论】:

【参考方案1】:

每个 VAO 都存储当前 GL_ELEMENT_ARRAY_BUFFER_BINDING 的值。

当您调用 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0])glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[1]) 时会设置该存储值。

您的代码的问题是您对glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...) 的第二次调用覆盖了第一次调用存储的值。这是因为每个 VAO 只能为 GL_ELEMENT_ARRAY_BUFFER_BINDING 存储一个值。也就是说,每个 VAO 只允许 1 个 IBO。

我提出的一些解决方案:

您可以以不同的方式存储材质数据,使其与网格中的索引相匹配。这可能意味着您需要复制材料数据。 您可以将材质数据存储在统一缓冲区中,然后将材质数据的索引作为每个顶点的顶点属性存储在统一缓冲区中。 您的材质似乎定义了照明信息。也许您可以将渲染拆分为多个通道。 (即环境光通道、漫反射通道、镜面反射通道...)延迟光照等渲染方法可以解决此问题。 您可以将顶点和材质的索引组合成一个大 IBO。 (可能与我提到的其他方法结合使用。) 如果您的数据符合该模式,您或许可以使用 glVertexAttribDivisor

无论哪种方式,核心问题是每个 VAO 只能有 1 个 IBO。您必须具有创造性才能找到适合您使用的解决方案。祝你好运!

【讨论】:

非常感谢您的帮助,抱歉耽误了谢谢! :)

以上是关于VAO 中的 C++ GLSL 多个 IBO的主要内容,如果未能解决你的问题,请参考以下文章

使用 IBO/EBO 时,程序仅在我调用 glBindBuffer 以在创建 VAO 后绑定 IBO/EBO 时才有效

通过 IBO 了解 VAO

VAO 是不是同时记住 EBO/IBO(元素或索引)和 VBO?

VAO 与 VBO 和 IBO 的手动绑定

两个不同的对象 OpenGL。 VAO VBO IBO 网格变形问题

在 GLSL 着色器中访问 VBO/VAO 数据