Qt中实现OpenGL应用的编程框架

在现代图形应用开发中,Qt与OpenGL的结合已成为构建高性能、跨平台图形界面应用的首选方案。Qt作为一个功能强大的C++ GUI框架,提供了丰富的UI组件和跨平台支持;而OpenGL作为行业标准的图形API,能够充分发挥GPU的渲染能力。两者的整合使得开发者能够在保持图形渲染性能的同时,实现复杂的用户交互和界面设计。Qt 通过 QOpenGLWidget QOpenGLWindow 等类封装了 OpenGL 的集成过程,简化了跨平台开发流程,同时保留了对现代 OpenGL 特性的支持。本报告将深入分析Qt中实现OpenGL应用的编程框架,包括集成方式、开发环境配置、核心类使用方法、信号槽交互策略以及性能优化和跨平台兼容性解决方案。

一、Qt与OpenGL的集成方式

Qt提供了多种方式将OpenGL集成到应用程序中,主要包括QOpenGLWidget和QOpenGLWindow两种主要类,它们各自适用于不同的场景。

QOpenGLWidget是Qt 5.4版本引入的类,继承自QWidget,适用于需要将 OpenGL 渲染内容嵌入到Qt 窗口或布局中的场景 。它提供了三个核心虚拟函数:initializeGL()用于初始化OpenGL资源和状态,resizeGL()用于设置视口和投影,paintGL()用于执行实际的渲染操作。这种设计使得开发者可以像使用其他QWidget继承类一样方便地集成OpenGL内容 [2] 。QOpenGLWidget内部使用帧缓冲区对象(FBO)进行离屏渲染,这与QOpenGLWindow的行为相似,更新行为设置为PartialUpdateBlit或PartialUpdateBlend,意味着在paintGL()调用之间保留内容,便于增量渲染 [15]

QOpenGLWindow则继承自QWindow,适合需要独立窗口或直接管理渲染上下文的场景。它提供了更底层的控制,允许开发者直接处理窗口系统和OpenGL上下文的关系。QOpenGLWindow通常用于全屏应用或需要直接与底层窗口系统交互的情况,而QOpenGLWidget更适合与Qt的其他GUI组件一起使用。

在Qt6中,QOpenGLWidget仍然是集成OpenGL的主要方式,但需要注意一些API变化。例如,Qt6推荐使用CMake作为构建系统而非qmake,因此配置OpenGL的方式有所调整。同时,Qt6中QOpenGLWidget的更新行为默认为PartialUpdate,这意味着颜色缓冲区和辅助缓冲区不会在帧之间失效,从而提高了渲染效率 。

二、开发环境配置与项目设置

在Qt中使用OpenGL需要进行适当的环境配置和项目设置,确保OpenGL库能够正确加载和使用。

对于使用qmake的项目,需要在.pro文件中添加QT += opengl openglwidgets语句,以声明使用QtOpenGL模块 。这会确保qmake在生成编译器所需的Makefile时添加所需的OpenGL库依赖。同时,在代码中需要包含相应的头文件,如#include 。

对于使用CMake的Qt6项目,配置过程略有不同。需要在CMakeLists.txt中使用find_package(Qt6OpenGL)来查找OpenGL模块,并在目标链接中包含Qt6::OpenGLWidgets [12] 。完整的CMake配置示例如下:

复制代码
cmake_minimum_required(VERSION 3.16)
project(MyOpenGLApp LANGUAGES CXX)

find_package(Qt6 REQUIRED COMPONENTS Widgets OpenGLWidgets)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)


# 添加源文件
add_executable(myapp main.cpp glwidget.cpp glwidget.h)

# 链接Qt模块和OpenGL库
target_link_libraries(myapp PRIVATE
    Qt6::Widgets
    Qt6::OpenGLWidgets
)

在跨平台配置方面,需要考虑不同操作系统的差异。在macOS上,由于Apple已弃用OpenGL,推荐使用MoltenVK将Vulkan转换为Metal API [40] 。在Linux上,需要确保系统安装了适当的OpenGL库(如mesa),并且可能需要处理GLVND(OpenGL Version Negotiation Done)与传统库路径的兼容性问题。在Windows上,则需要确保安装了适当的OpenGL驱动,并且在项目中链接了opengl32库。

