La scorsa settimana ho iniziato ad introdurre il tema delle operazioni di texturing, partendo dalla definizione di texture e facendo brevi cenni alle texture 2D. Mi ero ripromesso di limitarmi ad accennare soltanto alcuni argomenti ma, dalle domande postemi, mi rendo conto che è opportuno spenderci qualche parola in più, tornando brevemente sull’argomento. In particolare, vorrei riprendere dall’operazione di “applicazione” della texture, facendo uso dei parametri di shape ed entity e, in particolare, di quest’ultimo.
Nell’immagine precedente, riportiamo i quattro modi utilizati per scegliere l’orientamento di una texture rispetto ad una superficie. I quesiti sono molteplici, tra cui: come viene applicata una texture su una superficie che presenti così tante irregolarità? L’applicazione della texture su una superfice del genere introduce delle deformazioni alla texture stessa e, se si, queste deformazioni come vengono corrette?
Dall’immagine si vede che i modi per scegliere la forma e l’orientamento di una texture rispetto ad un oggetto sono diversi e possono essere combinati tra loro, dando luogo a diverse soluzioni. Uno è quello di mettere in relazione 1:1 i punti della superficie dell’oggetto con il suo object bounding box, in modo da effettuare una proiezione dell’oggetto stesso su una “scatola” che lo contiene.
A questo punto, la texture si applica sulla “scatola” in modo da far corrispondere i texel dell’una con i pixel dell’altra. L’operazione avviene facendo riferimento al “contenitore” dell’oggetto nell’object space. Questo contenitore è un cubo con delle sue proprie coordinate che, lungo ciascuno dei tre assi, variano tra 0 ed 1.
Ovviamente, ad ogni punto del “cubo” sono comunque associati tre valori di (x, y, z) che rappresentano la posizione “reale” di quel punto dell’oggetto all’interno del world space e, soprattutto, del view space (e del clip space). Questo significa che, nel momento in cui l’oggetto viene “riportato nel mondo reale”, ovvero si applica la trasformazione inversa rispetot a aquella che lo aveva proiettato sul suo object bounding box, può accadere che le mesh piuttosto grandi che abbiano particolari inclinazioni rispetto al punto di vista dell’osservatore, possono introdurre delle deformazioni della prospettiva che richiedono delle “correzioni prospettiche”.
Un altro metodo di scelta dell’orientamento della texture rispetto all’oggetto è quello basato sull’orientazione della normale alla superficie dell’oggetto stesso in ogni suo punto o per ogni primitiva di tipo “planare” che lo compone. In questo caso, detto in parole povere (e con molto poco rigore), è come se si prendesse la texture, assimilabile ad una tela, e, triangolo per triangolo, la si “cucisse” sull’oggetto seguendone la forma. Ovviamente qnche questo metodo comporta delle deformazioni che, vanno, a loro volta, corrette. Non mi dilungo sugli altri due metodi e passo a fare un breve cenno alle equazioni di tipo parametrico.
Quando si opera con delle patch di tipo parametrico, si parte dalla superficie su cui si deve applicare la texture; quindi si normalizzano le coordinate (x, y) rispetto a z limitando la superficie al’interno di un quadrato i cui vertici sono posizionati in punti le cui coordinate variano, in OpenGl, tra -1 e 1 e in DirectX tra 0 e 1; La texture applicata su di essa avrà, in entrambe le API, coordinate comprese tra 0 e 1.
A questo punto, l’oggetto da renderizzare è ridotto ad una superficie piana su cui si può “stendere” la texture.
Può succedere (non è un caso infrequente) che la texture da applicare sia troppo grande o troppo piccola rispetto alla superficie. In questo caso si può ricorrere ai cosiddetti filtri di magnification e minification che servono, rispettivamente, il primo quando un pixel della superficie risulta troppo grande rispetto alla rispettiva texel che lo deve coprire o quando la superficie è molto porssima all’osservatore, il secondo quando accade che una texel copra più pixel o quando la superficie è molto distante dall’osservatore.
Il primo caso è quello tipico di un fps in cui ci avvicina improvvisamente ad una parete; in questa situazione deve aumentare il dettaglio della superficie renderizzata e, di conseguenza, servono testure più grandi e dettagliate. Mentre si carica un livello superiore del mipmapping, il filtro di magnification maschera la superficie “pixellosa” attraverso una serie di interpolazioni.
Con il termine “mipmapping” si introduce un altro argomento; ricordiamo che abbiamo a che fare con immagini 2D (il monitor è una matrice di punti bidimensionale) con cui si cerca di dare l’illusione del 3D creando una prospettiva.
Questo significa che, quando pensiamo alla realizzazione di una texture che, ad esmepio, deve andare a rivestire una parete, dobbiamo tener conto del fatto che questa parete (o pavimento o qualunque altra cosa) potrà avere dei punti vicini e dei punti distanti rispetto all’osservatore; per questo motivo, sarà necessario pensare a texture più grandi e dettagliate in prossimità dell’osservatore e a texture più piccole e meno dettagliate per i punti più distanti dall’osservatore. Si deve, quindi, in quanlche modo, misurare il Livello del Dettaglio (LoD) che la superficie deve avere rispetto al punto di osservazione e, in base a quello, utilizzare le dimensioni più adeguate della texture scelta.
Il LoD è un parametro che si misura partendo dal punto di osservazione; questo significa che i punti più vicini all’osservatore avranno LoD pari a 0 (in realtà si possono impostare anche valori di LoD negativi; la cosa può portare dei miglioramenti ulteriori della qualità d’immagine ma potrebbe anche creare rpoblemi di visualizzazione in caso di non ottimizzazione per questo tipo di impostazioni). Una volta stabilito il LoD si deve scegliere la giusta texture da applicare. Uno dei metodi utilizzati per avere a disposizione più texture dello stesso tipo ma con livelli di dettaglio differenti, è quello di generare, a partire da una texture originaria, un insieme di texture di dimensioni e livelli di dettaglio differenti, come mostrato in figura
La creazione di questa struttura a “piramide” è definita mipmapping e serve ad avere, per ogni livello di dettaglio, la texture adeguata da applicare.
A questo punto, sorge un altro problema: se ho una parete o, ad esempio, un pavimento che si estende in profondità, avrò in prossimità dell’osservatore texture più dettagliate e, man mano che mi allontano, livelli di dettaglio inferiori. Questo dà luogo, nelle zone di transizione tra texture a differente livello di dettaglio, a brutte quanto evidenti transizioni che, per migliorare la qualità dell’immagine, devono essere rese “poco visibili”.
Si noti bene che ho scritto poco visibili e non eliminate, perchè, di fatto, come anche visto per l’aliasing, non è possibile eliminare del tutto questi artefatti ma solo ridurne l’impatto a livello visivo. A questo scopo si fa uso di tecniche di filtraggio che vanno dal semplice filtro bilineare al più complesso anisotropico. Alle tecniche di texture filtering dedicherò un paragrafo a parte. Per ora, mi limiterò ad aggiungere che il mipmapping è una delle tecniche adoperate per generare texture di diverse dimensioni a partire da una texture originaria; è una tecnica che permette di avere a disposizione più campioni per ogni disegno di partenza ma richiede una notevole occupazione di memoria.
In questo contesto, voglio invece, fare un breve cenno ad alcuni dei metodi di generazione delle texture, che vanno da quelle con pattern regolare a quelle con pattern di tipo “stocastico”. Le prime sono generate partendo da una medesima trama che viene ripetuta fino a riempire tutta la superficie che la texture deve occupare.
Queste texture sono caratterizzate dalla ripetitività dello stesso motivo e sono facilmente identificabili, in quanto, ad esempio, tornando sempre al solito muro, se sulla superficie di mattoni o pietre c’è una irregolarità, la stessa irregolarità si ritrova a intervallli… regolari. Una delle tecniche tipiche atte a generare texture con pattern di tipo “ripetitivo” è il tiling, che consiste proprio nel prendere una “tessera” contenente la trama che si vuole utilizzare e ripeterla ad libitum.
Un’altra tecniche che prende spunto dal tiling per generare texture con trama pseudo random è, invece, definita chaos mosaic: ideata da Microsoft, si basa sull’idea di prendere il disegno di partenza, fare un’operazione di tiling e poi intervenire sulla trama prendendo parti di essa, scelte in maniera casuale per posizione e dimensioni e “incollarle” sulla texture ottenuta sfumando le transizioni con il resto della trama.
Un altro algoritmo di generazione casuale fa uso un procedimento analogo al tiling ma, invece di ripetere l’intera trama del campione si prende a caso, per ogni tessera della texture finale, una porzione della texture “base”, come mostrato in figura
Nell’immagine, il riquadro rosso della texture base (sulla sinistra) si muove in maniera del tutto casuale e, ai suoi spostamenti, corrispondono i movimenti del riquadro della texture finale (sulla destra) che invece, riempie la superficie partendo dal riquadro in alto a sinistra e procedendo in maniera ordinata da sinistra a destra e dall’alto in basso (come il pennello di un cinescopio CRT).
All’estremo opposto, ci sono invece le texture con pattern generato in maniera casuale, sempre partendo da un motivo di partenza. Questi algoritmi tengono conto, in realtà solo di pochi parametri relativi al campione, come ad esempio, il colore medio, la minima luminosità ed il massimo contrasto.
I risultati ottenuti con algoritmi così differenti sono, ovviamente, molto diversi tra di loro e vanno da trame di tipo ripetitivo a trame con pattern del tutto casuale
Quanto visto in questa puntata, vale per le texture 2D introdotte la scorsa settimana, ma anche per le texture 3D che vedremo in seguito che, rispetto alle prime, si differenziano solo per l’operazione di “displacement mapping” cui sono soggette. Prossimamente daremo un’occhiata agli effetti dell’applicazione di più texture sulla stessa superficie, introdurremo le texture 3D e ci occuparemo in maniera più approfondita delle operazioni di filtraggio.