QT的OpenGL渲染窗QOpenGLWidget Class

Qt - QOpenGLWidget (class) (runebook.dev)

一、说明

QOpenGLWidget 类是用于渲染 OpenGL 图形的小部件。从Qt 5.4就开始退出,它对于OpenGL有专门的配合设计。

二、QOpenGLWidget类的成员


2.1 Public类函数

QOpenGLWidget(QWidget *parent= nullptr,Qt::WindowFlagsf= Qt::WindowFlags())
virtual~QOpenGLWidget()
QOpenGLContext *context() const
GLuintdefaultFramebufferObject() const
voiddoneCurrent()
QSurfaceFormatformat() const
QImagegrabFramebuffer()
boolisValid() const
voidmakeCurrent()
voidsetFormat (常量 QSurfaceFormat &format)
voidsetTextureFormat(GLenumtexFormat)
voidsetUpdateBehavior(QOpenGLWidget::UpdateBehaviorupdateBehavior)
GLenumtextureFormat() const
QOpenGLWidget::UpdateBehaviorupdateBehavior() const

2.2 信号对象Signals

voidaboutToCompose()
voidaboutToResize()
voidframeSwapped()
voidresized()

2.3 保护性虚函数

virtual voidinitializeGL()
virtual voidpaintGL()
virtual voidresizeGL(intw, inth)

2.4 重新实现 Protected 功能

virtual boolevent(QEvent *e) override
virtual intmetric(QPaintDevice::PaintDeviceMetricmetric) 常量覆盖
virtual QPaintEngine *paintEngine () 常量覆盖
virtual voidpaintEvent(QPaintEvent *e) override
virtual QPaintDevice *redirected(QPoint *p) 常量覆盖
virtual voidresizeEvent(QResizeEvent *e) override

三、QOpenGLWidget类的详细描述

        QOpenGLWidget 提供了集成到 Qt 应用程序中的显示 OpenGL 图形的功能。使用起来非常简单:让您的类继承它并像任何其他 QWidget 一样使用子类,只不过您可以选择使用 QPainter 和标准 OpenGL 渲染命令。

3.1 基本三个虚函数

        QOpenGLWidget 提供了三个方便的虚拟函数,您可以在子类中重新实现它们来执行典型的 OpenGL 任务:

  • paintGL () - 渲染 OpenGL 场景。每当小部件需要更新时就会被调用。
  • resizeGL () - 设置 OpenGL 视口、投影等。每当调整小部件的大小时(以及第一次显示它时,因为所有新创建的小部件都会自动获得调整大小事件),都会调用它。
  • initializeGL () - 设置 OpenGL 资源和状态。在第一次调用 resizeGL () 或 paintGL () 之前调用一次。

        如果您需要从 paintGL () 以外的地方触发重绘(典型的示例是使用 timers 制作场景动画时),您应该调用小部件的 update () 函数来安排更新。

        当调用 paintGL ()、 resizeGL () 或 initializeGL () 时,小部件的 OpenGL 渲染上下文将变为当前上下文。如果您需要从其他地方调用标准OpenGL API函数(例如在您的小部件的构造函数中或在您自己的绘制函数中),您必须首先调用 makeCurrent ()。

        所有渲染都发生在 OpenGL 帧缓冲区对象中。 makeCurrent () 确保它绑定在上下文中。在 paintGL () 的渲染代码中创建和绑定附加帧缓冲区对象时请记住这一点。切勿重新绑定 ID 为 0 的帧缓冲区。而是调用 defaultFramebufferObject () 来获取应绑定的 ID。

        当平台支持时,QOpenGLWidget 允许使用不同的 OpenGL 版本和配置文件。只需通过 setFormat ()设置请求的格式即可。但请记住,在同一窗口中拥有多个 QOpenGLWidget 实例要求它们都使用相同的格式,或者至少使用不会使上下文不可共享的格式。为了解决这个问题,最好使用 QSurfaceFormat::setDefaultFormat () 而不是 setFormat ()。

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

3.2 绘图技术

        如上所述,子类化 QOpenGLWidget 以通过以下方式渲染纯 3D 内容:

  • 重新实现 initializeGL ()和 resizeGL ()函数来设置OpenGL状态并提供透视变换。
  • 重新实现 paintGL ()来绘制3D场景,仅调用OpenGL函数。

        还可以使用 QPainter 将 2D 图形绘制到 QOpenGLWidget 子类上:

  • 在 paintGL () 中,不是发出 OpenGL 命令,而是构造一个 QPainter 对象以在小部件上使用。
  • 使用 QPainter 的成员函数绘制基元。
  • 仍然可以发出直接 OpenGL 命令。但是,您必须确保它们包含在对画家的 beginNativePainting() 和 endNativePainting() 的调用中。

        仅使用 QPainter 执行绘图时,也可以像普通小部件一样执行绘图:通过重新实现 paintEvent ()。

  • 重新实现 paintEvent ()函数。
  • 构造一个针对小部件的 QPainter 对象。将小部件传递给构造函数或 QPainter::begin () 函数。
  • 使用 QPainter 的成员函数绘制基元。
  • 绘画完成后, QPainter 实例被销毁。或者,显式调用 QPainter::end ()。