值得注意的是,在构造 QApplication 实例之前,应该调用 QSurfaceFormat::setDefaultFormat() 来设置 OpenGL 上下文格式 ,特别是在macOS上请求核心配置文件上下文时。这可以确保所有后续创建的OpenGL上下文使用相同的版本和配置文件,避免兼容性问题 [15]

三、QOpenGLWidget类的使用方法与渲染流程

QOpenGLWidget是Qt中实现OpenGL渲染的核心类,其使用方法包括继承、重写核心函数和资源管理几个方面。

首先,创建一个继承自QOpenGLWidget的类,并包含QOpenGLFunctions作为受保护的基类,以方便调用OpenGL函数:

复制代码
#include <QOpenGLWidget>
#include <QOpenGLFunctions>

class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
    Q_OBJECT
public:
    MyOpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {}

protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int width, int height) override;
};

在initializeGL()函数中,需要初始化OpenGL环境、创建和编译着色器、分配和填充顶点缓冲区等操作:

复制代码
void MyOpenGLWidget::initializeGL() {
    // 初始化OpenGL函数指针
    initializeOpenGLFunctions();

    // 设置清除颜色
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // 创建顶点缓冲对象
    m_vbo.create();
    m_vbo.bind();
    m_vbo.allocate(m_points.data(), m_points.size() * sizeof(QVector3D));

    // 创建着色器程序
    m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
    m_program.link();
}

在paintGL()函数中,执行实际的渲染操作。每次调用 paintGL() 时,应首先调用 glClear() 清除缓冲区,然后绑定着色器程序和顶点缓冲区,设置顶点属性指针,最后执行绘制命令 [15]

复制代码
void MyOpenGLWidget::paintGL() {
    // 清除颜色和深度缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 绑定着色器程序
    m_program.bind();

    // 绑定顶点缓冲区
    m_vbo.bind();

    // 设置顶点属性指针
    int positionLocation = m_program attributeLocation("position");
    m_program enableAttributeArray(positionLocation);
    m_program.setAttributeBuffer(positionLocation, GL_FLOAT, 0, 3, sizeof(QVector3D));

    // 绘制图形
    glDrawArrays(GL_TRIANGLES,0, m_points.size());

    // 释放资源
    m_vbo.release();
    m_program.release();
}

在resizeGL()函数中,设置视口和投影矩阵,以适应窗口大小的变化:

复制代码
void MyOpenGLWidget::resizeGL(int width, int height) {
    // 设置视口
    glViewport(0, 0, width, height);

    // 设置投影矩阵
    mprojection = QMatrix4x4();
    mprojection.perspective(45.0f, float(width)/float(height), 0.1f, 100.0f);
}

渲染流程的优化是提高应用程序性能的关键。在Qt6中,QOpenGLWidget提供了多种优化选项。例如,可以使用QSurfaceFormat来设置深度缓冲区大小、模板缓冲区大小和OpenGL版本:

复制代码
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);

此外,还可以使用QOpenGLWidget的updateBehavior()函数来设置更新行为,如使用NoPartialUpdate或PartialUpdate,以适应不同的渲染需求 。

对于大规模图形渲染,可以考虑使用QOpenGLWidget的离屏渲染能力,将渲染结果保存到纹理中,然后在需要时进行显示。这种方法可以避免在每次渲染时都重新计算和绘制所有内容,提高渲染效率。

四、Qt信号与槽机制与OpenGL渲染的交互策略

Qt的信号与槽机制是实现用户交互与OpenGL渲染之间通信的核心机制。通过信号与槽,可以实现从用户界面事件到 OpenGL 渲染更新的无缝连接,同时确保跨线程通信的安全性。

在单线程场景中,可以通过简单的信号槽连接实现用户交互与渲染的更新。例如,当用户点击按钮时,发出一个信号,触发OpenGL渲染的更新:

复制代码
connectui->btnRotate, &QPushButton::clicked, this, [this]{
    emit updateRotation(10.0f); // 发送旋转角度更新信号
});

