Вопрос

В настоящее время мое приложение использует для графики только Direct3D9, однако в будущем я планирую расширить его до D3D10 и, возможно, OpenGL.Вопрос в том, как это сделать аккуратно?

В настоящее время в моем коде есть различные методы рендеринга.

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();
}

И пример класса, полученного из объекта::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 против OpenGL)...

Это было полезно?

Решение

Определите интерфейс, достаточный для требований вывода графики вашего приложения.Затем реализуйте этот интерфейс для каждого средства визуализации, которое вы хотите поддерживать.

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) движки?По моему опыту, разработка такого рода интерфейсов действительно отвлекает от того, что вы на самом деле хотите сделать :)

Другие советы

Я бы сказал, что если вы хотите получить действительно полный ответ, посмотрите исходный код Ogre3D.У них есть оба D3D и OpenGL задние концы.Посмотри на : http://www.ogre3d.orgПо сути, их API заставляет вас работать в стиле D3D: создавать буферные объекты и наполнять их данными, а затем выполнять вызовы отрисовки для этих буферов.В любом случае аппаратному обеспечению это нравится, так что это неплохой путь.

А затем, как только вы увидите, как они что-то делают, вы можете просто использовать его и избавить себя от необходимости заново реализовывать все, что он уже предоставляет.:-)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top