3.3 OpenGL 函数调用、标头和 QOpenGLFunction

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

        在 paintGL () 中,当前上下文始终可以通过调用 QOpenGLContext::currentContext () 来访问。从此上下文中,可以通过调用 QOpenGLContext::functions () 检索已初始化、可供使用的 QOpenGLFunctions 实例。对每个 GL 调用添加前缀的替代方法是从 QOpenGLFunctions 继承并在 initializeGL () 中调用 QOpenGLFunctions::initializeOpenGLFunctions ()。

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

四、代码示例

        首先,最简单的 QOpenGLWidget 子类可能如下所示:

class MyGLWidget : public QOpenGLWidget
{
public:MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { }protected:void initializeGL() override{// 设置渲染上下文,加载着色器和其他资源等:QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);...}void resizeGL(int w, int h) override{// 更新投影矩阵和其他尺寸相关的设置:m_projection.setToIdentity();m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);...}void paintGL() override{// 绘制场景:QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();f->glClear(GL_COLOR_BUFFER_BIT);...}};

        或者,可以通过从 QOpenGLFunctions 派生来避免每个 OpenGL 调用的前缀:

class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{...void initializeGL() override{initializeOpenGLFunctions();glClearColor(...);...}...
};

        要获取与给定 OpenGL 版本或配置文件兼容的上下文,或者请求深度和模板缓冲区,请调用 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

        在 OpenGL 3.0+ 上下文中,当可移植性并不重要时,版本化的 QOpenGLFunctions 变体可以轻松访问给定版本中可用的所有现代 OpenGL 功能:

    ...void paintGL() override{QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();...f->glDrawArraysInstanced(...);...}...

        如上所述,全局设置请求的格式更简单且更稳健,以便它在应用程序的生命周期内应用于所有窗口和上下文。下面是一个例子:

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();
}

4.1 多重采样Multisampling

        要启用多重采样,请设置 QSurfaceFormat 上传递给 setFormat () 的请求样本数。在不支持它的系统上,该请求可能会被忽略。

        多重采样支持需要支持多重采样渲染缓冲区和帧缓冲区位块传送。在 OpenGL ES 2.0 实现中,这些可能不会出现。这意味着多重采样将不可用。对于现代 OpenGL 版本和 OpenGL ES 3.0 及更高版本,这通常不再是问题。

4.2 线程Threading

        在工作线程上执行离屏渲染,例如生成纹理,然后在 paintGL () 的 GUI/主线程中使用,通过公开小部件的 QOpenGLContext 来支持,以便可以在每个线程上创建与之共享的其他上下文。

        通过重新实现 paintEvent () 不执行任何操作,可以在 GUI/主线程之外直接绘制到 QOpenGLWidget 的帧缓冲区。必须通过 QObject::moveToThread () 更改上下文的线程关联性。之后, makeCurrent ()和 doneCurrent ()就可以在工作线程上使用了。之后请小心将上下文移回 GUI/主线程。

        仅仅为 QOpenGLWidget 触发缓冲区交换是不可能的,因为它没有真正的屏幕本机表面。由小部件堆栈来管理 GUI 线程上的组​​合和缓冲区交换。当线程完成帧缓冲区更新后,在 GUI/主线程上调用 update () 来安排合成。

        当 GUI/主线程执行合成时,必须格外小心,避免使用帧缓冲区。当乐曲开始和结束时,将发出信号 aboutToCompose () 和 frameSwapped ()。它们在 GUI/主线程上发出。这意味着通过使用直接连接, aboutToCompose () 可以阻塞 GUI/主线程,直到工作线程完成渲染。之后,工作线程必须不再执行渲染,直到发出 frameSwapped () 信号。如果这是不可接受的,工作线程必须实现双缓冲机制。这涉及使用完全由线程控制的替代渲染目标(例如附加帧缓冲区对象)进行绘制,并在适当的时间位块传输到 QOpenGLWidget 的帧缓冲区。

4.3 上下文共享Context Sharing

        当多个 QOpenGLWidget 作为子级添加到同一个顶级 widget 时,它们的上下文将相互共享。这不适用于属于不同窗口的 QOpenGLWidget 实例。

