“如何设计OpenGL DirectX”;“抽象层”;

“如何设计OpenGL DirectX”;“抽象层”;,opengl,opengl-es,directx,abstraction,Opengl,Opengl Es,Directx,Abstraction,我在读关于创建图形“抽象层”的书,以方便在图形平台之间切换。不幸的是,我未能找到关于这个主题的很多细节。这样的抽象在功能级别上可以实现吗 void pushMatrix(){ if (directx){ // do directx function }else if (opengl){ // do opengl function } } 这就是它的工作原理吗?有更好的办法吗?有没有人能给我举一些例子,这些例子可以完成这个或更多的示例代码?最终会变得杂乱无章,

我在读关于创建图形“抽象层”的书,以方便在图形平台之间切换。不幸的是,我未能找到关于这个主题的很多细节。这样的抽象在功能级别上可以实现吗

void pushMatrix(){
  if (directx){
     // do directx function

  }else if (opengl){
     // do opengl function
  }

}

这就是它的工作原理吗?有更好的办法吗?有没有人能给我举一些例子,这些例子可以完成这个或更多的示例代码?

最终会变得杂乱无章,效率低下。我将通过场景图进行抽象,即对“场景”有一个通用的高级表示。然后,该场景将由“渲染器”实例渲染,该实例可以使用OpenGL或Direct3D实现


我建议您看看Ogre3d这样的跨平台图形引擎。

是的,这就是它的工作原理。通过抽象您所使用的图形API,您可以将其从程序员需要担心的事情中移除。这类似于GDI抽象被写入设备的方式,比如程序员不必担心它

从这个意义上讲,与上面类似的函数库与HDC类似。它是这个抽象的接口

这将比简单地检查API,然后调用适当的函数更加困难。这两个API(DirectX和OpenGL)非常不同,将它们都抽象为一个接口并不容易,尤其是如果您想涵盖大部分功能的话

您需要进行更多的抽象,而不是简单地生成通用函数。您需要创建更复杂的结构

假设OpenGL要求您调用函数A,然后调用函数B来实现某些事情,但DX要求您调用函数B,然后调用函数A。为了适应这一点,您需要执行类似的操作:

void functionA(...) {
  if (OpenGL) {
    glFuncA();
  } else {
    //store parameters
  }
}

void functionB(...) {
  if (OpenGL) {
    glFuncB();
  } else {
    dxFuncB();
    dxFuncA( saved params );
  }
}

这不是一个很好的例子,但它证明了原则。为非常大和不同的API创建一个抽象将需要更多的思考和努力,然后再包装每个函数。

通常要做的是为“通用”渲染器提供一个接口:

class RendererInterface{
    virtual DrawMesh() = 0;
    virtual SwapBuffers() = 0;
    /// etc
}
每个库有一个实现:

class OpenGLRenderer : public RendererInterface{
    virtual DrawMesh(){... }
    ....
}

但是这个概念和亚历山大的答案是一样的。

我100%同意默奇的观点。通过重新构造渲染器,将重点放在它所做的事情上,而不是放在如何做上,可以使设计更加清晰

围绕API进行设计时,如果使用
if(this_platform){do_this();}或{do_this();}
将代码乱七八糟地乱七八糟地乱七八糟

我的建议是浏览你的应用程序,找出它的功能清单,尽量不要太在意它是如何工作的。在您的项目中这样做可能已经晚了,我不知道您的具体场景,但是(IMHO)将它从一个API调用混乱的噩梦重构为一个对它进行充分抽象的东西将改进您的最终结果


虽然乍一看,您可能会认为实现场景绘图系统会增加大量开销。事实上,通过使用场景图来管理状态更改,我的渲染引擎得到了极大的加速,避免了状态更改(更改纹理、更改着色器等),并以更优化的顺序绘制场景。像实例化这样的东西被优雅地集成到场景图形系统中,可以给你带来巨大的加速,同时清除代码中所有以API为中心的混乱,并将“它做什么”和“它如何做”分开在您的主程序逻辑中。

Hmm这看起来效率很低,因为我必须重写我的大多数类,但我确实理解您使用更高级别的函数/类的意思。您的方法的问题是,您将添加大量不必要的分支,并将不同的实现分散到所有代码中。如果你必须写超过2个API的话,它会变得更糟——考虑Direct3D 9、Direct3D 10/11、OpenGL 2、X、OpenGL 3/4、OpenGL ES 1、OpenGL ES 2、PlayStation、Wii等。通过抽象将绘制逻辑分解成单独的块,它变得更为可维护。你也可以使用继承来在相似的渲染器之间共享逻辑,例如,渲染器由Direct3DRenderer和OpenGLRenderer子类化,OpenGLRenderer由OpenGLS2Renderer子类化,等等。您对混合方法有何看法?对于在这两种方法中工作相同的常见函数,我采用了if-else方法。然后我为渲染模型之类的东西编写完全不同的渲染代码?你可以,这真的取决于你,但我会尝试完全封装渲染器内的所有渲染逻辑。作为一个例子,这里是食人魔的渲染器-对于像OpenGL到OpenGL ES 2.0这样的东西呢?@Justin:OpenGL到OpenGL ES是一个小得多的变化。DirectX和OpenGL是根本不同的,OpenGL和OpenGL ES非常相似(比较)。这可能只需要
if-else
blocks就可以了。OpenGL到OpenGL ES的变化会更小,是的。但是你很幸运能用if-else积木逃脱。可能这方面最好的例子就是食人魔。它使用模块将DirectX和OpenGL抽象为统一的内部形式。有很多代码,但它工作得很好,所以您可能想检查一下。