在同一应用程序中使用传统OpenGL和现代OpenGL

Using Legacy OpenGL and Modern OpenGL in same application

本文关键字:OpenGL 传统 应用程序      更新时间:2023-10-16

我有一台只支持OpenGL 2.1的工作笔记本电脑,我家的桌面上有OpenGL 4.4。我正在我的桌面上进行一个项目。所以我制作了一个与现代OpenGL兼容的程序。但我想在我的工作笔记本电脑上开发这个项目。我的问题是,我能让这个项目与Legacy和Modern OpenGL兼容吗?

就像这样。

#ifdef MODERN_OPENGL
some code..
glBegin(GL_TRIANGLES);
...
glEnd();
#else
glGenBuffers(&vbo);
...
#endif

您的建议是完全可能的,但是如果您通过预处理器宏来执行,您将最终陷入条件编译地狱。对于您的方法,最好的选择是编译到共享库中,一个为遗留库编译,另一个为现代库编译,并根据需要加载正确的变体。然而,当从这个方向接近它时,你也可以放弃预处理器的杂耍,只需将渲染路径变体移动到它们自己的编译单元中。

另一种方法是决定在运行时使用什么渲染路径。这是我喜欢的方法,我通常通过函数指针表(vtable)来实现它。例如,我提供的体积光栅化器库完全支持OpenGL-2.x和现代核心配置文件,并将动态调整其代码路径着色器的GLSL代码,以匹配其正在使用的OpenGL上下文的功能。

如果您担心性能,请记住,实际上每个允许多态函数覆盖的运行时环境都必须经历这个瓶颈。是的,这确实有一定的成本,但OTOH非常常见,现代CPU的指令预取和间接跳转电路已经进行了优化,以应对这种情况。


编辑:关于";"遗留";OpenGL是什么

因此,我首先忘记了写一些非常重要的内容:LegacyOpenGL不是glBegin/glEnd。默认情况下,它有一个固定的函数管道,顶点数组位于客户端侧。

让我重申:Legacy OpenGL-1.1及更高版本确实有顶点数组这实际上意味着,大量与布局和填充顶点数组内容有关的代码将适用于所有OpenGL。不同之处在于如何将顶点数组数据实际提交给OpenGL。

在传统的固定函数管道OpenGL中,您有许多预定义的属性和函数,在进行glDraw…调用之前,您可以使用这些属性和函数将OpenGL指向存储这些属性数据的内存区域。

当着色器被引入时(OpenGL-2.x,或通过早期的ARB扩展),它们附带了非常相同的glVertexAttribPointer函数,这些函数仍在现代OpenGL中使用。事实上,在OpenGL-2中,您仍然可以将它们指向客户端缓冲区。

OpenGL-3.3核心强制使用缓冲区对象。然而,缓冲区对象也可用于较旧的OpenGL版本(OpenGL-1.5中的核心)或通过ARB扩展;您甚至可以将它们用于上个世纪的不可编程GPU(这实际上意味着第一代Nvidia GeForce)。

底线是:您可以完美地为OpenGL编写与大量版本配置文件兼容的代码,并且只需要很少的版本特定代码即可管理传统/现代转换。

我将首先使用"新的"OpenGL 3/4 Core API编写应用程序,但仅限于OpenGL 2.1中支持的子集。正如datenwolf在上面指出的,即使在2.1 中也有顶点属性指针和缓冲区

因此,没有glBegin/End块,但也没有矩阵推送/弹出/加载,没有推送/跳出属性状态,没有照明。使用统一材质在顶点和片段着色器中执行所有操作。

将自己限制在2.1会比在OpenGL4中使用很酷的新东西更痛苦,但不会太痛苦。根据我的经验,无论OpenGL的版本是什么,从矩阵堆栈和内置照明切换都是最困难的部分,这是你无论如何都必须做的工作。

最后,您将有一个单一的代码版本,如果/当您决定放弃2.1支持时,更新会更容易。

根据您使用的实用程序库/扩展加载程序,您可以在运行时通过检查GLAD_GL_VERSION_X_XglfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR/MINOR)等来检查当前上下文支持哪个版本,并创建适当的渲染器。