VAO 绘制错误的索引缓冲区

Posted

技术标签:

【中文标题】VAO 绘制错误的索引缓冲区【英文标题】:VAO drawing the wrong Index Buffer 【发布时间】:2018-10-25 15:39:42 【问题描述】:

我正在尝试使用(相同的)基本着色器程序绘制多个对象。这些对象具有顶点缓冲区,我打算通过调用 glDrawElements 使用关联的索引缓冲区进行绘制。我为每个对象设置了一个 VAO,并认为我已将索引缓冲区和顶点缓冲区与 VAO 相关联,但是当我绘制第二个(以及任何其他对象)时,它们使用错误的顶点进行绘制。

这是我设置 VBO 和 EBO 的(伪)代码:

glGenBuffers(1, &vboCube);
glBindBuffer(GL_ARRAY_BUFFER, vboCube);
glBufferData(GL_ARRAY_BUFFER, getNumSphereVertices() * sizeof(Vertex), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glGenBuffers(1, &iboCube);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboCube);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, getNumCubeIndices() * sizeof(uint32), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);


glGenBuffers(1, &vboSphere);
glBindBuffer(GL_ARRAY_BUFFER, vboSphere);
glBufferData(GL_ARRAY_BUFFER, getNumSphereVertices() * sizeof(Vertex), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

glGenBuffers(1, &iboSphere);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboSphere);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, getNumSphereIndices() * sizeof(uint32), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

编辑: 这些已更新为使用 DSA 等效项,但问题仍然存在。 DSA 代码如下:

glCreateBuffers(1, &vboCube);
glBindBuffer(GL_ARRAY_BUFFER, vboCube);
glNamedBufferData(vboCube, getNumCubeVertices() * sizeof(Vertex), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

接下来链接我的程序属性:

glUseProgram(programID);

uint32 vaoCube;
glCreateVertexArrays(1, &vaoCube);
glBindVertexArray(vaoCube);
i = 0
for each attribute:
    uint32 attribIndex = glGetAttribLocation(program, name.c_str());
    glVertexArrayVertexBuffer(vaoCube, i, vboCube, 0, stride);
    glEnableVertexArrayAttrib(vaoCube, attribIndex);
    glVertexArrayAttribFormat(vaoCube, attribIndex, numCells, dataType, normalise, offset);
    glVertexArrayAttribBinding(vaoCube, attribIndex, i);
    glVertexArrayBindingDivisor(vaoCube, i, divisor);
    i++
glBindVertexArray(0);

glBindVertexArray(vaoCube);
glVertexArrayElementBuffer(vaoCube, iboCube);
glBindVertexArray(0);


uint32 vaoSphere;
glCreateVertexArrays(1, &vaoSphere);
glBindVertexArray(vaoSphere);
i = 0
for each attribute:
    uint32 attribIndex = glGetAttribLocation(program, name.c_str());
    glVertexArrayVertexBuffer(vaoSphere, i, vboSphere, 0, stride);
    glEnableVertexArrayAttrib(vaoSphere, attribIndex);
    glVertexArrayAttribFormat(vaoSphere, attribIndex, numCells, dataType, normalise, offset);
    glVertexArrayAttribBinding(vaoSphere, attribIndex, i);
    glVertexArrayBindingDivisor(vaoSphere, i, divisor);
    i++
glBindVertexArray(0);

glBindVertexArray(vaoSphere);
glVertexArrayElementBuffer(vaoSphere, iboSphere);
glBindVertexArray(0);

最后绘制对象:

glBindVertexArray(vaoCube);
glDrawElements(GL_TRIANGLES, getNumCubeIndices(), GL_UNSIGNED_INT, (GLvoid*)0);
glBindVertexArray(0);


glBindVertexArray(vaoSphere);
glDrawElements(GL_TRIANGLES, getNumSphereIndices(), GL_UNSIGNED_INT, (GLvoid*)0);
glBindVertexArray(0);

终于出结果了:

VAO 设置是否不正确?

【问题讨论】:

@Rabbid76 抱歉,这是一个错误的代码来质疑转换。 vertexBufferBinding 是 VBO(本例中为 vboCube 和 vboSphere)的绑定点。我已经编辑了代码 sn-p 以反映这一点。 【参考方案1】:

如果您使用的是 ARB_direct_state_access/OpenGL 4.5,则应该始终如一地完全这样做。因此,“用于设置 VBO 和 EBO 的我的(伪)代码:”中的所有内容都是错误的。您应该使用glCreateBufferglNamedBufferData 等。

这很重要,因为GL_ARRAY_BUFFER 是上下文状态的一部分,GL_ELEMENT_ARRAY_BUFFER 是 VAO 状态的一部分。如果您使用的是核心 OpenGL 并且没有绑定 VAO……这意味着没有元素数组缓冲区状态。所以你的glBindBuffer 调用应该出错了,你随后尝试使用它们也会同样失败。

【讨论】:

感谢您的反馈。我已将缓冲区创建和填充函数更新为 DSA 方法。有趣的是,我在其他设置中没有收到任何 GL 错误。不过,损坏球体的问题仍然存在。【参考方案2】:

问题出在上面显示的代码之外。上面的代码确实有效。

【讨论】:

以上是关于VAO 绘制错误的索引缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL ES之VBOEBO与VAO的说明和使用

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

c_cpp 使用VAO(顶点数组对象)和顶点缓冲区定义和绘制矩形。

在 iOS 上使用具有多个 VBO 和 IBO(多个对象)OpenGLES 2 的 VAO 进行绘制

多个缓冲器和 VAO 性能

快速修改 OpenGL VAO 缓冲区