本文只介绍基本的 QOpenGLWidget 和 QOpenGLFunctions 的使用,想要学习 OpenGL 的朋友,建议访问经典 OpenGL 学习网站:LearnOpenGL CN

本篇文章,我们将以绘制一个经典的三角形为例,讲一讲,怎么在 Qt 中使用 OpenGL 来进行 GPU 绘制。

前言

在高性能渲染场景中,CPU资源常被过度消耗,导致界面卡顿。而OpenGL作为业界标准的图形API,能通过GPU硬件加速显著降低CPU负载。本文将以绘制三角形为例,教你如何通过Qt的QOpenGLWidget和QOpenGLFunctions实现跨平台GPU渲染。

QOpenGLFunctions

OpenGL函数在不同平台(Windows/Linux/Mac)的实现存在差异。例如:

平台 函数加载方式
Windows wglGetProcAddress
Linux glXGetProcAddress

Qt通过QOpenGLFunctions封装了这些底层差异,开发者只需继承此类,即可用glClear() 等统一接口调用OpenGL函数,无需编写平台特定代码。通过这样,我们就可以用一套代码,在不同平台下使用 OpenGL 相。要使用这个类也很简单,让我们的类直接继承 QOpenGLFuntions 就好了。同时也可以配合 QOpenGLWidget 来使用,在 initializeGL 函数里,调用 initializeOpenGLFunctions 后,就可以直接使用 OpenGL 的函数

