【问题标题】:Using latest OpenGL functions across classes in Qt 5.4在 Qt 5.4 中跨类使用最新的 OpenGL 函数
【发布时间】:2015-01-30 12:10:12
【问题描述】:

我之前发布了一个关于如何让 OpenGL 在 Qt 上运行的问题,但现在我希望能够使用 OpenGL 提供的最新功能。在 Qt 之前,我使用的是 glew;但 Qt 说 glew 与其 QtOpenGL 头文件冲突。我研究了 QGLWidget 和 QGLFunctions,但坦率地说,我很困惑我应该做什么才能简单地访问 OpenGL 的函数。

现在,我使用 Qt Creator 3.3.0 获得了 Qt 5.4,并且正在使用新的 QOpenGLWidget;然而,在它应该如何使用方面缺乏指导让我有点失望:Qt 文档在那里并且确实有帮助,但它只演示了如何实例化它,而不是在程序的其他位置使用它。我知道这个 QOpenGLWidget 的功能类似于 QGLWidget。我应该从它继承的 Qt 细节;但是我没有在它想要使用 OpenGL 函数的类中实例化 OpenGL 上下文;这发生在“glWidget”类中,它继承自 QOpenGLWidget。

例如,摘自我的一个使用 OpenGL 代码的课程:

void Mesh::init()
{
    pNumIndices = pIndices.size();

    glGenVertexArrays(1, &pVAO);
    glGenBuffers(1, &pVertexBuffer);
    glGenBuffers(1, &pIndexBuffer);
    glBindVertexArray(pVAO);

    glBindBuffer(GL_ARRAY_BUFFER, pVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, pVertices.size() * sizeof(Vertex),
                 &pVertices[0], GL_STATIC_DRAW);

    // etc..
}

Mesh 是一个不继承任何东西的类。最初,它只使用 glew 来获取 OpenGL 函数的声明;它不需要知道它们是否有效,因为那是 glew 的工作。然后在 mainApp 类中,我将实例化 glew。我也知道还有一个 QOpenGLFunctions 类,它的功能有点类似于 glew,但是对于所有这些 GL 类,知道使用什么是公然的混乱。更重要的是,我尝试寻找 glGenVertexArrays(..) 但在 QOpenGLBuffer、QOpenGLFunctions 或 QOpenGLWidget 中找不到;据我所知,从 OpenGL 4.5 开始,它仍然是规范的一部分;但我的图形驱动程序不使用 OpenGL 4.5,所以我改用 OpenGL 4.3。我只想说我愿意放弃 glew 采用 Qt 自己的方法来调用 OpenGL 函数。

在各种类都使用 OpenGL 函数的程序中,我如何利用 Qt 来调用它们而不使用 glew? Mesh 是那些不实例化 OpenGL 的类之一,但仅使用其功能。

大家都知道,我使用 Qt 已经有一段时间了(虽然还不够!)并且很喜欢 Qt;但我确实需要知道如何将 Qt 与 OpenGL 结合使用来继续开发。大多数教程仍然使用 5.4 之前的内容。

【问题讨论】:

  • glGenVertexArrays 用于顶点数组对象,那么您应该查找的类名是什么?没错,QOpenGLVertexArrayObject
  • 我个人不喜欢 Q 的东西,它集中封装了 OpenGL 的东西。我非常喜欢自己在自己的课程中做这类事情。

标签: c++ qt opengl opengl-es qt5


【解决方案1】:

在 Qt 5.4 中,有特定版本的 OpenGL 函数的头文件,所以:

#include <QOpenGLFunctions_3_3_Core>

或您想使用的任何版本。然后在像 QOpenGLWidget::initializeGL() 这样具有有效 OpenGL 上下文的地方创建并初始化一个 QOpenGLFunctions 对象:

QOpenGLFunctions_3_3_Core *fun = new QOpenGLFunctions_3_3_Core;
fun->initializeOpenGLFunctions();

然后在您的绘图代码中,只需使用该对象的 OpenGL 函数:

fun->glSomething(1,2,3)

