首页 > 其他分享 >QOpenGLWidget类讲解

QOpenGLWidget类讲解

时间:2023-03-08 09:37:14浏览次数:36  
标签:调用 format OpenGL QOpenGLFunctions 讲解 paintGL QOpenGLWidget

Detailed Description
QOpenGLWidget类是用于渲染OpenGL图形。

除了可以选择使用QPainter和标准的OpenGL渲染图形,QOpenGLWidget类提供了在Qt应用程序中显示OpenGL图形的功能。它使用起来非常简单:新建类继承于QOpenGLWidget,使用方法就像继承于QWidget类子类一样。

QOpenGLWidget类提供了三个方便的虚函数,可以在新建的子类中重新实现以完成OpenGL的任务:

paintGL()—渲染OpenGL场景,需要更新Widget时就会调用。
resizeGL()—设置OpenGL视口,投影等。每当调整Widget的大小时(第一次显示窗口Widget时会调用它,因为所有新创建Widget都会自动获得调整大小的事件)。
initializeGL()—建立OpenGL的资源和状态。在第一次调用resizeGL()或paintGL()之前调用一次。
如果需要从paintGL()以外的地方触发重绘(一个典型的例子是使用定时器为场景设置动画),应该调用widget的update()函数来进行更新。

当调用paintGL(),resizeGL()或initializeGL()时,Widget的OpenGL渲染环境需要设为当前。如果需要从其他位置调用标准OpenGL API函数(例如,Widget的构造函数或自己的绘图函数中),则必须首先调用makeCurrent()。

所有渲染都发生在OpenGL帧缓冲对象中,makeCurrent()确保它在渲染环境中,在paintGL()中的渲染代码中创建和绑定其他帧缓冲对象时,不要使用ID 0重新绑定帧缓冲区,而是调用defaultFramebufferObject()来获取应该绑定的ID。

QOpenGLWidget允许在平台支持时使用不同的OpenGL版本和配置文件。只需通过setFormat()设置请求的格式。但在同一窗口中有多个QOpenGLWidget,要求它们都使用相同的格式,或者至少不是环境共享的格式。要解决此问题,使用QSurfaceFormat :: setDefaultFormat(),而不是setFormat()。

注意:在请求OpenGL核心配置文件上下文时,在构造QApplication实例之前调用QSurfaceFormat :: setDefaultFormat()在某些平台(例如,macOS)上是必需的。这是为了确保上下文之间的资源共享保持功能,因为所有内部上下文都是使用正确的版本和配置文件创建的。

OpenGL Function Calls, Headers and QOpenGLFunctions
在进行OpenGL函数调用时,强烈建议避免直接调用函数。相反,更喜欢使用QOpenGLFunctions(在制作可移植应用程序时)或版本化变体(例如,QOpenGLFunctions_3_2_Core等,当针对现代的,仅限桌面的OpenGL时)。这样,应用程序将在所有Qt构建配置中正常工作,包括执行动态OpenGL实现加载的应用程序,这意味着应用程序不直接链接到GL实现,因此直接函数调用是不可行的。

在paintGL()中,当前场景(context)始终可以通过调用QOpenGLContext :: currentContext()来访问。从这个context中,可以通过调用QOpenGLContext :: functions()来检索已经初始化的,准备好使用的QOpenGLFunctions实例。为每个GL调用添加前缀的替代方法是从QOpenGLFunctions继承并在initializeGL()中调用QOpenGLFunctions :: initializeOpenGLFunctions()。

至于OpenGL标题,请注意,在大多数情况下,不需要直接包含任何标题,如GL.h.与OpenGL相关的Qt头文件将包含qopengl.h,后者将包含适用于系统的标头。这可能是OpenGL ES 3.x或2.0标头,可用的最高版本,或系统提供的gl.h.此外,作为OpenGL和OpenGL ES的Qt的一部分,提供了扩展头的副本(在某些系统上称为glext.h)。这些将在可行的情况下自动包含在平台上。这意味着来自ARB,EXT,OES扩展的常量和函数指针typedef自动可用。

Code Examples
最简单的例子

class MyGLWidget : public QOpenGLWidget
{
public:
MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { }

protected:
void initializeGL()
{
// Set up the rendering context, load shaders and other resources, etc.:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
...
}

void resizeGL(int w, int h)
{
// Update projection matrix and other size related settings:
m_projection.setToIdentity();
m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);
...
}

void paintGL()
{
// Draw the scene:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClear(GL_COLOR_BUFFER_BIT);
...
}

};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
或通过使用QOpenGLFunction来代替OpenGL函数

class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
...
void initializeGL()
{
initializeOpenGLFunctions();
glClearColor(...);
...
}
...
};
1
2
3
4
5
6
7
8
9
10
11
12
要获得与给定OpenGL版本或配置文件兼容的context,或者要求深度和模板缓冲区,调用setFormat():

QOpenGLWidget *widget = new QOpenGLWidget(parent);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
widget->setFormat(format); // must be called before the widget or its parent window gets shown
1
2
3
4
5
6
7
使用OpenGL 3.0+ context时,当可移植性不重要时,版本化的QOpenGLFunctions变体可以轻松访问给定版本中可用的所有现代的OpenGL函数:

void paintGL()
{
QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
...
f->glDrawArraysInstanced(...);
...
}
1
2
3
4
5
6
7
如上所述,全局设置所要求的格式以使其在应用程序的生命周期内应用于所有窗口和context更简单且更鲁棒。 以下是此示例:

