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):封装和界面设计
与解码相关的主要代码在上一篇博客中已经做了介绍,本篇我们会先讨论一下如何控制解码速度再提供一个我个人的封装思路.最后回归到界面设计环节重点看一下如何保证播放器界面在缩放和拖动的过程中保证视频画面的宽高 ...
随机推荐
- button与subit区别
submit介绍 submit是button的一个特例,也是button的一种,它把提交这个动作自动集成了.如果表单在点击提交按钮后需要用JS进行处理(包括输入验证)后再提交的话,通常都必须把su ...
- C#枚举扩展方法,获取枚举值的描述值以及获取一个枚举类下面所有的元素
/// <summary> /// 枚举扩展方法 /// </summary> public static class EnumExtension { private stat ...
- nRF5 SDK Bootloader and DFU moudles(2)
镜像的验证 在执行设备固件更新之前,应验证新映像. 在传输实际固件(预验证)之前,可以检查某些信息(例如,兼容性). 其他信息,例如图像的散列,应在传输(验证后)后进行验证. Init packet ...
- [转帖]VIM常用快捷键
VIM常用快捷键 https://www.cnblogs.com/markleaf/p/7808817.html 快捷键能够显著的提高工作效率 一.移动光标 h,j,k,l 上,下,左,右ctrl-e ...
- [转帖]Docker学习之Dockerfile命令详解
Docker学习之Dockerfile命令详解 https://it.baiked.com/system/docker/2436.html 图挺好的 前言 之前,制作镜像的伪姿势搭建已经见过了,今天介 ...
- SQL SERVICES 搭建问题
一.SQL SERVICES 设置IP 连接 SQL2008是没有外围配置的,为了能用IP地址或者local登陆,需要做下面的配置. 打开Microsoft SQL Server 2008 R2→配 ...
- gin框架博客实战教程2019web页面开发go语言实战博客开发
视频教程: https://www.bilibili.com/video/av73698322?t=2400&p=5 资料下载地址(含数据库和main.go和controller里的代码) 注 ...
- django初步了解3
目录 JsonResponse模块 form表单上传文件 FBV与CBV django settings源码分析及实际应用 模板语法 模板传值 模板过滤器 标签 if标签 for标签 with标签 自 ...
- poj 2226 Muddy Fields (二分图)
大意:给定n*m网格, 每个格子为泥地或草地, 可以用一些长度任意宽度为1的木板盖住泥地, 要求不能盖到草地, 求最少要多少块木板能盖住所有泥地. 最小点覆盖板子题, 建图跑最大匹配即可. #incl ...
- asp.net 13 缓存,Session存储
1.缓存 将数据从数据库/文件取出来放在服务器的内存中,这样后面的用来获取数据,不用查询数据库,直接从内存(缓冲)中获取数据,提高了访问的速度,节省了时间,也减轻了数据库的压力. 缓冲空间换时间的技术 ...