gpt4 book ai didi

c++ - 渲染引擎设计 - 抽象出资源的 API 特定代码

转载 作者:IT老高 更新时间:2023-10-28 22:36:49 25 4
gpt4 key购买 nike

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

2年前关闭。




Improve this question




我的渲染代码中有一个非常大的设计绊脚石。基本上这是什么,不需要特定于 API 的代码(例如 OpenGL 代码或 DirectX)。现在我想了很多方法来解决这个问题,但是我不确定使用哪一种,或者我应该如何改进这些想法。

举一个简单的例子,我将使用一个纹理作为例子。纹理是表示 GPU 内存中纹理的对象,在实现方面它可以以任何特定方式相似,即实现是否使用 GLuintLPDIRECT3DTEXTURE9以类似于纹理。

现在这里是我想到的实际实现这一点的方法。我不确定是否有更好的方法,或者哪种方法比另一种更好。

方法一:继承

我可以使用继承,这似乎是最明显的选择。但是,此方法需要虚函数,并且需要 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 object 只会是 POD 类型。但是,为了使其工作,句柄对象/ID 必须存在于 Texture 中。类(class)。

例如, this is how I would more than likely implement it .虽然,我可以使用基类来概括整个 ID 的事情。如 Resource基类在这种情况下保存图形资源的 ID。

方法 3:Pimpl 成语

我可以使用 pimpl 成语,它实现了如何加载/重新加载/等。纹理。这很可能需要一个抽象工厂类来创建纹理。我不确定这比使用继承更好。这个 pimpl 习惯用法可以与方法 2 结合使用,即纹理对象将有一个指向它们的加载器的引用(指针)。

方法 4:使用概念/编译时多态

另一方面,我可以使用编译时多态性并且基本上使用我在继承方法中介绍的内容,除非不声明虚函数。这会起作用,但如果我想从 OpenGL 渲染动态切换到 DirectX 渲染,这将不是最佳解决方案。我会简单地将 OpenGL/D3D 特定代码放在 Texture 类中,其中将有多个纹理类具有相同的接口(interface)(加载/重新加载/getImage/等),包裹在某个命名空间中(类似于它使用的 API,例如 ogld3d 等)。

方法 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),我将不得不大量更改我的代码。对我的情况的任何建议将不胜感激。

    最佳答案

    从高层次的角度考虑。您的渲染代码将如何与其他游戏/应用程序模型配合使用?换句话说,您计划如何在场景中创建对象以及模块化程度如何?在我之前使用引擎的工作中,一个设计良好的引擎的最终结果通常有一个遵循模式的循序渐进的过程。例如:

    //Components in an engine could be game objects such as sprites, meshes, lights, audio sources etc. 
    //These resources can be created via component factories for convenience
    CRenderComponentFactory* pFactory = GET_COMPONENT_FACTORY(CRenderComponentFactory);

    一旦获得了组件,通常可以使用多种重载方法来构造对象。以 Sprite 为例, SpriteComponent可以以子组件的形式包含 Sprite 可能需要的一切;像 TextureComponent例如。
    //Create a blank sprite of size 100x100 
    SpriteComponentPtr pSprite = pFactory->CreateSpriteComponent(Core::CVector2(100, 100));

    //Create a sprite from a sprite sheet texture page using the given frame number.
    SpriteComponentPtr pSprite = pFactory->CreateSpriteComponent("SpriteSheet", TPAGE_INDEX_SPRITE_SHEET_FRAME_1);

    //Create a textured sprite of size 100x50, where `pTexture` is your TextureComponent that you've set-up elsewhere.
    SpriteComponentPtr pSprite = pFactory->CreateSpriteComponent(Core::CVector2(100, 50), pTexture);

    然后只需将对象添加到场景中即可。这可以通过创建一个实体来完成,它只是一个通用的信息集合,包含场景操作所需的一切;位置、方向等。对于场景中的每个实体,您的 AddEntity方法默认情况下会将该新实体添加到您的渲染工厂,从子组件中提取其他依赖于渲染的信息。例如:
    //Put our sprite onto the scene to be drawn
    pSprite->SetColour(CColour::YELLOW);
    EntityPtr pEntity = CreateEntity(pSprite);
    mpScene->AddEntity(pEntity);

    然后,您将拥有一种创建对象的好方法和一种模块化的应用程序编码方式,而无需引用“绘制”或其他特定于渲染的代码。一个好的图形管道应该是这样的:

    enter image description here

    This是渲染引擎设计的一个很好的资源(也是上图的来源)。跳到第 21 页并继续阅读,在那里您将看到有关场景图如何操作和一般发动机设计理论的深入解释。

    关于c++ - 渲染引擎设计 - 抽象出资源的 API 特定代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15548776/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com