        这意味着同一窗口中的所有 QOpenGLWidget 都可以访问彼此的可共享资源,例如纹理,并且不需要额外的 "global share" 上下文。

        要在属于不同窗口的 QOpenGLWidget 实例之间设置共享,请在实例化 QApplication 之前设置 Qt::AA_ShareOpenGLContexts 应用程序属性。这将触发所有 QOpenGLWidget 实例之间的共享,无需任何进一步的步骤。

        还可以创建额外的 QOpenGLContext 实例,与 QOpenGLWidget 的上下文共享纹理等资源。只需在调用 QOpenGLContext::create () 之前将从 context () 返回的指针传递给 QOpenGLContext::setShareContext () 即可。生成的上下文还可以在不同的线程上使用,从而允许线程化纹理生成和异步纹理上传。

        请注意,当涉及底层图形驱动程序时,QOpenGLWidget 期望资源共享的标准一致实现。例如,某些驱动程序(特别是针对移动和嵌入式硬件的驱动程序)在现有上下文和以后创建的其他上下文之间设置共享时存在问题。当尝试利用不同线程之间的共享资源时,其他一些驱动程序可能会以意想不到的方式运行。

4.4 资源初始化和清理

        每当调用 initializeGL () 和 paintGL () 时,QOpenGLWidget 关联的 OpenGL 上下文都保证是当前的。在调用 initializeGL () 之前不要尝试创建 OpenGL 资源。例如,在子类的构造函数中尝试编译着色器、初始化顶点缓冲区对象或上传纹理数据将失败。这些操作必须推迟到 initializeGL ()。一些 Qt 的 OpenGL 帮助器类(如 QOpenGLBuffer 或 QOpenGLVertexArrayObject )具有匹配的延迟行为:它们可以在没有上下文的情况下实例化,但所有初始化都会延迟到 create () 或类似的调用。这意味着它们可以用作 QOpenGLWidget 子类中的普通(非指针)成员变量,但 create () 或类似函数只能从 initializeGL () 调用。但请注意,并非所有类都是这样设计的。如有疑问,请将成员变量设置为指针,并分别在 initializeGL () 和析构函数中动态创建和销毁实例。

        释放资源还需要当前上下文。因此,执行此类清理的析构函数预计会在继续销毁任何 OpenGL 资源或包装器之前调用 makeCurrent ()。通过 deleteLater () 或 QObject 的育儿机制避免延迟删除。无法保证在相关实例真正被销毁时正确的上下文将是当前的。

        因此,在资源初始化和销毁​​方面,典型的子类通常如下所示:

class MyGLWidget : public QOpenGLWidget
{...private:QOpenGLVertexArrayObject m_vao;QOpenGLBuffer m_vbo;QOpenGLShaderProgram *m_program;QOpenGLShader *m_shader;QOpenGLTexture *m_texture;
};MyGLWidget::MyGLWidget(): m_program(0), m_shader(0), m_texture(0)
{// 这里没有进行OpenGL资源初始化。
}MyGLWidget::~MyGLWidget()
{// 确保上下文是当前的并且是显式的// 销毁所有底层 OpenGL 资源。makeCurrent();delete m_texture;delete m_shader;delete m_program;m_vbo.destroy();m_vao.destroy();doneCurrent();
}void MyGLWidget::initializeGL()
{m_vao.create();if (m_vao.isCreated())m_vao.bind();m_vbo.create();m_vbo.bind();m_vbo.allocate(...);m_texture = new QOpenGLTexture(QImage(...));m_shader = new QOpenGLShader(...);m_program = new QOpenGLShaderProgram(...);...
}

        这自然不是唯一可能的解决方案。一种替代方法是使用 QOpenGLContext 的 aboutToBeDestroyed () 信号。通过使用直接连接将插槽连接到此信号,每当要释放底层本机上下文句柄或整个 QOpenGLContext 实例时,就可以执行清理。以下代码片段原则上与上一个代码片段等效:

void MyGLWidget::initializeGL()
{// 从initializeGL 或paintGL 调用时,context() 和QOpenGLContext::currentContext() 是等效的。connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup);
}void MyGLWidget::cleanup()
{makeCurrent();delete m_texture;m_texture = 0;...doneCurrent();
}

        注意:对于在其生命周期内多次更改其关联的顶级窗口的小部件,组合方法至关重要。每当小部件或其父级重新设置父级以使顶级窗口变得不同时,小部件的关联上下文就会被销毁并创建一个新的上下文。然后调用 initializeGL (),其中所有 OpenGL 资源必须重新初始化。因此,执行正确清理的唯一选择是连接到上下文的 aboutToBeDestroyed() 信号。请注意,当信号发出时,所讨论的上下文可能不是当前的上下文。因此,最好在已连接的插槽中调用 makeCurrent ()。此外,必须从派生类的析构函数执行相同的清理步骤,因为当小部件被销毁时,连接到信号的槽将不会被调用。