在OpenGL渲染类中,可以定义一个槽函数来处理这些更新:

复制代码
class GLWidget : public QOpenGLWidget {
    Q_OBJECT
public:
    GLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {}

    // 定义信号
    signals:
        void frameRenderStart();
        void frameRenderFinished();

    // 定义槽函数
    slots:
        void handleRotationUpdate(float degrees) {
            m_rotation += degrees;
            update(); // 触发重新渲染
        }

    // 其他函数...
};

对于动画渲染,通常使用 QTimer 来定期触发 update() 函数,从而实现 paintGL() 的循环调用

复制代码
// 在构造函数中设置定时器
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &GLWidget::update);
timer->start(16); // 约60帧/秒

在多线程渲染场景中,信号与槽机制尤为重要。由于OpenGL渲染通常需要在特定的上下文中执行,跨线程通信需要特别注意上下文的安全性。

一种常见的多线程渲染方案是使用一个专门的渲染线程,该线程与QOpenGLWidget的上下文共享资源。通过信号槽机制,可以控制渲染线程的执行:

复制代码
class GLWidgetRenderer : public QObject, public QOpenGLFunctions {
    Q_OBJECT
public:
    GLWidgetRenderer/GLWidget *parent) : QObject(parent), m_parent(parent) {}

    // 设置OpenGL上下文
    void setGLContext(QOpenGLContext *context, QThread *thread) {
        m_context = context;
        m_thread = thread;
        move to thread(thread); // 将渲染对象移动到渲染线程
    }

    // 停止渲染
    void stopRenderer() {
        emit frameRenderFinished(); // 发送渲染完成信号
        m exiting = true;
    }

    // 获取渲染结果纹理
    RefTexture *grabTexture() {
        return m_outputTexture;
    }

public slots:
    void render() {
        // 在渲染线程中使用共享上下文
        m_context->makeCurrent(m_thread);

        // 渲染到纹理
        glClear(GL_COLOR_BUFFER_BIT);
        // ...渲染代码...
        emit frameRenderFinished(); // 发送渲染完成信号

        // 交换缓冲区
        m_parent->swapBUFFers();
    }

private:
    GLWidget *m_parent;
    QOpenGLContext *m_context;
    QThread *m_thread;
    RefTexture *m_outputTexture;
    bool m_exiting;
};

在主窗口中,可以使用信号槽机制控制渲染线程的执行:

复制代码
// 创建渲染线程
QThread *renderThread = new QThread;

// 创建渲染器
GLWidgetRenderer *renderer = new GLWidgetRendererui->glWidget);

// 将渲染器移动到渲染线程
renderer->moveToThread(renderThread);

// 设置上下文
renderer->setGLContext ui->glWidget->context(), renderThread);

// 连接信号槽
connect this, &MainWindow::startRenderer, renderer, &GLWidgetRenderer::render, Qt::QueuedConnection);
connect renderer, &GLWidgetRenderer::frameRenderFinished, this, &MainWindow::handleFrameFinished, Qt::QueuedConnection);
connect renderThread, &QThread::finished, renderer, &QObject::deleteLater);
connect renderer, &GLWidgetRenderer::frameRenderFinished, renderThread, &QThread::exit);

// 启动渲染线程
renderThread->start();

在跨平台场景中,信号与槽机制的延迟和性能表现可能有所不同 。例如,在macOS上使用Metal API时,渲染线程与UI线程的通信可能需要额外的优化。可以通过测量不同平台下信号槽的延迟,选择最适合的通信方式。

五、性能优化策略

在Qt中使用OpenGL进行图形渲染时,性能优化是确保应用程序流畅运行的关键。以下是几种常见的性能优化策略。

首先,使用现代 OpenGL 特性如 VAO VBO EBO 来管理顶点数据,避免在每次渲染时都重新发送顶点数据到GPU 。例如,可以使用以下代码创建和管理顶点数组对象:

复制代码
// 创建VAO和VBO对象
glGenVertexArrays(1, &VAO_id);
glGenBuffers(1, &VBO_id);

// 绑定VAO,开始记录属性相关
glBindVertexArray(VAO_id);

// 绑定VBO
glBindBuffer(GL_ARRAY_BUFFER,VBO_id);

