Qual è il metodo migliore per aggiornare le uniformi dello shader?


10

Qual è il modo più accettato per mantenere aggiornate le matrici di uno shader e perché?

Ad esempio, al momento ho una Shaderclasse che memorizza le maniglie nel programma shader e nelle uniformi GLSL. Ogni volta che muovo la telecamera devo passare la nuova matrice di visualizzazione allo shader, quindi ogni diverso oggetto del mondo devo passare la sua matrice modello allo shader.

Questo mi limita fortemente poiché non posso fare nulla senza avere accesso a quell'oggetto shader.

Ho pensato di creare una ShaderManagerclasse singleton che è responsabile per contenere tutti gli shader attivi. Posso quindi accedervi da qualsiasi luogo e un oggetto del mondo non dovrebbe sapere su quali shader sono attivi solo che deve far ShaderManagerconoscere le matrici desiderate ma non sono sicuro che questo sia il modo migliore e probabilmente ci sono alcuni problemi che deriverà da questo approccio.


Perché non passare i dati agli shader quando è il momento di renderizzarli?
Nick Caplinger,

Questo è quello che intendo ma come? Se un oggetto crea uno shader, come possono gli oggetti del mondo conoscere l'esistenza di quel shader e passargli le matrici necessarie?
Lerp,

Risposte:


11

Utilizzare buffer uniformi (ovvero buffer costanti nel gergo D3D).

Finché tutti i tuoi shader concordano sul layout e sul punto di rilegatura di ciascuno di questi buffer, l'aggiornamento diventa un gioco da ragazzi. I modelli non hanno bisogno di sapere nulla sugli shader. Devono solo aggiornare la matrice di visualizzazione del modello nel loro buffer costante e la pipeline di rendering lo utilizzerà automaticamente.

Almeno direi che dovresti avere due di questi buffer. Il primo dovrebbe memorizzare la matrice di proiezione, la matrice della videocamera, la matrice di proiezione della videocamera concatenata, le informazioni sulla vista, i dettagli frustrati e le inversioni della matrice. È necessario aggiornare questo buffer solo una volta per scena.

Quindi assegnare a ciascun modello un altro buffer per memorizzare la sua matrice vista modello, la matrice normale, le inversioni e le proprietà del materiale. Questo viene aggiornato una volta per ciascun modello e può essere eseguito in un passaggio di aggiornamento diverso (se / quando appropriato). Le informazioni sul materiale possono / devono essere spostate in un terzo buffer specifico del materiale se si ha la possibilità di condividere materiali tra più oggetti.

In una configurazione con ombreggiatura in avanti ha un certo senso mettere tutte le luci in un altro buffer e in ombre differite ha anche senso utilizzare un buffer per luce per il passaggio della luce (al posto di un buffer modello / materiale utilizzato nel passaggio della geometria).

Nota che hai bisogno di una versione moderatamente aggiornata di GL per usare tutti i buffer uniformi (3.1 o un'estensione; abbastanza comune oggi tranne che su alcuni laptop più vecchi ma ancora in servizio) e hai bisogno di una versione abbastanza recente per essere in grado di associare buffer uniformi a specifiche posizioni di associazione dall'interno del codice shader (4.2; ancora non comune ma migliorando) altrimenti devi fare più lavoro nel tuo codice lato CPU per impostare le cose (il tuo codice CPU deve conoscere il giusto legame punti comunque, quindi è più un odore di API che un problema serio). OpenGL | ES non ha aggiunto buffer uniformi fino alla 3.0, che purtroppo non è ancora supportato sulle piattaforme mobili più diffuse.

Se i buffer non sono un'opzione, sarà necessario un posto globale per memorizzare le posizioni degli indici per lo shader attivo. È possibile utilizzare glGetUniformLocationdopo aver caricato lo shader per trovare gli indici per nomi noti (simili ModelViewMatrixo simili), quindi archiviare questi indici. Il tuo rendering può mappare valori enum come MODEL_VIEWpassati aSetUniform funzione wrapper per guardare nello shader associato, trovare l'indice e chiamare glUniformcorrettamente. Non è un grande cambiamento nell'uso del codice client da parte dei buffer oltre alla necessità di impostare ciascuna uniforme singolarmente se si ottiene tutto ben confezionato.

Vedi GLSL Inteface Blocks e Uniform Buffer Objects .


Sapevo che sarebbe stato un modo integrato. Grazie!
Lerp,

4

Il modo più semplice per farlo è semplicemente standardizzare i nomi uniformi tra i tuoi shader e inviare tutti i dati appena prima di disegnare. Il sovraccarico non è folle, ma è possibile ottimizzarlo in un secondo momento per non inviare sempre uniformi meno aggiornate.

Il modo in cui lo faccio nel mio gioco è che ho una Materialclasse astratta . I materiali fungono da ponte tra il gioco e gli shader. Ognuno Materialha una Shadere varie proprietà che possono essere impostate, comprese le trame. Quando è il momento di disegnare un oggetto, Materialè legato. Il Bindmetodo ha un GraphicsStateparametro che contiene tutti gli stati grafici attuali: matrici, luci, ecc. Il Bindmetodo lega lo shader e le trame e imposta tutte le uniformi, usando tutto ciò di cui ha bisogno GraphicsState.

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.