Question

Actuellement, mon application utilise uniquement Direct3D9 pour les graphiques, mais à l'avenir, je prévois de l'étendre à D3D10 et éventuellement à OpenGL.La question est de savoir comment puis-je faire cela de manière ordonnée ?

Il existe actuellement différentes méthodes de rendu dans mon code

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

La fonction passée dépend alors de l'état exact, par exemple MainMenu->Render, Loading->Render, etc.Ceux-ci appelleront alors souvent les méthodes d’autres objets.

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

Et un exemple de classe dérivée de 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();
};

Chaque méthode s'occupe ensuite de la meilleure façon de rendre compte tenu des paramètres les plus détaillés (par exemple, les pixel shaders sont-ils pris en charge ou non).

Le problème est que je ne sais vraiment pas comment étendre cela pour pouvoir utiliser l'un des modes de rendu, ce qui peut être quelque peu différent (D3D v OpenGL)...

Était-ce utile?

La solution

Définissez une interface suffisante pour les demandes de sortie graphique de votre application.Implémentez ensuite cette interface pour chaque moteur de rendu que vous souhaitez prendre en charge.

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

Concevoir et entretenir correctement ces interfaces peut cependant s’avérer très difficile.

Si vous travaillez également avec des objets dépendants du pilote de rendu, tels que des textures, vous pouvez utiliser un modèle d'usine pour que les moteurs de rendu distincts créent chacun leur propre implémentation, par exemple.ITexture utilisant une méthode d'usine dans 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'est-ce pas une idée de regarder les moteurs existants (3D) ?D'après mon expérience, concevoir ce type d'interfaces détourne vraiment l'attention de ce que vous voulez réellement créer :)

Autres conseils

Je dirais que si vous voulez une réponse vraiment complète, allez consulter le code source de Ogre3D.Ils ont les deux D3D et OpenGL extrémités arrière.Regarder : http://www.ogre3d.orgFondamentalement, leur API vous oblige à travailler à la manière de D3D, en créant des objets tampon et en les remplissant de données, puis en émettant des appels de tirage sur ces tampons.De toute façon, c’est comme ça que le matériel l’aime, donc ce n’est pas une mauvaise façon de procéder.

Et puis, une fois que vous avez vu comment ils font les choses, autant continuer et l'utiliser et vous épargner la peine de devoir réimplémenter tout ce qu'il fournit déjà.:-)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top