Windows 下加载(wglGetProcAddress

例如在 Windows 下,我们使用 wglGetProcAddress来动态加载这些函数(例如 glClear),下面是加载代码:

  • 包含必要的头文件

    #include <windows.h>
    #include <GL/gl.h>
    #include <GL/glext.h> // 提供 OpenGL 扩展声明
  • 定义函数指针类型

    // 示例:定义 glClear 的函数指针类型
    typedef void (APIENTRY *PFNGLCLEARPROC)(GLbitfield);
    PFNGLCLEARPROC glClear;
  • 加载 OpenGL 函数

    // 初始化 OpenGL 函数
    void initOpenGLFunctions() {
    // 1. 加载 OpenGL 1.1 函数(由 opengl32.dll 提供)
    glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear"); // 2. 检查是否加载成功
    if (!glClear) {
    // 如果失败,可能是驱动不支持该函数
    MessageBoxA(NULL, "Failed to load glClear", "Error", MB_OK);
    exit(1);
    } // 3. 类似方式加载其他函数...
    // glDrawArrays = (PFNGLDRAWARRAYSPROC)wglGetProcAddress("glDrawArrays");
    // ...
    }
  • 使用加载的函数

    glClear(GL_COLOR_BUFFER_BIT);  // 现在可以正常调用

Linux 下加载(glXGetProcAddress

而在 linux 下,加载的函数变成了:glXGetProcAddress ,对应的代码是:

  • 包含必要的头文件

    #include <GL/gl.h>
    #include <GL/glx.h> // X11 的 OpenGL 扩展
    #include <GL/glext.h>
  • 定义函数指针类型

    // 示例:定义 glClear 的函数指针类型
    typedef void (*PFNGLCLEARPROC)(GLbitfield);
    PFNGLCLEARPROC glClear;
  • 加载 OpenGL 函数

    void initOpenGLFunctions() {
    // 1. 加载 glClear
    glClear = (PFNGLCLEARPROC)glXGetProcAddress((const GLubyte*)"glClear"); // 2. 检查是否加载成功
    if (!glClear) {
    fprintf(stderr, "Failed to load glClear\n");
    exit(1);
    } // 3. 类似方式加载其他函数...
    // glDrawArrays = (PFNGLDRAWARRAYSPROC)glXGetProcAddress((const GLubyte*)"glDrawArrays");
    // ...
    }
  • 使用加载的函数

    glClear(GL_COLOR_BUFFER_BIT);  // 现在可以正常调用

QOpenGLWidget

QOpenGLWidget 是 Qt 提供的一个 widget 类,用于在 Qt 应用程序中嵌入 OpenGL 渲染内容。它继承自 QWidget,内部管理了一个 OpenGL 上下文(例如 windows 下调用 wglMakeCurrent / wglDoneCurrent)和帧缓冲区,并提供了与 Qt 窗口系统无缝集成的能力。详细内容可看:QOpenGLWidget Class

我们可以创建自己的窗口,并继承 QOpenGLWidget,然后重写下面三个函数,来处理一些 OpenGL 相关的工作。

initializeGL

初始化一些 OpenGL 相关的资源或者状态。这个函数在在第一次调用 resizeGL或者 paintGL之前被调用。

paintGL

渲染 OpenGL 的场景,类似于我们平常使用的 QWidget::paintEvent,在窗口需要更新时调用。

resizeGL

调整 OpenGL Viewport 的大小或者投影等,在窗口需要调整大小时调用。

完整代码

#pragma once

#include <QOpenGLBuffer>
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions> #include "FrameObserver.h" 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 "OpenGLRenderWidget.h"

static const GLfloat coordinateBasic[] = {
// 顶点坐标,存储3个xyz坐标
// 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 (!vertexShader.compileSourceCode(VERTEX_SHADER_BASIC))
{
qDebug() << "Vertex shader compilation failed. Error: " << vertexShader.log();
return;
} QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
if (!fragmentShader.compileSourceCode(FRAGMENT_SHADER_BASIC))
{
qDebug() << "Fragment shader compilation failed. Error: " << fragmentShader.log();
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");
}

从零开始:在Qt中使用OpenGL绘制指南的更多相关文章

  1. Ubuntu中在QT中配置OpenGL

    之前搞实验室项目,博客有些天没有更新.现在学习需要,开始搞OpenGL+Ubuntu+QT. 搞了整整一天,由于是首次使用ubuntu,所以这ubuntu下配置qt和Opengl环境时走了很多的弯路, ...

  2. QT中文字的绘制

    为什么要做这次文字的介绍,因为在一般的教材中,还真没有文字的描述: 1.绘制最简单的文字. 我们更改重绘函数如下: void Dialog::paintEvent(QPaintEvent *){QPa ...

  3. 46.Qt 使用OpenGL绘制立方体

    main.cpp #include <QApplication> #include <iostream> #include "vowelcube.h" in ...

  4. Qt Examples - Boxes (在Qt场景视图中结合OpenGL渲染)

    QT自带例程Boxes使用QT Graphics View框架实现了2D图形和3D图形的混合渲染,综合性比较强,整合知识较多,值得学习. 可以使用鼠标通过以下方式控制演示中的元素: 按住鼠标左键的同时 ...

  5. opengl es中不同的绘制方式

    opengl es中不同的绘制方式 转载请保留出处:http://xiaxveliang.blog.163.com/blog/static/297080342013467344263/ 1. GL_P ...

  6. Qt 框架的图形性能高(OpenGL上的系统效率高),网络性能低,开发效率高,Quick是可以走硬件加速——Qt中分为好几套图形系统,差不多代表了2D描画的发展史。最经典的软描画系统

    -----图形性能部分-----Qt的widgets部分,运行时的图像渲染性能是一般的,因为大部分的界面内容都是Qt自绘,没有走硬件加速,也就是说很多图形内容都是CPU算出来的.但是widgets底层 ...

  7. Qt中OpenGL的初步使用

    结果预览: 一.代码5个文件 //glwidget.h #ifndef GLWIDGET_H #define GLWIDGET_H #include <QGLWidget> class G ...

  8. 在Android中使用OpenGL ES进行开发第(三)节:绘制图形

    一.前期基础知识储备笔者计划写三篇文章来详细分析OpenGL ES基础的同时也是入门关键的三个点: ①OpenGL ES是什么?与OpenGL的关系是什么?——概念部分 ②使用OpenGLES绘制2D ...

  9. qt中窗口绘制——图片的绘制

    在qt 中,QPixmap 用于表示一张图片,支持png,jpg格式的加载. QPixmap pm("c:/test.png"); 或者 QPixmap pm; pm.load(& ...

  10. OpenGL编程指南(第七版)

    OpenGL编程指南(第七版) 转自:http://blog.csdn.net/w540982016044/article/details/21287645 在接触OpenGL中,配置显得相当麻烦,特 ...

随机推荐

  1. Hutool-工具常用代码集

    Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以"甜甜的".Hutool ...

  2. cookie和session的详解与区别-copy

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...

  3. HashMap的底层实现原理? HashMap 和 Hashtable的异同? 负载因子值的大小,对HashMap有什么影响?

     1. HashMap的底层实现原理 HashMap的底层:数组+链表 (jdk7及之前) 数组+链表+红黑树 (jdk 8)HashMap的底层实现原理?以jdk7为例说明: HashMap map ...

  4. 【译】我们最喜欢的2024年的 Visual Studio 新功能

    去年,Visual Studio 团队发布了许多新的面向开发人员的改进和 AI 集成,其中许多直接来自您在开发者社区的反馈.在这篇文章中,我们将重点介绍2024年团队最喜欢的功能,这些功能可以提高生产 ...

  5. flutter设置导航栏顶部标题与组件Text和Center和Container详解

    无状态组件和有状态组件的介绍 StatelessWidget 是无状态组件,状态是不可以改变的 StatefulWidget 是有状态组件 持有的状态可能在 widge 生命周期中改变 Statele ...

  6. 开源标杆!天翼云TeleDB入选《2024央国企开源项目典型实践》!

    近日,由中国通信标准化协会主办.中国信通院承办的2024 OSCAR开源产业大会在北京召开,会上发布<2024央国企开源项目典型实践>,天翼云科技有限公司打造的"TeleDB分布 ...

  7. 部署Palworld幻兽帕鲁服务器最佳实践(Ubuntu)

    本文为您介绍Ubuntu系统部署Palworld幻兽帕鲁服务器的最/佳实践. 1.登录云主机控制台,选择创建云主机的资源池,点击"创建云主机"按钮. 2.基础配置. CPU架构选择 ...

  8. Jenkins插件:Generic Webhook Trigger

    Jenkins插件:Generic Webhook Trigger 作为一名软件测试工程师,在日常工作中,我经常需要使用Jenkins来进行持续集成和持续部署(CI/CD).而Jenkins的众多插件 ...

  9. Maven 打包的几种常用方式

    一.maven-jar-plugin 默认的打包插件,用来打普通的jar 包,需建立lib目录里来存放需要的依赖包 二.maven-shade-plugin (推荐) 将依赖的jar包打包到当前jar ...

  10. AI工具推荐:领先的开源 AI 代码助手——Continue

    前言 之前介绍了VS Code中的AI插件Cline与Roo Code,这两个都是根据给定一个任务,开始自动写代码的.除了这两个AI代码工具之外,在平常我还很喜欢的就是Continue . Conti ...