【讨论】:

  • 另一种选择是继承这样的类,所以你可以简单地写glSomething,它会起作用。
  • 好的,如果我有另一个不是 QOpenGLWidget 但使用 OpenGL 4.3 函数的类,那我该怎么办?
  • 创建一个 QOpenGLFunctions_3_3_Core 对象,或者从它派生。无论如何,它都与 QOpenGLWidget 无关。初始化时只需要一个有效的当前 OpenGL 上下文。
  • 上述解决方案有效;但有时会出现“未定义的对 QAbstractOpenGLFunctions 的 vtable 的引用”的问题。我确保所有析构函数对于从它继承的任何类都是虚拟的。当程序中不止一个类继承自QOpenGLFunctions_4_3_Core时,似乎会发生这种情况。
【解决方案2】:

使用 QOpenGLFunctions_X_X_* 并不能解决这个问题! 您需要先设置 openGL 上下文的版本,然后才能使用 QOpenGLFunctions_X_X_*。 Qt 使用默认版本(我认为是 1.X)所以你需要将此代码添加到你的 main.cpp 文件中

        QSurfaceFormat format;
//        format.setDepthBufferSize(24);
    //    format.setStencilBufferSize(8);

        format.setMajorVersion( 3 ); //whatever version
        format.setMinorVersion( 3 ); //
        format.setProfile(QSurfaceFormat::CoreProfile);
        QSurfaceFormat::setDefaultFormat(format);

干杯, 奈

【讨论】:

    【解决方案3】:

    OpenGL 的直接方法是创建一个包含函数指针的结构:

    struct sLGLAPI
    {
        sLGLAPI() { memset( this, 0, sizeof( *this ) ); };
        PFNGLACTIVETEXTUREPROC      glActiveTexture;
        PFNGLATTACHSHADERPROC       glAttachShader;
        PFNGLBEGINQUERYPROC         glBeginQuery;
        PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
        ...
    

    用来自 OpenGL 共享库的指针 dlsym-ed 填充它:

    API->glActiveTexture = ( PFNGLACTIVETEXTUREPROC )GetGLProc( "glActiveTexture" );
    API->glAttachShader = ( PFNGLATTACHSHADERPROC )GetGLProc( "glAttachShader" );
    API->glBeginQuery = ( PFNGLBEGINQUERYPROC )GetGLProc( "glBeginQuery" );
    API->glBindAttribLocation = ( PFNGLBINDATTRIBLOCATIONPROC )GetGLProc( "glBindAttribLocation" );
    

    并且只能通过这种结构在您的代码中访问 OpenGL。例如:

    API->glShaderSource( Shader, 1, &Code, nullptr );
    API->glCompileShader( Shader );
    

    这样您将能够隐藏完整的 OpenGL API,甚至在必要时使用存根函数,例如记录参数或在 OpenGL 和 OpenGL ES 之间切换。

    【讨论】:

    • 你的解决方案很贴切;但 dlsym 仅在 Linux 和类似系统上可用。我也使用 Linux;但我也必须让我的代码在 Windows 下工作。 Qt 不会有一个多平台的方式来处理这样的任务吗?
    • @Poriferous GetProcAddress 是最接近 dlsym 的东西
    • 这不是我想要的解决方案,尽管听起来很有趣;我需要更符合 Qt 的东西。
    • @Poriferous:在 Windows 上,您可以使用 LoadLibrary()GetProcAddress()
    • 这已经被 Qt 实现了。只需使用(版本化的)函数版本类之一,例如QOpenGLFunctionsQOpenGLFunctions_3_3_Core 左右。无需使用特定于平台的方法;最坏的情况,使用 QOpenGLContext 解析指针,而不是通过原生 API 调用。
    【解决方案4】:
    #include <QOpenGLFunctions_3_3_Core>
    
    class Mesh : public QOpenGLFunctions_3_3_Core
    {
    public:
        Mesh();//initializeOpenGLFunctions()
        ~Mesh();      
    
        void func();//glxxx in it. when using it ,you need an opengl context.
                    //for example, use makeCurrent() in QOpenGLWidget subclass.
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-16
      • 2013-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多