Qt with OpenGL: bind/release of Index Array Object
-
wrote on 19 Sept 2024, 00:18 last edited by
I have been following this answer for custom OpenGL rendering to a QML Item via
QQuickFrameBufferObject
. Briefly, the setup described is:vao.create(); vao.bind(); // Prepare shaders shaderpgm.addShader(...); shaderpgm.link(); // Prepare vertex array, VBO vbo.create(); vbo.setUsagePattern(QOpenGLBuffer::StaticDraw); vbo.bind(); vbo.allocate(vertices.data(), vertices.size()*sizeof(GLfloat)); vbo.release(); // Set shader attribs shaderpgm.bind(); vbo.bind(); shaderProgram.enableAttributeArray("vertex"); shaderProgram.setAttributeBuffer("vertex", GL_FLOAT, 0, 3); vbo.release(); shaderpgm.release(); vao.release();
In the
render
function we have:vao.bind(); glDrawArrays(GL_TRIANGLES, 0, vertices.size()); vao.release();
This makes sense, and works fine. However, this scheme does not seem to work for an Index Buffer Object. I thought that all that would be needed is to bind/allocate/release the IBO while the VAO is bound and that would take care of it (and of course, the
glDrawArrays
changes toglDrawElements
). Like so:vao.create(); vao.bind(); ... ibo.create(); ibo.setUsagePattern(QOpenGLBuffer::StaticDraw); ibo.bind(); ibo.allocate(indices.data(), indices.size()*sizeof(GLuint)); ibo.release(); ... vao.release();
However this does not work. After some trial and error, I found that either of the two following solutions work:
- Do not release the ibo in the above setup:
ibo.create(); ibo.setUsagePattern(QOpenGLBuffer::StaticDraw); ibo.bind(); ibo.allocate(indices.data(), indices.size()*sizeof(GLuint));
ibo.release();
- Or, do release it as before, but bind it again in the
render
call:
vao.bind(); ibo.bind(); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); ibo.release(); vao.release();
Why is this different for the IBO compared to the VBOs? I had thought that as long as the VAO is bound when you create various buffers, all of those get associated with that VAO, and in the
render
call you only need to bind/release the VAO. -
wrote on 27 Sept 2024, 22:19 last edited by
Turns out this is a quirk of OpenGL, and IBOs and VBOs are indeed different internally. From here:
For VBO: it is the call to
glVertexAttribPointer
(done inQOpenGLProgram::setAttributeArray
) that establishes the VBO bind within the VAO.glVertexAttribPointer(i, ...)
is the same asvao.attributes[i].vbo = vbo;
where i is the attribute index.Otoh the IBO bind
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO)
is directly stored inside the VAO. i.e.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
is the same asvao.ibo = ibo
;VBOs can be unbound but IBOs must not.
-