Nella scorsa puntata, avevamo creato gli oggetti e/o i personaggi presenti in una determinata scena e li avevamo collocati all’interno di un ambiente dotato di un comune sistema di riferimento, mettendoli in relazione spaziale tra di loro. Il passo successivo è quello di porre un osservatore all’interno di questo ambiente, decidendone la posizione e fissando la porzione di spazio che ricade nel suo campo visivo.
Una volta stabilita la posizione dell’osservatore che non coincide necessariamente con l’origine degli assi del WORLD SPACE, si fissa il sistema di coordinate utilizzando una terna sinistra, orientata in modo tale che X, Y e Z coincidano rispettivamente, con l’asse orizzontale, quello verticale e quello che attraversando perpendicolarmente il piano XY nella sua origine (posizione dell’osservatore) dà indicazioni sulla direzione ed il verso in cui si guarda.
La scelta più comune è quella rappresentata in figura, in cui allontanandosi dall’osservatore verso il fondo del campo visivo si hanno valori di Z positivi sempre più grandi, mentre spostandosi alle spalle dell’osservatore si hanno valori negativi di Z. Sono stati, così, definiti, gli elementi costitutivi del VIEW SPACE, aggiungendo allo spazio degli oggetti un osservatore collocato in un punto ben preciso, il cui sguardo è orientato secondo una direzione ed un verso ben definiti.
Ovviamente, però, il campo visivo di questo osservatore non è illimitato in tutte le direzioni e per stabilirne i confini si fissa un angolo solido, con vertice sulla posizione dell’osservatore che si “apre” nella direzione e nel verso in cui si “guarda”.
Si compie un’operazione analoga a quella di porre una cinepresa dove si trova l’osservatore (che indicherò con O), che proietta l’immagine che viene visualizzata; la differenza rispetto ad una proiezione cinematografica è che il target non è un piano bidimensionale (lo schermo cinematografico) ma uno spazio 3D che sarà delimitato, a questo punto, da una piramide che ha la sommità posta in O e l’asse Z coincidente con l’altezza.
Si fissano, inoltre, due piani perpendicolari all’asse Z (ossia alla direzione in cui si guarda), che servono sia delimitare il fondo del campo visivo (il FAR CLIPPING PLANE), sia a definire l’ampiezza di campo visivo in prossimità di O che non è assimilabile ad un punto ma ad una superficie (il NEAR CLIPPING PLANE). In tal modo, il campo visivo risulta limitato, di fatto, da 6 superfici che formano un tronco di piramide detto VIEW FRUSTUM (VF).
Queste superfici sono definite CLIPPING PLANE. ed hanno una notevole importanza, in quanto delimitando il “campo visivo” danno una prima indicazione su ciò che è necessario renderizzare in un determinato frame e costituiscono, in tal senso, una prima forma di ottimizzazione per le operazioni di rendering.
Un view frustum culling semplice è costituito dal test di inclusione nel VF su ogni poligono: il risultato possibile è:
1) inside VF = rendered
2) outside VF = culled
Questo tipo di test è semplice e rapido ma è inefficace in presenza di un alto numero di poligoni, in quanto molto dispendiosa in termini di tempo.
In quel caso conviene far ricorso ad un algoritmo di tipo gerarchico che si potrebbe schematizzare nel modo seguente: innanzitutto non si procede per poligoni ma per celle in grado, ciascuna, di contenere più poligoni. Si effettua il test per ogni cella e in base al risultato:
1) cella tutta fuori dal VF, poligoni in essa contenuti = culled
2) cela tutta dentro al VF = poligoni rendered
3) cella parzialmente contenuta nel VF: si procede per celle di dimensioni inferiori e, in ultima analisi, per poligoni; oppure, se i poligoni contenuti nella cella sono pochi, si renderizzano tutti (anche quelli che di fatto sono nascosti), preferendo il risparmio di tempo ad un’analisi ancora più accurata.
Senza entrare nello specifico, faccio presente che contestualmente si effettuano anche test di coerenza frame to frame, per fare previsioni sulle superfici che restano nascoste anche nei frame successivi, in seguito a movimenti di traslazione o rotazione in tutte le direzioni permesse.
Dopo aver l’operazione di CLIPPING si procede a quella di BACKFACE CULLING che serve a rimuovere le superfici di un oggetto solido coperte alla vista in quanto nascoste da altre superfici visibili dello stesso oggetto. Uno dei metodi per individuare le superfici da rimuovere è quello di adoperare le normali alle stesse superfici; qualora la normale è orientata verso l’osservatore il poligono è detto FRONTFACING ed è visibile; in caso contrario è definito BACKFACING e risulta invisibile.
Matematicamente, si effettua il prodotto scalare tra il vettore che rappresenta la normale alla superficie del poligono in un punto (N) e quello che rappresenta il raggio visivo che arriva in quello stesso punto (V). Se N*V>0 allora si rimuove la superficie, in caso contrario il poligono è visibile.
Nel caso di oggetti convessi racchiusi da una superficie poligonale chiusa, i poligoni backfacing sono sempre nascosti da quelli frontfacing.
Questa soluzione permette di arrivare a rimuovere, mediamente, il 50% dei poligoni nascosti ma non è molto efficiente, in quanto è possibile conoscere le orientazioni dei poligono dopo le trasformazioni geometriche.
Per aumentare ulteriormente l’efficienza, sarebbe opportuno, però, rimuovere questi poligoni nascosti in fase di preprocessing; per farlo si ricorre ad alcuni algoritmi tra i quali quello che fa uso di NORMAL MASK, di cui non approfondiremo la conoscenza (qui si vuole solo dare un’idea del tipo di operazioni necessarie alla costruzione di un’immagine 3D senza entrare nello specifico di come queste operazioni vengono realmente eseguite).
A questo punto, abbiamo posto un osservatore nel nostro spazio, definito il suo punto di vista ed il suo campo visivo, rimossi tutti i poligoni (o quasi) che non cadono all’interno del VF e quelli nascosti da altri poligoni FACENTI PARTE DELLO STESSO OGGETTO. Bisogna iniziare a pensare alla destinazione finale dell’immagine, ovvero il monitor. La sua forma rettangolare mal si adatta ad uno spazio a forma di tronco di piramide. Quindi, il passo successivo è quello di PROIETTARE l’immagine del clip space all’interno di un altro spazio a forma di cubo con le coordinate X, Y che possono variare tra -1 e +1. e la Z da 0 (per il near clipping plane) a 1 (per il far clipping plane) in D3D e da -1 a +1 in OpenGL.
L’adozione di queste coordinate rende molto agevoli le operazioni di trasformazione che si effettuano in questo spazio.
Il clip space è uno spazio intrinsecamente privo di prospettiva contenente oggetti che, invece, presentano una deformazione prospettica determinata dall’operazione di proiezione dal view space.
I passaggi sopra descritti, non avvengono necessariamente nell’ordine in cui sono stati esposti; ad esempio, le operazioni di culling possono avvenire nel clip space, come pure quelle di lightning che possono aver luogo nel view space o nel clip space.
A questo punto restano ancora alcune cose da fare: eliminare le superfici nascoste da altri oggetti (occlusion culling) e trasformare uno spazio 3D in uno 2D.