我已经阅读了关于 SO 的所有问题,我可以找到关于 qt 4 和 5 opengl 的所有问题。这是 Qt 5 中最接近的 OpenGL vs QOpenGL/QtOpenGL:差异和限制? ,我不知道它为什么被关闭,因为它是一个很好的问题。我认为它缺少的唯一方面是速度差异。
更具体一点,我需要使用 physx、tcp/ip 通信以及大量快速更新的顶点和网格。目标是尽可能接近实时地执行此操作。渲染之类的事情不是问题,但是 qt 的任何开销都是有害的。 (一切都是用 C++ 制作的 3D)
您的问题中有多个问题。
“原始”OpenGL 与“Qt”OpenGL
这个问题不恰当,因为没有“Qt OpenGL”之类的东西。 OpenGL 是 Khronos 拥有和发布的标准。 Qt 只是使用它。
Qt 可以为您做的就是帮助您的应用程序管理几件事情。
窗口/上下文创建
您是否尝试过在 Win32 下创建 OpenGL 上下文?它需要一堆样板代码(参见here 或here),其中包括创建一个临时上下文来检查WGL 功能,然后在最后创建实际上下文...
您是否尝试过在 X11 下创建 OpenGL 上下文?它需要一堆样板代码(请参阅here),其中涉及检查GLX_ARB_create_context 的存在,然后使用它来创建上下文,或者回退到 GLX 1.3 代码路径和...
您是否尝试过在 Mac OS X 下创建 OpenGL 上下文?
您是否尝试过在 Android 下创建 OpenGL 上下文?
您是否尝试过在 QNX 下创建 OpenGL 上下文?
您是否尝试过在 DirectFB/EGLFS 下创建 OpenGL 上下文?
哦,等等。 Qt 来了:
class Window : public QWindow {
QOpenGLContext *context;
public:
Window() {
QSurfaceFormat format;
format.setVersion(3,3);
format.setProfile(QSurfaceFormat::CoreProfile);
setSurfaceType(OpenGLSurface);
setFormat(format);
create();
context = new QOpenGLContext;
context->setFormat(format);
context->create();
}
...
是的,仅此而已。这将创建一个(顶层)OpenGL 窗口和一个 3.3 Core Profile 上下文。将它与 QTimer 结合起来,您就有了一个可行的渲染器。当然,哪个适用于上述所有平台:Win32、Mac、X11、Linux/EGLFS、QNX、iOS、Android。
您是否需要为所有这些支付开销?是的当然。但这绝对可以忽略不计。并且您只需支付一次,即在您创建窗口和上下文时。
真正重要的东西来自 OpenGL 绘图本身,它完全在您的控制之下:您将上下文设置为当前窗口并开始发出原始 OpenGL 命令。 Qt 不在那儿。 Qt 和 OpenGL 再次相遇的唯一时刻将是交换缓冲区时间;但这是一项几乎没有成本的操作。
所以:Qt 不会增加任何可测量的开销。
窗口管理
当然,与上述内容捆绑在一起的事实是,您可以 f.i.在任何这些平台上使用相同的代码处理键盘和鼠标输入。或调整窗口大小。或者让它全屏。或者关闭它。
OpenGL 帮助程序
Qt 不“只是”提供一种创建 OpenGL 表面和上下文的方法(以及相关操作:设置为当前、交换缓冲区等)。它走得更远,并提供了一整套辅助类和函数:
-
QMatrix4x4 是一个... 4x4 矩阵。它具有您在 OpenGL 程序中所需的所有出色功能:
lookAt()、ortho()、perspective()、normalMatrix() 等等。
-
QOpenGLContext::hasExtension 和 QOpenGLContext::getProcAddress 是与平台无关的解决 OpenGL 入口点的方法。
-
QOpenGLContext::versionFunctions 返回一个对象,其中包含已解析的给定版本/配置文件的所有 OpenGL 入口点。
-
QOpenGLBuffer 包装了一个缓冲区对象。
-
QOpenGLVertexArrayObject 包装了一个顶点数组对象(并且有一个 RAII 助手来绑定和取消绑定 VAO)。
-
QOpenGLTexture 包装了一个纹理对象。
-
QOpenGLFrameBufferObject 包装了一个帧缓冲对象。
-
QOpenGLShader 和 QOpenGLShaderProgram 封装了着色器和着色器程序,为 f.i.将 QMatrix4x4 设置为统一变量。因此,您可以使用上述方法在 CPU 上计算给定网格的 MVP,然后将其设置为均匀。
-
QOpenGLDebugLogger 包装
GL_KHR_debug 用于调试您的 OpenGL 应用程序。
- 还有一堆我现在不记得的东西。
有开销吗?是的,但它又一次是最小的,它不涉及您如何在您的 OpenGL 代码中使用这些对象。如果您的 OpenGL 代码速度快且结构良好,那么您会发现这些帮助程序对管理它很有用,而且它们不会让它运行得更慢。
(“管理它有用”的示例:QOpenGLVertexArrayObject 将允许您在 OpenGL 3.0 上使用 VAO,或者在存在 GL_ARB_vertex_array_object 扩展名的任何桌面 OpenGL 版本上使用 VAO,或者在 OpenGL ES2 上使用 GL_OES_vertex_array_object存在。您不需要根据运行时解析正确的函数集。Qt 会为您做这件事,并为创建、绑定、释放和销毁 VAO 提供相同的 API。
一切都那么好吗?不,我必须在这里说实话,有些细节会从一些爱中受益。
例如,QOpenGLFrameBufferObject 的 API 有限,不支持 f.i。任何数量的颜色附件。 QOpenGLBuffer 需要一些工作来支持更多的缓冲区类型/绑定目标。仍然不支持程序管道。仍然不支持统一缓冲区。
另一方面,你有 QOpenGLTexture 之类的东西,它支持不可变存储和纹理视图等最新功能。
这是否意味着您不能使用这些功能?当然可以。如果您需要 Qt 目前没有提供的功能,请返回原始 OpenGL 代码。或者,考虑contributing those features to Qt!
Qt
当然,一旦你走上了 Qt 的道路,你就拥有了 Qt。这意味着,仅在 QtCore 和 QtGui 库中:
- 事件循环
- 定时器
- 信号和槽
- 线程
- Unicode 字符串 + i18n
- 容器
- 正则表达式
- 文件处理
- 插件加载
- 设置
- 模仿类型
- 输入处理
- 图像 I/O
- 使用光栅引擎的二维命令式绘画
- JSON
- XML
- 还有一堆我现在不记得的东西。
当然,以上都是跨平台的。
顺便说一句,Qt还有:
- 用于跨平台二维小部件的 QtWidgets
- 用于数据库访问的 QtSql
- 用于 TCP/UDP/SSL 套接字的 QtNetwork,以及高级 HTTP/FTP 引擎
- 用于单元测试的 QtTest
- 用于嵌入 webkit 的 QtWebkit
- 还有一堆我现在不记得的东西
Qt 4 与 5 中的 OpenGL
在 Qt 4 和 Qt 5 中处理 OpenGL 的方式是否存在巨大差异?不是真的……
在 Qt 4 中,用于进行 OpenGL 渲染的类是 QGLWidget。它存在于 QtOpenGL 模块中(而不是在 QtGui 中——请记住,在 Qt 4 中,小部件也存在于 QtGui 中)。此外,我上面列出的 Qt 5 OpenGL 助手的子集实际上是在 QGLFoo 名称下可用的(例如 QGLBuffer 而不是 QOpenGLBuffer)。
在 Qt 5 中,QtOpenGL 模块仍然存在以保持旧应用程序的工作。但是:
QtGui 和 QtWidget 被拆分。 QtGui 现在包含处理 WM、创建 GL 上下文和表面、2d 绘画以及基本上我上面列出的东西的低级位。 QtWidgets 包含小部件本身。
QtOpenGL 仍然包含 QGL* 类,但现在链接到 QtWidgets(因为它包含 QGLWidget)。 这意味着使用 QGLWidget 意味着即使您根本不使用小部件,您也将链接到某个大型库(因为您的应用程序是纯 OpenGL)。
正如我之前所展示的,QtGui 足以创建顶级 OpenGL 窗口。但是,如果您想将其嵌入到基于小部件的应用程序中怎么办?然后你仍然可以使用 QGLWidget 或通过QWidget::createWindowContainer 嵌入 QWindow。 除了 QGLWidget,您不应该使用任何其他 QtOpenGL(即 QGL)类。使用 QtGui 中的对应物(即 QOpenGL 类)。
以上所有 QOpenGL* 类都在 QtGui 中,而不是在 QtOpenGL 中;并且它们比 QGL* 对应物更多(例如,没有 QGLVertexArrayObject),它们具有更多功能(例如,QOpenGLShader 支持几何和曲面细分着色器,QGLShader 不支持),并且通常可以使用(因为他们会看到错误修复和改进,QGL* 不会)。
鉴于现在 QtGui 提供 OpenGL 支持,很自然地期望 QGLWidget 替代品直接出现在 QtWidgets 中。确实会,希望在 5.4 中(准备工作将进入 5.3;但不幸的是,该功能本身会错过功能冻结)。
有什么理由可以期待 Qt 4 和 Qt 5 之间的巨大性能差异? 不,我希望您的 GL 代码执行完全相同。最后,Qt 并没有真正妨碍您。
桌面 GL / ES 2
您可以通过配置时间开关编译带有“Desktop GL”或“ES 2”支持的 Qt 5。
它显然会改变 QtGui 在编译时将使用哪些头文件,以及它将链接到哪些库(libGL 或 libGLES2 等)。它还将更改默认的表面格式:上面的 QWindow 代码将创建一个漂亮的 OpenGL ES2 表面(并且可能会导致上下文创建失败,因为没有 OpenGL ES 3.3,哦,好吧)。
但是你明白了:使用相同的代码你也可以支持 ES2。
问题(在我看来)是它还会改变一些其他更微妙的东西:例如 QOpenGLShader 将插入一些宏,例如
#define highp
#define mediump
#define lowp
如果您使用的是 Desktop GL,则在所有着色器之前。原因是它允许您在 ES2 和 Desktop GL 中重用相同的着色器,这缺少精度限定符;因此它们通过扩展为空的宏被擦除。
我认为这些小事并不是真正的收获。也许它们会减少对非常小且简单的着色器(以及仅由顶点和片段着色器制作的程序)的维护。如果 Qt hand 不尝试变得那么聪明会更好。
但您的 Desktop GL 代码路径可能会使用更多着色器阶段;或者只是一般使用 ES2 上不可用的功能。最终,它将显着偏离您的 ES2 代码路径。 (想想在 3.3 Core 中你必须使用 VAO,而 ES2 本身并不知道 VAO 是什么。)
个人咆哮:我讨厌,讨厌,讨厌 ES2 不像 OpenGL 配置文件左右,而是独立存在的事实。为了让 ES2 开心,基本上必须有一个不同的代码库。呸呸呸。
窗口
进入痛苦的世界!也称为Windows下的OpenGL驱动状态。
基本上,除了 NVIDIA 之外,任何人都在 Windows 上发布了损坏的 OpenGL 驱动程序。
至少,“开箱即用”。升级驱动程序通常可行,但您并不总是要求用户升级他们的驱动程序。他们是最终用户,而不是职业玩家。也许他们甚至没有管理员权限。
这是 OpenGL 应用程序的一个问题,尤其是 Qt 最强大的工具之一:Qt Quick 2。Qt 试图通过使用 ANGLE 来解决这个问题,它是一个 OpenGL ES2 -> Direct3D 转换层。因此,在 Windows 下,您可以选择
- 桌面 OpenGL 构建
- 通过 ANGLE 构建的 OpenGL ES2
选择并不相同——ES2 当然意味着忘记做任何严肃的现代 GL。但除此之外,可以使用here。
Qt 快速 2
这很重要,我认为值得一提。
但首先让我们澄清一下:您是否需要使用 Qt Quick 2 在 Qt 下构建 OpenGL 应用程序? NO、NO 和 NO。 Qt Quick 2 是一种完全独立的技术,它还利用 OpenGL 进行渲染。因此,您可以忽略它,直接构建您的 OpenGL 应用程序。
但是 Qt Quick 2 到底是什么?这是一个建立在QML language 之上的库,这是一种为创建动态用户界面而生的声明性语言(现在用于build systems...哦,好吧)。
记住区别:QML 是语言,Qt Quick 2 是一个库,其中包含您在 QML 中编程的一组可视项目(以及用于创建您自己的 C++ API)。
Qt Quick 2 恰好使用 OpenGL 来绘制这些视觉项目。这保证了良好的 60 FPS 无撕裂效果、极低的 CPU 使用率、各种基于着色器的视觉效果等等。
那又怎样?好吧,您可能有兴趣试一试。例如,API 允许将其叠加到您绘制的任何纯 OpenGL 内容上。因此,您可以考虑使用 Qt Quick 2 来处理更传统的 UI 位——按钮、滑块等,同时您可以控制主要内容的呈现。
或者,您可以忽略它存在的事实并继续使用 OpenGL。