// 把数据放进VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_data), vertices_data, GL_STATIC_DRAW);

// 解析数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// 解绑VBO和VAO
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);

其次,使用定时器驱动的渲染循环,而不是依赖于窗口系统的自动重绘机制。通过控制渲染频率,可以更好地管理性能和用户体验 :

复制代码
// 在构造函数中设置定时器
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &GLWidget::update);
timer->start(16); // 约60帧/秒

在Qt6.9版本中,QThread 现在支持指定CPU 能效核心调度策略 ,有助于提升多线程应用的性能表现。同时,OpenGL平台恢复了质groundbufferObject加速渲染,进一步提升了渲染效率 [36]

对于大规模图形数据,可以考虑使用分层渲染策略,将高频更新和低频更新的元素放在不同的图层中处理,减少不必要的渲染开销 。例如,可以将背景和静态元素放在一个图层中,而将动态元素放在另一个图层中,只在需要时更新特定图层。

此外,避免在渲染过程中频繁打印调试信息,特别是在性能敏感的应用场景中。研究表明,在单线程和多线程情况下,频繁打印调试信息会导致处理时间大幅增加,甚至达到无打印计算的400倍 。

最后,使用适当的渲染模式 ,如双缓冲或帧缓冲区对象(FBO)渲染,可以有效避免画面撕裂和闪烁现象 [15] 。在QOpenGLWidget中,可以通过设置updateBehavior()函数来选择合适的更新行为。

六、跨平台兼容性解决方案

Qt与OpenGL的结合提供了强大的跨平台能力,但不同平台上的实现细节和性能表现可能存在差异。以下是针对不同平台的兼容性解决方案。

在macOS上,由于Apple已弃用OpenGL,推荐使用MoltenVK将Vulkan转换为Metal API [40] 。可以通过以下方式配置:

复制代码
// 在macOS上设置使用Vulkan通过MoltenVK转译到Metal
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::Vulkan);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);

对于需要在macOS上使用OpenGL的应用,必须在构造 QApplication 实例之前调用QSurfaceFormat::setDefaultFormat() 来设置OpenGL 上下文格式 [15] ,特别是在请求核心配置文件上下文时。这可以确保所有后续创建的OpenGL上下文使用相同的版本和配置文件,避免兼容性问题。

在Linux上,需要确保系统安装了适当的OpenGL库(如mesa),并且可能需要处理GLVND与传统库路径的兼容性问题 [12] 。可以通过以下方式设置:

复制代码
// 在Linux上设置使用GLVND
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3, 3);
QSurfaceFormat::setDefaultFormat(format);

同时,可能需要在系统环境变量中设置OpenGL库路径:

复制代码
export LD_LIBRARY_PATH=/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH

在Windows上,需要确保安装了适当的OpenGL驱动,并且在项目中链接了opengl32库。可以通过以下方式配置:

复制代码
// 在Windows上设置使用OpenGL 3.3
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3, 3);
QSurfaceFormat::setDefaultFormat(format);

此外,Qt6.9 版本引入了新的渲染循环机制 ,在Windows平台上使用Direct3D垂直同步监视线程,降低CPU负载与延迟,显著改善拖拽等UI交互操作的响应速度 [36]

对于跨平台的纹理处理,需要注意不同平台对纹理格式的支持差异。例如,在macOS上,某些纹理格式可能不被支持,需要转换为兼容的格式。可以通过以下方式处理:

复制代码
// 创建纹理
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D,mTexture);

// 设置纹理参数
glTexParameteri(GL_TEXTURE_2D,GL_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_FILTER,GL_ LINEAR);

// 加载纹理数据
glTexImage2D(GL_TEXTURE_2D,0, GL RGB,width, height, 0, GL RGB, GL UNSIGNEDByte, data);

// 生成Mipmap(可选)
glGenerateMipmap(GL_TEXTURE_2D);

对于跨平台的着色器编译,需要注意不同平台对GLSL版本的支持差异。可以通过以下方式处理:

复制代码
// 编译着色器
QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, this);
vertexShader->setSourceCode(vertexShaderSource);
if (!vertexShader->compile()) {
    qDebug() << "Vertex Shader编译失败:" << vertexShader->log();
    return;
}

QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, this);
fragmentShader->setSourceCode(fragmentShaderSource);
if (!fragmentShader->compile()) {
    qDebug() << "Fragment Shader编译失败:" << fragmentShader->log();
    return;
}

// 链接着色器
m_program.addShader(vertexShader);
m_program.addShader(fragmentShader);
if (!m_program.link()) {
    qDebug() << "着色器程序链接失败:" << m_program.log();
    return;
}

// 释放资源
delete vertexShader;
delete fragmentShader;

七、实践案例与应用场景

Qt与OpenGL的结合在多种应用场景中表现出色,包括科学可视化、游戏开发、工业设计和医疗成像等。

在科学可视化领域,Qt与OpenGL的结合可以实现复杂的3D数据展示和交互 。例如,可以使用QOpenGLWidget来渲染地质数据或气象数据,同时使用Qt的界面组件来控制渲染参数和交互方式。这种组合能够提供直观的用户界面和高效的图形渲染能力,满足科学可视化应用的需求。

在工业设计领域,Qt与OpenGL的结合可以实现CAD软件中的3D模型展示和编辑 。例如,可以使用QOpenGLWidget来渲染机械部件或建筑模型,同时使用Qt的界面组件来提供工具栏、属性面板和实时预览等功能。这种组合能够提供专业的图形渲染能力和友好的用户界面,满足工业设计应用的需求。

在医疗成像领域,Qt与OpenGL的结合可以实现医学影像的三维重建和可视化 。例如,可以使用QOpenGLWidget来渲染CT或MRI扫描结果,同时使用Qt的界面组件来提供切片控制、颜色映射和测量工具等功能。这种组合能够提供高质量的图形渲染能力和专业的用户界面,满足医疗成像应用的需求。

在游戏开发领域,Qt与OpenGL的结合可以实现游戏引擎的开发,提供图形渲染和用户界面管理的能力 [6] 。例如,可以使用QOpenGLWidget来渲染游戏场景,同时使用Qt的界面组件来提供游戏菜单、设置面板和实时状态显示等功能。这种组合能够提供强大的图形渲染能力和灵活的界面设计,满足游戏开发应用的需求。

八、未来发展趋势与建议

随着图形技术的不断发展,Qt与OpenGL的结合也在不断演进。未来的发展趋势包括:

首先,Vulkan DirectX 12 等现代图形 API 的普及将影响Qt与OpenGL的结合方式。这些API提供了更低的开销和更高的性能,但学习曲线也更陡峭。Qt可能会提供对这些API的更好支持,或者通过抽象层简化它们的使用。

其次,跨平台渲染引擎的发展将使得Qt与OpenGL的结合更加灵活。例如,Qt Quick 3D已经提供了对多种图形API的支持,未来可能会进一步扩展,使得开发者可以在不同平台上选择最适合的渲染方式。

最后,AI 驱动的图形渲染技术将为Qt与OpenGL的结合带来新的可能性。例如,可以使用AI算法来优化图形渲染流程,提高渲染效率和质量。

基于以上分析,对开发者提出以下建议:

首先,熟悉 Qt6 OpenGL 4.x 的最新特性 ,特别是Qt6.9版本中引入的性能优化和跨平台改进 [36] 。这可以帮助开发者充分利用框架的优势,构建更高效的应用程序。

其次,采用模块化的设计方法,将UI组件和图形渲染逻辑分离,便于跨平台适配和维护。例如,可以将OpenGL渲染逻辑封装在单独的类中,而将UI交互逻辑封装在另一个类中,通过信号槽机制进行通信。

最后,关注跨平台性能优化,特别是在不同操作系统上针对特定图形API进行优化。例如,在macOS上可以考虑使用Metal API替代OpenGL,以获得更好的性能和兼容性。

九、结论

Qt与OpenGL的结合为开发者提供了一个强大的图形应用开发框架,能够兼顾图形渲染性能和用户界面设计的灵活性。通过QOpenGLWidget和QOpenGLWindow等类,可以方便地将OpenGL集成到Qt应用程序中,实现跨平台的图形渲染。