        注意:设置 Qt::AA_ShareOpenGLContexts 后,小部件的上下文永远不会更改,即使重新设置父级时也不会更改,因为保证可以从新的顶级上下文访问小部件的关联纹理。

        由于上下文共享,正确的清理尤为重要。即使每个 QOpenGLWidget 的关联上下文与 QOpenGLWidget 一起被销毁,该上下文中的可共享资源(如纹理)将保持有效,直到 QOpenGLWidget 所在的顶级窗口被销毁为止。此外, Qt::AA_ShareOpenGLContexts 和某些 Qt 模块等设置可能会触发更广泛的共享上下文,从而可能导致相关资源在应用程序的整个生命周期内保持活动状态。因此,最安全、最稳健的方法始终是对 QOpenGLWidget 中使用的所有资源和资源包装器执行显式清理。

4.5 限制Limitations

        将其他小部件放在下面并使 QOpenGLWidget 透明将不会导致预期的结果:下面的小部件将不可见。这是因为实际上 QOpenGLWidget 是在所有其他常规非 OpenGL 小部件之前绘制的,因此透明类型的解决方案是不可行的。其他类型的布局,例如在 QOpenGLWidget 之上放置小部件,将按预期运行。

        当绝对必要时,可以通过在 QOpenGLWidget 上设置 Qt::WA_AlwaysStackOnTop 属性来克服此限制。但请注意,这会破坏堆叠顺序,例如,在 QOpenGLWidget 之上不可能有其他小部件,因此它只能在需要半透明 QOpenGLWidget 且其他小部件在下面可见的情况下使用。

        请注意,当下面没有其他小部件并且目的是拥有半透明窗口时,这并不适用。在这种情况下,在顶级窗口上设置 Qt::WA_TranslucentBackground 的传统方法就足够了。请注意,如果仅在 QOpenGLWidget 中需要透明区域,则在启用 Qt::WA_TranslucentBackground 后,需要将 Qt::WA_NoSystemBackground 转回 false 。此外,根据系统的不同,通过 setFormat () 请求 QOpenGLWidget 上下文的 Alpha 通道可能也是必要的。

        QOpenGLWidget 支持多种更新行为,就像 QOpenGLWindow 一样。在保留模式下,前一个 paintGL () 调用的渲染内容可在下一个调用中使用,从而允许增量渲染。在非保留模式下,内容会丢失,并且 paintGL () 实现预计会重绘视图中的所有内容。

        在 Qt 5.5 之前,QOpenGLWidget 的默认行为是在 paintGL () 调用之间保留渲染内容。自 Qt 5.5 起,默认行为不再保留,因为这提供了更好的性能,并且大多数应用程序不需要以前的内容。这也类似于基于 OpenGL 的 QWindow 的语义,并与 QOpenGLWindow 的默认行为相匹配,因为每个帧的颜色和辅助缓冲区都无效。要恢复保留的行为,请使用 PartialUpdate 调用 setUpdateBehavior () 。

        注意:由于与其他基于 QWidget 的内容的合成方式,显示 QOpenGLWidget 需要关联的顶级窗口后备存储中的 Alpha 通道。如果没有alpha通道,QOpenGLWidget渲染的内容将不可见。当使用低于 24 的颜色深度时,这在远程显示设置(例如使用 Xvnc)中的 Linux/X11 上尤其重要。例如,16 的颜色深度通常会映射到使用具有以下格式的后备存储图像 QImage::Format_RGB16 (RGB565),没有为 Alpha 通道留出空间。因此,如果在将 QOpenGLWidget 的内容与窗口中的其他小部件正确合成时遇到问题,请确保服务器(例如 vncserver)配置为 24 或 32 位深度而不是 16 位深度。

4.6 代换物Alternatives

        将 QOpenGLWidget 添加到窗口中将为整个窗口启用基于 OpenGL 的合成。在某些特殊情况下,这可能并不理想,并且需要具有单独的本机子窗口的旧 QGLWidget 样式行为。了解此方法局限性的桌面应用程序(例如,当涉及重叠、透明度、滚动视图和 MDI 区域时),可以将 QOpenGLWindow 与 QWidget::createWindowContainer 结合使用 ()。这是 QGLWidget 的现代替代品,并且由于缺少额外的合成步骤而比 QOpenGLWidget 更快。强烈建议将此方法的使用限制在没有其他选择的情况下。请注意,此选项不适用于大多数嵌入式和移动平台,并且已知在某些桌面平台(例如 macOS)上也存在问题。稳定的跨平台解决方案始终是 QOpenGLWidget。

