• Non ci sono risultati.

Le classi presentate nelle precedenti sezioni sono sucienti a comprendere il fun- zionamento di base della nuova libreria; in questa sezione vediamo come procede il rendering di un frame esaminando le operazioni eseguite all'interno di ogni chia- mata principale e osservando come l'unico usso di esecuzione passa da un oggetto all'altro.

Visto che questa sezione ha lo scopo di chiarire il funzionamento di base della libreria, ci poniamo nel caso più semplice possibile: si vuole disegnare un singo- lo oggetto obj nella scena scene e nel corso del frame abbiamo un singolo blocco Begin()...End(). Diversi blocchi Begin()...End() possono servire quando si vo- gliono disegnare due scene diverse (o due viste diverse della medesima scena) in porzioni distinte della nestra OpenGL, oppure quando il rendering deve avveni- re in diversi passi sfruttando oggetti di tipo VR3FBO. Supponiamo di non essere in nessuno dei due casi.

All'interno del ciclo principale dell'applicazione (che si occupa di tracciare un frame ad ogni iterazione) avremo una cosa del tipo:

// Executed once per frame OnFrame () {

scene -> Begin (); // begin scene rendering obj -> Draw (); // draw the object

scene -> End (); // end scene rendering }

Trascuriamo tutti gli aspetti di inizializzazione della scena e dell'oggetto virtua- le obj, come di qualsiasi altro componente della libreria che potrebbe essere stato attivato. Le chiamate esaminate potrebbero sfruttare altre funzioni membro della stessa classe, di altre classi o di particolari namespace interni alla VR3Lib per svol- gere alcune delle loro operazioni: in questo caso il passaggio non sempre viene messo in evidenza (perché può risultare di scarso interesse in questa trattazione).

L'esecuzione procede come segue: 1. scene->Begin()

(a) Si imposta la trasformazione di viewport eseguita dalla pipeline OpenGL per ricoprire con la nuova immagine generata l'intera nestra dell'applicazione.

CAPITOLO 5. STRUTTURA E FUNZIONAMENTO DELLA VR3LIB 173 (b) Si imposta la scena corrente scene come scena attiva (sostituendo il valore

in VR3Scene::ms_activescene).

(c) Se viene specicata una telecamera diversa da quella corrente, si attiva la nuova telecamera come telecamera corrente (nel nostro caso non viene esplicitamente specicata la telecamera da utilizzare e dunque si lavora con quella corrente).

(d) Se non viene specicato altrimenti, si calcolano le matrici di projection e viewing sulla base della telecamera corrente e delle dimensioni del view- port, e i risultati vengono salvati in un'opportuna struttura da consultare in seguito. Questo passaggio può essere evitato usando un particolare ag da fornire alla funzione Begin().

(e) Se non viene specicato altrimenti, si salvano i parametri delle sorgen- ti luminose in una apposita struttura dati, nella forma in cui verranno eventualmente passati agli shader. Questo passaggio può essere evitato usando un particolare ag da fornire alla funzione Begin(). L'operazione avviene anche quando si ha illuminazione tramite environment mapping perché questi dati potrebbero servire nel caso in cui si utilizzi uno shader esterno specicato dall'utente.

(f) Se sono attive delle environment map (diuse o specular), queste vengono registrate come cube map attive sulle giuste texture unit OpenGL (per futuri accessi da parte degli shader).

(g) Se non viene specicato altrimenti, si ripuliscono il color buer e il depth buer del framebuer associato alla nestra OpenGL. È possibile evitare la ripulitura del color buer usando un particolare ag da fornire alla funzione Begin().

(h) Se vi è un simulatore sico (oggetto VR3PhysicsSimulator) attivo, que- sto è già stato preparato per la simulazione e non viene specicato al- trimenti, si provvede a recuperare i risultati della simulazione PhysX (se disponibili). Se l'operazione ha successo, si avvia una nuova simula- zione nel motore PhysX (i dati da essa prodotti verranno utilizzati nel prossimo frame, se disponibili). Questa operazione avviene mediante la funzione CollectResults() del simulatore sico e può venire evitata usando un particolare ag da fornire alla funzione Begin() (in tal caso si utilizzeranno i risultati precedentemente ottenuti).

