13

OpenGL 标准页面声明 OpenGL可从 C 和 C++调用。然而,API 当然是纯 C 语言。例如,由于 OpenGL 使用大量枚举,使用枚举类(来自 C++11)可以大大减少错误数量,并使 API 对初学者更可行。可以看出,创建了很多像 OpenTK(用于 C#)这样的绑定;创建好的 C++ API 应该不会更难

我找不到任何比不起眼的包装更多的东西,因此我的问题是:

  1. 是否有一个著名的 C++ 包装器使用 C++11 设施来支持 OpenGL?如果不,
  2. 这样的事情是由任何知名人士(尤其是 Khronos)策划的吗?
4

3 回答 3

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);
}

纹理仍然必须是 context 的一部分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 上下文管理都非常依赖于相关程序,因此必须专门针对所述程序进行定制。

于 2012-08-23T12:37:25.040 回答
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 版本。Renderer<...> 在编译时用一组或另一组实例化,这取决于我想要 D3D 还是 OpenGL 来完成这项工作。

于 2012-08-23T13:38:14.547 回答
2

是否有一个著名的 C++ 包装器使用 C++11 设施来支持 OpenGL?如果不,

不,已经有一些尝试了。

这样的事情是由任何知名人士(尤其是 Khronos)策划的吗?

Khronos ARB 并没有真正尝试直接与我们交流即将发生的事情。但是,我非常怀疑他们是否关心这种事情。

至于其他人,同样,那里有一些独立的项目。但一般来说,使用 OpenGL 的人对做这类事情并没有那么感兴趣。

基本事实如下: OpenGL 对象直接与一些全局概念相关联。即,OpenGL 上下文。这些对象只有在它们所在的上下文(因为对象可以在上下文之间共享)处于活动状态时才能被操作。

因此,任何 C++ 面向对象的系统都必须决定它想要的容错程度。也就是说,它想提供什么样的保证。如果你调用一个对一个对象进行操作的函数,你能确定这个调用成功吗?

以下是可以合理提供的保证级别列表:

完全肛门

在这种情况下,您可以确保每个函数调用要么成功,要么正确检测到错误条件并正确失败。

为了实现这一点,您需要一个显式的OpenGL 上下文对象。每个 OpenGL 对象都必须与上下文(或特定上下文本身,如果对象类型不可共享)之间的共享组相关联。

所有对象成员函数都必须采用上下文对象,该对象必须是它们所属的上下文或该上下文的共享组的成员。必须有一个上下文的每个线程缓存,以便他们可以检查当前上下文是否是给定的上下文,如果不是,则使其成为当前上下文。

当一个上下文被销毁时,依赖于该上下文存在的每个对象都必须立即失去功能。因此,每个这样的对象都需要访问某个标签(例如通过 a std::weak_ptr),让他们知道他们所有的函数调用都会失败。

如果要对对象进行适当的 RAII,则每个对象都必须能够确保它们可以在其中销毁的上下文(即:glDelete*函数)是当前的。如果不是,他们需要制作一个电流。所以基本上,每个对象都需要持有对有效上下文的引用,否则需要能够创建一个。

就个人而言,我觉得这一切都非常愚蠢。没有 API 具有这种容错能力,也不需要如此。有很多毫无意义的保姆和信息共享。C++ 不是一种安全语言,因此它不应该仅仅为了提供这种安全级别而浪费良好的内存和/或性能。

萨内

在这里,我们摆脱了基于上下文的安全检查。在尝试以任何方式使用任何对象之前,用户应确保正确的上下文是最新的。这与 C++ 一样。这个 API 的主要特点就是比原始的 C API 更好。

OpenGL 对象将是 RAII 样式,但它们也将具有“处理”函数,如果您希望它们清除自身而不删除其相应对象,则可以调用该函数。如果您要关闭上下文并且不想运行并破坏所有对象,这很有用。

该系统基本上会假设您想要这些类的纯直接状态访问。因此,没有一个修改成员函数实际上将对象绑定到上下文。他们可以通过以下几种方式之一来实现:

  1. 使用 EXT_DSA 或等效的(如果有)。
  2. 如果 EXT_DSA 或等效项不可用,则存储修改后的状态并在下次绑定此对象时发送修改。
  3. 或者只是绑定它,进行修改,然后取消绑定。

某些类型的修改不能使用#2。例如glBufferDataglBufferSubDataglTexSubImage*D调用。用户真的希望它们现在发生。这些函数的命名方式应使它们与保证的非绑定函数区分开来。

任何此类绑定函数都不应努力恢复对象的先前绑定状态。

宽容的

基本上,C++ 成员函数和 C 函数之间存在 1:1 的对应关系。当然,您将使用 C++ 运算符重载等来减少不必要的函数变化。但归根结底,您几乎是在以编写 C 代码的方式编写 C++ 代码。

对象可能会使用 RAII,但除此之外它们不会提供任何真正的便利。成员函数要么绑定对象本身,要么期望你绑定它们。或者,如果 DSA 不可用,他们将使用 DSA 并失败。

何苦?

归根结底,从 C++ 接口到 OpenGL 并没有什么好处。当然,你会得到 RAII。好吧,您可以通过使用std::unique_ptr带有特殊删除器函子的 a 来获得 RAII(是的,真的,这是非常可能的)。但除了 API 带来的一些轻微便利之外,您还获得了哪些以前没有的真正表达能力?

如果您对使用 OpenGL 开发应用程序很认真,那么您可能会构建一个渲染系统,相对于您的其余代码,它将 OpenGL 的概念抽象出来。因此,除了您的渲染器之外,没有人会看到您花哨的 C++ 界面。您的渲染器也可以轻松使用 OpenGL 的 C API。如果它几乎没有给您带来任何好处,为什么还要从抽象中构建您的渲染器。

如果你只是在玩 OpenGL……那有什么关系呢?只需使用您拥有的界面即可。

于 2013-08-25T07:32:34.447 回答