QOpenGLWidget
QOpenGLWidget描述
QOpenGLWidget类是用于渲染OpenGL图形。
除了可以选择使用QPainter和标准的OpenGL渲染图形,QOpenGLWidget类提供了在Qt应用程序中显示OpenGL图形的功能。它使用起来非常简单:新建类继承于QOpenGLWidget,使用方法就像继承于QWidget类子类一样。
QOpenGLWidget类提供了三个方便的虚函数,可以在新建的子类中重新实现以完成OpenGL的任务:
paintGL()—渲染OpenGL场景,需要更新Widget时就会调用。
resizeGL()—设置OpenGL视口,投影等。每当调整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函数, 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自动可用。
最简单的例子
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);
...
}
};
或通过使用QOpenGLFunction来代替OpenGL函数
class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
...
void initializeGL()
{
initializeOpenGLFunctions();
glClearColor(...);
...
}
...
};
要获得与给定OpenGL版本或配置文件兼容的context,或者要求深度和模板缓冲区,调用setFormat():
QOpenGLWidget *widget = new QOpenGLWidget(parent);
QSurfaceFormat format;
format.setDepthBufferSize();
format.setStencilBufferSize();
format.setVersion(, );
format.setProfile(QSurfaceFormat::CoreProfile);
widget->setFormat(format); // must be called before the widget or its parent window gets shown
使用OpenGL 3.0+ context时,当可移植性不重要时,版本化的QOpenGLFunctions变体可以轻松访问给定版本中可用的所有现代的OpenGL函数:
void paintGL()
{
QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
...
f->glDrawArraysInstanced(...);
...
}
如上所述,全局设置所要求的格式以使其在应用程序的生命周期内应用于所有窗口和context更简单且更鲁棒。 以下是此示例:
int main(int argc, char **argv)
{
QApplication app(argc, argv); QSurfaceFormat format;
format.setDepthBufferSize();
format.setStencilBufferSize();
format.setVersion(, );
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format); MyWidget widget;
widget.show(); return app.exec();
}
关于老版QGLWidget
传统的QtOpenGL模块(以QGL为前缀的类)提供了一个名为QGLWidget的widget。QOpenGLWidget旨在成为它的替代品。因此,特别是在新的应用程序中,一般建议使用QOpenGLWidget。
虽然API非常相似,但两者之间存在重要差异:QOpenGLWidget始终使用帧缓冲对象在屏幕外渲染。另一方面,QGLWidget使用原生窗口和曲面。后者在复杂的用户界面中使用它时会引起问题,因为根据平台,这种本机子窗口小部件可能具有各种限制,例如关于堆叠命令。QOpenGLWidget通过不创建单独的本机窗口来避免这种情况。
由于帧缓冲对象的支持,QOpenGLWidget的行为与QOpenGLWindow非常相似,更新行为设置为PartialUpdateBlit或PartialUpdateBlend。这意味着在paintGL()调用之间保留内容,以便可以进行增量渲染。使用QGLWidget(当然QOpenGLWindow具有默认的更新行为)通常不是这种情况,因为交换缓冲区会使后台缓冲区中的内容不确定。
注意:大多数应用程序不需要增量渲染,因为它们将在每次绘制调用时呈现视图中的所有内容。在这种情况下,在paintGL()中尽早调用glClear()非常重要。这有助于使用基于图块的体系结构的移动GPU识别出图块缓冲区不需要使用帧缓冲区的先前内容重新加载。省略明确的呼叫可能导致此类系统的性能显着下降。
注意:避免在QOpenGLWidget上调用winId()。此功能触发创建本机窗口,从而降低性能并可能出现毛刺。
QOpenGLWidget与QGLWidget的区别
除了framebuffer对象支持的主要概念差异之外,QOpenGLWidget和旧的QGLWidget之间存在许多较小的内部差异:
调用paintGL()时的OpenGL状态。 QOpenGLWidget通过glViewport()设置视口。 它不执行任何清算。
当开始绘画时通过QPainter清除。 与常规widget不同,QGLWidget默认为autoFillBackground的值为true。 然后,每次使用QPainter :: begin()时,它都会清除调色板的背景颜色。 QOpenGLWidget不遵循:autoFillBackground默认为false,就像任何其他widget一样。 唯一的例外是当用作QGraphicsView等其他小部件的视口时。 在这种情况下,autoFillBackground将自动设置为true,以确保与基于QGLWidget的视口兼容。
QOpenGLWidget的更多相关文章
- Qt自定义阴影效果和QOpenGLWidget冲突导致控件不刷新
Qt5.6.2版本存在这样一个问题(其它版本未测试),当main函数中设置了application.setAttribute(Qt::AA_NativeWindows)(用于使得每个子界面都可以获取w ...
- QOpenglWidget 与QGLWidget的选择
1. QGLWidget 是Qt OpenGL模块,但是从其官方说明,推荐在Qt5.4 之后,使用QOpenglWidget版本,具体说明如下: Note: This class is part of ...
- 【Qt】QOpenGLWidget展示蒙版效果
关键代码是派生QOpenGLWidget,覆写paintEvent函数 QPainter p; p.begin(this); p.drawImage(QPoint(, ), m_Img); QLine ...
- Visual Studio 2017 无法打开包括文件: “QOpenGLWidget”: No such file or directory
编译项目时,发现报错:VS 无法打开包括文件: “QOpenGLWidget”: No such file or directory,在Qt对应的目录(E:\Qt\Qt5.12.2\5.12.2\ms ...
- 在qt的QOpenGLWidget开启opengl的抗锯齿
在QOpenGLWidget的构造函数添加下面几句代码即可 QSurfaceFormat surfaceFormat; surfaceFormat.setSamples();//多重采样 setFor ...
- 2.通过QOpenGLWidget绘制三角形
参考:1.opengl绘制三角形 1.QOpenGLWidget的早先版本 QGLWidget是遗留Qt OpenGL模块的一部分,和其他QGL类一样,应该在新的应用程序中避免使用.相反,从Qt 5. ...
- Cross-compiling Qt Embedded 5.5 for Raspberry Pi 2
This tutorial shows how to cross-compile the Embedded build of Qt 5.5 for Raspberry Pi 2. The Embedd ...
- 【Qt for Android】OpenGL ES 绘制彩色立方体
Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...
- Qt与FFmpeg联合开发指南(二)——解码(2):封装和界面设计
与解码相关的主要代码在上一篇博客中已经做了介绍,本篇我们会先讨论一下如何控制解码速度再提供一个我个人的封装思路.最后回归到界面设计环节重点看一下如何保证播放器界面在缩放和拖动的过程中保证视频画面的宽高 ...
随机推荐
- 【CodeForces - 939A】Love Triangle(模拟)
Love Triangle Descriptions: 正如你所知道的,没有男性飞机也没有女性飞机.然而,地球上的每一个平面都喜欢另一个平面.地球上有n个平面,编号从1到n,编号i的平面喜欢编号fi的 ...
- Zabbix介绍及安装(1)
Zabbix的介绍 一.什么是zabbix及优缺点(对比cacti和nagios) Zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种 ...
- React中this指向常用的2种修正方式
一.使用bind方法(构造函数内绑定) <!DOCTYPE html> <html> <head> <meta charset="utf-8&quo ...
- moment的简单使用方式
官网地址:http://momentjs.cn/ 常见示例↓ moment().format('YYYY-MM-DD HH:mm:ss'); // ’2015-11-30 23:10:10‘ mome ...
- 如何禁止谷歌浏览器隐藏url的www前缀
若要将Chrome浏览器的设置恢复为隐藏HTTP.HTTPS以及WWW前缀,则只需再次进入此页面: chrome://flags/#omnibox-ui-hide-steady-state-url-s ...
- airflow 安装配置celery+rabbitmq celery+redis
AirFlow的安装可以参考:https://www.cnblogs.com/braveym/p/11378851.html 这里介绍的是AirFlow 安装配置celery+rabbitmq 和 ...
- ARST第四周打卡
Algorithm : 做一个 leetcode 的算法题 ////////////////////////////////////////////////////////////////////// ...
- 并不对劲的bzoj4231: 回忆树
题目大意 \(n\)个点的树,每条边上有一个小写字母. 操作:给定2个点\(u\),\(v\)(\(u\)可能等于\(v\))和一个非空字符串\(s\),问从\(u\)到\(v\)的简单路径上的所有边 ...
- 使用python操作kafka
使用python操作kafka目前比较常用的库是kafka-python库 安装kafka-python pip3 install kafka-python 生产者 producer_test.py ...
- BufferedImage类、Image类、Graphics类
BufferedImage Image是一个抽象类,BufferedImage是其实现类,是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中(BufferedImage生成的图片在内存里有一个图像 ...