Pagina principale

Texturing

L'elaborato fa un uso estremo del texture mapping per dare un aspetto più realistico ai vari elementi della scena. Quasi tutti gli oggetti renderizzati a schermo (inclusa l'interfaccia utente, con poche eccezioni) prevedono l'utilizzo di texture colore.

Gli elementi della scena che fanno uso di texture derivanti da dei materiali applicati sono l'elicottero, le mongolfiere, il tabellone e le casse. La gestione delle librerie .mtl rende infatti estremamente semplice applicare il texture mapping a dei modelli preparati con tool di modellazione e opportunamente adattati. In questi casi il programmatore non deve nemmeno curarsi di fornire le coordinate texture al sottosistema grafico visto che lo sforzo è preso in carico dal formato .obj e dalla funzione renderModel() di model.c.
In molti altri casi (specialmente nella gestione dell'interfaccia utente) le texture vengono caricate esplicitamente e le coordinate vengono fornite direttamente dal codice.
Nella realizzazione dell'enviromental mapping e nella gestione della minimappa, le texture vengono invece generate manualmente, piuttosto che caricate dal disco fisso.

È chiaro che con un utilizzo così frequente del texturing è utile avvalersi di un componente che si occupi di fornire un supporto flessibile al caricamento del file di immagine, al binding in OpenGL e al filtering secondo i parametri che più si adattano al contesto di utilizzo.
Queste funzionalità vengono da due importantissime procedure definite in texture.h.

La prima delle due, loadTextureFromTGA(), è una funzione di basso livello che carica dal filesystem un'immagine nel formato .tga (viene eventualmente supportata la compressione RLE) e la riversa in un'area di memoria, pronta per essere utilizzata.

La procedura bindTexture()utilizzata praticamente ovunque dagli altri componenti – si prende l'incarico di caricare un'immagine specificata in input (richiamando loadTextureFromTGA()) e di realizzarne il binding in OpenGL, preoccupandosi di richiedere un nome per la texture (un intero senza segno che identifica univocamente la texture nel contesto OpenGL attivo) e svolgendo altri compiti utilissimi quali la generazione automatica dei diversi livelli di mipmap e il setting delle funzioni di filtering.
Per fare in modo che la funzione possa adattarsi alle diverse esigenze, viene presa in input una semplice struttura (TexParam) che specifica i diversi parametri da utilizzare per gestire la texture richiesta: un flag per richiedere la generazione automatica dei livelli di mipmap, i filtri di minification e magnification, il formato della texture (utile per poter utilizzare sia immagini GL_RGB che GL_RGBA) e il tipo di wrap da impiegare (GL_REPEAT oppure GL_CLAMP). In alternativa è possibile passare un valore nullo e la funzione proseguirà utilizzando dei parametri di default.

Ovviamente queste procedure non alterano lo stato OpenGL nel momento in cui vengono richiamate. Nei punti del codice dove è necessario fare utilizzo di texture mapping ci si preoccupa di abilitare il flag GL_TEXTURE_2D. Si è deciso, per esigenza di uniformità, di adottare la convenzione per cui – durante la fase di rendering – soltanto il flag GL_DEPTH_TEST e GL_CULL_FACE sono abilitati. Qualora una funzione di rendering abbia bisogno di funzionalità più avanzate (texturing, shading, blending, stenciling, …) deve preoccuparsi non solo di abilitare o disabilitare i flag a seconda dell'effetto che vuole ottenere, ma anche ripristinare lo stato precedente alla sua chiamata per non lasciare le procedure successive in uno stato intermedio non prevedibile. Una funzionalità estremamente utile offerta da OpenGL a tale scopo è data dalle istruzioni glPushAttrib() e glPopAttrib() che consentono per mezzo di opportuni flag di salvare selettivamente lo stato OpenGL e ripristinarlo successivamente in maniera del tutto analoga a quanto avviene con le matrici di trasformazione.
È importante sottolineare che durante la fase di disegno dell'interfaccia grafica, viene utilizzata una convenzione diversa: il flag GL_DEPTH_TEST viene disabilitato per ovvi motivi, GL_TEXTURE_2D e GL_BLENDING vengono invece tenuti attivi visto che quasi tutti i componenti dell'interfaccia utilizzano queste funzionalità. Anche in questo caso, qualora una funzione intenda alterare lo stato deve avere cura di riportarlo nelle condizioni in cui lo ha trovato.

L'elaborato supporta soltanto immagini .tga, ma è comunque facile estenderne il supporto ad altri formati in quanto è sufficiente implementare una procedura adeguata per il parsing dei formati che si desidera utilizzare e richiamare da bindTexture() la funzione di caricamento adeguata, magari distinguendo in base all'estensione del nome del file passato in input.

NB: anche se le specifiche originali di OpenGL imponevano l'utilizzo di texture dalle dimensioni corrispondenti a potenze di due, questo requisito è in realtà stato rilassato da numerose versioni a questa parte, visto che le moderne architetture hardware riescono tranquillamente a supportare immagini di ogni dimensione. Laddove possibile si è comunque cercato di adeguarsi a questa direttiva, ma non tutte le texture utilizzate dal progetto seguono strettamente questa imposizione.

Pagina principale