OpenGL 多个 VBO 只渲染一个

Posted

技术标签:

【中文标题】OpenGL 多个 VBO 只渲染一个【英文标题】:OpenGL multiple VBOs only rendering one 【发布时间】:2014-09-08 08:57:40 【问题描述】:

我有一个网格类如下

Mesh_PTI::Mesh_PTI(bool dynamic) : m_dynamic(dynamic), m_drawCount(0)

    glGenVertexArrays(1, m_vertexArrays);
    glBindVertexArray(m_vertexArrays[0]);

    glGenBuffers(NUM_BUFFERS, m_buffers);

    glBindVertexArray(0);


Mesh_PTI::Mesh_PTI(glm::vec3 positions[], glm::vec2 texCoords[], unsigned short indices[], unsigned short numVertices, unsigned int numIndices, bool dynamic) :
    m_dynamic(dynamic)

    glGenVertexArrays(1, m_vertexArrays);
    glBindVertexArray(m_vertexArrays[0]);

    glGenBuffers(NUM_BUFFERS, m_buffers);

    createBuffers(positions, texCoords, indices, numVertices, numIndices, false);

    glBindVertexArray(0);

    m_drawCount = numIndices;


Mesh_PTI::~Mesh_PTI()

    glDeleteBuffers(NUM_BUFFERS, m_buffers);
    glDeleteVertexArrays(1, m_vertexArrays);


void Mesh_PTI::draw()

    if(m_drawCount > 0)
    
        glBindVertexArray(m_vertexArrays[0]);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[INDEX_VB]);
        glDrawElements(GL_TRIANGLES, m_drawCount, GL_UNSIGNED_SHORT, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    


void Mesh_PTI::setData(glm::vec3 positions[], glm::vec2 texCoords[], unsigned short indices[], unsigned short numVertices, unsigned int numIndices)

    glBindVertexArray(m_vertexArrays[0]);
    createBuffers(positions, texCoords, indices, numVertices, numIndices, false);
    glBindVertexArray(0);
    m_drawCount = numIndices;


void Mesh_PTI::createBuffers(glm::vec3 positions[], glm::vec2 texCoords[], unsigned short indices[], unsigned short numVertices, unsigned int numIndices, bool dynamic)

    glBindBuffer(GL_ARRAY_BUFFER, m_buffers[POSITION_VB]);
    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(positions[0]), positions, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, m_buffers[TEXCOORD_VB]);
    glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(texCoords[0]), texCoords, GL_STATIC_DRAW);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, NULL);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffers[INDEX_VB]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices * sizeof(indices[0]), indices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 1, GL_SHORT, GL_FALSE, 0, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

我需要更新顶点数据。如果我删除网格并使用构造函数加载顶点数据,一切正常。

如果我使用第一个构造函数对其进行初始化并使用setData 函数加载顶点数据,则此类的多个实例只会呈现调用了setData 的最后一个实例。

我做错了什么?

【问题讨论】:

在调用 setData 之间是否调用 draw? 【参考方案1】:

glGenBuffers 仅在调用该方法时返回可用的缓冲区名称,它不保留这些名称。因此,下次您调用glGenBuffers 时没有将任何内容绑定到调用 glGenBuffers 的第一个缓冲区,您将获得相同的名称,因为它们尚未使用。当您稍后调用 glBindBuffers 时,您会发现所有实例都为其 VBO 使用相同的名称,因此它们相互覆盖。

您还尝试将元素数组缓冲区绑定为顶点属性,这不会 有任何意义,因为索引被用作 glDrawElements 的一部分(除非您使用 由于某种原因,它们在您的着色器中)。

glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 1, GL_SHORT, GL_FALSE, 0, NULL);
//                          ^~~~~ but your indices are GL_UNSIGNED_SHORT

关于相关说明:您不需要每次在使用 VAO 绘制之前绑定索引缓冲区,因为索引缓冲区是 VAO state 的一部分。使用 glVertexPointer* 函数绑定指定的顶点数据,因此顶点->属性绑定及其相应的 VBO 也是状态的一部分,但 GL_ARRAY_BUFFER 不是。

【讨论】:

以上是关于OpenGL 多个 VBO 只渲染一个的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL - 会使用多个 VBO 减慢渲染速度吗?

opengl交错vbo不渲染到屏幕

OpenGL:一个 VBO 的多个 VAO

OpenGL纹理初始化/渲染问题

使用 VBO 渲染顶点的问题 - OpenGL

opengl vbo 纹理