在实际应用中,开发者需要根据具体需求选择合适的集成方式和渲染策略。对于需要将图形渲染嵌入到复杂用户界面的应用,QOpenGLWidget是更合适的选择;而对于需要直接控制渲染上下文和窗口系统的应用,QOpenGLWindow可能更适合。

性能优化和跨平台兼容性是Qt与OpenGL应用开发中的重要挑战。通过采用现代OpenGL特性、优化渲染循环、管理多线程通信和适配不同平台的图形API,可以构建高效、流畅的跨平台图形应用程序。

随着图形技术的不断发展,Qt与OpenGL的结合方式也在不断演进。开发者应该关注框架的最新特性和发展趋势,以便构建更高效、更现代的应用程序。

参考来源:

1. Qt结合OpenGL4.x的高效跨平台框架指南-CSDN文库

2. 探索现代OpenGL与Qt框架整合实现-CSDN文库

3. 探索Qt与OpenGL的完美结合:高效图形程序开发-CSDN文库

4. Qt与OpenGL基础功能实现详解-CSDN文库

5. Qt环境下的OpenGL模块使用实践教程-CSDN博客

6. qt通过OpenGL实现3d游戏开发框架-腾讯云开发者社区-腾讯云

7. 001 使用Qt学习OpenGL---环境配置

8. 探索QtOpenGL:一个强大的图形编程框架-CSDN博客

9. QT6+VS2022 中关于OpenGL的问题

10. 当下 Qt 如何优雅的使用 OpenGL?

11. CMake查找OpenGL的详细过程及配置解析-CSDN博客

12. qt的cmake工程,查找opengl的流程-CSDN博客

13. 使用QOpenGLWidget(调用GPU)渲染QImage加载的图片

14. Qt结合OpenGL 4.x的高效跨平台框架指南-CSDN文库

15. Qt QOpenGLWidget类讲解-CSDN博客

16. Qt音视频开发24-视频显示QOpenGLWidget方式(占用GPU)知...

17. QGLWidget、QOpenGLWidget详解及区别

18. Qt6.3.1中使用QOpenGLWidget-飘杨.-博客园

19. qt6下配置qopengl_qt6 qopenglwidget-CSDN博客

20. Qt如何显示百万个点的点云?

21. qt+opengl着色器VAO、VBO、EBO(四)qtopengl vaovbo-CSDN博客

22. 绘制(Qt官方文档,Qt6.4)

23. QOpenGLWidget的多线程渲染_opengl多线程渲染-CSDN博客

24. QT编程入门教程:从HelloQt到OpenGL绘图-CSDN文库

25. 当下 Qt 如何优雅的使用 OpenGL?

26. 关于QOpenGLWidget的多线程渲染_contextqopenglwidget-CSDN博客

27. QT6性能优化-知乎

28. Qt 6 系列教程(02)设计器、信号与槽-知乎

29. Qt 6.9新版本来袭:3D可视化与AI工具革新,如何应对职场挑战?Unicode_应用_支持

30. Qt 信号与槽-知乎

31. QT6学习之路03-信号槽机制的基本理解

32. Qt|定时器的使用

33. QT定时器与槽函数实现摇奖功能教程-CSDN文库

34. Qt 6.9发布

35. OpenGL、Vulkan、DirectX、Metal 在移动端和 PC 端的对比分析

36. Qt框架6.9发布:增强 3D 数据可视化、升级 emoji 支持-IT之家

37. 事实胜于雄辩,苹果MacOs能不能玩儿机器/深度(ml/dl)学习...

38. linux下Qt开发环境配置-知乎

39. 使用QOpenGLWidget(调用GPU)渲染QImage加载的图片

40. OpenGL、Vulkan、DirectX、Metal 在移动端和 PC 端的对比分析

41. Linux下配置QT的完整过程-CSDN博客

42. QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于...

43. Linux环境下编译配置Qt开源版全攻略-CSDN文库

44. 使用QOpenGLWidget(调用GPU)渲染QImage加载的图片

45. QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于...

46. Qt开发笔记:QGLWidget、QOpenGLWidget详解及区别-CSDN博客