(i) Se vi è un controllore di ombre (oggetto VR3ShadowController) attivo e non viene specicato altrimenti, si disegnano e ltrano tutte le shadow map per le varie sorgenti d'ombra attive nel controllore (trascurando even- tuali ottimizzazioni come i vari tipi di culling visti in sez. 5.5). Queste vengono inoltre attivate come texture bidimensionali sulle giuste texture unit OpenGL per futuri accessi da parte degli shader. Alcuni parame- tri delle sorgenti d'ombra attive vengono salvati in un'apposita struttura dati nella forma in cui verranno eventualmente passati agli shader per la modulazione del colore sulla base delle ombre. Questa operazione avvie- ne mediante la funzione DrawShadowMaps() del controllore delle ombre e può venire evitata usando un particolare ag da fornire alla funzio- ne Begin() (in tal caso si utilizzeranno le mappe prodotte dall'ultima chiamata di DrawShadowMaps()). Naturalmente, durante il disegno del- le shadow map bisogna disegnare i vari oggetti registrati come caster all'interno del controllore (ma non entriamo nei dettagli).

(j) Si disegna lo sfondo statico o la skybox, se presente, tramite la fun- zione Draw() del membro privato m_background della scena (di ti- po VR3Background). Non esaminiamo in dettaglio questa funzione di disegno.

2. obj->Draw()

(a) Nel caso in cui vi sia uno shadow controller attivo, si verica se l'ogget- to obj appartiene all'insieme dei ricevitori. In caso aermativo si attiva un ag ad indicare che l'oggetto dovrà subire una modulazione di colore dipendente dalle shadow map generate al passo 1i. Tale ag viene pro- pagato nelle chiamate successive di funzioni Draw() su eventuali oggetti gli e sulla eventuale mesh selezionata per il disegno.

(b) Si calcola la matrice di modeling per l'oggetto obj sulla base della matrice ricevuta dal padre (in questo caso la matrice identità) e delle trasforma- zioni specicate per il particolare oggetto. Nel caso in cui sia attivo un simulatore sico e l'oggetto risulti tra quelli simulati, si provvede a recu- perare la matrice di modeling direttamente da PhysX tramite la funzione GetModelMat() del simulatore sico.

(c) Si invoca la Draw() su tutti gli oggetti di tipo VR3Obj che risultano gli dell'oggetto obj. Nel nostro caso abbiamo supposto che obj fosse l'unico

CAPITOLO 5. STRUTTURA E FUNZIONAMENTO DELLA VR3LIB 175 oggetto nella scena e dunque non avrà oggetti gli. Ai gli verrebbe passata la matrice di modeling calcolata al passo precedente in modo tale da rendere le trasformazioni dei gli relative al sistema di riferimento del padre (nel caso in cui non siano simulati).

(d) Si seleziona un livello di dettaglio tra quelli disponibili e si disegna la mesh corrispondente (se ne è stata trovata una) tramite la sua funzione di disegno (m_meshes[LOD]->Draw()). Il disegno di una mesh procede secondo i seguenti passi quando si utilizzano gli shader predeniti nella libreria e non si sta disegnando l'oggetto all'interno di una shadow map (trascurando eventuali ottimizzazioni come il view frustum culling).

i. Si calcolano i valori di alcune variabili uniform dipendenti dalla mesh complessiva, ad esempio la matrice di trasformazione totale (mode- ling, viewing e projection) da applicare ai vertici in spazio oggetto all'interno degli shader. Tali valori vengono salvati in una struttura dati opportuna da consultare in seguito. I valori calcolati vengono prodotti anche sulla base dei dati memorizzati nelle strutture dati introdotte nei passi 1d e 1e.

ii. Per ognuno dei subset presenti nella mesh:

• Si verica se lo shader program correntemente attivo (usato per il precedente subset) deve essere usato anche per il subset corrente, in caso negativo si attiva il nuovo shader program e si caricano i valori delle variabili uniform dipendenti dalla mesh. Se lo shader program non deve essere modicato si evita invece il caricamento delle variabili uniform dipendenti dalla mesh (che avranno già il giusto valore dal subset precedente). Nel passaggio di questi va- lori si sfruttano le informazioni memorizzate nella struttura dati di cui al passo 2(d)i, ma anche i dati nelle strutture introdotte nei passi 1d, 1e, 1i.

• Si carica il valore delle variabili uniform dipendenti dal particola- re subset (come quelle relative al materiale) attivando le eventuali texture sulle giuste texture unit OpenGL per renderle accessibili da shader.

• Si disegnano tutti i poligoni del subset con lo shader program attualmente attivo.

3. scene->End()

In questa funzione si ha soltanto il ripristino dello stato che si aveva prima della chiamata alla funzione Begin(), ed inoltre si aggiornano le statistiche sulle pre- stazioni per la scena corrente che vengono mantenute dall'oggetto scene stesso. Qualsiasi operazione di disegno tentata fuori da un blocco Begin()...End() verrà riutata dalla VR3Lib e l'applicazione terminerà con errore.

Nonostante alcune operazioni minori siano state trascurate in questo semplice esem- pio, lo schema sopra dovrebbe chiarire il modello d'esecuzione adottato dalla VR3Lib per il rendering di ogni frame.