我有两个不同的系统,一个是OpenGL 1.4,一个是3.我的程序使用Shaders,它是OpenGL 3的一部分,仅在1.4实现中作为ARB扩展支持。
由于我无法在OpenGL 1.4中使用OpenGL 3功能,有没有一种方法可以支持两种OpenGL版本而无需编写两次相同的OpenGL代码(ARB / EXT和v3)?
答案 0 :(得分:10)
除非你真的因为某些原因需要支持10年历史的显卡,否则我强烈建议使用OpenGL 2.0而不是1.4(事实上,我甚至会达到目标版本2.1)。
由于使用“3.0中为核心的着色器”必然意味着显卡必须能够至少某种版本的GLSL,这排除了任何无法提供至少的硬件OpenGL 2.0。这意味着如果某人有OpenGL 1.4 和可以运行着色器,他就会使用8到10岁的驱动程序。除此之外几乎没有什么可以获得(除了支持梦魇)。
目标OpenGL 2.1是合理的,现在几乎没有任何系统不支持(即使假设最小的OpenGL 3.2可能是一个完全合理的选择)。
入门级OpenGL 3.3兼容卡的市场价格大约是两年前高端OpenGL 1.4卡的1000倍,大约是25美元。如果您打算出售您的申请,您必须问自己,无法负担(或者不想负担)的人是否是您合理期望为您的软件支付的人。
话虽如此,同时支持OpenGL 2.x和OpenGL> 3.1是一场噩梦,因为着色语言中的非平凡变化远远超出#define in varying
并且会咬你定期
因此,我选择了个人来永远不再使用实例化数组和着色器对象来定位低于3.2版的任何内容。这适用于可以合理预期具有运行现代应用程序的处理能力的所有硬件,并且它包括懒得将其驱动程序升级到3.3的用户,在单个代码路径中提供相同的功能。如果可用,OpenGL 4.x功能可作为扩展加载,这很好 但是,当然,每个人都必须自己决定哪种鞋最适合。
够了我的等等,回到实际的问题:
关于不复制扩展/核心的代码,在许多情况下,您可以使用相同的名称,函数指针和常量。但是,请注意:作为一揽子声明,这是非法的,未定义的和危险的。
实际上,大多数(并非所有!)扩展都与相应的核心功能相同,并且工作方式相同。但是如何知道哪些可以使用,哪些会吃掉你的猫?查看gl.spec - 具有alias
条目的函数是相同的,并且与其别名无法区分。您可以安全地互换使用这些
有问题的扩展通常在某处也有解释性注释(例如“这不是PrimitiveRestartIndexNV的别名,因为它设置服务器而不是客户端状态。”),但不依赖于这些,依赖alias
字段。
答案 1 :(得分:5)
就像@Nicol Bolas已经告诉过你的那样,为OpenGL-3核心和OpenGL-2创建两个代码路径是不可避免的。 OpenGL-3核心故意破坏兼容性。但是赌注并不像看起来那么糟糕,因为大多数情况下代码只会在细微差别上有所不同,而且两个代码路径都可以写在单个源文件中并使用条件编译方法。
例如
#ifdef OPENGL3_CORE
glVertexAttribPointer(Attribute::Index[Position], 3, GL_FLOAT, GL_FALSE, attribute.position.stride(), attribute.position.data());
glVertexAttribPointer(Attribute::Index[Normal], 3, GL_FLOAT, GL_FALSE, attribute.position.stride(), attribute.position.data());
#else
glVertexPointer(3, GL_FLOAT, attribute.position.stride(), attribute.position.data());
glNormalPointer(GL_FLOAT, attribute.normal.stride(), attribute.normal.data());
#endif
GLSL着色器可以类似地重复使用。使用宏来改变预定义但已被删除的标识符或引入更高版本的关键字,例如。
#ifdef USE_CORE
#define gl_Position position
#else
#define in varying
#define out varying
#define inout varying
vec4f gl_Position;
#endif
通常,程序的着色器管理代码中会有一组标准头文件来构建最终源代码,传递给OpenGL,当然这取决于使用的代码路径。
答案 2 :(得分:3)
这取决于:您想使用OpenGL 3.x功能吗?不仅要使用API,还要使用该API背后的实际硬件功能。
如果没有,那么您可以针对GL 1.4编写并依赖兼容性配置文件。如果这样做,那么您将需要单独的代码路径来处理您打算支持的不同级别的硬件。这是标准配置,仅用于支持不同级别的硬件功能。