I'm currently trying to render a skybox using the QOpenGL library of Qt. For that, I tried to modify the QOpenGL "cube" example that is provided by Qt (I'm using the latest Qt 5.13 version).
The vertex and index buffers are initialized in a class called GeometryEngine
, in which vertex and index array are defined as well. In the example, the vertex array has texture coordinates, so I got rid of those and kept only the position coordinates, because every operation regarding the skybox texture will be done in the shaders.
There's also a function called initTextures
in the window class that I modified to load the textures of the 6 faces of the cube (I don't know if this part is correct though).
I also set up an OpenGL debug Logger using this example : https://www.trentreed.net/blog/qt5-opengl-part-5-debug-logging/.
When I execute the code, I only get a window with a black screen and nothing rendered and the following error messages :
GL_INVALID_OPERATION error generated. Invalid VAO/VBO/pointer usage.
and
GL_INVALID_OPERATION error generated. Array object is not active.
Has anynone encountered this issue before and fixed it ? Because I don't think I forgot any part of the rendering process. I only modified the input data and the shaders (but I got no error from that part).
First, I thought the core of the problem was due to the vertex and index array, so I tried to use only a vertex buffer by repeating the vertices for each triangle in the vertex array, but I got the same error messages.
Since I got no compile error, I tried to locate the problem by using the #if 0 [...] #endif
on each functions until I got no OpenGL error messages. I finally isolated the origin in the drawCubeGeometry
method in the GeometryEngine
class, where the position attribute are sent to the shaders and the draw call is issued. there seems to be a problem with the setAttributeBuffer
and glDrawElements
calls, but I can't figure it out.
I tried looking for solutions online but there is so little questions asked about QOpenGL.
In GeometryEngine.cpp :
void GeometryEngine::initCubeGeometry()
{
QVector3D vertices[] = {
// Vertex data for face 0
QVector3D(-1.0f, -1.0f, 1.0f), // v0
QVector3D( 1.0f, -1.0f, 1.0f), // v1
QVector3D(-1.0f, 1.0f, 1.0f), // v2
QVector3D( 1.0f, 1.0f, 1.0f), // v3
// Vertex data for face 1
QVector3D( 1.0f, -1.0f, 1.0f), // v4
QVector3D( 1.0f, -1.0f, -1.0f), // v5
QVector3D( 1.0f, 1.0f, 1.0f), // v6
QVector3D( 1.0f, 1.0f, -1.0f), // v7
// Vertex data for face 2
QVector3D( 1.0f, -1.0f, -1.0f), // v8
QVector3D(-1.0f, -1.0f, -1.0f), // v9
QVector3D( 1.0f, 1.0f, -1.0f), // v10
QVector3D(-1.0f, 1.0f, -1.0f), // v11
// Vertex data for face 3
QVector3D(-1.0f, -1.0f, -1.0f), // v12
QVector3D(-1.0f, -1.0f, 1.0f), // v13
QVector3D(-1.0f, 1.0f, -1.0f), // v14
QVector3D(-1.0f, 1.0f, 1.0f), // v15
// Vertex data for face 4
QVector3D(-1.0f, -1.0f, -1.0f), // v16
QVector3D( 1.0f, -1.0f, -1.0f), // v17
QVector3D(-1.0f, -1.0f, 1.0f), // v18
QVector3D( 1.0f, -1.0f, 1.0f), // v19
// Vertex data for face 5
QVector3D(-1.0f, 1.0f, 1.0f), // v20
QVector3D( 1.0f, 1.0f, 1.0f), // v21
QVector3D(-1.0f, 1.0f, -1.0f), // v22
QVector3D( 1.0f, 1.0f, -1.0f) // v23
};
GLushort indices[] = {
0, 1, 2, 3, 3,
4, 4, 5, 6, 7, 7,
8, 8, 9, 10, 11, 11,
12, 12, 13, 14, 15, 15,
16, 16, 17, 18, 19, 19,
20, 20, 21, 22, 23
};
// Transfer vertex data to VBO 0
arrayBuf.bind();
arrayBuf.allocate(vertices, 24 * sizeof(QVector3D));
// Transfer index data to VBO 1
indexBuf.bind();
indexBuf.allocate(indices, 34 * sizeof(GLushort));
}
void GeometryEngine::drawCubeGeometry(QOpenGLShaderProgram *program)
{
// Tell OpenGL which VBOs to use
arrayBuf.bind();
indexBuf.bind();
// Offset for position
quintptr offset = 0;
// Tell OpenGL programmable pipeline how to locate vertex position data
int vertexLocation = program->attributeLocation("a_position");
program->enableAttributeArray(vertexLocation);
program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(QVector3D));
// Draw cube geometry using indices from VBO 1
glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, 0);
}
GLWidget.cpp :
void GLWidget::paintGL()
{
// Clear color and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
texture->bind();
// Calculate model view transformation
QMatrix4x4 matrix;
matrix.translate(0.0, 0.0, 0.0);
matrix.rotate(rotation);
// Set modelview-projection matrix
program.setUniformValue("mvp_matrix", projection * matrix);
// Use texture unit 0 which contains cube.png
program.setUniformValue("texture", 0);
// Draw cube geometry
geometries->drawCubeGeometry(&program);
}
For now I only try to display a red cube (in the fragment shader) to see if it works. I will focus on applying the texture later.