OpenGL标准页面指出OpenGL是来自C和C ++的 callable 。然而,API当然是纯粹的C.由于OpenGL使用了很多枚举,使用枚举类(来自C ++ 11)可以大大减少错误数量并使API对初学者更加可行。可以看出,许多绑定如OpenTK(用于C#)被创建;创建优秀的C ++ API不应该太多更难。
我无法找到任何不仅仅是一个模糊的包装器,因此我的问题是:
答案 0 :(得分:11)
OpenGL的工作方式并不能很好地映射到OOP:http://www.opengl.org/wiki/Common_Mistakes#The_Object_Oriented_Language_Problem
本文中未说明的是上下文关联性问题。在OpenGL中,一切都发生在上下文中,所以一个类“纹理”,正确的只不过是一个与上下文一起使用的荣耀句柄。
错误:
class Texture {
/* ... */
public:
void bind();
}
仅当纹理是当前活动上下文的一部分时才会起作用。
这也不是更好:
class Texture {
/* ... */
public:
void bind(Context &ctx);
}
纹理仍然必须是上下文ctx
的一部分,并且只有当ctx
处于活动状态时它才有效。
那么这个:
class Context {
/* ... */
public:
void bindTextureToUnit(TextureUnit &tu, Texture &t);
};
更好,但仍然不正确,因为上下文必须是当前线程中当前活动的上下文。您可能会想“哦,如果上下文不活跃,我只会抛出异常”。请不要这样做。
那么呢
class ActiveContext : Context {
/* ... */
public:
void bindTextureToUnit(TextureUnit &tu, Texture &t);
}
现在,您最终确保每个线程只能有一个ActiveContext实例。最终你会遇到各种奇怪的线程单身麻烦。
事实上,我曾多次尝试从OpenGL状态和对象实现一个干净,理智的映射到一组C ++类,但总有一些情况下根本无法解决或最终导致可怕的代码混乱。
恕我直言,最好不要尝试将OpenGL API映射到一组C ++类(它不能做得很好),而是使用专门类的常规OpenGL API。任何OpenGL上下文管理都是如此依赖于程序中的问题,它必须专门针对所述程序进行定制。
答案 1 :(得分:6)
包装 OpenGL和OpenGL 对象模型是两个不同的概念。 OpenGL实体可以很容易地组成对象来包装它们的功能,如果你想编写一个可以用OpenGL或D3D实例化的渲染器,这是一个严格的必要条件。
我有这样的课程:
class Device
class State
class Buffer
class BufferUniform
class BufferVertices
class BufferIndices
class BufferArray
class Texture
class Texture1d
class Texture2d
class Texture3d
class TextureCubeMap
class TextureArray
class TextureRender
class TextureFrame
class Shader
class ShaderPixel
class ShaderVertex
class ShaderGeometry
class ShaderEvaluator
class ShaderTessellator
class ShaderProgram
class ShaderGenerator
class ShaderGeneratorParser
class ShaderGeneratorNode
class ShaderGeneratorCondition
......以及每个的D3D或OpenGL版本。渲染器和LT; ...>在编译时使用一组或另一组进行实例化,具体取决于我是否需要D3D或OpenGL来完成工作。
答案 2 :(得分:2)
是否有一个着名的C ++包装器使用C ++ 11工具进行OpenGL?如果没有,
没有。已经有一些尝试。
这是一个众所周知的人(特别是Khronos)的计划吗?
Khronos ARB并没有真正尝试直接与我们沟通有关即将推出的内容。但是,我非常怀疑他们是否关心这类事情。
至于其他任何人,还有一些独立的项目。但一般来说,使用OpenGL的人并不会对做这类事情感兴趣。
基本事实是:OpenGL对象与某些全局概念直接相关。即,OpenGL上下文。这些对象只有在它们存在的上下文(因为对象可以在上下文之间共享)处于活动状态时才能被操作。
因此,任何C ++面向对象的系统必须决定它想要的容错程度。也就是说,它想要提供什么样的保证。如果你调用一个对某个对象进行操作的函数,那么这个调用成功的确定程度如何?
这里列出了可以合理提供的保证级别:
在这种情况下,您可以确保每个函数调用成功或正确检测到错误情况并正确失败。
为了解决此问题,您需要一个显式 OpenGL上下文对象。每个OpenGL对象必须与上下文之间的共享组相关联(或者如果对象类型不可共享,则与特定上下文本身相关联。)
所有对象成员函数都必须使用上下文对象,该对象必须是它们所属的上下文或该上下文的共享组的成员。必须存在上下文的每线程缓存,以便他们可以检查当前上下文是否是给定的上下文,如果不是,则将其设置为当前上下文。
当一个上下文被破坏时,依赖于该上下文存在的每个对象必须立即变得不起作用。因此,每个这样的对象都需要访问某些标记(例如通过std::weak_ptr
),让他们知道所有的函数调用都会失败。
如果对象要正确RAII,那么每个对象必须能够确保它们可以被销毁的上下文(即:glDelete*
函数)是最新的。如果不是,他们需要制作一个电流。所以基本上,每个对象都需要持有对有效上下文的引用,否则需要能够创建一个。
就个人而言,我发现这一切都是非常痛苦的。没有API 此容错,也不需要。有很多毫无意义的保姆和信息共享。 C ++不是一种安全语言,因此它不应该浪费良好的内存和/或性能,只是为了提供这种安全级别。
在这里,我们摆脱了基于情境的安全检查。在尝试以任何方式使用任何对象之前,确定正确的上下文是最新的你用户。这与C ++一样。这个API的主要特点是比原始C API更好。
OpenGL对象将是RAII风格,但它们也会有一个" dispose"函数,如果你希望它们自己清除而不用删除它们相应的对象,就可以调用它。如果您正在关闭上下文并且不希望必须运行并破坏所有对象,这将非常有用。
该系统基本上假设您需要为这些类提供纯直接状态访问。因此,没有任何修改成员函数实际将对象绑定到上下文。他们可以通过以下几种方式实现这一目标:
某些类型的修改不能使用#2。例如,glBufferData
,glBufferSubData
和glTexSubImage*D
来电。用户真的希望它们现在发生。这些函数的命名方式应与保证非绑定函数区分开来。
任何此类绑定函数都不应该努力恢复对象的先前绑定状态。
基本上,C ++成员函数和C函数之间存在1:1的对应关系。当然,您将使用C ++运算符重载等来减少函数的不必要变化。但是当它出现时,你就像编写C代码一样编写C ++代码。
对象可以使用RAII,但除此之外,它们不会提供任何真正的便利。成员函数将自己绑定对象或者希望绑定它们。或者,如果DSA不可用,他们将使用DSA并失败。
在一天结束时,从使用C ++接口到OpenGL,获得并没有多大帮助。当然,你得到RAII。好吧,你可以使用带有特殊删除函数的std::unique_ptr
来获得RAII(是的,真的,这很可能)。但是除了API的一些轻微的便利之外,你获得了以前没有的真正富有表现力的 power 吗?
如果您认真使用OpenGL开发应用程序,那么您可能会构建一个渲染系统,相对于其他代码,它将OpenGL的概念抽象化。所以除了你的渲染器,没有人会看到你喜欢的C ++界面。您的渲染器可以轻松使用OpenGL的C API。如果你的渲染器几乎什么都不买,那么为什么要从渲染中构建你的渲染器呢。
如果您只是玩弄OpenGL ......这有什么关系?只需使用您拥有的界面。