Domanda

Attualmente la mia app utilizza solo Direct3D9 per la grafica, tuttavia in futuro ho intenzione di estenderlo a D3D10 e possibilmente OpenGL.La domanda è: come posso farlo in modo ordinato?

Al momento ci sono vari metodi di rendering nel mio codice

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

La funzione passata dipende quindi dallo stato esatto, ad esempio MainMenu->Render, Loading->Render, ecc.Questi poi chiameranno spesso i metodi di altri oggetti.

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

E una classe di esempio derivata da entità::Base

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

Ciascun metodo si occupa quindi del modo migliore per eseguire il rendering in base alle impostazioni più dettagliate (ad esempio, i pixel shader sono supportati o meno).

Il problema è che non sono davvero sicuro di come estenderlo per poter utilizzare una delle modalità di rendering che potrebbero essere leggermente diverse (D3D v OpenGL)...

È stato utile?

Soluzione

Definisci un'interfaccia sufficiente per le esigenze di output grafico della tua applicazione.Quindi implementa questa interfaccia per ogni renderer che desideri supportare.

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

Tuttavia, progettare e mantenere correttamente queste interfacce può essere molto impegnativo.

Nel caso in cui operi anche con oggetti dipendenti dal driver di rendering come le texture, puoi utilizzare un modello di fabbrica per fare in modo che i renderer separati creino ciascuno la propria implementazione, ad es.ITexture utilizzando un metodo factory in 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);
    }
  //...
};

Non sarebbe un'idea guardare ai motori esistenti (3d)?Nella mia esperienza, progettare questo tipo di interfacce distrae davvero da ciò che vuoi effettivamente realizzare :)

Altri suggerimenti

Direi che se vuoi una risposta davvero completa, vai a guardare il codice sorgente di Ogre3D.Hanno entrambi D3D E OpenGL estremità posteriori.Guarda a : http://www.ogre3d.orgFondamentalmente il loro tipo di API ti costringe a lavorare in modo simile a D3D, creando oggetti buffer e riempiendoli di dati, quindi emettendo chiamate di disegno su quei buffer.Questo è comunque il modo in cui piace all'hardware, quindi non è una brutta strada da percorrere.

E poi, una volta che vedi come fanno le cose, potresti anche semplicemente andare avanti e usarlo e risparmiarti la fatica di dover reimplementare tutto ciò che già fornisce.:-)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top