4

目前,我的应用程序仅使用 Direct3D9 进行图形处理,但将来我计划将其扩展到 D3D10 和可能的 OpenGL。问题是我怎样才能以整洁的方式做到这一点?

目前我的代码中有各种Render方法

void Render(boost::function<void()> &Call)
{
    D3dDevice->BeginScene();
    Call();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

然后传递的函数取决于确切的状态,例如 MainMenu->Render、Loading->Render 等。这些将经常调用其​​他对象的方法。

void RenderGame()
{
    for(entity::iterator it = entity::instances.begin();it != entity::instance.end(); ++it)
        (*it)->Render();
    UI->Render();
}

以及从 entity::Base 派生的示例类

class Sprite: public Base
{
    IDirect3DTexture9 *Tex;
    Point2 Pos;
    Size2 Size;
public:
    Sprite(IDirect3DTexture9  *Tex, const Point2 &Pos, const Size2 &Size);
    virtual void Render();
};

然后,每种方法都会根据更详细的设置(例如是否支持像素着色器)来处理如何最好地渲染。

问题是我真的不确定如何扩展它以能够使用其中一种可能有所不同的(D3D v OpenGL)渲染模式......

4

2 回答 2

6

定义一个足以满足应用程序图形输出需求的界面。然后为您要支持的每个渲染器实现此接口。

class IRenderer {
  public:
    virtual ~IRenderer() {}
    virtual void RenderModel(CModel* model) = 0;
    virtual void DrawScreenQuad(int x1, int y1, int x2, int y2) = 0;
    // ...etc...
};

class COpenGLRenderer : public IRenderer {
  public:
    virtual void RenderModel(CModel* model) {
      // render model using OpenGL
    }
    virtual void DrawScreenQuad(int x1, int y1, int x2, int y2) {
      // draw screen aligned quad using OpenGL
    }
};

class CDirect3DRenderer : public IRenderer {
  // similar, but render using Direct3D
};

但是,正确设计和维护这些接口可能非常具有挑战性。

如果您还使用与渲染驱动程序相关的对象(如纹理)进行操作,您可以使用工厂模式让单独的渲染器每个都使用 IRenderer 中的工厂方法创建自己的 ITexture 实现:

class IRenderer {
  //...
    virtual ITexture* CreateTexture(const char* filename) = 0;
  //...
};

class COpenGLRenderer : public IRenderer {
  //...
    virtual ITexture* CreateTexture(const char* filename) {
      // COpenGLTexture is the OpenGL specific ITexture implementation
      return new COpenGLTexture(filename);
    }
  //...
};

看看现有的(3d)引擎不是一个想法吗?根据我设计这种界面的经验,真的会分散你真正想要做的事情:)

于 2008-09-13T19:33:55.107 回答
1

我想说,如果您想要一个真正完整的答案,请查看Ogre3D. 他们有两端D3DOpenGL后端。看看:http : //www.ogre3d.org 基本上他们的 API 迫使你以 D3D 的方式工作,创建缓冲区对象并用数据填充它们,然后在这些缓冲区上发出绘图调用。无论如何,这就是硬件喜欢它的方式,所以这不是一个坏方法。

然后,一旦您了解他们是如何做事的,您不妨继续使用它,而不必重新实现它已经提供的所有功能。:-)

于 2008-09-16T03:09:46.493 回答