int main(int argc, char **argv)
{
QApplication app(argc, argv);

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

MyWidget widget;
widget.show();

return app.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Relation to QGLWidget
传统的QtOpenGL模块(以QGL为前缀的类)提供了一个名为QGLWidget的widget。QOpenGLWidget旨在成为它的替代品。因此,特别是在新的应用程序中,一般建议使用QOpenGLWidget。

虽然API非常相似,但两者之间存在重要差异:QOpenGLWidget始终使用帧缓冲对象在屏幕外渲染。另一方面,QGLWidget使用原生窗口和曲面。后者在复杂的用户界面中使用它时会引起问题,因为根据平台,这种本机子窗口小部件可能具有各种限制,例如关于堆叠命令。QOpenGLWidget通过不创建单独的本机窗口来避免这种情况。

由于帧缓冲对象的支持,QOpenGLWidget的行为与QOpenGLWindow非常相似,更新行为设置为PartialUpdateBlit或PartialUpdateBlend。这意味着在paintGL()调用之间保留内容,以便可以进行增量渲染。使用QGLWidget(当然QOpenGLWindow具有默认的更新行为)通常不是这种情况,因为交换缓冲区会使后台缓冲区中的内容不确定。

注意:大多数应用程序不需要增量渲染,因为它们将在每次绘制调用时呈现视图中的所有内容。在这种情况下,在paintGL()中尽早调用glClear()非常重要。这有助于使用基于图块的体系结构的移动GPU识别出图块缓冲区不需要使用帧缓冲区的先前内容重新加载。省略明确的呼叫可能导致此类系统的性能显着下降。

注意:避免在QOpenGLWidget上调用winId()。此功能触发创建本机窗口,从而降低性能并可能出现毛刺。

Differences to QGLWidget
除了framebuffer对象支持的主要概念差异之外,QOpenGLWidget和旧的QGLWidget之间存在许多较小的内部差异:

调用paintGL()时的OpenGL状态。 QOpenGLWidget通过glViewport()设置视口。 它不执行任何清算。
当开始绘画时通过QPainter清除。 与常规widget不同,QGLWidget默认为autoFillBackground的值为true。 然后,每次使用QPainter :: begin()时,它都会清除调色板的背景颜色。 QOpenGLWidget不遵循:autoFillBackground默认为false,就像任何其他widget一样。 唯一的例外是当用作QGraphicsView等其他小部件的视口时。 在这种情况下,autoFillBackground将自动设置为true,以确保与基于QGLWidget的视口兼容。
————————————————
原文链接:https://blog.csdn.net/qq_25548063/article/details/81393323

 

标签:调用,format,OpenGL,QOpenGLFunctions,讲解,paintGL,QOpenGLWidget
From: https://www.cnblogs.com/im18620660608/p/17190770.html

相关文章

  • 山东csp-j2022 试题答案及视频讲解
    山东csp-j2022试题答案及视频讲解T319771植树节(planting)山东CSP-J2022入门组1题目链接:https://www.luogu.com.cn/problem/T319771题目讲解:#include<iostream>#inc......
  • 详细讲解23种设计模式
    详细讲解23种设计模式 工厂方法模式(FactoryMethodPattern)工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定要实例化的类是哪一个。工......
  • Python Flask 之 路由和渲染模板讲解与示例演示
    目录一、概述二、路由三、渲染模板四、重定向和错误五、日志六、集成WSGI中间件一、概述Flask是一款使用Python编写的Web应用框架,其设计理念是轻量级和简单易学。......
  • 第三方模块源码下载安装步骤讲解
    第一步:在Gitee上clone下来第二步:在本机下载目录找下载好了的源码文件第三步:装完之后,首先把路径复制下来第四步:之后来到项目,在terminal里面先CD到C盘,再把刚刚复制的......
  • Java 语言模型 - javax.lang.model 包讲解
    注:官方文档地址:javax.lang.model概览在自定义注解处理器的过程中,我们可以对java源码做处理。为了从源码中拿到自己想要的数据、信息,我们需要对源码进行建模。建模工作......
  • C++ 深度优先搜索(DFS) 讲解
    目录DFS初步概念DFS例题-迷宫游戏题目描述输入输出格式输入输出样例输入#1输出#1输入#2输出#2解题思路代码DFS初步概念DFS是一种深度搜索算法,它的特点是"不撞南墙不回头"......
  • Adapter基础讲解
    这一节我们要讲的UI控件都是跟Adapter(适配器)打交道的,了解并学会使用Adapter很重要,Adapter是用来帮助填充数据的中间桥梁,简单来说就是:将各种数据以合适的形式显示到view上......
  • Springboot Condition 实用讲解,只看一遍包学会
    前言 该篇文章,还是一贯的风格,源码+示例+自言自语的分析,目的只有一个:就是想让大家都会玩 Condition、Conditional。   正文先看看Condition是被放在包spr......
  • pip换源和制作虚拟环境操作步骤讲解
    目录一、pip换源及虚拟环境二.虚拟环境一、pip换源及虚拟环境我们Python的强大之处就是有非常多的牛逼的第三方模块,后面的程序员只需要下载第三方模块,然后站在大佬们的肩......
  • springCache整合redis详细讲解和配置
    SpringCache的简介缓存,就是将数据从数据库等数据来源获取数据,将数据缓存在内存或其他设备如Redis中,为了二次查询能够快速高效的响应结果.SpringCache是3.1开始提供,......