Hello Qt, Hello OpenGL, Hello World

The example project that I am going to share in this post is the absolute beginner guide version of using OpenGL in Qt (Specially Qt5 and latest versions of OpenGL) which to my surprise I could not find anywhere. By checking the existing OpenGL examples in Qt I noticed they all make some assumptions about what you know about OpenGL and then go ahead and describe how to use in in Qt. [I hope, I really do] that is not what you’ll find here. So without further ado here is the most simple example.

First of all you need to add opengl module to your project. Do it by adding the following line to your project:

QT += opengl

And be sure to go over this documentation page to learn about QOpenGLWidget as much as you can because it’s the base class we have used here. And I might have missed some crucial points but the documentation is always the best reference.

The most important trick here is to know that you need to sub-class a public QOpenGLWidget (and protected QOpenGLFunctions) object and override three of its methods:

void initializeGL();
void paintGL();
void resizeGL(int w, int h);


initializeGL is where you do all the required initialization. What you see below is the most simple example of an initializeGL method:

void MyGL::initializeGL()
{
	initializeOpenGLFunctions(); // obvious

	GLfloat vertices[6][2] =
	{
	{ -0.90f, -0.90f }, // Triangle 1
	{ +0.85f, -0.90f },
	{ -0.90f, +0.85f },

	{ +0.90f, -0.85f }, // Triangle 2
	{ +0.90f, +0.90f },
	{ -0.85f, +0.90f }
	};

	buffer = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
	buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
	Q_ASSERT(buffer.create());
	Q_ASSERT(buffer.bind());
	buffer.allocate(sizeof(vertices));
	buffer.write(0, vertices, sizeof(vertices));

	shaderProg.addShaderFromSourceFile(QOpenGLShader::Vertex, "path_to_vertex_shader_file");
	shaderProg.addShaderFromSourceFile(QOpenGLShader::Fragment, "path_to_fragment_shader_file");
	Q_ASSERT(shaderProg.link());
	Q_ASSERT(shaderProg.bind());

	const int vPosition = 0;

	glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, NULL);

	glEnableVertexAttribArray(vPosition);

	glClear(GL_COLOR_BUFFER_BIT);

	glClearColor(0.25, 0.45, 0.65, 1.0);

}

I think the first line is as obvious as it can be right?

initializeOpenGLFunctions();

After that comes the vertices we need to draw on screen. In this example we are going to draw two triangles on screen.

GLfloat vertices[6][2] =
{
{ -0.90f, -0.90f }, // Triangle 1
{ +0.85f, -0.90f },
{ -0.90f, +0.85f },

{ +0.90f, -0.85f }, // Triangle 2
{ +0.90f, +0.90f },
{ -0.85f, +0.90f }
};

Then we create a buffer and add those points to the buffer. Remember, buffers will be drawn on screen:

buffer = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
Q_ASSERT(buffer.create());
Q_ASSERT(buffer.bind());
buffer.allocate(sizeof(vertices));
buffer.write(0, vertices, sizeof(vertices));

buffer is a QOpenGLBuffer which is defined globally. Here QOpenGLBuffer::VertexBuffer in the constructor means that we are providing Vertex data and setUsagePattern(QOpenGLBuffer::StaticDraw) helps make sure data is drawn on the screen as it is. The rest is creating and binding and allocating and filling it with data. Simple!



Next we have to load our shaders. We MUST have a vertex and a fragment shader at the least and I’ll also provide you with the shaders later in this guide but for now let’s say you  have saved your shaders to disk. So we load, link and bind the shaders like this:

shaderProg is a QOpenGLShaderProgram.

Next, and probably the only part of the code where you’ll probably feel lost if this is the first OpenGL program is this:

const int vPosition = 0;
glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(vPosition);

This part of the code is actually quite simple after you dig a little bit into the world of OpenGL. Here you are enabling a pointer between the shaders and C++ code. It’s like saying: “Points and vertex data from my C++ code will go to the location vPosition, which is zero, in the GLSL shaders.”

