不同的QT widgets只获取一个QOpenGLContext

Get only one QOpenGLContext for different QT widgets

我遇到了以下问题:

我想要一个由许多视图组成的应用程序,这些视图从不同的视角、照明和其他选项渲染一个常见的 OpenGL 场景。

基本上,我的问题是用 qt 做到这一点的最佳方法是什么?

我的第一次尝试是创建多个 QOpenGLWidget 并获得一个通用的 QOpenGLContext,我在其中存储纹理以及网格和着色器。 但它不适用于网格,因为顶点数组对象似乎不可共享。 经过多次尝试,一个可能的解决方案是为每个需要网格的小部件存储一个 VAO,但这看起来真的很糟糕。

所以,我想知道是否有解决此类问题的好方法,或者是否有很好的文档来了解这些 QOpenGLContext 的工作原理。

我想象的最简单的想法是只创建一个 QOpenGLContext 并在不同的小部件中使用它。但是我不知道如何单独创建一个 QOpenGLContext,也不知道什么样的 QWidgets 能够显示这些效果图。

这是我的第一个post所以我不知道它是否足够清楚或者我是否需要描述我的整个架构。

你已经尝试过了,所以我传递有关共享上下文的信息。

OpenGL 上下文绑定到 window:如果您只需要一个上下文,直接的答案是只有一个 window。

使用小部件模块,您可以在同一 QOpenGLWidget 中使用多个视口获得同一场景的多个视图。类似于:

void myWidget::paintGL() {
    //...

    glViewport(
        0, 0,
        this->width()/2, this->height()/2
    );

    // draw scene from one point of view

    glViewport(
        this->width()/2, this->height()/2,
        this->width()/2, this->height()/2
    );

    // draw scene from an other point of view

    //...
}

您或许应该设计一个视口 class 来存储和管理每个视口的渲染参数。

缺点是您必须检测用户在哪个视口中单击以处理交互:某种 if event.pos.x is between 0 and this->width()/2 ...


另一种方法可能是放下小部件模块并使用 Qt Quick 和 QML:快速 window 声明一个唯一的 OpenGL 上下文,其中每个快速项就像一个视口,但封装在自己的视口中对象,因此您不必考虑用户在何处进行交互。

继承 QQuickItem 而不是 QOpenGLWidget,并使用 qmlRegisterType() 宏将 class 导出到 QML。然后您可以在您的程序中创建一个 QQuickView 以加载您声明项目的 QML 代码。 Qt 文档中的示例 here.

我认为由于多个 views/surfces 可以独立更新,不幸的是不可能有一个单独的 QOpenGLContext 来完成这项工作。共享上下文有您在问题中已经指出的限制。

QOpenGLContext can be moved to a different thread with moveToThread(). Do not call makeCurrent() from a different thread than the one to which the QOpenGLContext object belongs. A context can only be current in one thread and against one surface at a time, and a thread only has one context current at a time.

Link : http://doc.qt.io/qt-5/qopenglcontext.html

因此,让它工作的一种方法是按顺序对视图进行独立更新,并逐个使上下文成为当前视图并在移动到下一个视图之前进行渲染。这将保证上下文在任何给定时间仅在一个视图中是当前的。也许使用 QMutex 来序列化更新。

或者,您也可以在线程之间传递上下文并序列化它们的更新,但这是一种糟糕的方法。