我的渲染代码中有一个很大的设计绊脚石。基本上这是什么,不需要特定于 API 的代码(例如 OpenGL 代码或 DirectX)。现在我想了很多方法来解决这个问题,但是我不确定使用哪一种,或者我应该如何改进这些想法。
举一个简单的例子,我将使用一个纹理作为例子。纹理是在 GPU 内存中表示纹理的对象,在实现方面,它可以以任何特定方式相似,即实现是否使用纹理GLuint
或LPDIRECT3DTEXTURE9
类似于纹理。
现在这里是我想到的实际实现这一点的方法。我很不确定是否有更好的方法,或者哪种方法比另一种更好。
方法一:继承
我可以使用继承,这似乎是这件事最明显的选择。但是,此方法需要虚函数,并且需要 TextureFactory 类才能创建 Texture 对象。这将需要调用new
每个Texture
对象(例如renderer->getTextureFactory()->create()
)。
这是我在这种情况下考虑使用继承的方式:
class Texture
{
public:
virtual ~Texture() {}
// Override-able Methods:
virtual bool load(const Image&, const urect2& subRect);
virtual bool reload(const Image&, const urect2& subRect);
virtual Image getImage() const;
// ... other texture-related methods, such as wrappers for
// load/reload in order to load/reload the whole image
unsigned int getWidth() const;
unsigned int getHeight() const;
unsigned int getDepth() const;
bool is1D() const;
bool is2D() const;
bool is3D() const;
protected:
void setWidth(unsigned int);
void setHeight(unsigned int);
void setDepth(unsigned int);
private:
unsigned int _width, _height, _depth;
};
然后为了创建 OpenGL(或任何其他特定于 API)的纹理,必须创建一个子类,例如OglTexture
.
方法 2:使用“TextureLoader”或其他类
这个方法听起来很简单,我使用另一个类来处理纹理的加载。这可能会或可能不会使用虚拟功能,这取决于情况(或者我是否觉得有必要)。
例如多态纹理加载器
class TextureLoader
{
public:
virtual ~TextureLoader() {}
virtual bool load(Texture* texture, const Image&, const urect2& subRect);
virtual bool reload(Texture* texture, const Image&, const urect2& subRect);
virtual Image getImage(Texture* texture) const;
};
如果我要使用它,Texture
对象将只是 POD 类型。但是,为了使其工作,类中必须存在句柄对象/ID Texture
。
例如,这就是我很可能实现它的方式。虽然,我可以使用基类来概括整个 ID 事物。例如Resource
基类,在这种情况下保存图形资源的 ID。
方法 3:Pimpl 成语
我可以使用 pimpl idiom,它实现了如何加载/重新加载/等。纹理。这很可能需要一个抽象工厂类来创建纹理。我不确定这比使用继承更好。这个 pimpl 习惯用法可以与方法 2 结合使用,即纹理对象将具有指向其加载器的引用(指针)。
方法4:使用概念/编译时多态
另一方面,我可以使用编译时多态性并基本上使用我在继承方法中介绍的内容,除非不声明虚函数。这可行,但如果我想从 OpenGL 渲染动态切换到 DirectX 渲染,这不是最好的解决方案。我只是将 OpenGL/D3D 特定代码放在 Texture 类中,其中会有多个纹理类具有一些相同的接口(load/reload/getImage/etc.),包装在某个命名空间中(类似于它使用的 API,例如ogl
,d3d
等)。
方法 5:使用整数
我可以只使用整数来存储纹理对象的句柄,这看起来相当简单,但可能会产生一些“混乱”的代码。
其他 GPU 资源(例如 Geometry、Shaders 和 ShaderPrograms)也存在此问题。
我还想过让 Renderer 类处理图形资源的创建、加载等。但是,这将违反SPR。例如
Texture* texture = renderer->createTexture(Image("something.png"));
Image image = renderer->getImage(texture);
有人可以指导我吗,我想我想太多了。我尝试观察各种渲染引擎,例如 Irrlicht、Ogre3D 以及我在网上找到的其他引擎。Ogre 和 Irrlicht 使用继承,但我不确定这是最好的方法。正如其他一些人只是使用 void*、整数,或者只是将特定于 API(主要是 OpenGL)的代码放在他们的类中(例如 GLuint 直接放在 Texture 类中)。我真的无法决定哪种设计最适合我。
我要定位的平台是:
- Windows/Linux/Mac
- iOS
- 可能是安卓
我考虑过只使用 OpenGL 特定的代码,因为 OpenGL 适用于所有这些平台。但是,我觉得如果我这样做,如果我希望移植到其他不能使用 OpenGL 的平台,例如 PS3,我将不得不更改我的代码。任何关于我的情况的建议将不胜感激。