Francesco Guastella

aka romeoxbm

Gestione delle uniform in OpenGL (parte 1)

Download in formato PDF

La gestione delle variabili uniform può rappresentare un aspetto cruciale per un’applicazione 3D che fa utilizzo delle api opengl.
Esistono molti tutorial sull’argomento, molti di questi facilmente reperibili in rete, ma quello che sicuramente ha più stuzzicato il mio ingegno (colgo l’occasione per consigliarvi di leggerlo) lo potete trovare in Game Engine Gems 2.
Il motivo per il quale state leggendo questo articolo è molto semplice: tutti questi tutorial mi hanno lasciato un profondo senso di insoddisfazione quando hanno presentano la loro implementazione della classe Uniform.
Nessuno ha infatti affrontato la tematica della gestione dei differenti tipi di dati con il quale avremo sicuramente a che fare, limitandosi semplicemente a descrivere la gestione di variabili di tipo float.
L’obiettivo di queste righe è quindi di sopperire a tale senso di insoddisfazione, proponendo l’implementazione completa di un sistema di gestione per tali variabili, rivolgendo particolare attenzione alle problematiche che possono sorgere (con relative soluzioni) nel tentativo di creare una classe Uniform in grado di gestire differenti tipi di dati
e un differente numero di componenti (si pensi al tipo vec3 ad esempio che fondamentalmente è l’insieme di tre valori float).
Il principio alla base di questo sistema è molto semplice ed alquanto efficace: una volta creato il nostro shader program, otteniamo tutte le variabili uniform in esso contenute, e facciamo in modo che ogni uniform invii il suo valore alla scheda grafica soltanto se è stato effettivamente modificato nel corso dell’esecuzione.
In questo modo siamo in grado di evitare chiamate ridondanti e di raggiungere un livello di astrazione che ci permette di interagire con i nostri programmi GPU in maniera molto semplice. Vediamo un esempio di ciò che vogliamo quindi ottenere:

Partiamo con l’implementazione di quanto serve nella classe ShaderProgram, la quale rappresenta l’argomento principale di questo articolo (parleremo infatti della classe Uniform nel successivo).
Conferiremo a ShaderProgram il seguente aspetto:

Dobbiamo anzitutto sapere esattamente quali e quante variabili uniform sono presenti nel nostro shader program, e lo faremo utilizzando i metodi activeUniformCount e _getUniforms, dei quali è possibile osservare l’implementazione proposta:

Il metodo _getUniforms utilizza gl::GetProgramResourceiv per ottenere la lunghezza del nome, il tipo (gl::FLOAT, gl::DOUBLE, etc.) e la locazione di ogni uniform, ed infine crea un oggetto che verrà memorizzato all’interno
di una std::map che usa chiavi stringa.
Parleremo dell’implementazione del metodo _createUniform nel prossimo articolo.
L’implementazione del metodo uniformByName invece è molto semplice:

Fin qui abbiamo creato gli strumenti che ci permetteranno di ottenere le variabili unifom del nostro shader program.
Un altro step fondamentale è quello di far si che ogni variabile, come già accennato in precedenza, aggiorni lo shader program soltanto se modificata; raggiungeremo questo scopo aggiungendo in ShaderProgram un vettore contenente le uniform dirty, ovvero tutte quelle variabili che hanno subito modifiche, e utilizzeremo questo vettore, come vedremo qui di seguito, nel metodo upload di ShaderProgram, responsabile dell’invio alla GPU dei nostri dati:

Per far si che ShaderProgram sia consapevole di quali uniform hanno ricevuto aggiornamenti, e quindi popolare il vettore _dirtyUniforms, dobbiamo notificare allo ShaderProgram ogni avvenuta modifica attraverso il metodo set di Uniform.
Supponiamo per un’istante che la classe Uniform gestisca dati di tipo float; ecco quindi come chiudere il nostro cerchio, supponendo ulteriormente che l’implementazione di Uniform::set sia la seguente:

Dove _owner è un puntatore a ShaderProgram e _value è il membro di tipo float della classe Uniform.
Il metodo della classe ShaderProgram notifyDirty, ovviamente, si occuperà di inserire l’oggetto appena modificata all’interno del vettore _dirtyUniforms.

Quanto descritto fin’ora completa, dal punto di vista della classe ShaderProgram, la realizzazione di questo sistema di gestione delle variabili uniform.
Nel prossimo articolo descriveremo come implementare la classe Uniform, mostrando come sia possibile far si che sia in grado di gestire ogni tipo di dato e un differente numero di componenti (non dimentichiamo che avremo spesso a che fare con vettori di due, tre o quattro componenti, quaternioni e matrici).

Download in formato PDF

Tags: ,


Lascia un commento

Switch to our mobile site