The last part of initializeGL is:

glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.25, 0.45, 0.65, 1.0);

In which you clear the buffer and prepare it for drawing. Note that you also give it bluish color.

After we’re done with initializeGL, we move to paintGL method. It only contains the actual drawing code which is:

void MyGL::paintGL()
{
	glDrawArrays(GL_TRIANGLES, 0, 6);
	glFlush();
}

First you say I want to draw triangles using 6 points. (Two triangles that is!) And then flush to make sure it’s all drawn as soon as possible.

In my example you can leave out resizeGL function like this:

void MyGL::resizeGL(int w, int h)
{
	Q_UNUSED(w); Q_UNUSED(h);
}

Means do nothing on resize 🙂 but don’t worry about it at all for now.

And finally to the shaders. Your vertex shader needs to be like this:

#version 430 core
layout(location = 0) in vec4 vPosition;
void main()
{
	gl_Position = vPosition;
}

And fragment shader like this:

#version 430 core
out vec4 fColor;
void main()
{
	fColor = vec4(0.0, 0.0, 1.0, 1.0);
}

These are the most simple shaders. Vertex shader here just passes any points you give it and the fragment shader just colors it with a blue color.

Your widget should look like this it is drawn on a Window:

gl example

Good luck!



7 Replies to “Hello Qt, Hello OpenGL, Hello World”

  1. (edit/correction to previous comment)..
    Your tutorial has been very helpful to a n00b like myself trying to learn. I would however like to point out that you confused the heck out of me right off the bat. You start off great but then you jump right to this paragraph…

    “The most important trick here is to know that you need to sub-class a public QOpenGLWidget (and protected QOpenGLFunctions) object …”

    — and completely lost me because you claim that it is one of the most important things you must know and do,.. but you never explain HOW or WHERE to accomplish this “sub-class”‘ing at all. It took me 2 days of digging elsewhere on the Internet to figure out what you were trying to say there, as you never show how to implement this.

    Perhaps an update to your article to show this part? — thanks

    1. Sorry to hear that it got you confused, but glad you figured it out on your own 🙂
      However, the assumption I have when I write any C++/Qt/OpenCV/OpenGL (and so on) tutorials, is that the reader has enough experience in C++.
      I think with that assumption it’s safe to say my following note is clear enough, even though I totally appreciate you mentioning it:
      “The most important trick here is to know that you need to sub-class a public QOpenGLWidget (and protected QOpenGLFunctions) object …”

  2. Your tutorial has been very helpful to a n00b like myself trying to learn. I would however like to point out that you confused the heck out of me right off the bat. You start off great but then you jump right to this paragraph…

    “The most important trick here is to know that you need to sub-class a public QOpenGLWidget (and protected QOpenGLFunctions) object and override three of its methods:”

    — and completely lost me because you claim that it is one of the most important things you must know and do,.. but you never explain HOW or WHERE to accomplish this at all. It took me 2 days of digging elsewhere on the Internet to figure out what you were trying to say there, as you never show how to implement this.

    Perhaps an update to your article to show this part? — thanks

  3. i have an onboard intel graphic card and its GLSL Version is 1.20.8, i tried to change the version in the fragment and vertex shader program from 430 to 120 but it didn’t work 🙁 so I wrote the program from scratch, I used this code and now it’s working 🙂

    <<<<<>>>>>
    #version 120
    attribute vec4 position;
    void main()
    {
    gl_Position = position;
    }

    <<<<<>>>>>
    #version 120
    void main()
    {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }

  4. i’ve been looking for a tutorial on how to use OpenGL with QT, something very basic, a bare minimum project. the examples shipped with Qt library are a little too advanced for me (for now :p) and this article is exactly what i’ve been looking for, so thank you very much for sharing your knowledge.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.