Grafico della scena per il motore di rendering differito


10

Come esercizio di apprendimento ho scritto un motore di rendering differito. Ora vorrei aggiungere un grafico di scena a questo motore, ma sono un po 'perplesso su come farlo.

Su un normale (motore di rendering in avanti) aggiungerei semplicemente tutti gli elementi (tutti implementando IDrawable e IUpdateAble) al mio grafico di scena, quindi viaggerei prima sull'ampiezza del grafico di scena e chiamerei Draw () ovunque.

Tuttavia, in un motore di rendering differito, devo separare le chiamate di disegno. Per prima cosa devo disegnare la geometria, quindi le rotelle delle ombre e poi le luci (tutte con obiettivi di rendering diversi), prima di combinarle tutte. Quindi, in questo caso, non posso semplicemente viaggiare sul grafico della scena e chiamare semplicemente il disegno. Per come la vedo io devo viaggiare 3 volte sull'intero grafico della scena, controllando che tipo di oggetto deve essere disegnato, oppure devo creare 3 grafici di scena separati che sono in qualche modo collegati tra loro. Entrambe sembrano soluzioni scadenti, mi piacerebbe gestire gli oggetti di scena in modo più trasparente.

Un'altra soluzione a cui ho pensato era viaggiare attraverso il grafico della scena come di consueto e aggiungere elementi a 3 elenchi separati, separare la geometria, le ruote d'ombra e le luci, e poi iterare questi elenchi per disegnare le cose giuste, è meglio, ed è vero? saggio ripopolare 3 elenchi per ogni fotogramma?

Risposte:


6

Un approccio che ho usato in un progetto C ++ è che il grafico di scena (che ha l'indice spaziale) riempie uno std :: vettore di hit "visibile" basato sull'attuale frustum di visualizzazione. Questo elenco visibile è gestito dal grafico della scena, quindi viene ricalcolato solo quando la telecamera si sposta: gli oggetti in movimento nel grafico vengono spostati in questo elenco e utilizzando pietre tombali e elenchi di modifiche non ordinati che vengono ordinati e uniti nuovamente quando necessario.

L'elenco degli elementi visibili viene ordinato per ID shader prima e all'interno di ciascun tipo in base alla distanza dalla telecamera. Gli ID dello shader sono assegnati in modo tale che prima il terreno sia ordinato e poi gli edifici e poi le unità e quindi i proiettili e quindi le particelle e così via - essendo un RTS. Alcuni modelli hanno più di uno shader, ma pubblicizzano solo il loro shader principale. Quando viene chiesto loro di disegnare, anche quelli che hanno bisogno di bit disegnati con un altro shader si aggiungono a un singolo elenco di link successivi.

Quindi il disegno passa attraverso l'array visibile in un passaggio e in quello passa viene creato un elenco collegato di quegli elementi da rivisitare e vengono disegnati un secondo passaggio e così via.

Disegnare fronte-retro e opaco-poi-trasparente aiuta a mantenere tutto sano di mente.

Questo forse non sta minimizzando il numero di cambi di shader ecc. Ma è abbastanza praticabile e semplice da implementare.

Non ho idea di XNA e di quanto sia applicabile e di quanto di queste cose di basso livello che crei temo. Sarebbe molto interessante sapere cosa pensano i veterani di questo approccio per i CTS RTS.


Ehi Will, mi piace molto questa risposta, soprattutto perché è totalmente diverso da quello a cui ho pensato finora. Il tuo metodo sembra molto sano, specialmente quando pensi anche a oggetti semi-trasparenti (che per lo più ho evitato finora). Costruire un elenco (collegato) dal grafico della scena per gli oggetti da visitare sembra un'ottima idea. E sì, in XNA dobbiamo fare anche tutte queste cose di basso livello :).
Roy T.

3

Il mio suggerimento sarebbe un approccio in 2 fasi su misura per le tue esigenze specifiche simile a quello che hai descritto tu stesso. Hai bisogno di un grafico di scena e di una "collezione di rendering" per ciascuna delle fasi di rendering, nel tuo caso ombra, geometria, luci (forse un quarto è oggetti trasparenti?)

Il grafico della scena può essere basato su qualsiasi tipo di relazione, ma la mia preferenza personale si baserebbe su relazioni spaziali in cui ciascun nodo può contenere gli altri nodi per facilitare l'abbattimento rapido.

Le raccolte di rendering possono essere qualsiasi tipo di struttura di dati su misura per il passaggio specifico. Ad esempio, la raccolta di ombre potrebbe essere un elenco o un albero ordinato in base alla profondità per massimizzare il rifiuto iniziale. La raccolta della geometria potrebbe essere ordinata in base all'utilizzo dello shader per ridurre al minimo le modifiche (stato) dello shader. La raccolta di luci potrebbe essere un elenco o un albero ordinato in base alla distanza, alle dimensioni o ad una combinazione di quelle in modo da poter limitare il rendering della luce solo alle luci più efficaci se le prestazioni sono un problema.

Qualunque sia la struttura di dati che scegli, assicurati che l'operazione di inserimento sia veloce e assicurati che utilizzi il pooling e altre tecniche per eliminare qualsiasi allocazione / distruzione dei dati perché cancellerai e riempirai questi elenchi ogni frame.

Ora legare tutto insieme è facile. Basta attraversare il grafico della scena e aggiungere ogni elemento alle raccolte di rendering pertinenti. Aiuta se la struttura dei dati ordina / struttura automaticamente le nuove voci in base ai requisiti. Al termine, scorrere le raccolte di rendering nell'ordine richiesto e renderle.

Poiché le strutture dei dati hanno un inserimento rapido e non generano immondizia, non vi è alcuna penalità per il ripopolamento degli elenchi, come menzionato.

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.