Pergunta

Atualmente meu aplicativo usa apenas Direct3D9 para gráficos, mas no futuro pretendo estender isso para D3D10 e possivelmente OpenGL.A questão é como posso fazer isso de maneira organizada?

Atualmente existem vários métodos Render no meu código

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

A função passada depende do estado exato, por exemplo, MainMenu->Render, Load->Render, etc.Freqüentemente, eles chamarão os métodos de outros objetos.

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

E uma classe de amostra derivada de entidade::Base

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

Cada método então cuida da melhor forma de renderizar, dadas as configurações mais detalhadas (por exemplo, se os pixel shaders são suportados ou não).

O problema é que realmente não tenho certeza de como estender isso para poder usar um dos modos de renderização que podem ser um pouco diferentes (D3D v OpenGL) ...

Foi útil?

Solução

Defina uma interface que seja suficiente para as demandas de saída gráfica da sua aplicação.Em seguida, implemente essa interface para cada renderizador que você deseja oferecer suporte.

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

No entanto, projetar e manter adequadamente essas interfaces pode ser muito desafiador.

Caso você também opere com objetos dependentes do driver de renderização, como texturas, você pode usar um padrão de fábrica para que cada renderizador separado crie sua própria implementação, por exemplo.ITexture usando um método de fábrica no 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);
    }
  //...
};

Não é uma ideia olhar para os motores (3D) existentes?Na minha experiência, projetar esse tipo de interface realmente distrai o que você realmente deseja fazer :)

Outras dicas

Eu diria que se você quiser realmente completar a resposta, dê uma olhada no código-fonte de Ogre3D.Eles têm ambos D3D e OpenGL extremidades traseiras.Olhe para : http://www.ogre3d.orgBasicamente, a API deles força você a trabalhar de maneira D3D, criando objetos de buffer e preenchendo-os com dados e, em seguida, emitindo chamadas de desenho nesses buffers.De qualquer forma, é assim que o hardware gosta, então não é uma má opção.

E então, depois de ver como eles fazem as coisas, você pode simplesmente ir em frente e usá-lo e evitar o trabalho de reimplementar tudo o que ele já oferece.:-)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top