        OpenGL 是 Silicon Graphics, Inc. 在美国和其他国家/地区的商标。

        另请参见 QOpenGLFunctions 、 QOpenGLWindow 、 Qt::AA_ShareOpenGLContexts 和 UpdateBehavior 。

五、QT5.5版新增成员类型补充文档

5.1 枚举 QOpenGLWidget::UpdateBehavior

        该枚举描述了 QOpenGLWidget 的更新语义。

ConstantValueDescription
QOpenGLWidget::NoPartialUpdate0QOpenGLWidget 渲染到屏幕后, QOpenGLWidget 将丢弃颜色缓冲区和辅助缓冲区的内容。这与使用默认启用 opengl 的 QWindow 作为参数调用 QOpenGLContext::swapBuffers 所期望的行为相同。当帧缓冲区对象用作渲染目标时,NoPartialUpdate 可以在移动和嵌入式空间中常见的某些硬件架构上具有一些性能优势。使用 glDiscardFramebufferEXT(如果支持)或 glClear 使帧缓冲区对象在帧之间失效。请参阅 EXT_discard_framebuffer 的文档以获取更多信息:https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt
QOpenGLWidget::PartialUpdate1帧缓冲区对象颜色缓冲区和辅助缓冲区在帧之间不会失效。

        该枚举是在 Qt 5.5 中引入或修改的。

        另请参见 updateBehavior () 和 setUpdateBehavior ()。

5.2 成员函数文档

QOpenGLWidget::QOpenGLWidget(QWidget *parent= nullptr, Qt::WindowFlags f= Qt::WindowFlags())

构造一个小部件,它是parent,小部件标志设置为f.

  • [signal] void QOpenGLWidget::aboutToCompose()

当小部件的顶级窗口即将开始合成其 QOpenGLWidget 子部件和其他小部件的纹理时,会发出此信号。

  • [signal] void QOpenGLWidget::aboutToResize()

当小部件的大小更改时会发出此信号,因此将重新创建帧缓冲区对象。

  • [signal] void QOpenGLWidget::frameSwapped()

该信号在小部件的顶级窗口完成合成并从其可能阻塞的 QOpenGLContext::swapBuffers () 调用返回后发出。

  • [signal] void QOpenGLWidget::resized()

由于调整小部件的大小而重新创建帧缓冲区对象后,会立即发出此信号。

  • [virtual] QOpenGLWidget::~QOpenGLWidget()

        销毁 QOpenGLWidget 实例,释放其资源。

      QOpenGLWidget 的上下文在析构函数中成为当前上下文,允许安全销毁可能需要释放属于该小部件提供的上下文的 OpenGL 资源的任何子对象。

        警告:如果您有将 OpenGL 资源(例如 QOpenGLBuffer 、 QOpenGLShaderProgram 等)包装为 OpenGLWidget 子类成员的对象,则可能还需要在该子类的析构函数中添加对 makeCurrent () 的调用。由于C++对象销毁的规则,这些对象将被销毁before调用此函数(但在子类的析构函数运行之后),因此使 OpenGL 上下文在此函数中处于当前状态,对于安全处置来说为时已晚。

