This article only introduces the use of basic QOpenGLWidget and QOpenGLFunctions. Friends who want to learn OpenGL are recommended to visit the classic OpenGL learning website:LearnOpenGL CN
In this article, we will take drawing a classic triangle as an example and talk about how to use OpenGL in Qt to draw GPU.
Preface
In high-performance rendering scenarios, CPU resources are often over-consuming, resulting in interface stuttering. As an industry-standard graphics API, OpenGL can significantly reduce CPU load through GPU hardware acceleration. This article will use drawing triangles as an example to teach you how to implement cross-platform GPU rendering through QT's QOpenGLWidget and QOpenGLFunctions.
QOpenGLFunctions
There are differences in the implementation of OpenGL functions on different platforms (Windows/Linux/Mac). For example:
platform | Function loading method |
---|---|
Windows | wglGetProcAddress |
Linux | glXGetProcAddress |
Qt byQOpenGLFunctions
Encapsulated these underlying differences, developers only need to inherit this class and use itglClear()
The unified interface calls OpenGL functions without writing platform-specific code. In this way, we can use an OpenGL phase on different platforms using a set of code. It is also very simple to use this class, let our class inherit directlyQOpenGLFuntions
That's fine. It can also cooperateQOpenGLWidget
Come to use, ininitializeGL
In the function, callinitializeOpenGLFunctions
After that, it's OKDirectly use OpenGL functions。
Loading under Windows (wglGetProcAddress
)
For example, under Windows, we usewglGetProcAddress
To load these functions dynamically (e.g.glClear
), here is the loading code:
-
Contains the necessary header files
#include <> #include <GL/> #include <GL// Provide OpenGL extension statement
-
Define function pointer type
// Example: Define the function pointer type of glClear typedef void (APIENTRY *PFNGLCLEARPROC)(GLbitfield); PFNGLCLEARPROC glClear;
-
Loading OpenGL functions
// Initialize OpenGL function void initOpenGLFunctions() { // 1. Load the OpenGL 1.1 function (provided by) glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear"); // 2. Check whether the loading is successful if (!glClear) { // If it fails, it may be that the driver does not support the function MessageBoxA(NULL, "Failed to load glClear", "Error", MB_OK); exit(1); } // 3. Load other functions in a similar way... // glDrawArrays = (PFNGLDRAWARRAYSPROC)wglGetProcAddress("glDrawArrays"); // ... }
-
Using loaded functions
glClear(GL_COLOR_BUFFER_BIT); // It can be called normally now
Loading under Linux (glXGetProcAddress
)
And in linux, the loaded function becomes:glXGetProcAddress
, the corresponding code is:
-
Contains the necessary header files
#include <GL/> #include <GL// OpenGL extension for X11 #include <GL/>
-
Define function pointer type
// Example: Define the function pointer type of glClear typedef void (*PFNGLCLEARPROC)(GLbitfield); PFNGLCLEARPROC glClear;
-
Loading OpenGL functions
void initOpenGLFunctions() { // 1. Load glClear glClear = (PFNGLCLEARPROC)glXGetProcAddress((const GLubyte*)"glClear"); // 2. Check whether the loading is successful if (!glClear) { fprintf(stderr, "Failed to load glClear\n"); exit(1); } // 3. Load other functions in a similar way... // glDrawArrays = (PFNGLDRAWARRAYSPROC)glXGetProcAddress((const GLubyte*)"glDrawArrays"); // ... }
-
Using loaded functions
glClear(GL_COLOR_BUFFER_BIT); // It can be called normally now
QOpenGLWidget
QOpenGLWidget
is a widget class provided by Qt to embed OpenGL rendering content in Qt applications. It inherits fromQWidget
, an OpenGL context is managed internally (for example, under Windows callswglMakeCurrent
/ wglDoneCurrent
) and frame buffers and provide the ability to seamlessly integrate with the Qt windowing system.For details, please see:QOpenGLWidget Class
We can create our own window, inherit QOpenGLWidget, and then rewrite the following three functions to handle some OpenGL-related work.
initializeGL
Initialize some OpenGL-related resources or states.This function is called firstresizeGL
orpaintGL
Called before.
paintGL
Rendering OpenGL scenes, similar to what we usually useQWidget::paintEvent
, called when the window needs to be updated.
resizeGL
Resize or project the OpenGL Viewport, etc., and call it when the window needs to be resized.
Complete code
#pragma once
#include <QOpenGLBuffer>
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include ""
class COpenGLRenderWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit COpenGLRenderWidget(QWidget *parent = nullptr);
~COpenGLRenderWidget() override;
private:
void InitShaders();
private:
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
private:
QOpenGLShaderProgram m_shaderProgram;
QOpenGLBuffer m_vbo;
};
#include ""
static const GLfloat coordinateBasic[] = {
// Vertex coordinates, storing 3 xyz coordinates
// x y z
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f,
};
constexpr auto VERTEX_SHADER_BASIC = R"(
attribute vec3 vertexIn;
varying vec2 textureOut;
void main(void)
{
gl_Position = vec4(vertexIn, 1.0);
}
)";
constexpr auto FRAGMENT_SHADER_BASIC = R"(
varying vec2 textureOut;
void main(void)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
)";
COpenGLRenderWidget::COpenGLRenderWidget(QWidget *parent)
: QOpenGLWidget(parent)
{}
COpenGLRenderWidget::~COpenGLRenderWidget()
{}
void COpenGLRenderWidget::initializeGL()
{
initializeOpenGLFunctions();
glDisable(GL_DEPTH_TEST);
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(coordinateBasic, sizeof(coordinateBasic));
InitShaders();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
void COpenGLRenderWidget::paintGL()
{
m_shaderProgram.bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
m_shaderProgram.release();
}
void COpenGLRenderWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
update();
}
void COpenGLRenderWidget::InitShaders()
{
QOpenGLShader vertexShader(QOpenGLShader::Vertex);
if (!(VERTEX_SHADER_BASIC))
{
qDebug() << "Vertex shader compilation failed. Error: " << ();
return;
}
QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
if (!(FRAGMENT_SHADER_BASIC))
{
qDebug() << "Fragment shader compilation failed. Error: " << ();
return;
}
m_shaderProgram.addShader(&vertexShader);
m_shaderProgram.addShader(&fragmentShader);
m_shaderProgram.link();
m_shaderProgram.bind();
m_shaderProgram.setAttributeBuffer("vertexIn", GL_FLOAT, 0, 3, 3 * sizeof(float));
m_shaderProgram.enableAttributeArray("vertexIn");
}