Come gestire i materiali in un sistema Entity / Component


13

La mia implementazione E / C è quella di base in cui le entità sono solo ID, i componenti sono dati e i sistemi agiscono sui dati. In questo momento ho problemi con i materiali degli oggetti e il rendering in generale. Per oggetti semplici ho un ModelComponent, legato a un RenderSystem, ModelComponentha gli ID del buffer dei vertici utilizzati dal sistema di rendering. Un semplice MaterialComponentavrebbe probabilmente una forza cromatica o speculare, ecc., Ma volevo che fosse abbastanza flessibile da consentire più di un passaggio di rendering e "effetti" generali che non sono facili come una semplice variabile nel file MaterialComponent.

Cercando di risolvere questi problemi, ho trovato due soluzioni:

1 - Componente materiale super-generico

Qualcosa come questo:

struct Material : public Component
{
    ShaderData* shader;
    std::vector<std::pair<std::string, boost::any>> uniforms;
    [...]
};

e nel sistema di rendering farei un ciclo e passerei le uniformi allo shader. Suppongo che questo sarebbe lento, ma abbastanza veloce per i miei scopi.

2 - Un altro strato di astrazione, MaterialData

Avendo una classe per avvolgere materiali specifici, che potrebbero essere ereditati da qualsiasi materiale specializzato, la classe base avrebbe qualcosa di simile void set_shader_constants(ShaderData* d)ma l'implementazione dipende da ogni classe e MaterialComponentavrebbe un puntatore a un oggetto MaterialData.

Non sono sicuro di quale approccio preferirei, ma nessuno di questi tocca l'argomento di passaggi multipli o altre tecniche di rendering complesse.

Qualche idea su come realizzare questo?

Risposte:


26

I materiali sono un concetto grafico e appartengono al tuo renderer. Un renderer è un pezzo di architettura di livello troppo basso per essere costruito sopra un sistema di entità. I sistemi di entità dovrebbero essere per oggetti di gioco di livello superiore. Non tutto deve essere un componente e , in effetti, è generalmente una cattiva idea provare a forzare tutto in un unico paradigma del genere. Crea una soluzione con il minimo comune denominatore.

Di conseguenza, consiglierei di adottare un approccio diverso:

  • Un materiale è solo un altro tipo nel tuo renderer.
  • Il tuo renderer ha un tipo che rappresenta "una cosa da disegnare sullo schermo". Spesso questi sono chiamati "istanze di rendering" o "renderable" o persino "modelli". Questo tipo ha un riferimento al materiale che utilizzerà durante il disegno e fornisce un'API pubblica per consentire a un consumatore del renderer di impostare quel materiale su ciò che si desidera.

Questo essenzialmente ti chiede di prendere il tuo ModelComponente rinominarlo Model, rimuovendo la dipendenza dal livello entità / componente e spostandolo in un livello inferiore di astrazione, insieme al resto del tuo renderer.

Quindi, fai questo:

  • Nello stesso livello di astrazione degli altri componenti, hai una sorta di "componente aspetto" che rappresenta la presentazione visiva di un'entità. Questo componente contiene solo un riferimento ad alcuni renderizzabili (come descritto sopra), che a sua volta contiene il riferimento a un materiale. Il componente può fornire un'API per esporre il renderable (permettendo così ai clienti di manipolarlo) o può avvolgere l'API del renderable per controllare l'esposizione. Dipende da te.

Questo risolve il problema di interdipendenza dei componenti in cui ti imbatti avendo modelli e materiali entrambi componenti; un'entità dovrebbe avere un aspetto o no, e quell'aspetto dovrebbe essere in grado di codificare tutto sulla presentazione dell'entità, incluso il materiale.

Questo ti dà anche la flessibilità di adottare altri approcci con l'oggetto materiale che sarebbe più difficile avere a che fare con quell'oggetto come componente a causa della mancanza di parità con il resto dell'astrazione del sistema di rendering.

Il problema di consentire effetti più complessi e passaggi multipli potrebbe essere risolto principalmente nel materiale, esponendo le funzioni da interrogare e impostare le costanti shader denominate esposte dal file shader del materiale. Ciò è particolarmente vero se si utilizzano file di effetti (in D3D) che supportano passaggi multipli e simili. Anche se non stai utilizzando file di effetti, puoi esporre l'idea di più passaggi dal materiale, ognuno con shader distinti, e consentire all'API del materiale di fornire manipolatori per questo. Sarebbe più facile e pulito integrarsi molto probabilmente nell'API di rendering, poiché il materiale è ora allo stesso livello di astrazione.


1
Grazie per la tua risposta, questo problema mi ha tormentato per un bel po 'di tempo, ma creare un renderer senza i vincoli di E / C è molto più semplice.
Luca B.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.