OpenGL in Qt 5.1 – Part 2

This article continues our series on what is new in Qt 5.1 with respect to OpenGL. The first installment can be found here.

Vertex Array Objects

Qt has QOpenGLBuffer (and before that QGLBuffer) to help manage various types of OpenGL buffer objects such as per-vertex attribute data and element index buffers. OpenGL also has a simple related container type call Vertex Array Objects (VAOs) to help with managing sets of vertex buffer objects.

KDAB has added code to Qt 5.1 that encapsulates VAOs with the QOpenGLVertexArrayObject class. Binding an instance of this class causes OpenGL to “remember” any vertex specification state that you then set up. We can later restore this vertex specification state very quickly by simply re-binding the VAO itself. This allows us to very rapidly switch between vertex states for “objects” that we wish to draw in our rendering function:

void Scene::initialize() { // Assumes we have a current QOpenGLContext and that // m_shaderProgram is a QOpenGLShaderProgram // Create VAO for first object to render m_vao1 = new QOpenGLVertexArrayObject( this ); m_vao1->create(); m_vao1->bind(); // Setup VBOs and IBO (use QOpenGLBuffer to buffer data, // specify format, usage hint etc). These will be // remembered by the currently bound VAO m_positionBuffer.create(); m_positionBuffer.setUsagePattern( QOpenGLBuffer::StreamDraw ); m_positionBuffer.bind(); m_positionBuffer.allocate( positionData, vertexCount * 3 * sizeof( float ) ); m_shaderProgram.enableAttributeArray( "vertexPosition" ); m_shaderProgram.setAttributeBuffer( "vertexPosition", GL_FLOAT, 0, 3 ); m_colorBuffer.create(); m_colorBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); m_colorBuffer.bind(); m_colorBuffer.allocate( colorData, vertexCount * 3 * sizeof( float ) ); m_shaderProgram.enableAttributeArray( "vertexColor" ); m_shaderProgram.setAttributeBuffer( "vertexColor", GL_FLOAT, 0, 3 ); // Repeat for buffers of normals, texture coordinates, // tangents, ... ... // Create VAO for second object to render m_vao2 = new QOpenGLVertexArrayObject( this ); m_vao2->create(); m_vao2->bind(); // Setup VBOs and IBO for next object ... // Rinse and repeat for other objects m_skyBoxVAO = new QOpenGLVertexArrayObject( this ); ... } void Scene::render() { // Clear buffers m_funcs->glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Bind shader program, textures for first set of objects m_phongShaderProgram->bind(); ... // Switch to the vertex data for first object and draw it m_vao1->bind(); m_funcs->glDrawElements(...); // Switch to the vertex data for second object and draw it m_vao2->bind(); m_funcs->glDrawElements(...); // Maybe change shader program, textures etc // and draw other objects m_skyboxShaderProgram->bind(); ... m_skyboxVAO->bind(); m_funcs->glDrawElements(...); ... }

VAOs were introduced with OpenGL 3 but are required for OpenGL 3.1 and for OpenGL >=3.2 with the Core profile. In addition, VAOs are available via the GL_ARB_vertex_array_object or GL_OES_vertex_array_object extensions on OpenGL 2 and OpenGL ES 2 respectively. The QOpenGLVertexArrayObject will use the core feature if available or fall-back to the appropriate extension if available.

The use of VAOs can greatly simplify your rendering code and make it faster due to the OpenGL driver having to potentially do less sanity checking than if doing more buffer operations.

Read Part 3…