        另请参见 makeCurrent 。

QOpenGLContext *QOpenGLWidget::context() 常量

返回此小部件使用的 QOpenGLContext 或 0 (如果尚未初始化)。

注意:通过 setParent () 重新调整小部件的父级时,小部件使用的上下文和帧缓冲区对象会发生变化。

另请参见 QOpenGLContext::setShareContext () 和 defaultFramebufferObject ()。

GLuint QOpenGLWidget::defaultFramebufferObject() const

返回 帧缓冲区对象句柄或 0 (如果尚未初始化)。

注意:framebuffer对象属于 context ()返回的上下文,可能无法从其他上下文访问。

注意:通过 setParent () 重新调整小部件的父级时,小部件使用的上下文和帧缓冲区对象会发生变化。此外,帧缓冲区对象在每次调整大小时都会发生变化。

另请参见 context ()。

void QOpenGLWidget::doneCurrent()

释放上下文。

大多数情况下没有必要调用此函数,因为小部件将确保在调用 paintGL () 时正确绑定和释放上下文。

[override virtual protected] bool QOpenGLWidget::事件( QEvent *e)

重新实现: QWidget::event (QEvent *事件)。

QSurfaceFormat QOpenGLWidget::format() const

返回此小部件及其顶级窗口使用的上下文和表面格式。

在创建小部件及其顶层、调整大小并显示之后,此函数将返回上下文的实际格式。如果平台无法满足请求,则这可能与请求的格式不同。也可以获得比要求更大的颜色缓冲区大小。

当widget的窗口和相关的OpenGL资源尚未初始化时,返回值是通过 setFormat ()设置的格式。

另请参见 setFormat () 和 context ()。

QImage QOpenGLWidget::grabFramebuffer()

渲染并返回帧缓冲区的 32 位 RGB 图像。

注意:这是一个潜在昂贵的操作,因为它依赖于 glReadPixels() 来读回像素。这可能会很慢并且可能会导致 GPU 管道停顿。

[virtual protected] void QOpenGLWidget::initializeGL()

该虚函数在第一次调用 paintGL () 或 resizeGL () 之前调用一次。在子类中重新实现它。

此函数应设置任何所需的 OpenGL 资源和状态。

不需要调用 makeCurrent (),因为调用该函数时已经完成了。但请注意,帧缓冲区在此阶段尚不可用,因此请避免从此处发出绘制调用。将此类调用推迟到 paintGL ()。

另请参见 paintGL () 和 resizeGL ()。

bool QOpenGLWidget::isValid() const

Returnstrue如果小部件和 OpenGL 资源(如上下文)已成功初始化。请注意,在显示小部件之前,返回值始终为 false 。

void QOpenGLWidget::makeCurrent()

通过将相应的上下文设置为当前上下文并绑定该上下文中的帧缓冲区对象,准备为此小部件渲染 OpenGL 内容。

大多数情况下没有必要调用该函数,因为它在调用 paintGL () 之前会自动调用。

另请参见 context ()、 paintGL () 和 doneCurrent ()。

[override virtual protected] int QOpenGLWidget::公制( QPaintDevice::PaintDeviceMetric metric) const

重新实现: QWidget::metric(QPaintDevice::PaintDeviceMetric m) const 。

[override virtual protected] QPaintEngine *QOpenGLWidget::paintEngine() const

重新实现: QWidget::paintEngine() const 。

[override virtual protected] void QOpenGLWidget::paintEvent( QPaintEvent *e)

重新实现: QWidget::paintEvent (QPaintEvent *事件)。

处理绘画事件。

调用 QWidget::update ()将导致发送绘画事件e,从而调用该函数。(注意,这是异步的,并且会在从 update () 返回后的某个时刻发生)。经过一些准备后,该函数将调用虚拟 paintGL () 来更新 QOpenGLWidget 帧缓冲区的内容。然后,小部件的顶级窗口会将帧缓冲区的纹理与窗口的其余部分合成。

[virtual protected] void QOpenGLWidget::paintGL()

每当需要绘制小部件时就会调用此虚拟函数。在子类中重新实现它。

不需要调用 makeCurrent (),因为调用该函数时已经完成了。

在调用此函数之前,上下文和帧缓冲区已绑定,并且通过调用 glViewport() 设置视口。框架不设置其他状态,也不执行任何清除或绘制操作。

另请参见 initializeGL () 和 resizeGL ()。

[override virtual protected] QPaintDevice *QOpenGLWidget::重定向( QPoint *p) const

[override virtual protected] void QOpenGLWidget::resizeEvent( QResizeEvent *e)

重新实现: QWidget::resizeEvent (QResizeEvent *事件)。

处理在中传递的调整大小事件e事件参数。调用虚函数 resizeGL ()。

注意:避免在派生类中重写此函数。如果这不可行,请确保也调用 QOpenGLWidget 的实现。否则,底层帧缓冲区对象和相关资源将无法正确调整大小,并导致错误渲染。

[virtual protected] void QOpenGLWidget::resizeGL(int w, int h)

只要调整小部件的大小,就会调用此虚拟函数。在子类中重新实现它。新的尺寸被传入wandh.

不需要调用 makeCurrent (),因为调用该函数时已经完成了。此外,帧缓冲区也被绑定。

另请参见 initializeGL () 和 paintGL ()。

void QOpenGLWidget::setFormat(const QSurfaceFormat &format)

设置所需的表面format.

当没有通过该函数显式设置格式时,将使用 QSurfaceFormat::defaultFormat () 返回的格式。这意味着当有多个 OpenGL 小部件时,在创建第一个小部件之前,对此函数的单独调用可以替换为对 QSurfaceFormat::setDefaultFormat () 的一次调用。

注意:当目的是使其他小部件可见时,通过此函数请求 alpha 缓冲区不会产生所需的结果。相反,使用 Qt::WA_AlwaysStackOnTop 启用半透明 QOpenGLWidget 实例,并在下面显示其他小部件。但请记住,这会破坏堆叠顺序,因此将不再可能在 QOpenGLWidget 之上放置其他小部件。

另请参见 format ()、 Qt::WA_AlwaysStackOnTop 和 QSurfaceFormat::setDefaultFormat ()。

[since 5.10] void QOpenGLWidget::setTextureFormat(GLenum texFormat)

设置自定义内部纹理格式texFormat.

使用 sRGB 帧缓冲区时,需要指定 GL_SRGB8_ALPHA8 等格式。这可以通过调用该函数来实现。

注意:如果在小部件已经显示并因此执行初始化之后调用该函数,则该函数无效。

注意:此函数通常必须与将颜色空间设置为 QSurfaceFormat::sRGBColorSpace 的 QSurfaceFormat::setDefaultFormat () 调用结合使用。

该功能是在 Qt 5.10版本中引入的。

另请参见 textureFormat ()。

[since 5.5] void QOpenGLWidget::setUpdateBehavior( QOpenGLWidget::UpdateBehavior updateBehavior)

将此小部件的更新行为设置为updateBehavior.

该功能是在 Qt 5.5版本中引入的。

另请参见 updateBehavior ()。

[since 5.10] GLenum QOpenGLWidget::textureFormat() const

如果小部件已经初始化,则返回活动的内部纹理格式;如果已设置但小部件尚未可见,则返回请求的格式;如果未调用 setTextureFormat () 并且小部件尚未可见,则返回 nullptr 。

该功能是在 Qt 5.10版本中引入的。

另请参见 setTextureFormat ()。

[since 5.5] QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const

返回小部件的更新行为。

该功能是在 Qt 5.5版本中引入的。

另请参见 setUpdateBehavior ()。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/45301.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android高级——Logger日志系统

Logger日志系统 Logger日志系统是基于内核中的Logger日志驱动程序实现将日志记录保存在内核空间中使用一个环形缓冲区来保存日志&#xff0c;满了之后&#xff0c;新的日志就会覆盖旧的日志 日志类型 main&#xff0c;记录应用程序级别system&#xff0c;记录系统级别radio&…

在Ubuntu下安装samba实现和Windows系统文件共享

一、安装 apt install -y samba samba-clientSamba is not being run as an AD Domain Controller: Masking samba-ad-dc.service Please ignore the following error about deb-systemd-helper not finding those services. (samba-ad-dc.service masked) Created symlink /et…

Electron31.x+vite5+vue3 setup客户端Exe聊天系统演示

electron31-vue3chat&#xff1a;首创研发跨桌面端electron31vite5pinia2element-plus等技术实战搭建仿微信电脑版聊天程序。整合聊天、联系人、收藏、朋友圈、小视频号、我的等功能模块。 首创Electron31Vite5ElementPlus仿微信电脑端聊天Exe系统【完整演示】 框架技术 Vscod…

百度网盘资料使用

1. 将链接复制到浏览器打开&#xff0c;点击提取文件 2. 提取文件&#xff0c;进入如下界面 3. 因为文件太大&#xff0c;而且未开会员&#xff0c;所以无法全部转存到网盘&#xff0c;只能分批次转存 点击目录&#xff0c;进入文件夹 1&#xff09;选择一个喜欢的文件&#…

9.Python学习:Socket

1.网络通信要素&#xff08;IP端口传输协议&#xff09; 2.Socket编程 2.1TCP、UDP协议了解 2.2 Socket流程 服务端有两个socket对象&#xff0c;客户端有一个 3.Socket实战 服务端代码&#xff1a; import socket #创建Socket对象 sksocket.socket() #绑定ip与端口号-使…

Rust 集合与字符串

Rust 集合与字符串 Rust 是一种系统编程语言,以其内存安全性、速度和并发性而闻名。在 Rust 中,集合和字符串是处理数据的重要组成部分。本文将深入探讨 Rust 中的集合和字符串,包括它们的类型、用法和性能特点。 集合 Rust 提供了多种集合类型,用于存储和处理数据。这些…

在分布式环境中,怎样保证 PostgreSQL 数据的一致性和完整性?

文章目录 在分布式环境中保证 PostgreSQL 数据的一致性和完整性一、数据一致性和完整性的重要性二、分布式环境对数据一致性和完整性的挑战&#xff08;一&#xff09;网络延迟和故障&#xff08;二&#xff09;并发操作&#xff08;三&#xff09;数据分区和复制 三、保证 Pos…

Apache Spark分布式计算框架架构介绍

目录 一、概述 二、Apache Spark架构组件栈 2.1 概述 2.2 架构图 2.3 架构分层组件说明 2.3.1 支持数据源 2.3.2 调度运行模式 2.3.3 Spark Core核心 2.3.3.1 基础设施 2.3.3.2 存储系统 2.3.3.3 调度系统 2.3.3.4 计算引擎 2.3.4 生态组件 2.3.4.1 Spark SQL 2.…

网络基础:Vlan原理与配置

VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;是一种将一个物理网络划分为多个逻辑子网的技术。它通过在网络交换机上配置&#xff0c;使得不同VLAN中的设备即使连接在同一个物理交换机上&#xff0c;也不能直接进行通信&#xff0c;从而实现…

HiFi音频解码器:音质提升的秘密武器

HiFi音频解码器&#xff1a;音质提升的秘密武器 在音频爱好者的世界里&#xff0c;解码器、耳放、前置放大器和后级功放等设备是不可或缺的神器。它们不仅能让高端音箱和耳机表现出色&#xff0c;还能让音乐听起来更加真实动人。但对于刚刚入门的音频新手来说&#xff0c;这些设…

某企业数据治理总体解决方案(45页PPT)

引言&#xff1a;集团企业数据治理总体解决方案旨在构建一个高效、安全、合规且灵活的数据管理体系&#xff0c;以支持企业决策优化、业务创新、风险管理和运营效率提升。该方案通过整合数据资源、规范数据流程、强化数据质量和促进数据共享&#xff0c;实现数据资产的最大化价…

java基础(知识点整理)

目录 1.main方法 2.修饰符 3.基本数据类型&#xff1a; 4.包装器类&#xff1a; 5.static关键字 6.finall关键字 7.String类型 8.八大排序 9.抽象类和接口的区别&#xff1a; 10.面向对象&#xff1a;封装 继承 多态 11.Object类 12.内部类&#xff1a; 13.lambda…

Lingo学习(三)——工厂合并、运算符、内置函数

一、工厂合并 &#xff08;一&#xff09; 工厂合并——生产二维矩阵 【引入】 sets: factory /1..6/ : a; plant /1..8/ : d; Cooperation(factory,p lant) : c, x; endsets 以上程序可…

【YOLOv8】 用YOLOv8实现数字式工业仪表智能读数(三)

上一篇圆形表盘指针式仪表的项目受到很多人的关注&#xff0c;咱们一鼓作气&#xff0c;把数字式工业仪表的智能读数也研究一下。本篇主要讲如何用YOLOV8实现数字式工业仪表的自动读数&#xff0c;并将读数结果进行输出&#xff0c;若需要完整数据集和源代码可以私信。 目录 &a…

网络安全应急响应信息收集利器-Eagle_Eye

项目介绍: 网络安全应急响应信息收集利器 - Eagle_Eye&#xff1a;您的终端信息自动收集专家 在网络安全的紧急时刻&#xff0c;每一秒都至关重要。Eagle_Eye&#xff0c;这款专为应急响应设计的工具&#xff0c;如同一位随时待命的侦察兵&#xff0c;能够在危机时刻迅速收集…

Xcode数据分析全解:洞察应用性能的密钥

标题&#xff1a;Xcode数据分析全解&#xff1a;洞察应用性能的密钥 在应用开发和优化的过程中&#xff0c;数据分析是提升用户体验和应用性能的关键步骤。Xcode作为苹果官方的集成开发环境&#xff0c;提供了多种工具和集成方案来支持应用的数据分析。本文将详细介绍如何在Xc…

嵌入式工程师从0开始,到底该学什么,怎么学?

作为嵌入式工程师&#xff0c;从零开始学习需要掌握以下几个关键方面。我收集归类了一份嵌入式学习包&#xff0c;对于新手而言简直不要太棒&#xff0c;里面包括了新手各个时期的学习方向编程教学、问题视频讲解、毕设800套和语言类教学&#xff0c;敲个22就可以免费获得。 基…

6. 年份计数

年份计数 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 20212021 是一个特殊的年份&#xff0c;它的千位和十位相同&#xff0c;个位比百位多一。请问从 10001000&#xff08;含&#xff09; 到 99999999&#…

yarn底层原理详解:(第33天)

系列文章目录 一、yarn总体架构 二、yarn核心组件及功能 三、yarn资源分配与调度 四、yarn提交和执行流程 五、yarn调度算法 六、yarn安全性与容错性 文章目录 系列文章目录前言一、总体架构二、核心组件及功能1. ResourceManager&#xff08;RM&#xff09;2. NodeManager&am…

day29--452. 用最少数量的箭引爆气球+435. 无重叠区间+763.划分字母区间

一、452. 用最少数量的箭引爆气球 题目链接&#xff1a;https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/ 文章讲解&#xff1a;https://programmercarl.com/0452.%E7%94%A8%E6%9C%80%E5%B0%91%E6%95%B0%E9%87%8F%E7%9A%84%E7%AE%AD%E5%BC%95%E7%88…