目前我的应用程序仅使用Direct3D9进行图形处理,但是将来我计划将其扩展到D3D10和可能的OpenGL。问题是如何以一种整洁的方式做到这一点?
目前我的代码中有各种Render方法
void Render(boost::function<void()> &Call)
{
D3dDevice->BeginScene();
Call();
D3dDevice->EndScene();
D3dDevice->Present(0,0,0,0);
}
传递的函数取决于确切的状态,例如MainMenu-&gt; Render,Loading-&gt; 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)渲染模式......
答案 0 :(得分: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
};
正确地设计和维护这些接口可能非常具有挑战性。
如果您还使用渲染驱动程序相关对象(如纹理)进行操作,则可以使用工厂模式让单独的渲染器分别创建自己的实现,例如: ITexture在IRenderer中使用工厂方法:
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)引擎不是一个想法吗?根据我的经验,设计这种界面真的会分散你实际想做的事情:)
答案 1 :(得分:1)
我想说如果你想要一个非常完整的答案,请查看Ogre3D
的源代码。他们有D3D
和OpenGL
后端。看看:http://www.ogre3d.org
基本上他们的API类型迫使你以D3D-ish方式工作,创建缓冲区对象并用数据填充它们,然后在这些缓冲区上发出绘制调用。这就是硬件喜欢它的方式,所以这不是一个糟糕的方式。
然后,一旦你看到他们如何做事,你也可以只是继续使用它,省去了必须重新实现它已经提供的所有功能的麻烦。 : - )