progettazione e realizzazione di una libreria basata su opengl per il ...
progettazione e realizzazione di una libreria basata su opengl per il ...
progettazione e realizzazione di una libreria basata su opengl per il ...
Trasformi i suoi PDF in rivista online e aumenti il suo fatturato!
Ottimizzi le sue riviste online per SEO, utilizza backlink potenti e contenuti multimediali per aumentare la sua visibilità e il suo fatturato.
UNIVERSITÀ DEGLI STUDI DI MILANO<br />
Facoltà <strong>di</strong> Scienze Matematiche, Fisiche e Naturali<br />
Corso <strong>di</strong> Laurea Triennale in Informatica<br />
PROGETTAZIONE E REALIZZAZIONE<br />
DI UNA LIBRERIA BASATA SU<br />
OPENGL PER IL CARICAMENTO E LA<br />
GESTIONE IN TEMPO REALE DI<br />
MODELLI TRIDIMENSIONALI DAL<br />
FORMATO 3DSTUDIO<br />
Relatore: Prof. Daniele MARINI<br />
Correlatori: Dott. Stefano MOTTURA<br />
Dott. Giovanni Paolo VIGAN Ò<br />
Anno Accademico 2002-2003<br />
Tesi <strong>di</strong> Laurea <strong>di</strong>:<br />
Alessandro MULLONI<br />
Matricola n. 654024
Ringraziamenti<br />
Ringrazio <strong>il</strong> <strong>di</strong>rettore dell’ITIA-CNR Prof. Francesco Jovane<br />
<strong>per</strong> aver messo a mia <strong>di</strong>sposizione tutte le strutture e le<br />
strumentazioni dell’ITIA-CNR;<br />
<strong>il</strong> Dott. Stefano Mottura <strong>per</strong> la <strong>su</strong>a pazienza nel seguirmi<br />
durante l’intero <strong>per</strong>iodo <strong>di</strong> tesi;<br />
<strong>il</strong> Dott. Giampaolo Viganò <strong>per</strong> i consigli e i <strong>su</strong>ggerimenti<br />
che hanno chiarito molti dubbi;<br />
<strong>il</strong> Dott. Emanuele Travaini e <strong>il</strong> Dott. Luca Greci<br />
<strong>per</strong> la gent<strong>il</strong>ezza, la simpatia e la <strong>di</strong>sponib<strong>il</strong>ità <strong>di</strong>mostrate;<br />
<strong>il</strong> Dott. Marco Sacco <strong>per</strong> la <strong>su</strong>a cor<strong>di</strong>alità;<br />
<strong>il</strong> Prof. Daniele Marini <strong>per</strong> <strong>il</strong> sostegno accademico che dà<br />
alla grafica 3D ed al game programming.<br />
Ringrazio <strong>il</strong> papà Roberto e la mamma Angela<br />
<strong>per</strong> <strong>il</strong> continuo <strong>su</strong>pporto che sempre mi hanno fornito,<br />
<strong>per</strong> tutti i sogni che tale <strong>su</strong>pporto ha realizzato,<br />
<strong>per</strong> tutti i sogni che realizzerà.
In<strong>di</strong>ce<br />
In<strong>di</strong>ce i<br />
Elenco delle figure v<br />
1 Prefazione 1<br />
2 La realtà virtuale 3<br />
2.1 Origine del termine . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />
2.2 Gli esor<strong>di</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />
2.3 L’evoluzione negli anni <strong>su</strong>ccessivi . . . . . . . . . . . . . . . . . . . . 5<br />
2.4 Gli anni ’80: la prima commercializzazione della realtà virtuale . . . . 6<br />
2.5 Realtà virtuale negli anni ’90 . . . . . . . . . . . . . . . . . . . . . . 7<br />
2.6 La realtà virtuale ai nostri giorni . . . . . . . . . . . . . . . . . . . . 9<br />
2.7 Il sistema <strong>di</strong> realtà virtuale . . . . . . . . . . . . . . . . . . . . . . . . 10<br />
3 La grafica 3D in tempo reale 13<br />
3.1 La nascita e l’evoluzione delle librerie grafiche 3D . . . . . . . . . . . 13<br />
3.1.1 Il Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />
3.1.2 Il GKS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />
3.1.3 Le altre librerie alla fine degli anni ’80 . . . . . . . . . . . . . 15<br />
3.1.4 OpenGL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />
3.1.5 Direct3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
3.2 Le librerie <strong>di</strong> vi<strong>su</strong>alizzazione . . . . . . . . . . . . . . . . . . . . . . . 18<br />
3.3 I modelli e i loader . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />
3.4 I loader 3DS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
i
INDICE ii<br />
4 Introduzione al lavoro <strong>di</strong> tesi 21<br />
5 Il Loader 24<br />
5.1 L’interfaccia e <strong>il</strong> runtime bin<strong>di</strong>ng . . . . . . . . . . . . . . . . . . . . 24<br />
5.2 La struttura <strong>di</strong> un f<strong>il</strong>e 3DS . . . . . . . . . . . . . . . . . . . . . . . . 26<br />
5.3 Il Loader 3DS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />
5.4 L’inizializzazione prima del parsing . . . . . . . . . . . . . . . . . . . 28<br />
5.5 Le tre fasi <strong>di</strong> parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
5.5.1 I materiali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
5.5.2 Gli oggetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />
5.5.3 La gerarchia . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />
5.6 Il postprocessing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />
5.6.1 La correzione degli errori . . . . . . . . . . . . . . . . . . . . . 36<br />
5.6.2 L’applicazione delle trasformazioni geometriche . . . . . . . . 38<br />
5.6.3 La collocazione <strong>di</strong> queste o<strong>per</strong>azioni . . . . . . . . . . . . . . . 39<br />
6 La gestione della gerarchia 40<br />
6.1 Le funzionalità <strong>per</strong> l’ut<strong>il</strong>izzo della gerarchia . . . . . . . . . . . . . . . 40<br />
6.2 L’importanza <strong>di</strong> <strong>una</strong> gerarchia . . . . . . . . . . . . . . . . . . . . . . 41<br />
6.3 Boun<strong>di</strong>ng box e centro <strong>di</strong> un oggetto . . . . . . . . . . . . . . . . . . 43<br />
6.4 Il culling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />
6.5 Le trasformazioni geometriche in tempo reale . . . . . . . . . . . . . . 55<br />
6.6 L’or<strong>di</strong>namento dei figli . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />
7 La gestione del rendering 62<br />
7.1 Le funzionalità a <strong>su</strong>pporto del rendering . . . . . . . . . . . . . . . . 62<br />
7.2 Le texture <strong>su</strong>pportate . . . . . . . . . . . . . . . . . . . . . . . . . . . 63<br />
7.2.1 Texture <strong>di</strong> colore <strong>di</strong>ffusivo . . . . . . . . . . . . . . . . . . . . 65<br />
7.2.2 Mappa <strong>di</strong> riflessione ambientale . . . . . . . . . . . . . . . . . 66<br />
7.2.3 Texture <strong>di</strong> colore speculare . . . . . . . . . . . . . . . . . . . . 68<br />
7.2.4 Mappa <strong>di</strong> riflessività . . . . . . . . . . . . . . . . . . . . . . . 69<br />
7.2.5 Texture <strong>di</strong> colore emissivo . . . . . . . . . . . . . . . . . . . . 70<br />
7.2.6 Bump mapping . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />
7.2.7 Mappa <strong>di</strong> luminosità . . . . . . . . . . . . . . . . . . . . . . . 72
INDICE iii<br />
7.2.8 Mappa <strong>di</strong> opacità . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />
7.3 Il rendering multipassata . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />
7.3.1 Lo stenc<strong>il</strong> buffer . . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />
7.3.2 Lo z-buffer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />
7.3.3 Il blen<strong>di</strong>ng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />
7.3.4 L’algoritmo ut<strong>il</strong>izzato . . . . . . . . . . . . . . . . . . . . . . . 78<br />
7.3.5 L’or<strong>di</strong>ne delle texture . . . . . . . . . . . . . . . . . . . . . . . 80<br />
7.4 I materiali trasparenti . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />
8 Demo e Benchmark 84<br />
8.1 Il programma <strong>di</strong>mostrativo . . . . . . . . . . . . . . . . . . . . . . . . 84<br />
8.2 Benchmark . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />
9 Conclusioni e sv<strong>il</strong>uppi futuri 89<br />
9.1 Conclusioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />
9.2 Sv<strong>il</strong>uppi futuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />
A Il formato 3DS 91<br />
A.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />
A.2 I chunk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />
B Le estensioni OpenGL 100<br />
B.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
B.2 Elenco delle estensioni presenti . . . . . . . . . . . . . . . . . . . . . 100<br />
B.3 Ut<strong>il</strong>izzare le estensioni OpenGL . . . . . . . . . . . . . . . . . . . . . 101<br />
B.4 Le estensioni ut<strong>il</strong>izzate nella presente <strong>libreria</strong> . . . . . . . . . . . . . . 101<br />
C Il frustum culling 104<br />
C.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104<br />
C.2 Il calcolo del frustum . . . . . . . . . . . . . . . . . . . . . . . . . . . 104<br />
C.3 Il frustum culling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />
D Il bump mapping 110<br />
D.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110<br />
D.2 La texture <strong>di</strong> bump mapping . . . . . . . . . . . . . . . . . . . . . . . 111
INDICE iv<br />
D.3 L’embossing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />
E L’algoritmo <strong>di</strong> or<strong>di</strong>namento 120<br />
E.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />
E.2 Distanza fra un poligono ed <strong>il</strong> punto <strong>di</strong> vista . . . . . . . . . . . . . . 120<br />
E.3 Distanza fra un nodo della gerarchia ed <strong>il</strong> punto <strong>di</strong> vista . . . . . . . 122<br />
E.4 L’algoritmo <strong>di</strong> or<strong>di</strong>namento . . . . . . . . . . . . . . . . . . . . . . . 122<br />
F I quaternioni e la rotazione 125<br />
F.1 Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />
F.2 Matematica base dei quaternioni . . . . . . . . . . . . . . . . . . . . 127<br />
F.3 Rotazione con i quaternioni . . . . . . . . . . . . . . . . . . . . . . . 128<br />
G Screenshot della demo realizzata 129<br />
G.1 Demo 1: la gerarchia e le trasformazioni geometriche in tempo reale . 129<br />
G.2 Demo 2: bump mapping . . . . . . . . . . . . . . . . . . . . . . . . . 131<br />
G.3 Demo 3: trasparenza e mo<strong>di</strong>fica delle texture in tempo reale . . . . . 133<br />
G.4 Demo 4: mappe <strong>di</strong> luminosità ed integrazione fra modelli importati<br />
da formati <strong>di</strong>fferenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134<br />
Bibliografia 136
Elenco delle figure<br />
2.1 Il Sensorama <strong>di</strong> Morton He<strong>il</strong>ig, 1956 . . . . . . . . . . . . . . . . . . . . 4<br />
2.2 L’HMD <strong>di</strong> Evans e Sutherland . . . . . . . . . . . . . . . . . . . . . . . 5<br />
2.3 Il Videoplace <strong>di</strong> Myron Krueger . . . . . . . . . . . . . . . . . . . . . . 6<br />
2.4 Il DataGlove della VPL . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />
2.5 CAVE Automatic Virtual Environment . . . . . . . . . . . . . . . . . . 8<br />
2.6 ImmersaDesk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />
2.7 Occhiali <strong>per</strong> proiezione attiva (a sinistra) e passiva (a destra) . . . . . . . 10<br />
2.8 Un esempio <strong>di</strong> sistema <strong>di</strong> realtà virtuale . . . . . . . . . . . . . . . . . . 11<br />
3.1 Un’immagine generata tramite PHIGS . . . . . . . . . . . . . . . . . . . 16<br />
3.2 La scena <strong>di</strong> figura 3.1 ricreata con OpenGL . . . . . . . . . . . . . . . . 17<br />
4.1 La <strong>di</strong>visione fra formato e semantica . . . . . . . . . . . . . . . . . . . . 22<br />
5.1 Il late bin<strong>di</strong>ng nella classe Loader . . . . . . . . . . . . . . . . . . . . . 25<br />
5.2 La struttura base <strong>di</strong> un f<strong>il</strong>e 3DS . . . . . . . . . . . . . . . . . . . . . . 26<br />
5.3 Le tre fasi della procedura load f<strong>il</strong>e . . . . . . . . . . . . . . . . . . . . . 29<br />
5.4 Le tre fasi <strong>di</strong> parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />
5.5 La struttura <strong>di</strong> un materiale . . . . . . . . . . . . . . . . . . . . . . . . 32<br />
5.6 La struttura <strong>di</strong> un oggetto . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />
5.7 La struttura <strong>di</strong> un nodo della gerarchia . . . . . . . . . . . . . . . . . . 35<br />
6.1 Le trasformazioni geometriche <strong>su</strong> un nodo si <strong>di</strong>ffondono <strong>su</strong>l <strong>su</strong>o sottoalbero 42<br />
6.2 Con <strong>una</strong> semplice o<strong>per</strong>azione logica si può sostituire l’oggetto Automob<strong>il</strong>e<br />
1 con l’oggetto Automob<strong>il</strong>e 2 lasciando invariato <strong>il</strong> resto della gerarchia . . 44<br />
6.3 Boun<strong>di</strong>ng box minima (in grigio) e <strong>di</strong> rapida computazione (in nero) . . . 45<br />
v
ELENCO DELLE FIGURE vi<br />
6.4 Il culling scarta la porzione <strong>di</strong> scena che non cade all’interno del campo <strong>di</strong><br />
vista. La parte <strong>di</strong> scena non scartata è stata scurita . . . . . . . . . . . . 51<br />
6.5 La pipeline grafica OpenGL. Informazioni geometriche (Vertex data) e<br />
informazioni raster (Pixel data) dopo varie o<strong>per</strong>azioni computazionalmente<br />
costose convergono a formare <strong>il</strong> frame che verrà vi<strong>su</strong>alizzato (contenuto nel<br />
Framebuffer) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />
6.6 Culling <strong>di</strong> punti e <strong>di</strong> poligoni: P0 viene mantenuto, P1 è scartato. T0 è<br />
mantenuto interamente, T1 solo parzialmente, T2 è scartato (in grigio le<br />
parti mantenute) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
6.7 Un parallelepipedo con i lati paralleli ai tre assi definisce <strong>su</strong> ciascun asse<br />
un intervallo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />
6.8 Trasformazione da coor<strong>di</strong>nate della vista a Clipping Coor<strong>di</strong>nate . . . . . . 54<br />
6.9 Blen<strong>di</strong>ng errato (in alto) e corretto (in basso) fra due oggetti . . . . . . . 60<br />
7.1 La modulazione fra <strong>il</strong> riflesso <strong>di</strong>ffusivo e la texture <strong>di</strong> colore <strong>di</strong>ffusivo (A)<br />
ricrea l’oggetto (B) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65<br />
7.2 Si nota come l’immagine della texture originale applicata <strong>su</strong> <strong>una</strong> semisfera<br />
(A) appaia come riflessa <strong>su</strong>l modello 3D (B) se lo si inscrive all’interno<br />
della semisfera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<br />
7.3 Si nota come l’immagine delle sei texture originali applicate <strong>su</strong> un cubo<br />
(A) appaiano come riflesse <strong>su</strong>l modello 3D (B) se lo si inscrive all’interno<br />
del cubo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<br />
7.4 La modulazione fra <strong>il</strong> riflesso speculare e la texture <strong>di</strong> colore speculare (A)<br />
ricrea l’oggetto (B) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />
7.5 La riflessività dell’etichetta <strong>su</strong>ll’estintore a destra è stata annullata <strong>per</strong><br />
mezzo <strong>di</strong> <strong>una</strong> mappa <strong>di</strong> riflessività . . . . . . . . . . . . . . . . . . . . . 69<br />
7.6 I fanali <strong>di</strong> un automob<strong>il</strong>e appaiono accesi nell’immagine <strong>di</strong> destra grazie<br />
all’uso <strong>di</strong> <strong>una</strong> texture <strong>di</strong> colore emissivo . . . . . . . . . . . . . . . . . . 70<br />
7.7 Una <strong>su</strong><strong>per</strong>ficie senza (a sinistra) e con (al centro e a destra) bump mapping<br />
(si noti nelle ultime due immagini come le ombre dei mattoni in r<strong>il</strong>ievo<br />
varino in funzione della posizione della luce) . . . . . . . . . . . . . . . . 71<br />
7.8 Il bump mapping <strong>su</strong> un materiale lucido è quasi im<strong>per</strong>cettib<strong>il</strong>e (A) se non<br />
si ut<strong>il</strong>izza la simulazione <strong>di</strong> ruvi<strong>di</strong>tà (B) . . . . . . . . . . . . . . . . . . 73
ELENCO DELLE FIGURE vii<br />
7.9 Nei poligoni l’<strong>il</strong>luminazione calcolata <strong>per</strong> vertice (A) in base ai vettori<br />
normali non è precisa quanto quella calcolata <strong>per</strong> pixel (B) . . . . . . . . 74<br />
7.10 Illuminazione in tempo reale (a sinistra) e precalcolata (a destra) (si noti<br />
la migliore resa delle ombreggiature nella seconda) . . . . . . . . . . . . . 75<br />
7.11 La trasparenza <strong>di</strong> un pannello <strong>di</strong> vetro decorato (A) può essere modulata<br />
in maniera non uniforme <strong>per</strong> mezzo <strong>di</strong> <strong>una</strong> mappa <strong>di</strong> opacità (B) . . . . . 75<br />
7.12 Interpretazione grafica dei valori scritti nello stenc<strong>il</strong> buffer dall’algoritmo<br />
implementato durante <strong>il</strong> rendering (0 = nero, 1 = bianco) . . . . . . . . . 77<br />
8.1 Un modello 3DS rappresentante <strong>una</strong> vasta zona rurale . . . . . . . . . . . 87<br />
9.1 Un’ambientazione caricata <strong>per</strong> mezzo del loader <strong>di</strong> f<strong>il</strong>e BSP . . . . . . . . 90<br />
A.1 La struttura a blocchi dei f<strong>il</strong>e 3DS . . . . . . . . . . . . . . . . . . . . . 91<br />
A.2 I chunk caricati dalla classe Loader3DS . . . . . . . . . . . . . . . . . 93<br />
C.1 I sei piani che definiscono <strong>il</strong> volume del frustum <strong>di</strong> vista . . . . . . . . . . 108<br />
C.2 Solamente i poligoni completamente all’interno <strong>di</strong> uno semispazio negativo<br />
vengono eliminati. Per questo motivo la boun<strong>di</strong>ng box B0 viene scartata<br />
dal frustum culling, mentre B1 viene mantenuta . . . . . . . . . . . . . . 109<br />
D.1 Una texture <strong>di</strong> bump mapping <strong>per</strong> <strong>il</strong> pianeta Terra . . . . . . . . . . . . 111<br />
D.2 La somma fra la texture <strong>di</strong> bump mapping e la <strong>su</strong>a inversa genera <strong>una</strong><br />
texture uniforme grigia . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />
D.3 Se la texture <strong>di</strong> bump mapping viene scostata rispetto alla <strong>su</strong>a inversa la<br />
loro somma genera due <strong>di</strong>slivelli <strong>di</strong> colore, uno più scuro ed uno più chiaro 113<br />
D.4 Un triangolo con le coor<strong>di</strong>nate <strong>di</strong> texture dei vari vertici . . . . . . . . . . 114<br />
D.5 Sono stati i calcolati i versori <strong>di</strong> avanzamento delle coor<strong>di</strong>nate <strong>di</strong> texture<br />
D.6<br />
<strong>per</strong> <strong>il</strong> triangolo <strong>di</strong> Figura D.4 (sono mostrati solo quelli <strong>per</strong> P 0) . . . . . . 116<br />
È necessario calcolare <strong>il</strong> versore con <strong>di</strong>rezione uguale a quella della luce<br />
e verso opposto. Calcolando la norma della <strong>su</strong>a proiezione <strong>su</strong>l versore<br />
<strong>di</strong> avanzamento della coor<strong>di</strong>nata <strong>di</strong> texture si ottiene lo scostamento da<br />
applicare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
ELENCO DELLE FIGURE viii<br />
E.1 Sistema <strong>di</strong> riferimento globale (A) e sistema <strong>di</strong> riferimento della vista (B).<br />
La trasformazione della vista porta <strong>il</strong> punto <strong>di</strong> vista nell’origine degli assi<br />
ed orienta la <strong>di</strong>rezione della vista lungo l’asse z . . . . . . . . . . . . . . 121<br />
F.1 Rotazione con i tre angoli <strong>di</strong> Eulero (A) e con un angolo ed un asse generico<br />
(B) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />
F.2 Una doppia rotazione <strong>di</strong> 90 ◦ eseguita <strong>su</strong> (A) causa la sovrapposizione <strong>di</strong><br />
due assi (B) con la <strong>per</strong><strong>di</strong>ta <strong>di</strong> un grado <strong>di</strong> libertà . . . . . . . . . . . . . 126<br />
G.1 Un modello rappresentante <strong>una</strong> vasta area rurale. Esso è composto da<br />
23519 facce triangolari memorizzate in <strong>una</strong> gerarchia formata da 2902 no<strong>di</strong><br />
(cfr. Capitolo 6) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129<br />
G.2 Un nodo della gerarchia viene aggiunto e mo<strong>di</strong>ficato senza influenzare <strong>il</strong><br />
resto del modello (cfr. Capitolo 6) . . . . . . . . . . . . . . . . . . . . . 130<br />
G.3 I due mezzi appaiono in movimento <strong>su</strong>lla strada grazie all’applicazione in<br />
tempo reale <strong>di</strong> <strong>una</strong> traslazione variab<strong>il</strong>e nel tempo (cfr. 6.5) . . . . . . . . 130<br />
G.4 Quando la luce si sposta le ombre <strong>su</strong> un pavimento con bump mapping<br />
ab<strong>il</strong>itato variano (cfr. 7.2.6) . . . . . . . . . . . . . . . . . . . . . . . . 131<br />
G.5 Quando la luce si sposta le ombre <strong>su</strong> un muro <strong>di</strong> mattoni con bump<br />
mapping ab<strong>il</strong>itato variano (cfr. 7.2.6) . . . . . . . . . . . . . . . . . . . 132<br />
G.6 Un pannello semitrasparente posto al centro <strong>di</strong> <strong>una</strong> stanza rivestita <strong>di</strong><br />
piastrelle (cfr. 6.6) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />
G.7 La texture del pannello trasparente viene mo<strong>di</strong>ficata in tempo reale in<br />
maniera da simulare la proiezione <strong>di</strong> <strong>una</strong> animazione <strong>su</strong> <strong>di</strong> esso (cfr. 7.2) . 133<br />
G.8 La trasparenza del pannello è uniforme nell’immagine a sinistra, modulata<br />
in maniera non uniforme <strong>per</strong> mezzo <strong>di</strong> <strong>una</strong> mappa <strong>di</strong> opacità nel pannello<br />
<strong>di</strong> destra (cfr. 7.2 e 7.2.8) . . . . . . . . . . . . . . . . . . . . . . . . . 134<br />
G.9 Nella scena <strong>di</strong> sinistra l’<strong>il</strong>luminazione è calcolata in tempo reale, nella scena<br />
<strong>di</strong> destra sono sfruttate le mappe <strong>di</strong> luminosità (cfr. 7.2.7) . . . . . . . . 134<br />
G.10 L’ambiente è stato importato da un f<strong>il</strong>e BSP (cfr. 9.2) mentre la teiera è<br />
stata importata da un f<strong>il</strong>e 3DS (cfr. 3.4). Come si può notare l’in<strong>di</strong>pen-<br />
denza dal formato <strong>di</strong> provenienza delle classi Group e Object (cfr. Capitolo<br />
4) consente <strong>una</strong> totale integrazione fra modelli provenienti da tipi <strong>di</strong> f<strong>il</strong>e<br />
<strong>di</strong>fferenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
CAPITOLO 1<br />
Prefazione<br />
Il presente lavoro <strong>di</strong> tesi è stato svolto presso l’Istituto <strong>di</strong> Tecnologie Industriali e<br />
Automazione del Consiglio Nazionale delle Ricerche (ITIA-CNR), la cui attività si<br />
colloca nella ricerca applicata <strong>per</strong> l’automazione industriale e <strong>per</strong> <strong>il</strong> sostegno dell’in-<br />
novazione dell’impresa. Le problematiche <strong>su</strong> cui l’ITIA lavora variano dal campo<br />
della <strong>progettazione</strong>, alla robotica e l’automazione.<br />
All’interno dell’istituto o<strong>per</strong>a <strong>il</strong> gruppo VME (Virtual Manufacturing Environment),<br />
che focalizza la propria attività <strong>su</strong>llo stu<strong>di</strong>o, l’ideazione e la <strong>realizzazione</strong> <strong>di</strong> ambienti<br />
immersivi <strong>di</strong> realtà virtuale. Gli ambienti immersivi sono ut<strong>il</strong>izzati <strong>per</strong> seguire varie<br />
fasi <strong>di</strong> sv<strong>il</strong>uppo <strong>di</strong> un prodotto, a partire dal design sino alla gestione dell’impian-<br />
tistica della catena <strong>di</strong> montaggio. Le applicazioni sv<strong>il</strong>uppate fanno ovviamente un<br />
uso intensivo <strong>di</strong> grafica 3D in tempo reale.<br />
Fino a qualche anno fa i calcolatori ut<strong>il</strong>izzati dall’ITIA <strong>per</strong> le applicazioni 3D im-<br />
mersive erano tutti macchine S<strong>il</strong>icon Graphics. Tali computer, in quanto prodotti<br />
specialistici ad alte prestazioni (ne fanno uso anche aziende cinematografiche e <strong>di</strong><br />
grafica non in tempo reale <strong>per</strong> le loro elevate potenzialità <strong>di</strong> rendering), erano e sono<br />
tuttora venduti a prezzi piuttosto elevati. Anche i costi del software ri<strong>su</strong>ltavano inci-<br />
sivi, poiché un gruppo <strong>di</strong> ricerca con un vasto ambito <strong>di</strong> <strong>per</strong>tinenza come <strong>il</strong> VME non<br />
può limitarsi ad un ut<strong>il</strong>izzo a lungo termine <strong>di</strong> un unico pacchetto software specifico<br />
in quanto tale specificità è in conflitto con l’elevata variab<strong>il</strong>ità degli obiettivi nel<br />
tempo. Il software che veniva eseguito era principalmente della Multigen-Para<strong>di</strong>gm,<br />
<strong>una</strong> <strong>di</strong>tta fornitrice <strong>di</strong> prodotti professionali che necessitano <strong>di</strong> un continuo rinno-<br />
vamento <strong>di</strong> licenze d’uso, talvolta non solo da parte dello sv<strong>il</strong>uppatore ma anche da<br />
parte dell’utente finale.<br />
1
CAPITOLO 1. PREFAZIONE 2<br />
Negli ultimi tempi l’avvento <strong>di</strong> schede grafiche <strong>per</strong> PC e librerie che sfruttino le loro<br />
potenzialità – in grado <strong>di</strong> competere <strong>su</strong>l rapporto prestazioni/prezzo con le macchine<br />
e gli ambienti <strong>di</strong> sv<strong>il</strong>uppo precedentemente ut<strong>il</strong>izzati dall’ente – ha fatto nascere<br />
all’interno del team <strong>di</strong> sv<strong>il</strong>uppo <strong>il</strong> desiderio <strong>di</strong> muoversi verso nuove metodologie più<br />
economiche e più flessib<strong>il</strong>i <strong>per</strong> la <strong>realizzazione</strong> dei propri applicativi. Già da qualche<br />
anno <strong>il</strong> VME si è <strong>per</strong>ciò dotato <strong>di</strong> alcuni Personal Computer – che ora o<strong>per</strong>ano al<br />
fianco delle workstation S<strong>il</strong>icon Graphics – e de<strong>di</strong>ca parte dei <strong>su</strong>oi sforzi allo stu<strong>di</strong>o<br />
e l’implementazione <strong>di</strong> nuove soluzioni ut<strong>il</strong>izzando le librerie grafiche OpenGL.<br />
Lo spostamento graduale verso questi nuovi ambienti ha apportato la necessità <strong>di</strong><br />
<strong>una</strong> base software che, o<strong>per</strong>ando ad un livello leggermente <strong>su</strong><strong>per</strong>iore alle OpenGL,<br />
ma facendolo in maniera trasparente, fornisca delle funzioni elementari <strong>per</strong> la ge-<br />
stione <strong>di</strong> ambienti tri<strong>di</strong>mensionali. Uno degli scopi principali <strong>di</strong> tale <strong>libreria</strong> – creata<br />
internamente all’istituto <strong>per</strong> l’istituto – è <strong>di</strong> non riproporre le limitazioni inevitab<strong>il</strong>-<br />
mente imposte da un pacchetto software commerciale prodotto da terzi, prima fra<br />
le quali la bassa possib<strong>il</strong>ità <strong>di</strong> interazione con gli strati software sottostanti.<br />
All’interno <strong>di</strong> questo progetto si colloca questo lavoro <strong>di</strong> tesi, integrandosi con <strong>una</strong><br />
precedente parte della <strong>libreria</strong> incaricata della gestione <strong>di</strong> telecamere, luci, gerarchie<br />
della scena e posizionamento degli oggetti nello spazio, con lo scopo <strong>di</strong> fornire agli svi-<br />
luppatori routine <strong>per</strong> un’agevole importazione e rendering <strong>di</strong> modelli tri<strong>di</strong>mensionali<br />
nelle applicazioni.
2.1 Origine del termine<br />
CAPITOLO 2<br />
La realtà virtuale<br />
Il termine Virtual Reality (Realtà Virtuale) fu coniato nel 1989 da Jaron Lanier –<br />
fondatore della VPL Research – programmatore, inventore e artista. Egli presentava<br />
la realtà virtuale come “<strong>il</strong> primo me<strong>di</strong>um che non limiti l’anima dell’uomo” (J.<br />
Lanier). A quei tempi VR in<strong>di</strong>cava unicamente la Immersive Virtual Reality (Realtà<br />
Virtuale Immersiva), un sottoinsieme <strong>di</strong> ciò che oggi comunemente si intende quando<br />
si ut<strong>il</strong>izza la medesima parola.<br />
Fra i sinonimi ut<strong>il</strong>izzati nel corso del tempo si possono citare in or<strong>di</strong>ne cronologico<br />
Realtà Artificiale (Myron Krueger, anni ’70), Cyberspazio (W<strong>il</strong>liam Gibson, 1984) e<br />
i più recenti Mon<strong>di</strong> Virtuali e Ambienti Virtuali (anni ’90). [BEI03, BAC00]<br />
2.2 Gli esor<strong>di</strong><br />
Gli stu<strong>di</strong> <strong>di</strong> ricerca nel campo della realtà virtuale risalgono in realtà ad un paio<br />
<strong>di</strong> decenni prima della VPL. Il primo <strong>di</strong>spositivo in grado <strong>di</strong> fornire un’es<strong>per</strong>ien-<br />
za immersiva al <strong>su</strong>o utente era <strong>il</strong> Sensorama, <strong>una</strong> macchina dotata <strong>di</strong> proiezione<br />
stereoscopica, <strong>su</strong>ono stereo, simulatore <strong>di</strong> vento e <strong>di</strong>ffusore <strong>di</strong> odori. Tutto era pre-<br />
registrato, <strong>per</strong> cui questa prima es<strong>per</strong>ienza ri<strong>su</strong>ltava piuttosto passiva. Il Sensorama<br />
era stato progettato da un cinematografo <strong>di</strong> Hollywood, Morton He<strong>il</strong>ig e riprodu-<br />
ceva varie situazioni realistiche – fra cui un viaggio in motocicletta <strong>per</strong> le strade <strong>di</strong><br />
Brooklyn – coinvolgendo artificialmente gran parte dei sensi <strong>di</strong> chi vi si sedeva <strong>di</strong><br />
3
CAPITOLO 2. LA REALTÀ VIRTUALE 4<br />
Figura 2.1: Il Sensorama <strong>di</strong> Morton He<strong>il</strong>ig, 1956<br />
fronte e offrendogli “la realtà <strong>per</strong> un nichelino” (M. He<strong>il</strong>ig). Era a tutti gli effet-<br />
ti un videogioco <strong>di</strong> realtà virtuale. Tuttavia né i videogiochi né la realtà virtuale<br />
esistevano ancora.<br />
L’Head Mounted Display (Schermo posizionato <strong>su</strong>lla testa) fu presentato nel 1968 da<br />
Ivan Sutherland, cofondatore della Evans & Sutherland, azienda ancora in attività<br />
ed es<strong>per</strong>ta nel settore <strong>di</strong> simulazioni grafiche immersive <strong>per</strong> addestramenti. Esso<br />
funzionava sovrapponendo immagini in wireframe alla realtà circostante 1 , e posse-<br />
deva anche un sistema <strong>di</strong> tracciamento della posizione della testa, <strong>di</strong>sponib<strong>il</strong>e sia<br />
meccanico che a ultra<strong>su</strong>oni.<br />
Negli stessi anni nascevano anche i primi sistemi tatt<strong>il</strong>i. Il GROPE dell’Università<br />
del North Carolina consisteva in un braccio robotico con sei gra<strong>di</strong> <strong>di</strong> libertà dotato<br />
<strong>di</strong> motori. I motori erano attivati dall’ambiente virtuale <strong>per</strong> simulare i campi <strong>di</strong><br />
forza fra atomi presenti nelle molecole, che venivano mostrate in 3D <strong>su</strong> un <strong>di</strong>splay.<br />
1 Questo tipo <strong>di</strong> sistema è denominato “realtà aumentata” ed è caratterizzato dalla sovraimpressione<br />
<strong>di</strong> elementi virtuali alla realtà circostante.
CAPITOLO 2. LA REALTÀ VIRTUALE 5<br />
Figura 2.2: L’HMD <strong>di</strong> Evans e Sutherland<br />
La navigazione avveniva tramite <strong>il</strong> medesimo braccio. [COH00, STE01]<br />
2.3 L’evoluzione negli anni <strong>su</strong>ccessivi<br />
La ricerca dei due decenni che seguirono fu incentrata <strong>su</strong>llo sv<strong>il</strong>uppo delle tecniche <strong>di</strong><br />
tracciamento, vi<strong>su</strong>alizzazione e interfacciamento tatt<strong>il</strong>e sv<strong>il</strong>uppate dai pionieri degli<br />
anni ’60.<br />
Fra i più celebri ri<strong>su</strong>ltati ottenuti si possono elencare i Virtual Pushbuttons (Pulsanti<br />
virtuali) <strong>di</strong> Knowlton (1975), <strong>una</strong> tastiera inclinata <strong>su</strong> cui ad <strong>una</strong> certa <strong>di</strong>stanza era<br />
posto un vetro semitrasparente <strong>per</strong> la proiezione <strong>di</strong> immagini virtuali, in maniera tale<br />
che l’utente avesse l’<strong>il</strong>lusione <strong>di</strong> premere ciò che era proiettato, e non la pulsantiera<br />
sottostante; <strong>il</strong> LEEP (Large Expanse, Extra Perspective), un binocolo in grado <strong>di</strong><br />
fornire un campo <strong>di</strong> vista <strong>su</strong>l mondo virtuale <strong>di</strong> 140 ◦ ; la Videopostazione <strong>di</strong> Krueger,<br />
che tramite <strong>una</strong> telecamera consentiva all’utente <strong>di</strong> interagire con <strong>il</strong> mondo virtuale<br />
<strong>per</strong> mezzo <strong>di</strong> gesti. [COH00]
CAPITOLO 2. LA REALTÀ VIRTUALE 6<br />
Figura 2.3: Il Videoplace <strong>di</strong> Myron Krueger<br />
2.4 Gli anni ’80: la prima commercializzazione della realtà<br />
virtuale<br />
Le ricerche nel campo della realtà virtuale continuavano e apportavano nuovi prodot-<br />
ti quali <strong>il</strong> Virtual Cockpit (Cabina <strong>di</strong> p<strong>il</strong>otaggio virtuale) e altri strumenti immersivi.<br />
Nel frattempo qualcos’altro si stava <strong>per</strong>ò muovendo in un ambiente fino ad allora<br />
abbastanza lontano dalla VR: le aziende. La fondazione della VPL da parte <strong>di</strong><br />
Jaron Lanier è datata 1985. Essa era la prima società che si de<strong>di</strong>casse a progetti<br />
<strong>di</strong> realtà virtuale. I prodotti della VPL spaziavano dagli strumenti <strong>di</strong> input tatt<strong>il</strong>e<br />
(DataGlove) all’output visivo (EyePhone) e sonoro (Au<strong>di</strong>oSphere).<br />
Un ulteriore f<strong>il</strong>one si andava evolvendo: erano da poco sorti i primi videogiochi <strong>di</strong><br />
avventura, basati <strong>su</strong> interfacce testuali e <strong>per</strong>ciò apparentemente totalmente scollegati<br />
da ciò che a quei tempi era la realtà virtuale. Essi modellavano <strong>per</strong>ò a tutti gli effetti<br />
degli ambienti virtuali, senza dubbio più interattivi <strong>di</strong> quelli del Sensorama. Una
CAPITOLO 2. LA REALTÀ VIRTUALE 7<br />
Figura 2.4: Il DataGlove della VPL<br />
particolare branca dei videogiochi era quella dei MUD 2 in cui l’interazione avveniva<br />
anche con altri esseri umani, sempre all’interno <strong>di</strong> un mondo fittizio.<br />
A tutto questo si aggiungeva la cinematografia. Il manifesto <strong>di</strong> Tron (Disney, 1982)<br />
parlava <strong>di</strong> “un mondo all’interno del computer dove l’uomo non è mai stato, mai<br />
prima d’ora”. Tron narrava la storia <strong>di</strong> un ragazzo imprigionato all’interno <strong>di</strong> un<br />
computer e costretto a cercare la libertà in un mondo virtuale dove gli stessi program-<br />
mi erano esseri umani. Nel 1987 esor<strong>di</strong>va Star Trek, con <strong>il</strong> <strong>su</strong>o Holodeck, strumento<br />
immaginario <strong>di</strong> vi<strong>su</strong>alizzazione 3D basato <strong>su</strong> ologrammi. [COH00, STE01]<br />
2.5 Realtà virtuale negli anni ’90<br />
I lavori <strong>su</strong>lla realtà virtuale procedevano <strong>su</strong>i due f<strong>il</strong>oni della ricerca e della commer-<br />
cializzazione.<br />
Nel 1992 <strong>il</strong> CAVE (CAVE Automatic Virtual Environment) veniva alla luce. Esso<br />
era composto da <strong>una</strong> stanza cubica <strong>di</strong> cui 4 facce erano ut<strong>il</strong>izzate come <strong>di</strong>splay.<br />
L’utente poteva interagire con l’ambiente, mentre la <strong>su</strong>a posizione veniva tracciata<br />
2 Multi User Dungeon, ovvero Segreta Multiutente. Dungeon non è in realtà legato ad <strong>una</strong> prigione<br />
sotterranea, ma deriva da un omonimo gioco d’avventura a giocatore singolo. Il primo MUD voleva<br />
appunto ricreare l’atmosfera <strong>di</strong> quel gioco aggiungendo la possib<strong>il</strong>ità <strong>di</strong> multiutenza.
CAPITOLO 2. LA REALTÀ VIRTUALE 8<br />
Figura 2.5: CAVE Automatic Virtual Environment<br />
con 6 gra<strong>di</strong> <strong>di</strong> libertà, e i fotogrammi proiettati <strong>su</strong>lle pareti variavano in funzione <strong>di</strong><br />
essa.<br />
Sempre nel 1992 usciva anche Wolfenstein 3D (ID Software), primo vero video-<br />
gioco con ambientazione virtuale tri<strong>di</strong>mensionale (in realtà ut<strong>il</strong>izzava delle sprite 3<br />
animate).<br />
Due anni dopo, nel Novembre 1994, veniva redatta la prima bozza delle specifiche<br />
del VRML 1.0, un linguaggio <strong>per</strong> la descrizione <strong>di</strong> scenari tri<strong>di</strong>mensionali virtuali e<br />
delle possib<strong>il</strong>i interazioni con essi.<br />
Nel frattempo erano commercializzati altri strumenti <strong>di</strong> <strong>su</strong>pporto alla progettazio-<br />
ne fra cui l’ImmersaDesk (1995), <strong>una</strong> scrivania virtuale che consentiva <strong>di</strong> creare e<br />
vi<strong>su</strong>alizzare i ri<strong>su</strong>ltati del proprio lavoro tri<strong>di</strong>mensionalmente.<br />
Contemporaneamente la ricerca <strong>su</strong>lla realtà virtuale si stava espandendo anche in<br />
altri settori, fra cui la me<strong>di</strong>cina (chirurgia, ortope<strong>di</strong>a, ecc.) e le simulazioni inge-<br />
gneristiche (ad esempio <strong>per</strong> stu<strong>di</strong>are le conseguenze <strong>di</strong> forti eventi atmosferici <strong>su</strong> un<br />
ponte). [COH00, STE01]<br />
3 Una sprite – nel gergo dei videogiochi – è un’immagine bi<strong>di</strong>mensionale sovrapposta ad uno sfondo<br />
in base a determinati criteri <strong>di</strong> trasparenza, ut<strong>il</strong>e <strong>su</strong> certi hardware poiché non è necessario dover<br />
ri<strong>di</strong>segnare lo scenario completo ad ogni fotogramma. La maggior parte dei videogame moderni<br />
ut<strong>il</strong>izzano modelli poligonali al posto delle sprite.
CAPITOLO 2. LA REALTÀ VIRTUALE 9<br />
Figura 2.6: ImmersaDesk<br />
2.6 La realtà virtuale ai nostri giorni<br />
In quasi 40 anni dove è giunta la realtà virtuale? Ben lungi dall’essere ancora un pro-<br />
dotto esclusivamente immersivo e riservato ai ricercatori e pochi altri, oggi la realtà<br />
virtuale – <strong>su</strong>pportata dai nuovi hardware e software capaci <strong>di</strong> buone prestazioni <strong>su</strong>lla<br />
grafica 3D a un costo molto più contenuto rispetto a qualche tempo fa – è presente<br />
in molti settori, fra cui quelli me<strong>di</strong>co, ingegneristico, educativo, videolu<strong>di</strong>co, ed è<br />
anche più semplicemente ut<strong>il</strong>izzata come semplice <strong>su</strong>pporto <strong>per</strong> la vi<strong>su</strong>alizzazione<br />
<strong>di</strong> dati. Sono oggi <strong>di</strong>sponib<strong>il</strong>i varie soluzioni <strong>per</strong> la resa dell’immersività e <strong>per</strong> <strong>il</strong><br />
tracciamento.<br />
Gli strumenti <strong>di</strong> proiezione più moderni si <strong>su</strong>d<strong>di</strong>vidono in passivi e attivi. La tec-<br />
nologia dei proiettori passivi si basa <strong>su</strong>lla polarizzazione delle onde luminose 4 e gli<br />
occhiali <strong>per</strong> vi<strong>su</strong>alizzare la scena tri<strong>di</strong>mensionale sono meno costosi, in quanto for-<br />
mati unicamente da due membrane trasparenti che f<strong>il</strong>trino la luce polarizzata. Nella<br />
4 La luce è prodotta da cariche elettriche vibranti in tutte le <strong>di</strong>rezioni, nella luce polarizzata<br />
linearmente queste vibrazioni sono limitate ad un piano. [HR94, SIC58]
CAPITOLO 2. LA REALTÀ VIRTUALE 10<br />
proiezione attiva sono invece gli occhiali a ricreare <strong>una</strong> visione tri<strong>di</strong>mensionale chiu-<br />
dendo alternativamente la lente sinistra o destra in sincronia con l’immagine <strong>su</strong>l<br />
<strong>di</strong>splay 5 . I <strong>su</strong>pporti <strong>per</strong> la proiezione spaziano da semplici scrivanie analoghe all’Im-<br />
mersaDesk ai nuovi sistemi CAVE con proiezione <strong>su</strong> tutte le pareti del cubo. Inoltre<br />
è <strong>di</strong>sponib<strong>il</strong>e anche <strong>una</strong> vasta gamma <strong>di</strong> HMD.<br />
Figura 2.7: Occhiali <strong>per</strong> proiezione attiva (a sinistra) e passiva (a destra)<br />
L’evoluzione tecnologica ha portato al quasi totale abbandono dei sistemi <strong>di</strong> traccia-<br />
mento meccanici, rimpiazzati dagli strumenti elettromagnetici, ad ultra<strong>su</strong>oni oppure<br />
ottici. I guanti moderni ut<strong>il</strong>izzano sensori elettrici oppure fibre ottiche e si <strong>di</strong>fferen-<br />
ziano fra loro sostanzialmente <strong>per</strong> i gra<strong>di</strong> <strong>di</strong> libertà r<strong>il</strong>evati, <strong>per</strong> <strong>il</strong> numero <strong>di</strong> sensori<br />
presenti <strong>su</strong> ogni <strong>di</strong>to e infine <strong>per</strong> l’interfaccia fra <strong>il</strong> guanto e <strong>il</strong> calcolatore.<br />
Per quanto concerne invece l’u<strong>di</strong>to, <strong>il</strong> <strong>su</strong>ono 3D è oggi simulato piuttosto efficien-<br />
temente, e impianti in grado <strong>di</strong> gestirlo sono <strong>di</strong>sponib<strong>il</strong>i anche a prezzi abbastanza<br />
bassi (piccoli impianti <strong>di</strong> home video ottengono già un elevato livello <strong>di</strong> tri<strong>di</strong>men-<br />
sionalità), mentre i cinema più professionali – in combinazione con i moderni f<strong>il</strong>m –<br />
<strong>per</strong>mettono es<strong>per</strong>ienze sonore immersive.<br />
2.7 Il sistema <strong>di</strong> realtà virtuale<br />
Tutti gli strumenti presentati finora non sono solamente macchinari a sé stanti. Un<br />
sistema <strong>di</strong> realtà virtuale comprende <strong>di</strong>fatti vari hardware e un software che <strong>su</strong>pporti<br />
la loro intercomunicazione.<br />
Il ponte fra l’uomo e l’ambiente virtuale è realizzato dal sottosistema <strong>di</strong> interazio-<br />
ne. Le soluzioni ut<strong>il</strong>izzab<strong>il</strong>i sono molteplici, principalmente collocab<strong>il</strong>i nei due f<strong>il</strong>oni<br />
dell’interazione passiva e attiva. Nell’interazione passiva l’utente è monitorato da<br />
5 Per questo motivo sono spesso chiamati “shutterglasses”, ovvero gli occhiali che chiudono.
CAPITOLO 2. LA REALTÀ VIRTUALE 11<br />
Figura 2.8: Un esempio <strong>di</strong> sistema <strong>di</strong> realtà virtuale<br />
un sistema <strong>di</strong> tracciamento che ne identifica la posizione con un certo numero <strong>di</strong><br />
gra<strong>di</strong> <strong>di</strong> libertà e <strong>una</strong> certa precisione variab<strong>il</strong>i. L’interazione attiva avviene invece<br />
tramite qualche strumento <strong>di</strong> input gestito <strong>di</strong>rettamente dall’utente, quale potrebbe<br />
essere <strong>una</strong> tastiera, un joystick oppure un guanto. Interazione passiva e attiva non<br />
sono fra loro esclusive.<br />
Il software sv<strong>il</strong>uppato e ut<strong>il</strong>izzato è responsab<strong>il</strong>e della corrispondenza fra l’input<br />
dell’utente e l’output. L’elaborazione dei segnali provenienti dal sottosistema <strong>di</strong><br />
interazione mo<strong>di</strong>ficano lo stato del programma, e questa variazione viene evidenziata<br />
nel rendering della scena tri<strong>di</strong>mensionale. La vi<strong>su</strong>alizzazione dell’ambiente generato<br />
dal programma può avvenire tramite i già citati sistemi CAVE, HMD o altri.<br />
A questo quadro generale <strong>di</strong> un sistema base <strong>di</strong> realtà virtuale immersiva si possono<br />
aggiungere <strong>una</strong> moltitu<strong>di</strong>ne <strong>di</strong> altri strumenti fra cui impianti <strong>di</strong> output sonoro 3D,<br />
oppure bracci meccanici che consentano <strong>di</strong> <strong>per</strong>cepire un feedback come la resistenza<br />
alla pressione.<br />
Queste sono dunque attualmente le componenti base <strong>di</strong> un sistema <strong>di</strong> realtà virtuale:<br />
• un sottosistema <strong>di</strong> input (guanti, tracciamento, joystick, . . . );<br />
• un sottosistema <strong>di</strong> output (HMD, CAVE, . . . );
CAPITOLO 2. LA REALTÀ VIRTUALE 12<br />
• un software interme<strong>di</strong>o che converta le informazioni ricevute come input in<br />
dati ut<strong>il</strong>i <strong>per</strong> l’output.<br />
Il fondamentale software interme<strong>di</strong>o deve <strong>per</strong>ciò contenere necessariamente parti <strong>di</strong><br />
co<strong>di</strong>ce <strong>per</strong>:<br />
• l’interpretazione dell’input e <strong>il</strong> conseguente aggiornamento delle strutture dati<br />
del programma;<br />
• la lettura <strong>di</strong> tali strutture dati e la renderizzazione delle informazioni in esse<br />
contenute.<br />
In un sistema <strong>di</strong> realtà virtuale immersiva la renderizzazione deve essere tri<strong>di</strong>mensio-<br />
nale e in tempo reale. Le tecnologie attuali <strong>per</strong> questo tipo <strong>di</strong> grafica sono presentate<br />
nel Capitolo 3.
CAPITOLO 3<br />
La grafica 3D in tempo reale<br />
3.1 La nascita e l’evoluzione delle librerie grafiche 3D<br />
3.1.1 Il Core<br />
Quando nel 1974 lo SIGGRAPH (Special Interest Group for Computer Graphics)<br />
dell’ACM (Association for Computing Machinery) si riunì <strong>per</strong> l’annuale conferen-<br />
za lo scenario del <strong>su</strong>pporto alla programmazione grafica era molto frammentato.<br />
La competitività dei prodotti hardware era strettamente legata anche alle routine<br />
software che li accompagnavano, e negli anni precedenti era <strong>per</strong>ciò sorta <strong>una</strong> mol-<br />
titu<strong>di</strong>ne <strong>di</strong> librerie proprietarie – create dalle stesse case produttrici – che nel loro<br />
complesso ri<strong>su</strong>ltavano estremamente ridondanti. Questo non favoriva la portab<strong>il</strong>ità<br />
dei programmi da un sistema hardware all’altro, <strong>per</strong>ché la mancanza <strong>di</strong> uno stan-<br />
dard rallentava la conversione del co<strong>di</strong>ce. I programmatori – che oramai avevano<br />
assaporato i vantaggi <strong>di</strong> un linguaggio <strong>di</strong> alto livello – non erano molto desiderosi <strong>di</strong><br />
ritornare all’ut<strong>il</strong>izzo intensivo dell’Assembly. Fu istituito un comitato con <strong>il</strong> compito<br />
<strong>di</strong> analizzare <strong>il</strong> problema e presentarlo ad <strong>una</strong> delle conferenze <strong>su</strong>ccessive.<br />
Tre anni più tar<strong>di</strong> tale comitato presentò al convegno SIGGRAPH del 1977 la <strong>su</strong>a<br />
proposta <strong>per</strong> un “Core” <strong>di</strong> <strong>su</strong>broutine grafiche che sarebbero dovute essere fornite da<br />
ogni produttore <strong>di</strong> hardware. Alcune delle idee alla base <strong>di</strong> questo processo <strong>di</strong> uni-<br />
formazione provenivano dalla conferenza dell’anno precedente organizzata dall’IFIP<br />
(International Federation of Information Processing) in Francia. Fra le caratteristi-<br />
che fondamentali <strong>di</strong> <strong>una</strong> <strong>libreria</strong> grafica emerse a quel convegno le più importanti<br />
erano:<br />
13
CAPITOLO 3. LA GRAFICA 3D IN TEMPO REALE 14<br />
• la necessità <strong>di</strong> mantenere separate le funzioni <strong>di</strong> input e <strong>di</strong> output, <strong>per</strong> fac<strong>il</strong>itare<br />
la comprensib<strong>il</strong>ità del co<strong>di</strong>ce e l’intuitività dell’ut<strong>il</strong>izzo delle routine. Fino ad<br />
allora erano state spesso implementate procedure che svolgessero entrambi i<br />
compiti a seconda dei parametri ricevuti.<br />
• l’in<strong>di</strong>pendenza dallo specifico hardware in maniera tale che <strong>il</strong> co<strong>di</strong>ce rispettante<br />
lo standard fosse <strong>il</strong> più possib<strong>il</strong>e portab<strong>il</strong>e;<br />
• la separazione fra coor<strong>di</strong>nate del mondo e coor<strong>di</strong>nate della <strong>per</strong>iferica <strong>per</strong> man-<br />
tenere <strong>una</strong> <strong>di</strong>stinzione fra lo spazio del problema e lo spazio <strong>di</strong> uno specifico<br />
strumento <strong>di</strong> output.<br />
Il Core non ebbe molta fort<strong>una</strong> e non <strong>di</strong>ventò mai uno standard. Innanzitutto inclu-<br />
deva anche varie funzioni <strong>per</strong> la grafica 3D e <strong>per</strong> questo motivo non si adattava bene<br />
al ruolo <strong>di</strong> <strong>libreria</strong> base <strong>per</strong> <strong>di</strong>spositivi <strong>di</strong> output prevalentemente bi<strong>di</strong>mensionale.<br />
Inoltre non si adeguò – neppure dopo la revisione del 1979 – ai nuovi <strong>di</strong>spositi-<br />
vi raster 1 che avevano proprio in quegli anni rimpiazzato gran parte dei <strong>di</strong>splay<br />
vettoriali 2 . [LAF99]<br />
3.1.2 Il GKS<br />
Nel frattempo in Europa nasceva EUROGRAPHICS (l’associazione europea <strong>per</strong> la<br />
computer grafica). Era <strong>il</strong> 1980. A settembre dello stesso anno si tenne la prima<br />
conferenza dell’ente, e si parlò molto del problema <strong>di</strong> <strong>una</strong> standar<strong>di</strong>zzazione delle<br />
librerie grafiche. Il sollevamento <strong>di</strong> queste problematiche portò a <strong>su</strong>ccessive <strong>di</strong>scus-<br />
sioni dalle quali nacque la proposta <strong>per</strong> <strong>il</strong> GKS (Graphische KernSystem 3 ), ispirata<br />
in parte anche alle idee del Core. Il GKS fu presentato nel 1982 come bozza, e venne<br />
approvato dalla ISO (International Standard Organization) tre anni più tar<strong>di</strong>, con<br />
le specifiche ISO 7942 del 1985. [ISO85]<br />
1 Un <strong>di</strong>spositivo raster mantiene un copia dell’immagine da vi<strong>su</strong>alizzare in memoria e la ut<strong>il</strong>izza<br />
<strong>per</strong> aggiornare lo schermo senza che sia necessario ri<strong>di</strong>segnare tutto ad ogni fotogramma. La<br />
copia è sostanzialmente <strong>una</strong> matrice <strong>di</strong> elementi (denominati pixel) corrispondenti ai singoli punti<br />
colorati che compongono un’immagine <strong>di</strong>screta. I <strong>di</strong>spositivi raster si contrappongono ai <strong>di</strong>spositivi<br />
vettoriali, nei quali l’immagine non è <strong>di</strong>scretizzata in <strong>una</strong> matrice <strong>di</strong> punti ma è composta da<br />
primitive definite geometricamente e ri<strong>di</strong>segnate interamente ad ogni fotogramma.<br />
2 Cfr. Nota 1.<br />
3 Sistema grafico nocciolo.
CAPITOLO 3. LA GRAFICA 3D IN TEMPO REALE 15<br />
Rispecchiando le idee dell’IFIP sì seguì <strong>il</strong> principio dell’astrazione dall’hardware.<br />
Vennero ideate delle entità denominate Workstation ut<strong>il</strong>izzab<strong>il</strong>i come <strong>per</strong>iferiche<br />
virtuali <strong>per</strong>mettendo al programmatore <strong>di</strong> non doversi preoccupare della gestione <strong>di</strong><br />
tutte le possib<strong>il</strong>i strumentazioni <strong>di</strong>fferenti. Qualsiasi Workstation era <strong>di</strong>fatti ut<strong>il</strong>iz-<br />
zab<strong>il</strong>e in maniera analoga a tutte le altre. Un altra particolarità interessante dello<br />
standard era la completa in<strong>di</strong>pendenza da qualsiasi linguaggio <strong>di</strong> programmazione:<br />
le implementazioni <strong>per</strong> i linguaggi allora più comuni furono definite in <strong>su</strong>ccessive<br />
specifiche ISO (ISO 8651). [ISO88A]<br />
A <strong>di</strong>fferenza della proposta fatta dal SIGGRAPH, questo standard prevedeva so-<br />
lamente funzioni <strong>per</strong> l’output grafico bi<strong>di</strong>mensionale, <strong>per</strong> un totale <strong>di</strong> un paio <strong>di</strong><br />
centinaia <strong>di</strong> routine. L’approccio stratificato impiegato <strong>per</strong> definire le necessarie<br />
funzionalità del sistema – sia <strong>per</strong> l’input che <strong>per</strong> l’output – lasciava <strong>per</strong>ò ampio spa-<br />
zio allo sv<strong>il</strong>uppo <strong>di</strong> procedure <strong>di</strong> livello <strong>su</strong><strong>per</strong>iore che implementassero funzioni <strong>per</strong><br />
la grafica 3D.<br />
Questa possib<strong>il</strong>ità fu sfruttata fin da <strong>su</strong>bito, e già nel 1988 un nuovo standard, GKS-<br />
3D (ISO 8805, 1988), si affiancò alla <strong>libreria</strong> base, aggiungendole funzionalità <strong>per</strong> la<br />
grafica tri<strong>di</strong>mensionale. [LAF99, SAA95, ISO88B]<br />
3.1.3 Le altre librerie alla fine degli anni ’80<br />
Parallelamente al GKS-3D si andavano evolvendo anche altri progetti. I più impor-<br />
tanti portarono alla nascita <strong>di</strong> PHIGS e Iris GL.<br />
PHIGS (Programmer’s Hierarchical Interactive Graphics System) definiva uno stan-<br />
dard (ISO 9592, 1989) <strong>per</strong> la manipolazione e la vi<strong>su</strong>alizzazione <strong>di</strong> oggetti grafici<br />
bi<strong>di</strong>mensionali e tri<strong>di</strong>mensionali. La gestione <strong>di</strong> questi modelli avveniva tramite<br />
l’inserimento nel PHIGS graphics database <strong>di</strong> <strong>di</strong>splay lists, particolari strutture dati<br />
<strong>per</strong> la memorizzazione della geometria da renderizzare. La vi<strong>su</strong>alizzazione veniva<br />
poi gestita dal database stesso, in<strong>di</strong>fferentemente <strong>su</strong> <strong>una</strong> o più <strong>per</strong>iferiche <strong>di</strong> output.<br />
Come <strong>il</strong> GKS, anche PHIGS ut<strong>il</strong>izzava delle Workstation che astraevano dallo speci-<br />
fico hardware. PHIGS era privo <strong>di</strong> molti meto<strong>di</strong> <strong>per</strong> <strong>il</strong> fotorealismo, e lo scrupoloso<br />
rispetto de<strong>di</strong>cato alle specifiche rallentava spesso le prestazioni rendendolo un pro-<br />
dotto più adatto alla vi<strong>su</strong>alizzazione ingegneristica e industriale che ad altri campi<br />
come la grafica in realtime. [ISO89]
CAPITOLO 3. LA GRAFICA 3D IN TEMPO REALE 16<br />
Figura 3.1: Un’immagine generata tramite PHIGS<br />
PHIGS affiancò Xlib (e <strong>il</strong> protocollo PEX 4 fu accostato al già ut<strong>il</strong>izzato protocollo<br />
X) come <strong>libreria</strong> <strong>per</strong> lo sv<strong>il</strong>uppo <strong>di</strong> applicazioni grafiche in ambiente Unix. [SMI95]<br />
Fra la fine degli anni ottanta e l’inizio degli anni novanta la S<strong>il</strong>icon Graphics Incorpo-<br />
rated realizzò Iris GL come <strong>su</strong>pporto <strong>per</strong> la programmazione grafica <strong>su</strong>lle omonime<br />
macchine che essa stessa produceva. Oltre alle funzioni ut<strong>il</strong>i <strong>per</strong> le geometrie 2D<br />
e 3D, Iris GL forniva anche un <strong>su</strong>pporto <strong>per</strong> <strong>il</strong> fac<strong>il</strong>e ut<strong>il</strong>izzo <strong>di</strong> altre funzioni del<br />
sistema o<strong>per</strong>ativo, fra cui la creazione e mo<strong>di</strong>fica delle finestre.<br />
3.1.4 OpenGL<br />
Nel 1992 da Iris GL nacque OpenGL (Open Graphic Library). Questo passaggio<br />
segnò un cambiamento ra<strong>di</strong>cale della <strong>libreria</strong>, in quanto volutamente non si badò<br />
alla garanzia <strong>di</strong> compatib<strong>il</strong>ità all’in<strong>di</strong>etro. Venne scar<strong>di</strong>nata dalle specifiche tutta la<br />
sezione troppo strettamente legata all’implementazione del sistema o<strong>per</strong>ativo, fra cui<br />
le funzioni <strong>di</strong> gestione delle finestre. Ciò che rimaneva era un nocciolo <strong>di</strong> procedure<br />
grafiche che grazie all’elevata portab<strong>il</strong>ità ed all’astrazione dalla configurazione hard-<br />
4 PHIGS Extension for X (Estensione PHIGS <strong>per</strong> X).
CAPITOLO 3. LA GRAFICA 3D IN TEMPO REALE 17<br />
ware erano in grado <strong>di</strong> funzionare – seppure con le ovvie variazioni <strong>di</strong> <strong>per</strong>formance<br />
– <strong>su</strong> mainframe così come <strong>su</strong> PC.<br />
Figura 3.2: La scena <strong>di</strong> figura 3.1 ricreata con OpenGL<br />
Il controllo dello sv<strong>il</strong>uppo <strong>di</strong> OpenGL fu affidato esternamente e la <strong>libreria</strong> – non più<br />
<strong>di</strong> proprietà della SGI – è da allora r<strong>il</strong>asciata senza necessità <strong>di</strong> licenze. Fin da <strong>su</strong>bito<br />
l’organo competente <strong>per</strong> l’evoluzione <strong>di</strong> OpenGL è stato l’ARB (Architecture Review<br />
Board) ai cui vertici si trovano i rappresentanti delle maggiori case produttrici <strong>di</strong><br />
hardware <strong>per</strong> la grafica. L’ARB si occupa anche del monitoraggio delle estensioni<br />
alla <strong>libreria</strong> create dalle singole aziende <strong>per</strong> <strong>su</strong>pportare meglio le caratteristiche<br />
hardware delle proprie <strong>per</strong>iferiche (cfr. Appen<strong>di</strong>ce B). L’ARB aggiunge inoltre<br />
nuove funzionalità alle specifiche, standar<strong>di</strong>zzando le estensioni più <strong>di</strong>ffuse.<br />
La versione attuale è OpenGL 1.5, r<strong>il</strong>asciata <strong>il</strong> 29 Luglio 2003. [OPE03]<br />
3.1.5 Direct3D<br />
Direct3D è un sottoinsieme <strong>di</strong> <strong>una</strong> più vasta <strong>libreria</strong> chiamata DirectX e sv<strong>il</strong>uppata<br />
da Microsoft a partire dal 1995. Lo scopo che portò alla <strong>su</strong>a creazione fu <strong>il</strong> tentati-<br />
vo <strong>di</strong> spostare l’ambiente ut<strong>il</strong>izzato dai programmatori grafici da DOS a Windows.<br />
Prima <strong>di</strong> allora gran parte degli sforzi degli sv<strong>il</strong>uppatori erano de<strong>di</strong>cati all’implemen-
CAPITOLO 3. LA GRAFICA 3D IN TEMPO REALE 18<br />
tazione <strong>di</strong> co<strong>di</strong>ce complesso che potesse <strong>su</strong>pportare la maggior parte degli hardware<br />
in commercio. Le DirectX implementano la metodologia <strong>di</strong> astrazione del sistema<br />
fisico sottostante ut<strong>il</strong>izzata anche dalle altre librerie.<br />
Per l’ut<strong>il</strong>izzo <strong>di</strong> questa <strong>libreria</strong> non sono necessarie licenze, ma <strong>il</strong> <strong>su</strong>pporto è garantito<br />
solamente <strong>su</strong>i sistemi o<strong>per</strong>ativi Microsoft. La versione attuale è DirectX 9, r<strong>il</strong>asciata<br />
nell’estate del 2003. [EG01]<br />
3.2 Le librerie <strong>di</strong> vi<strong>su</strong>alizzazione<br />
Ad un livello <strong>su</strong><strong>per</strong>iore delle librerie grafiche 3D, e solitamente posando le proprie<br />
fondamenta <strong>su</strong> <strong>di</strong> esse, si collocano le librerie <strong>di</strong> vi<strong>su</strong>alizzazione. Esse sono spesso<br />
dei pacchetti software specializzati de<strong>di</strong>cati alla fac<strong>il</strong>itazione della programmazione<br />
in un settore preciso (realtà virtuale, <strong>progettazione</strong> ingegneristica, ecc.).<br />
Alcune fra quelle attualmente ut<strong>il</strong>izzate nel settore della realtà virtuale sono le<br />
librerie offerte da Multigen-Para<strong>di</strong>gm e da SGI.<br />
OpenInventor e OpenGL Performer sono prodotti S<strong>il</strong>icon Graphics. OpenInventor<br />
è un ambiente <strong>di</strong> sv<strong>il</strong>uppo orientato agli oggetti <strong>per</strong> la creazione <strong>di</strong> applicazioni 3D<br />
interattive, OpenGL Performer – membro <strong>di</strong> <strong>una</strong> più grande <strong>su</strong>ite <strong>di</strong> aus<strong>il</strong>io alla<br />
programmazione (OpenGL Shader, Optimizer, Volumizer, ecc.) – è un <strong>su</strong>pporto <strong>per</strong><br />
gli sv<strong>il</strong>uppatori <strong>di</strong> applicativi <strong>di</strong> realtà virtuale orientati alle prestazioni. Si basano<br />
entrambi <strong>su</strong> OpenGL.<br />
Vega (Multigen-Para<strong>di</strong>gm) è <strong>una</strong> <strong>libreria</strong> <strong>per</strong> la creazione e la simulazione in tempo<br />
reale <strong>di</strong> ambienti virtuali.<br />
È <strong>su</strong>pportata da un’interfaccia grafica <strong>per</strong> mo<strong>di</strong>ficare i<br />
parametri dell’applicazione anche in fase <strong>di</strong> esecuzione (LynX). Solo <strong>di</strong> recente è<br />
stata commercializzata anche in <strong>una</strong> versione <strong>per</strong> Windows, ma fino a poco tempo<br />
fa era <strong>di</strong>sponib<strong>il</strong>e solamente <strong>per</strong> le workstation IRIX della S<strong>il</strong>icon Graphics. Vega è<br />
<strong>basata</strong> <strong>su</strong> OpenGL Performer.<br />
Il problema legato a queste librerie d’alto livello è spesso la loro troppo elevata<br />
chiu<strong>su</strong>ra in se stesse, che rende <strong>di</strong>ffic<strong>il</strong>e l’interazione con gli strati sottostanti. Se da<br />
un lato la programmazione è resa fac<strong>il</strong>e dai costrutti più intuitivi e più potenti messi<br />
a <strong>di</strong>sposizione dello sv<strong>il</strong>uppatore, dall’altro lato è spesso molto complesso riuscire a<br />
mo<strong>di</strong>ficare un particolare stato del sottostrato <strong>di</strong> rendering <strong>di</strong> basso livello.<br />
A questo si aggiunge anche la necessità economicamente onerosa dell’acquisto e
CAPITOLO 3. LA GRAFICA 3D IN TEMPO REALE 19<br />
<strong>il</strong> mantenimento continuo nel tempo <strong>di</strong> licenze <strong>per</strong> l’ut<strong>il</strong>izzo, in quanto – a <strong>di</strong>ffe-<br />
renza delle librerie 3D – questi software <strong>di</strong> vi<strong>su</strong>alizzazione <strong>di</strong> più alto livello sono<br />
solitamente a pagamento.<br />
3.3 I modelli e i loader<br />
Qualsiasi applicazione 3D necessita <strong>di</strong> modelli da vi<strong>su</strong>alizzare, siano essi dei semplici<br />
triangoli oppure rappresentazioni più articolate <strong>di</strong> oggetti del mondo che ci circonda.<br />
Spesso le necessità <strong>di</strong> realismo vi<strong>su</strong>ale impongono oltre alle specifiche dei vertici<br />
anche l’impiego <strong>di</strong> materiali (texture o più semplicemente colori), vettori normali e<br />
altri dati. Le modalità <strong>per</strong> ottenere oppure creare queste informazioni all’interno<br />
<strong>di</strong> un applicativo sono varie, e non sono fra loro esclusive. Quale scegliere <strong>per</strong> un<br />
particolare oggetto o insieme <strong>di</strong> oggetti è a <strong>di</strong>screzione dello sv<strong>il</strong>uppatore.<br />
La metodologia più elementare – ma più scomoda quando la complessità dei modelli<br />
aumenta – è quella <strong>di</strong> definire manualmente all’interno del programma tutto ciò<br />
che è necessario <strong>per</strong> descrivere la geometria e i materiali. Se questo può essere<br />
sod<strong>di</strong>sfacente quando si ha bisogno <strong>di</strong> poche forme geometriche, certamente non lo<br />
è quando si necessita <strong>di</strong> qualcosa <strong>di</strong> più dettagliato.<br />
Sicuramente è più comodo <strong>per</strong> molte applicazioni ut<strong>il</strong>izzare <strong>una</strong> definizione mate-<br />
matica o algoritmica dell’oggetto da modellare. Questo metodo è molto pratico<br />
<strong>per</strong> applicazioni che facciano uso <strong>di</strong> figure e soli<strong>di</strong> geometrici, ma anche curve e<br />
<strong>su</strong><strong>per</strong>fici (Spline, NURBS, ecc.) nonché frattali. Tali applicazioni non si limita-<br />
no a software <strong>di</strong> ricerca scientifica, ma possono essere programmi appartenenti a<br />
qualsiasi settore (dalla prototipazione <strong>di</strong> carrozzerie <strong>di</strong> automob<strong>il</strong>e alla generazione<br />
automatica <strong>di</strong> alberi <strong>per</strong> un ambiente virtuale). I limiti <strong>di</strong> questo approccio sono<br />
evidenti: non è possib<strong>il</strong>e adottarlo qualora sia necessario un modello non definib<strong>il</strong>e<br />
matematicamente o algoritmicamente.<br />
Il sistema più flessib<strong>il</strong>e è creare l’oggetto con un programma <strong>di</strong> modellazione 2D o<br />
3D esterno ed importarlo nella propria applicazione. Questo è reso possib<strong>il</strong>e da un<br />
loader. Un loader è <strong>una</strong> particolare porzione <strong>di</strong> programma in grado <strong>di</strong> importare<br />
all’interno del programma stesso delle particolari informazioni da <strong>una</strong> sorgente <strong>di</strong><br />
provenienza; in questo caso si tratta dell’importazione <strong>di</strong> modelli geometrici da f<strong>il</strong>e.<br />
Un loader può essere creato appositamente dallo stesso programmatore che ne farà
CAPITOLO 3. LA GRAFICA 3D IN TEMPO REALE 20<br />
uso oppure prodotto esternamente da terzi che possono <strong>di</strong>stribuirlo a pagamento<br />
oppure gratis. Anche <strong>il</strong> formato <strong>di</strong> input può essere un formato standard e accessib<strong>il</strong>e<br />
a tutti (ad esempio VRML oppure XML) oppure proprietario (ad esempio FLT <strong>di</strong><br />
OpenFlight della Multigen-Para<strong>di</strong>gm).<br />
3.4 I loader 3DS<br />
Per quanto concerne <strong>il</strong> formato 3DS 5 sono già <strong>di</strong>sponib<strong>il</strong>i vari loader, sia a pagamento<br />
che gratuiti. Entrambe le tipologie hanno delle limitazioni.<br />
I loader a pagamento sono solitamente soggetti a problemi <strong>di</strong> bassa possib<strong>il</strong>ità <strong>di</strong><br />
interazione con i livelli sottostanti e necessità <strong>di</strong> mantenimento delle licenze. I<br />
loader più noti <strong>di</strong> questo tipo sono quelli integrati nelle librerie <strong>di</strong> vi<strong>su</strong>alizzazione,<br />
<strong>per</strong> esempio nel già citato OpenGL Performer. 6 .<br />
I loader gratuiti sono invece nella maggior parte dei casi delle demo software fini<br />
a se stesse, e <strong>il</strong> tentativo <strong>di</strong> integrarli all’interno <strong>di</strong> un’applicazione è spesso mol-<br />
to <strong>di</strong>fficoltoso. OpenGL è infatti <strong>una</strong> macchina a stati, e questi loader – essendo<br />
progettati <strong>per</strong> la semplice vi<strong>su</strong>alizzazione dei modelli e non <strong>per</strong> l’ut<strong>il</strong>izzo all’interno<br />
<strong>di</strong> un più vasto applicativo – sono soliti mo<strong>di</strong>ficare gli stati senza ripristinare poi i<br />
valori precedenti, con conseguenze catastrofiche <strong>su</strong>lla renderizzazione del rimanente<br />
ambiente che circonda <strong>il</strong> modello caricato.<br />
Un ultimo appunto <strong>su</strong>i loader re<strong>per</strong>ib<strong>il</strong>i esternamente è <strong>il</strong> fatto che talvolta durante<br />
l’importazione vengano tralasciati alcuni particolari attributi del modello – ritenuti<br />
non interessanti dallo sv<strong>il</strong>uppatore – ma che <strong>per</strong> l’applicazione che ne fa uso possono<br />
essere molto ut<strong>il</strong>i, se non in<strong>di</strong>spensab<strong>il</strong>i.<br />
5 Il formato 3DS è <strong>il</strong> formato <strong>di</strong> esportazione <strong>di</strong> Autodesk 3DStu<strong>di</strong>o (http://www.<strong>di</strong>screet.com); <strong>di</strong><br />
recente è stato affiancato dal nuovo formato MAX.<br />
6 Cfr. 3.2 a pagina 18.
CAPITOLO 4<br />
Introduzione al lavoro <strong>di</strong> tesi<br />
Lo scopo del presente lavoro <strong>di</strong> tesi è la <strong>progettazione</strong> e lo sv<strong>il</strong>uppo <strong>di</strong> un loader <strong>per</strong><br />
<strong>il</strong> formato 3DS che:<br />
• sia fac<strong>il</strong>mente integrab<strong>il</strong>e all’interno <strong>di</strong> applicazioni <strong>di</strong> realtà virtuale basate <strong>su</strong><br />
OpenGL, ovvero non comporti la necessità <strong>di</strong> apprendere nuovi linguaggi <strong>di</strong><br />
programmazione o <strong>di</strong> scripting;<br />
• non causi <strong>per</strong>turbazioni degli stati OpenGL e <strong>per</strong>ciò non influenzi <strong>il</strong> rendering<br />
complessivo dell’ambiente virtuale;<br />
• importi in maniera <strong>il</strong> più possib<strong>il</strong>e completa i modelli presenti all’interno <strong>di</strong> un<br />
f<strong>il</strong>e 3DS, in particolare le informazioni relative ai sistemi <strong>di</strong> coor<strong>di</strong>nate locali<br />
dei singoli oggetti ignorate dalla maggior parte dei loader;<br />
• <strong>per</strong>metta all’utente <strong>di</strong> ab<strong>il</strong>itare e <strong>di</strong>sab<strong>il</strong>itare in tempo reale (quin<strong>di</strong> in fase <strong>di</strong><br />
esecuzione) le caratteristiche dei materiali consentendo <strong>di</strong> scegliere <strong>di</strong> volta in<br />
volta <strong>il</strong> compromesso fra frame rate e fotorealismo desiderato.<br />
Il loader è stato implementato in ANSI C++, e si colloca all’interno <strong>di</strong> un più grande<br />
progetto dell’ITIA <strong>per</strong> la creazione <strong>una</strong> <strong>libreria</strong> <strong>di</strong> strumenti <strong>per</strong> la programmazione<br />
grafica in tempo reale (è stata <strong>di</strong> recente sv<strong>il</strong>uppata come lavoro <strong>di</strong> tesi <strong>di</strong> due colleghi<br />
la parte responsab<strong>il</strong>e della gestione delle telecamere, delle luci e del posizionamento<br />
dei modelli nel mondo). Il co<strong>di</strong>ce si basa <strong>su</strong> OpenGL, in quanto dovrà essere integrato<br />
in applicazioni che faranno uso <strong>di</strong> tale <strong>libreria</strong> grafica.<br />
21
CAPITOLO 4. INTRODUZIONE AL LAVORO DI TESI 22<br />
Figura 4.1: La <strong>di</strong>visione fra formato e semantica
CAPITOLO 4. INTRODUZIONE AL LAVORO DI TESI 23<br />
In fase <strong>di</strong> <strong>progettazione</strong> si è deciso <strong>di</strong> mantenere la <strong>su</strong>d<strong>di</strong>visione logica fra formato e<br />
semantica. Sono state <strong>per</strong>ciò ideate due parti software in<strong>di</strong>pendenti, <strong>una</strong> specializ-<br />
zata nella lettura dei dati dal formato <strong>di</strong> salvataggio ma ignorante <strong>il</strong> significato <strong>di</strong><br />
ciò che legge, l’altra conscia unicamente del senso delle informazioni lette e ignara<br />
della loro provenienza (cfr. Figura 4.1).<br />
Si è giunti <strong>per</strong>ciò alla creazione <strong>di</strong> due classi separate incaricate <strong>di</strong> svolgere questi<br />
compiti. Una classe è stata denominata Loader, l’altra ha preso come nome Object.<br />
La classe Loader presentata nel Capitolo 5 contiene un parser <strong>di</strong> f<strong>il</strong>e che si occupa<br />
anche del riempimento delle strutture dati <strong>di</strong> <strong>una</strong> istanza della classe Object con ciò<br />
che legge. Una volta terminata la scansione del f<strong>il</strong>e viene restituito all’applicazione<br />
un puntatore a tale istanza e viene cancellato dalla memoria del loader qualsiasi<br />
frammento <strong>di</strong> dato residuo.<br />
La classe Object presentata nel Capitolo 7 contiene meto<strong>di</strong> <strong>per</strong> l’impostazione della<br />
geometria e dei materiali. Al momento della creazione <strong>una</strong> <strong>su</strong>a istanza è <strong>di</strong>fatti<br />
vuota, ed è necessario inserirvi dati dall’esterno. Possiede anche dei meto<strong>di</strong> in<br />
grado <strong>di</strong> configurare automaticamente gli stati ed invocare <strong>il</strong> motore <strong>di</strong> rendering<br />
OpenGL, <strong>per</strong> agevolare la renderizzazione dei propri modelli. Gestisce infine anche<br />
le informazioni <strong>su</strong>lla gerarchia ad albero della scena, memorizzando puntatori ai<br />
propri figli e al proprio padre. Per risparmiare memoria è stata creata anche <strong>una</strong><br />
classe Group con un sottoinsieme delle funzionalità <strong>di</strong> Object. Un’istanza della<br />
classe Group contiene infatti i dati riguardanti la gerarchia, ma è priva <strong>di</strong> geometria<br />
e materiali. La classe Group è presentata nel Capitolo 6.
CAPITOLO 5<br />
Il Loader<br />
5.1 L’interfaccia e <strong>il</strong> runtime bin<strong>di</strong>ng<br />
In fase <strong>di</strong> <strong>progettazione</strong> si è deciso <strong>di</strong> creare innanzitutto <strong>una</strong> interfaccia generale<br />
<strong>per</strong> rappresentare <strong>il</strong> generico loader. Si è inoltre fatto in modo che qualsiasi altro<br />
loader più specialistico si debba attenere rigorosamente allo standard definito da<br />
questa interfaccia. Tale scelta ha portato alla implementazione della classe astratta<br />
Loader.<br />
La classe Loader è composta da un unico metodo load f<strong>il</strong>e che riceve un nome <strong>di</strong> f<strong>il</strong>e<br />
come input e restituisce al programma un puntatore ad un oggetto <strong>di</strong> tipo Group con-<br />
tenente l’intero albero della scena importato da tale f<strong>il</strong>e. Essendo <strong>una</strong> classe astratta<br />
non può essere istanziata. Inoltre <strong>il</strong> <strong>su</strong>o unico metodo deve essere obbligatoriamente<br />
ridefinito da qualsiasi classe figlia.<br />
Questo rappresenta tutto ciò che è necessario conoscere <strong>per</strong> ut<strong>il</strong>izzare le specializ-<br />
zazioni <strong>di</strong> questa classe: qualsiasi loader <strong>per</strong> un formato specifico è <strong>di</strong>fatti gestib<strong>il</strong>e<br />
come se fosse un oggetto <strong>di</strong> tipo Loader, senza preoccuparsi che venga invocata <strong>di</strong><br />
volta in volta la procedura corretta.<br />
Il trucco che <strong>per</strong>mette questa semplificazione <strong>di</strong> ut<strong>il</strong>izzo deriva <strong>di</strong>rettamente dalle<br />
potenzialità <strong>di</strong> un linguaggio orientato agli oggetti come <strong>il</strong> C++, che consente <strong>di</strong><br />
ottenere dei particolari comportamenti del programma senza troppi sforzi. Fra le<br />
peculiarità del linguaggio c’è la possib<strong>il</strong>ità <strong>di</strong> scegliere fac<strong>il</strong>mente fra due modalità<br />
<strong>di</strong> bin<strong>di</strong>ng 1 :<br />
1 Per bin<strong>di</strong>ng si intende l’associare alla chiamata <strong>di</strong> <strong>una</strong> funzione la corrispondente locazione <strong>di</strong><br />
memoria contenente la routine da eseguire.<br />
24
CAPITOLO 5. IL LOADER 25<br />
• l’early bin<strong>di</strong>ng, che avviene da parte del comp<strong>il</strong>atore e del linker, semplicemente<br />
salvando in fase <strong>di</strong> comp<strong>il</strong>azione i nomi delle funzioni 2 e i relativi in<strong>di</strong>rizzi <strong>di</strong><br />
memoria all’interno <strong>di</strong> <strong>una</strong> tabella e quin<strong>di</strong> sostituendo nel co<strong>di</strong>ce macchina le<br />
chiamate <strong>di</strong> funzione con salti a quegli in<strong>di</strong>rizzi 3 ;<br />
• <strong>il</strong> late bin<strong>di</strong>ng, detto anche runtime bin<strong>di</strong>ng, che avviene in fase <strong>di</strong> esecuzione.<br />
I linguaggi e i comp<strong>il</strong>atori che lo <strong>su</strong>pportano usano metodologie <strong>di</strong>fferenti <strong>per</strong><br />
implementarlo. I comp<strong>il</strong>atori C++ <strong>di</strong> solito introducono automaticamente al-<br />
l’interno delle classi un array <strong>di</strong> puntatori contenente gli in<strong>di</strong>rizzi delle funzioni<br />
che necessitano <strong>di</strong> late bin<strong>di</strong>ng, e aggiungono anche istruzioni <strong>per</strong> istanziare<br />
questo vettore correttamente in funzione della classe a cui appartiene.<br />
Figura 5.1: Il late bin<strong>di</strong>ng nella classe Loader<br />
2 In realtà non vengono solitamente salvati i reali nomi, ma dei nomi simbolici. La funzione<br />
int f(int a, char b) verrà salvata internamente da un comp<strong>il</strong>atore C come f, mentre un comp<strong>il</strong>atore<br />
<strong>per</strong> C++ – linguaggio che <strong>su</strong>pporta l’overloa<strong>di</strong>ng delle funzioni, ovvero l’esistenza <strong>di</strong> più<br />
funzioni con lo stesso nome ma parametri <strong>di</strong>versi – la salverà internamente come qualcosa <strong>di</strong> sim<strong>il</strong>e<br />
a f int char.<br />
3 Questa è ovviamente <strong>una</strong> semplificazione, poiché un salto <strong>di</strong> questo tipo non viene tradotto solamente<br />
con <strong>una</strong> jmp ma deve essere necessariamente posto in <strong>una</strong> cornice <strong>di</strong> salvataggio e ripristino<br />
del contesto.
CAPITOLO 5. IL LOADER 26<br />
Il metodo load f<strong>il</strong>e è stato definito virtual, e questo fa sì che sia soggetto a late<br />
bin<strong>di</strong>ng, sia nella classe Loader che nelle classi che specializzino tale interfaccia, come<br />
<strong>il</strong>lustrato in Figura 5.1. Una <strong>di</strong> queste è la classe Loader3DS, realizzata all’interno<br />
del lavoro <strong>di</strong> tesi <strong>per</strong> l’importazione dei modelli dal formato 3DS. [ECK98]<br />
5.2 La struttura <strong>di</strong> un f<strong>il</strong>e 3DS<br />
In Autodesk 3D Stu<strong>di</strong>o l’intera scena (che comprende modelli, luci e telecamere) è<br />
gestita <strong>per</strong> mezzo <strong>di</strong> un unico grande albero. I f<strong>il</strong>e 3DS – nei quali viene esportata<br />
tale scena – rispecchiano questa conformazione ad albero.<br />
La particolarità del formato realmente ut<strong>il</strong>izzato nell’esportazione è data dal fatto<br />
che i dati siano presenti unicamente <strong>su</strong>lle foglie. Per questo motivo la struttura<br />
dei f<strong>il</strong>e è composta da blocchi innestati, a partire dal blocco maggiore – grande<br />
quanto <strong>il</strong> f<strong>il</strong>e e rappresentante la ra<strong>di</strong>ce dell’albero – sino a giungere ai piccoli blocchi<br />
contenenti le informazioni vere e proprie. Tutti questi blocchi sono solitamente<br />
chiamati chunk 4 .<br />
Figura 5.2: La struttura base <strong>di</strong> un f<strong>il</strong>e 3DS<br />
I chunk sono <strong>su</strong>d<strong>di</strong>visi all’interno del f<strong>il</strong>e in due gran<strong>di</strong> categorie:<br />
• i chunk che definiscono i modelli e le loro proprietà, denominati chunk dell’e-<br />
<strong>di</strong>tor;<br />
• i chunk che definiscono la posizione degli oggetti nello spazio (e nel tempo, nel<br />
caso in cui sia presente all’interno del f<strong>il</strong>e anche un’animazione) e la gerarchia,<br />
denominati chunk del keyframer.<br />
4 Chunk in<strong>di</strong>ca in inglese un “grosso pezzo” (<strong>di</strong> legno, . . . ).
CAPITOLO 5. IL LOADER 27<br />
La sezione dell’e<strong>di</strong>tor si <strong>su</strong>d<strong>di</strong>vide a <strong>su</strong>a volta in due chunk minori, denominati<br />
rispettivamente <strong>il</strong> chunk dei materiali e <strong>il</strong> chunk degli oggetti (contenente i modelli,<br />
le luci e le telecamere).<br />
I chunk saranno presentati più in dettaglio nell’Appen<strong>di</strong>ce A.<br />
5.3 Il Loader 3DS<br />
Da questa panoramica <strong>su</strong>lla struttura che <strong>il</strong> loader 5 dovrà caricare è fac<strong>il</strong>e intuire<br />
che <strong>il</strong> parser sv<strong>il</strong>uppato debba essere composto da procedure ni<strong>di</strong>ficate.<br />
È stata così<br />
implementata <strong>una</strong> serie <strong>di</strong> meto<strong>di</strong> specializzati in grado <strong>di</strong> scorrere <strong>il</strong> contenuto dei<br />
chunk <strong>di</strong> propria competenza e:<br />
• richiamare, <strong>per</strong> ogni sottoblocco in<strong>di</strong>viduato all’interno del proprio chunk, <strong>il</strong><br />
metodo opportuno;<br />
• salvare i dati contenuti all’interno del proprio chunk in un buffer temporaneo<br />
ed inviarli alla classe Object oppure Group a cui appartengono.<br />
Il secondo punto introduce <strong>il</strong> concetto che ha avuto un ruolo fondamentale nella fase<br />
<strong>di</strong> <strong>progettazione</strong> del loader: l’in<strong>di</strong>pendenza del loader dalla semantica dei dati letti.<br />
In base a questo principio ogni metodo del loader è a conoscenza della <strong>di</strong>mensione<br />
e del formato in cui sono riposti i dati, nonché dell’identità dell’oggetto che dovrà<br />
riceverli. Questo è tutto ciò che gli serve sa<strong>per</strong>e <strong>per</strong> svolgere <strong>il</strong> proprio compito,<br />
mentre altre classi (Group e Object, presentate nei Capitoli 6 e 7) sono preposte<br />
all’ut<strong>il</strong>izzo dei dati letti.<br />
Questa, se non correttamente analizzata, può sembrare <strong>una</strong> estremizzazione del-<br />
l’approccio orientato agli oggetti, con nefasti effetti <strong>su</strong> un aspetto più importante<br />
all’interno <strong>di</strong> un programma <strong>di</strong> grafica in tempo reale quale la <strong>per</strong>formance. Al<br />
contrario un’implementazione <strong>di</strong> questo tipo consente:<br />
• <strong>il</strong> riut<strong>il</strong>izzo del loader all’interno dello stesso programma <strong>per</strong> caricare poten-<br />
zialmente un’infinità <strong>di</strong> modelli.<br />
È quin<strong>di</strong> <strong>su</strong>fficiente istanziare <strong>una</strong> sola volta<br />
5 D’ora in avanti ci si riferirà al “loader <strong>di</strong> f<strong>il</strong>e 3DS”, implementato nella classe Loader3DS,<br />
semplicemente con <strong>il</strong> termine “loader”.
CAPITOLO 5. IL LOADER 28<br />
ogni loader specifico, minimizzando lo spreco <strong>di</strong> risorse. Ogni qualvolta verrà<br />
caricato un f<strong>il</strong>e, <strong>il</strong> loader restituirà <strong>una</strong> struttura opport<strong>una</strong> contenente i mo-<br />
delli importati e ripristinerà <strong>il</strong> proprio stato iniziale senza tener traccia <strong>di</strong> ciò<br />
che è stato caricato in precedenza.<br />
• l’in<strong>di</strong>pendenza della gestione dei modelli dal caricamento che <strong>per</strong>mette <strong>di</strong> dover<br />
intervenire unicamente <strong>su</strong>lla classe del loader <strong>per</strong> caricare modelli da formati<br />
<strong>di</strong>fferenti, senza dover mo<strong>di</strong>ficare anche le classi addette alla memorizzazione e<br />
ut<strong>il</strong>izzo <strong>di</strong> geometria e materiali, che rimangono ut<strong>il</strong>izzab<strong>il</strong>i in<strong>di</strong>pendentemente<br />
dalla sorgente <strong>di</strong> importazione.<br />
Questa <strong>su</strong>d<strong>di</strong>visione fra formato e semantica è spesso sottovalutata oppure ignorata<br />
nei loader gratuiti, all’interno del cui co<strong>di</strong>ce sono <strong>di</strong>ffic<strong>il</strong>mente separab<strong>il</strong>i le parti<br />
de<strong>di</strong>cate al caricamento da quelle incaricate <strong>di</strong> gestire <strong>il</strong> rendering.<br />
L’esecuzione del metodo load f<strong>il</strong>e della classe Loader3DS avviene in tre sta<strong>di</strong> <strong>su</strong>c-<br />
cessivi: l’inizializzazione, <strong>il</strong> parsing del f<strong>il</strong>e e <strong>il</strong> postprocessing.<br />
5.4 L’inizializzazione prima del parsing<br />
Il co<strong>di</strong>ce eseguito dalla classe Loader3DS prima che venga invocato <strong>il</strong> parser è piutto-<br />
sto elementare. Il lavoro necessario si limita infatti alla inizializzazione delle strut-<br />
ture dati necessarie <strong>per</strong> contenere temporaneamente i vari dati che verranno poi<br />
inviati ai vari oggetti, oppure ut<strong>il</strong>izzati <strong>per</strong> gestire alcuni aspetti dell’elaborazione<br />
seguente <strong>il</strong> parsing, fra cui ad esempio la creazione <strong>di</strong> un albero della gerarchia da<br />
restituire al programma che ha richiesto <strong>il</strong> caricamento <strong>di</strong> un f<strong>il</strong>e, come spiegato in<br />
5.6.<br />
Viene innanzitutto istanziato un nuovo oggetto <strong>di</strong> tipo Group, a cui è assegnato come<br />
nome quello del f<strong>il</strong>e che si sta caricando, <strong>per</strong> consentire allo sv<strong>il</strong>uppatore che farà<br />
uso della <strong>libreria</strong> <strong>di</strong> ritrovare rapidamente <strong>il</strong> modello desiderato fra i tanti caricati<br />
da f<strong>il</strong>e <strong>di</strong>fferenti. Questo oggetto sarà ut<strong>il</strong>izzato in seguito come ra<strong>di</strong>ce dell’intera<br />
gerarchia.<br />
Si salva inoltre <strong>il</strong> <strong>per</strong>corso da cui si sta caricando <strong>il</strong> f<strong>il</strong>e, così da poter re<strong>per</strong>ire i f<strong>il</strong>e<br />
contenenti le texture anche <strong>per</strong> i modelli non collocati nella <strong>di</strong>rectory in cui è in<br />
esecuzione <strong>il</strong> programma che ut<strong>il</strong>izza <strong>il</strong> loader.
CAPITOLO 5. IL LOADER 29<br />
Figura 5.3: Le tre fasi della procedura load f<strong>il</strong>e
CAPITOLO 5. IL LOADER 30<br />
Sono infine resettati correttamente gli array e i contatori che serviranno al mante-<br />
nimento temporaneo in memoria dei materiali, delle texture e degli oggetti caricati<br />
dal f<strong>il</strong>e, in attesa della fase <strong>di</strong> postprocessing esplicata nella sezione 5.6 poco oltre<br />
all’interno del capitolo.<br />
5.5 Le tre fasi <strong>di</strong> parsing<br />
Il parsing segue sequenzialmente i tre gran<strong>di</strong> blocchi dello standard 3DS già <strong>il</strong>lustrati<br />
nella Figura 5.2, inviando quanto più possib<strong>il</strong>e <strong>di</strong>rettamente agli oggetti proprietari<br />
dei dati, ma mantenendo temporaneamente in memoria alcuni dati con<strong>di</strong>visi che –<br />
se opport<strong>una</strong>mente ut<strong>il</strong>izzati – consentono non solo un minor spreco <strong>di</strong> risorse ma<br />
anche <strong>una</strong> migliore <strong>per</strong>formance.<br />
Per ulteriori informazioni più dettagliate concernenti tutti i dati caricati dai f<strong>il</strong>e 3DS<br />
si rimanda all’Appen<strong>di</strong>ce A.<br />
5.5.1 I materiali<br />
Nella prima fase <strong>di</strong> parsing ci si occupa del chunk contenente un numero variabi-<br />
le <strong>di</strong> materiali, ciascuno <strong>di</strong> essi contrad<strong>di</strong>stinto da un nome unico all’interno del<br />
f<strong>il</strong>e. Questo particolare è fondamentale <strong>per</strong> la <strong>su</strong>ccessiva fase <strong>di</strong> riconoscimento e<br />
assegnazione dei materiali corretti a ciascun oggetto.<br />
Ogni materiale è definito da uno o più chunk maggiormente specializzati che si<br />
occupano ciascuno <strong>di</strong> <strong>una</strong> particolare caratteristica.<br />
I chunk del colore memorizzano le proprietà cromatiche del materiale, definendo<br />
• <strong>il</strong> colore ambientale;<br />
• <strong>il</strong> colore <strong>di</strong>ffusivo;<br />
• <strong>il</strong> colore speculare;<br />
• <strong>il</strong> colore emissivo.<br />
Sono quin<strong>di</strong> re<strong>per</strong>ib<strong>il</strong>i altre proprietà del materiale fra cui i <strong>su</strong>oi livelli <strong>di</strong> riflessività<br />
(che influisce <strong>su</strong>lla quantità <strong>di</strong> colore speculare visib<strong>il</strong>e) e <strong>di</strong> trasparenza (che definisce<br />
l’opacità del materiale).<br />
Sono infine presenti i chunk delle texture, che possono definire
CAPITOLO 5. IL LOADER 31<br />
Figura 5.4: Le tre fasi <strong>di</strong> parsing
CAPITOLO 5. IL LOADER 32<br />
Figura 5.5: La struttura <strong>di</strong> un materiale<br />
• <strong>una</strong> texture <strong>di</strong>ffusiva, ut<strong>il</strong>e <strong>per</strong> modulare non uniformemente <strong>il</strong> colore <strong>di</strong>ffusivo;<br />
• <strong>una</strong> mappa <strong>di</strong> riflessione d’ambiente, <strong>per</strong> simulare <strong>il</strong> riflesso dell’ambiente<br />
circostante <strong>su</strong>ll’oggetto;<br />
• <strong>una</strong> texture speculare, ut<strong>il</strong>e <strong>per</strong> modulare non uniformemente <strong>il</strong> colore specu-<br />
lare;<br />
• <strong>una</strong> mappa <strong>di</strong> riflessività, <strong>per</strong> i materiali che non riflettono specularmente la<br />
luce in maniera uniforme;<br />
• <strong>una</strong> texture <strong>di</strong> colore emissivo, ut<strong>il</strong>e <strong>per</strong> modulare non uniformemente <strong>il</strong> colore<br />
emissivo;<br />
• <strong>una</strong> texture <strong>di</strong> bump mapping, <strong>per</strong> simulare i <strong>di</strong>slivelli e la rugosità dei mate-<br />
riali come l’asfalto oppure un materiale con delle scanalature;<br />
• <strong>una</strong> mappa <strong>di</strong> luminosità, <strong>per</strong> materiali <strong>su</strong>i quali non si applica l’<strong>il</strong>luminazione<br />
in tempo reale ma <strong>una</strong> <strong>il</strong>luminazione precalcolata;<br />
• <strong>una</strong> mappa <strong>di</strong> opacità, <strong>per</strong> materiali trasparenti in maniera non uniforme.<br />
Tutte queste texture possono essere presenti al più <strong>una</strong> volta <strong>per</strong> ciascun materiale.<br />
Le modalità con cui ciasc<strong>una</strong> <strong>di</strong> esse è ut<strong>il</strong>izzata nella presente <strong>libreria</strong> sono chiarite<br />
dettagliatamente in 7.2.
CAPITOLO 5. IL LOADER 33<br />
Nes<strong>su</strong>no dei chunk citati è obbligatorio, e l’assenza <strong>di</strong> uno <strong>di</strong> essi comporta sempli-<br />
cemente l’ut<strong>il</strong>izzo <strong>di</strong> un valore <strong>di</strong> default <strong>per</strong> l’attributo corrispondente. Lo stesso<br />
blocco dei materiali è facoltativo, in quanto a un modello non deve necessariamen-<br />
te essere assegnato un materiale (in tal caso la presente <strong>libreria</strong> ut<strong>il</strong>izza <strong>per</strong> tale<br />
modello un materiale grigio <strong>di</strong> default).<br />
L’intera fase può <strong>per</strong>ciò non venire eseguita <strong>per</strong> taluni f<strong>il</strong>e.<br />
5.5.2 Gli oggetti<br />
Una volta caricati gli eventuali materiali si passa al parsing degli oggetti. Sono<br />
possib<strong>il</strong>i f<strong>il</strong>e 3DS senza alcun modello al proprio interno; in tal caso <strong>il</strong> loader non<br />
eseguirà questa fase e restituirà <strong>una</strong> gerarchia vuota costituita dalla sola ra<strong>di</strong>ce del-<br />
l’albero, mantenendo la consistenza nel comportamento. Se – come è più probab<strong>il</strong>e<br />
che sia – vi fossero invece degli oggetti all’interno del f<strong>il</strong>e verrebbero importati i dati,<br />
un oggetto alla volta.<br />
Figura 5.6: La struttura <strong>di</strong> un oggetto<br />
Per ciascun oggetto è obbligatoria la presenza <strong>di</strong> alcuni blocchi:<br />
• <strong>il</strong> nome, fondamentale <strong>per</strong> in<strong>di</strong>viduarlo nella fase seguente quando sarà neces-<br />
sario ricostruire l’albero della scena;<br />
• i vertici, memorizzati come <strong>una</strong> lista <strong>di</strong> coor<strong>di</strong>nate;<br />
• le facce, rigorosamente triangolari, salvate nel f<strong>il</strong>e come triplette <strong>di</strong> in<strong>di</strong>ci.<br />
Questi in<strong>di</strong>ci si riferiscono all’array <strong>di</strong> vertici caricato precedentemente;
CAPITOLO 5. IL LOADER 34<br />
• <strong>il</strong> sistema <strong>di</strong> riferimento locale, ovvero <strong>il</strong> centro e gli assi del sistema <strong>di</strong> coor-<br />
<strong>di</strong>nate locale dell’oggetto, spesso <strong>di</strong>fferente dal sistema <strong>di</strong> riferimento globale.<br />
Questo insieme <strong>di</strong> dati consente <strong>di</strong> definire <strong>una</strong> semplice mesh <strong>di</strong> triangoli 6 senza<br />
alcun materiale ma con <strong>una</strong> collocazione nell’ambiente virtuale.<br />
Ulteriori dati facoltativi sono re<strong>per</strong>ib<strong>il</strong>i in questa sezione, fra cui <strong>il</strong> materiale asso-<br />
ciato a ciasc<strong>una</strong> delle facce appartenenti all’oggetto e le coor<strong>di</strong>nate delle texture <strong>per</strong><br />
ciascun vertice.<br />
Per minimizzare lo spreco <strong>di</strong> memoria, e <strong>per</strong> evitare un flusso <strong>di</strong> dati troppo elevato<br />
fra la RAM e la memoria della scheda video (che ridurrebbe notevolmente le pre-<br />
stazioni), le texture vengono caricate <strong>una</strong> sola volta e con<strong>di</strong>vise fra tutti gli oggetti<br />
che ne fanno uso.<br />
5.5.3 La gerarchia<br />
Le ultime informazioni re<strong>per</strong>ib<strong>il</strong>i all’interno del f<strong>il</strong>e sono quelle riguardanti la gerar-<br />
chia. Gli oggetti finora importati sono stati memorizzati in un array in attesa che<br />
venga ricreata la struttura ad albero che c’era al momento in cui furono esportati<br />
da 3DStu<strong>di</strong>o.<br />
Gli oggetti sono in<strong>di</strong>viduati all’interno dell’array grazie al proprio nome. Ciascun<br />
nodo dell’albero della gerarchia presente in questo chunk deve obbligatoriamente<br />
aver definiti in questa sezione i seguenti dati:<br />
• un numero identificativo unico all’interno del f<strong>il</strong>e, ut<strong>il</strong>izzato dai figli <strong>per</strong> in<strong>di</strong>-<br />
viduarlo come proprio padre;<br />
• <strong>il</strong> numero identificativo del proprio padre;<br />
• le tre trasformazioni geometriche che influiscono <strong>su</strong>ll’oggetto (e <strong>su</strong>i <strong>su</strong>oi figli):<br />
la traslazione, la rotazione <strong>su</strong> un’asse arbitrario, <strong>il</strong> ri<strong>di</strong>mensionamento <strong>su</strong>i tre<br />
assi (non necessariamente uniforme).<br />
In questa fase vengono anche introdotte le entità che giustificano la presenza del-<br />
la classe Group, ovvero i gruppi. I gruppi non compaiono nella fase <strong>di</strong> parsing<br />
6 Triangle mesh (maglia <strong>di</strong> triangoli) è un termine comunemente ut<strong>il</strong>izzato <strong>per</strong> identificare un modello<br />
complesso formato dall’unione <strong>di</strong> più triangoli.
CAPITOLO 5. IL LOADER 35<br />
Figura 5.7: La struttura <strong>di</strong> un nodo della gerarchia<br />
degli oggetti e <strong>per</strong>ciò non contengono né geometria né materiali. Essi sono no<strong>di</strong><br />
contrad<strong>di</strong>stinti da un nome particolare 7 e ut<strong>il</strong>izzati <strong>per</strong>:<br />
• raggruppare oggetti e altri gruppi, in base a un criterio <strong>di</strong> composizione pratico<br />
in caso <strong>di</strong> modelli complessi definib<strong>il</strong>i tramite sottoparti più semplici;<br />
• applicare le proprie trasformazioni a tutti i figli.<br />
Una volta introdotti anche i gruppi nell’array degli oggetti <strong>il</strong> lavoro <strong>di</strong> ricreazione<br />
dell’albero della scena è elementare. È infatti <strong>su</strong>fficiente scorrere <strong>il</strong> vettore, un<br />
elemento alla volta, leggere <strong>il</strong> numero identificativo dei padri, re<strong>per</strong>irli e aggiungervi<br />
come figli gli elementi in<strong>di</strong>viduati come tali.<br />
5.6 Il postprocessing<br />
Una volta ottenuta la gerarchia completa del modello importato dal f<strong>il</strong>e si esegue<br />
la precomputazione <strong>di</strong> tutte le trasformazioni, nodo <strong>per</strong> nodo. Questo è opportuno<br />
7 Nel blocco del nome è infatti presente la stringa $$$DUMMY, mentre <strong>il</strong> reale nome del gruppo si<br />
trova in un <strong>su</strong>ccessivo blocco de<strong>di</strong>cato (cfr. Appen<strong>di</strong>ce A).
CAPITOLO 5. IL LOADER 36<br />
<strong>per</strong> limitare le o<strong>per</strong>azioni da eseguire <strong>su</strong> ogni vertice in tempo reale, migliorando<br />
notevolmente le prestazioni in fase <strong>di</strong> rendering.<br />
Ciò non preclude comunque la possib<strong>il</strong>ità <strong>di</strong> ut<strong>il</strong>izzare trasformazioni geometriche<br />
in tempo reale, come verrà spiegato nella sezione 6.5, ma elimina <strong>il</strong> sovraccarico<br />
computazionale non necessario in realtime in quanto generato da oggetti statici, <strong>su</strong>i<br />
quali cioè non influiscono trasformazioni geometriche variab<strong>il</strong>i nel tempo.<br />
I vertici all’interno <strong>di</strong> un f<strong>il</strong>e 3DS sono solitamente memorizzati già trasformati, ma<br />
non sempre nella maniera corretta. Solo dopo un’attenta analisi del contenuto <strong>di</strong><br />
vari f<strong>il</strong>e si è giunti a capire <strong>il</strong> problema dell’errata memorizzazione dei vertici, che si<br />
è rivelata avvenire nel caso in cui la terna <strong>di</strong> assi del sistema <strong>di</strong> riferimento locale<br />
dell’oggetto non sia identica a quella del sistema <strong>di</strong> riferimento globale.<br />
È stato quin<strong>di</strong> necessario sv<strong>il</strong>uppare due meto<strong>di</strong>: uno <strong>per</strong> trasportare correttamente<br />
i vertici dal sistema locale al sistema globale eliminando gli errori e uno <strong>per</strong> trasfor-<br />
marli in base ai dati caricati dal f<strong>il</strong>e nella terza fase del parsing. Tradurre questo<br />
in co<strong>di</strong>ce non si è rivelato <strong>per</strong>ò <strong>su</strong>fficiente, in quanto si è notato che gli errori si<br />
tramandano <strong>di</strong> figlio in figlio sino alle foglie dell’albero della scena. Lo stesso vale<br />
anche <strong>per</strong> le trasformazioni geometriche corrette, che sono da applicare all’intero<br />
sottoalbero avente come ra<strong>di</strong>ce l’oggetto a cui si riferiscono.<br />
5.6.1 La correzione degli errori<br />
La corretta metodologia <strong>per</strong> eliminare gli errori consiste nel calcolare la trasforma-<br />
zione che, applicata al sistema <strong>di</strong> riferimento locale dell’oggetto, lo trasformi nel<br />
sistema <strong>di</strong> riferimento globale. A questo punto è <strong>su</strong>fficiente applicarla all’oggetto e<br />
a tutti i <strong>su</strong>oi figli, e infine <strong>per</strong> ciascun figlio eseguire lo stesso algoritmo dall’inizio,<br />
effettuando in pratica <strong>una</strong> sorta <strong>di</strong> scansione in pre-order 8 dell’albero, poiché gli<br />
errori del nodo padre vengono corretti prima <strong>di</strong> quelli relativi ai <strong>su</strong>oi sottoalberi. Se<br />
8Esistono tre modalità <strong>di</strong> scansione <strong>di</strong> un albero binario: pre-order (<strong>per</strong> ciascun nodo viene prima<br />
scan<strong>di</strong>to <strong>il</strong> nodo stesso, quin<strong>di</strong> <strong>il</strong> sottoalbero sinistro e quello destro), in-order (viene scan<strong>di</strong>to <strong>il</strong><br />
sottoalbero sinistro, poi <strong>il</strong> nodo stesso e infine <strong>il</strong> sottoalbero destro) e post-order (vengono scan<strong>di</strong>ti<br />
i due sottoalberi e infine <strong>il</strong> nodo stesso). I nostri non sono necessariamente alberi binari, <strong>per</strong> cui<br />
questa terminologia non è totalmente corretta. È stata tuttavia ut<strong>il</strong>izzata <strong>per</strong>ché si ritiene che<br />
renda bene l’idea <strong>di</strong> come o<strong>per</strong>i l’algoritmo. [SED93]
CAPITOLO 5. IL LOADER 37<br />
si parte dalla ra<strong>di</strong>ce, al termine della computazione l’intera scena sarà correttamente<br />
preparata <strong>per</strong> la <strong>su</strong>ccessiva applicazione delle trasformazioni importate dal f<strong>il</strong>e.<br />
Per <strong>il</strong> calcolo delle matrici si ado<strong>per</strong>a un metodo <strong>di</strong>verso da quello spiegato, in quanto<br />
in realtà si ut<strong>il</strong>izza l’inversa della matrice che trasforma <strong>il</strong> sistema <strong>di</strong> riferimento<br />
globale in quello locale. Supponendo che <strong>il</strong> sistema <strong>di</strong> riferimento locale, con i tre<br />
assi normalizzati, sia<br />
<<br />
⎛<br />
⎜<br />
⎝<br />
xx<br />
xy<br />
xz<br />
⎞<br />
⎛<br />
⎟ ⎜<br />
⎠ , ⎝<br />
yx<br />
yy<br />
zz<br />
⎞<br />
⎛<br />
⎟ ⎜<br />
⎠ , ⎝<br />
e rammentando che quello globale è semplicemente<br />
0<br />
0<br />
1<br />
zx<br />
zy<br />
zz<br />
⎞<br />
⎟<br />
⎠ ><br />
⎛ ⎞ ⎛ ⎞ ⎛ ⎞<br />
1 0 0<br />
⎜ ⎟ ⎜ ⎟ ⎜ ⎟<br />
< ⎝ 0 ⎠ , ⎝ 1 ⎠ , ⎝ 0 ⎠ ><br />
è elementare calcolare (passando alle coor<strong>di</strong>nate omogenee9 ) la matrice<br />
⎛<br />
⎞<br />
⎜<br />
M = ⎜<br />
⎝<br />
xx yx zx 0<br />
xy yy zy 0<br />
xz yz zz 0<br />
0 0 0 1<br />
tale che ⎛<br />
⎞<br />
xx<br />
⎜ xy ⎜<br />
⎝ xz<br />
yx<br />
yy<br />
yz<br />
zx<br />
zy<br />
zz<br />
0<br />
⎟<br />
0 ⎟<br />
0<br />
⎟<br />
⎠<br />
0 0 0 1<br />
×<br />
⎛ ⎞<br />
1<br />
⎜ ⎟<br />
⎜<br />
0 ⎟<br />
⎜<br />
⎝ 0<br />
⎟<br />
⎠<br />
0<br />
=<br />
⎛<br />
⎜<br />
⎝<br />
⎛<br />
⎞<br />
xx<br />
⎜ xy ⎜<br />
⎝ xz<br />
yx<br />
yy<br />
yz<br />
zx<br />
zy<br />
zz<br />
0<br />
⎟<br />
0 ⎟<br />
0<br />
⎟<br />
⎠<br />
0 0 0 1<br />
×<br />
⎛ ⎞<br />
0<br />
⎜ ⎟<br />
⎜<br />
1 ⎟<br />
⎜<br />
⎝ 0<br />
⎟<br />
⎠<br />
0<br />
=<br />
⎛<br />
⎜<br />
⎝<br />
9 Le coor<strong>di</strong>nate tri<strong>di</strong>mensionali omogenee sono nella forma (x, y, z, w) T . La quarta coor<strong>di</strong>nata è<br />
ut<strong>il</strong>e <strong>per</strong> vari scopi; agevola ad esempio la proiezione e consente <strong>di</strong> applicare ri<strong>di</strong>mensionamenti e<br />
traslazioni <strong>per</strong> mezzo <strong>di</strong> matrici. [MOR89]<br />
⎟<br />
⎠<br />
xx<br />
xy<br />
xz<br />
0<br />
yx<br />
yy<br />
yz<br />
0<br />
⎞<br />
⎟<br />
⎠<br />
⎞<br />
⎟<br />
⎠
CAPITOLO 5. IL LOADER 38<br />
⎛<br />
⎞<br />
xx<br />
⎜ xy ⎜<br />
⎝ xz<br />
yx<br />
yy<br />
yz<br />
zx<br />
zy<br />
zz<br />
0<br />
⎟<br />
0 ⎟<br />
0<br />
⎟<br />
⎠<br />
0 0 0 1<br />
×<br />
⎛ ⎞<br />
0<br />
⎜ ⎟<br />
⎜<br />
0 ⎟<br />
⎜<br />
⎝ 1<br />
⎟<br />
⎠<br />
0<br />
=<br />
⎛<br />
⎜<br />
⎝<br />
Per la <strong>su</strong>a inversione è infine <strong>su</strong>fficiente applicare <strong>il</strong> metodo del determinante, otte-<br />
nendo la matrice associata alla trasformazione desiderata, che è<br />
M −1 ⎛<br />
⎞<br />
det00/D<br />
⎜<br />
= ⎜<br />
−det01/D<br />
⎜<br />
⎝ det02/D<br />
−det10/D<br />
det11/D<br />
−det12/D<br />
det20/D<br />
−det21/D<br />
det22/D<br />
−det30/D<br />
⎟<br />
det31/D ⎟<br />
−det32/D<br />
⎟<br />
⎠<br />
−det03/D det13/D −det23/D det33/D<br />
dove i detij sono i determinanti delle sottomatrici 3 × 3 ottenute togliendo da M la<br />
riga i e la colonna j, mentre D è <strong>il</strong> determinante della matrice M. [ABA96]<br />
Se <strong>per</strong> un nodo si ha che Mp è la matrice <strong>per</strong> la correzione degli errori del padre,<br />
e Mf è quella atta a correggere gli errori del nodo stesso, <strong>su</strong> tale nodo Mp verrà<br />
applicata prima <strong>di</strong> Mf. Nulla ovviamente impe<strong>di</strong>sce <strong>il</strong> fatto che Mp sia a <strong>su</strong>a volta<br />
<strong>una</strong> matrice ottenuta <strong>per</strong> composizione <strong>di</strong> due o più altre matrici.<br />
5.6.2 L’applicazione delle trasformazioni geometriche<br />
Al termine dell’o<strong>per</strong>azione <strong>di</strong> correzione degli errori è possib<strong>il</strong>e applicare le tra-<br />
sformazioni geometriche (traslazione, rotazione e ri<strong>di</strong>mensionamento) corrette, che<br />
sono state importate e memorizzate temporaneamente nella terza fase <strong>di</strong> parsing.<br />
Per simmetria con la sezione precedente questa o<strong>per</strong>azione deve essere effettuata<br />
tramite <strong>una</strong> specie <strong>di</strong> scansione in post-order 10 <strong>su</strong>ll’albero.<br />
Il ri<strong>di</strong>mensionamento è applicato <strong>per</strong> primo, quin<strong>di</strong> avviene la rotazione <strong>su</strong> un asse<br />
arbitrario ed infine la traslazione.<br />
Per la rotazione sono stati ut<strong>il</strong>izzati i quaternioni, vettori quadri<strong>di</strong>mensionali compo-<br />
sti da uno scalare e da un vettore tri<strong>di</strong>mensionale che sono in grado <strong>di</strong> rappresentare<br />
un angolo <strong>di</strong> rotazione e l’asse <strong>su</strong> cui deve avvenire tale rotazione. Dato l’angolo θ<br />
e l’asse normalizzato (ax, ay, az) T è <strong>di</strong>fatti possib<strong>il</strong>e definire i due quaternioni<br />
10 Cfr. nota a piè <strong>di</strong> pagina 8.<br />
zx<br />
zy<br />
zz<br />
0<br />
⎞<br />
⎟<br />
⎠<br />
q = (cos θ<br />
2 , [ax · sin θ<br />
2 , ay · sin θ<br />
2 , az · sin θ<br />
2 ])
CAPITOLO 5. IL LOADER 39<br />
q ′ = (cos θ<br />
2 , [ax · (− sin θ<br />
2 ), ay · (− sin θ<br />
2 ), az · (− sin θ<br />
2 )])<br />
e rappresentare <strong>il</strong> punto (x, y, z) T da ruotare con la notazione<br />
<strong>per</strong> poter ottenere <strong>il</strong> punto ruotato<br />
p = (0, [x, y, z])<br />
p ′ = qpq ′ = (0, [x ′ , y ′ , z ′ ]) = (x ′ , y ′ , z ′ ) T<br />
Si rimanda all’Appen<strong>di</strong>ce F <strong>per</strong> chiarimenti riguardanti la modalità <strong>di</strong> esecuzione<br />
della rotazione tramite quaternioni. [KDL98]<br />
Il ri<strong>di</strong>mensionamento consiste in <strong>una</strong> moltiplicazione delle tre coor<strong>di</strong>nate del punto<br />
(x, y, z) T <strong>per</strong> <strong>il</strong> coefficiente corrispondente preso dal vettore (sx, sy, sz) T , portando a<br />
(x ′ , y ′ , z ′ ) T = (sx · x, sy · y, sz · z) T<br />
L’applicazione della traslazione è <strong>una</strong> semplice somma del punto (x, y, z) T con <strong>il</strong><br />
vettore dello spostamento (tx, ty, tz) T , da cui si ottiene <strong>il</strong> nuovo punto<br />
(x ′ , y ′ , z ′ ) T = (x + tx, y + ty, z + tz) T<br />
Tutte queste trasformazioni sono applicate in maniera inversa rispetto a quelle della<br />
fase precedente, <strong>per</strong> cui se <strong>per</strong> un nodo P si ha che la matrice Tp è associata alle<br />
trasformazioni del padre e la matrice Tf è associata a quelle del nodo stesso, verrà<br />
applicata al nodo prima Tf e poi Tp. Anche in questo caso nulla impe<strong>di</strong>sce a Tp <strong>di</strong><br />
essere a <strong>su</strong>a volta <strong>una</strong> composizione <strong>di</strong> due o più matrici associate a trasformazioni.<br />
5.6.3 La collocazione <strong>di</strong> queste o<strong>per</strong>azioni<br />
Queste procedure <strong>di</strong> postprocessing sono effettivamente un ibrido interme<strong>di</strong>o fra<br />
l’importazione dal formato 3DS e la gestione dei dati, e ri<strong>su</strong>ltano <strong>per</strong>ciò <strong>una</strong> parzia-<br />
le violazione al principio <strong>di</strong> separazione fra formato e semantica. Tuttavia introdurle<br />
all’interno <strong>di</strong> Group e Object anziché in Loader3DS sarebbe stato ugualmente errato,<br />
in quanto avrebbe introdotto conoscenze <strong>su</strong>l formato <strong>di</strong> provenienza all’interno delle<br />
due classi designate a gestire unicamente la semantica. Per motivi <strong>di</strong> ottimizzazione<br />
dell’ut<strong>il</strong>izzo della memoria – in quanto l’eliminazione degli errori e l’applicazione del-<br />
le trasformazioni avvengono unicamente in fase <strong>di</strong> loa<strong>di</strong>ng del f<strong>il</strong>e – le due procedure<br />
sono <strong>per</strong>ciò state introdotte nella classe Loader3DS.
CAPITOLO 6<br />
La gestione della gerarchia<br />
6.1 Le funzionalità <strong>per</strong> l’ut<strong>il</strong>izzo della gerarchia<br />
3DStu<strong>di</strong>o mantiene in memoria un albero contenente la gerarchia dell’intera scena,<br />
e la esporta nei <strong>su</strong>oi f<strong>il</strong>e 3DS. Tale gerarchia viene importata dal loader 3DS e ri-<br />
creata grazie ai meto<strong>di</strong> implementati all’interno delle classi Group e Object, ovvero<br />
quelli <strong>per</strong> l’aggiunta e la rimozione dei figli e <strong>per</strong> la mo<strong>di</strong>fica del padre <strong>di</strong> un nodo.<br />
È quin<strong>di</strong> possib<strong>il</strong>e gestire la gerarchia ut<strong>il</strong>izzando gli stessi meto<strong>di</strong> sopracitati <strong>per</strong><br />
mo<strong>di</strong>ficare, unire e <strong>di</strong>videre a piacimento gli alberi; sono inoltre stati implementati<br />
ulteriori meto<strong>di</strong> <strong>per</strong> invocare <strong>il</strong> rendering dell’intero albero, <strong>per</strong> applicare trasfor-<br />
mazioni geometriche in tempo reale <strong>su</strong>i vari no<strong>di</strong> e <strong>per</strong> or<strong>di</strong>nare gli stessi no<strong>di</strong> in<br />
base alla loro <strong>di</strong>stanza dal punto <strong>di</strong> vista. Tutto questo sarà analizzato in maniera<br />
dettagliata nel corso del capitolo.<br />
Viene ut<strong>il</strong>izzato anche <strong>per</strong> la gestione della gerarchia <strong>il</strong> runtime bin<strong>di</strong>ng 1 . Entram-<br />
be le classi mantengono i collegamenti con <strong>il</strong> padre e i figli tramite puntatori a<br />
Group, in<strong>di</strong>pendentemente dalla reale istanziazione (Group o Object) <strong>di</strong> tali no<strong>di</strong>;<br />
l’esecuzione del metodo corretto è <strong>di</strong> volta in volta assicurata dal bin<strong>di</strong>ng in fase <strong>di</strong><br />
esecuzione.<br />
Le classi Object e Group sono state create con lo scopo <strong>di</strong> gestire la gerarchia dei<br />
modelli e favorire la renderizzazione dell’intero albero <strong>di</strong> oggetti <strong>per</strong> mezzo <strong>di</strong> sem-<br />
plici chiamate a meto<strong>di</strong>. Le funzionalità implementate fanno in gran parte uso <strong>di</strong><br />
procedure a cascata che, a partire dal nodo <strong>su</strong> cui sono state invocate, si <strong>di</strong>ramano<br />
<strong>su</strong> tutti i figli e giungono sino alle foglie del sottoalbero.<br />
1 Cfr. 5.1 a pagina 24.<br />
40
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 41<br />
La classe Group sv<strong>il</strong>uppa un oggetto che può fungere da nodo attivo dell’albero, in<br />
quanto al <strong>su</strong>o interno sono implementati tutti i principali meto<strong>di</strong> <strong>per</strong> l’ut<strong>il</strong>izzo <strong>di</strong><br />
<strong>una</strong> struttura <strong>di</strong> questo tipo, primi fra i quali quelli <strong>per</strong> aggiungere e rimuovere i<br />
figli e <strong>per</strong> impostare <strong>il</strong> padre. Sono inoltre presenti funzionalità più avanzate quali<br />
<strong>il</strong> culling e l’or<strong>di</strong>namento dei no<strong>di</strong> figli in base alla loro <strong>di</strong>stanza dal punto <strong>di</strong> vista,<br />
molto ut<strong>il</strong>i in fase <strong>di</strong> rendering. La classe Object estende Group, e possiede <strong>per</strong>ciò<br />
anche tutti i meto<strong>di</strong> della classe padre.<br />
6.2 L’importanza <strong>di</strong> <strong>una</strong> gerarchia<br />
Come accennato parte delle funzionalità implementate sono de<strong>di</strong>cate alla creazione<br />
ed alla gestione della gerarchia. Lo scopo principale <strong>di</strong> tali funzionalità è <strong>per</strong>met-<br />
tere <strong>una</strong> ricostruzione fedele della gerarchia presente nei f<strong>il</strong>e 3DS da essi importata<br />
<strong>per</strong> mezzo del loader. La memorizzazione della gerarchia <strong>di</strong>rettamente all’interno<br />
dei no<strong>di</strong> consente <strong>per</strong>ò delle possib<strong>il</strong>ità che non si limitano alla creazione <strong>di</strong> <strong>una</strong><br />
mera copia statica del contenuto dei f<strong>il</strong>e 3DS. Tramite i meto<strong>di</strong> <strong>per</strong> l’aggiunta e la<br />
rimozione dei figli e <strong>per</strong> la reimpostazione del padre è possib<strong>il</strong>e infatti mo<strong>di</strong>ficare<br />
la gerarchia a proprio piacimento in tempo reale. Questo approccio modulare in<br />
cui ciascun nodo è conscio della propria posizione all’interno dell’albero gerarchico<br />
<strong>per</strong>mette, tramite i sopracitati meto<strong>di</strong>, <strong>di</strong> avere fra le mani un vero e proprio e<strong>di</strong>tor<br />
della gerarchia ut<strong>il</strong>izzab<strong>il</strong>e in realtime all’interno degli applicativi.<br />
Ma <strong>per</strong>ché è importante <strong>una</strong> gerarchia? La risposta è semplice. Perché all’interno<br />
<strong>di</strong> un albero gerarchico si possono effettuare interventi al livello <strong>di</strong> specializzazione<br />
desiderato, lavorando mentalmente come facciamo nel mondo reale. Siamo soliti<br />
<strong>di</strong>fatti pensare agli oggetti nel loro complesso, salvo poi scendere ad un maggiore<br />
livello <strong>di</strong> particolarizzazione <strong>per</strong> motivi <strong>di</strong> precisione. È <strong>su</strong>fficiente pensare alla<br />
<strong>di</strong>fferenza fra un automob<strong>il</strong>e dal punto <strong>di</strong> vista <strong>di</strong> un automob<strong>il</strong>ista me<strong>di</strong>o e dal punto<br />
<strong>di</strong> vista <strong>di</strong> un meccanico che deve effettuare <strong>una</strong> riparazione. Grazie alla gerarchia<br />
in un programma possiamo applicare <strong>una</strong> trasformazione geometrica all’automob<strong>il</strong>e<br />
intera (<strong>per</strong> muoverla come farebbe l’automob<strong>il</strong>ista me<strong>di</strong>o) e possiamo sostituire un<br />
nodo del sottoalbero avente come ra<strong>di</strong>ce la stessa automob<strong>il</strong>e (<strong>per</strong> effettuare <strong>una</strong><br />
riparazione come farebbe <strong>il</strong> meccanico).<br />
La gerarchia ha quin<strong>di</strong> un duplice compito:
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 42<br />
Figura 6.1: Le trasformazioni geometriche <strong>su</strong> un nodo si <strong>di</strong>ffondono <strong>su</strong>l <strong>su</strong>o sottoalbero<br />
• fac<strong>il</strong>ita la comprensib<strong>il</strong>ità della scena rappresentandola come un’albero nel<br />
quale <strong>il</strong> livello <strong>di</strong> specializzazione cresce man mano che si <strong>di</strong>scende verso le<br />
foglie;<br />
• implementa <strong>una</strong> struttura a no<strong>di</strong> ut<strong>il</strong>e <strong>per</strong> la rappresentazione <strong>di</strong> un sistema<br />
cinematico con vincoli, come quello presente nei f<strong>il</strong>e 3DS, ovvero un sistema<br />
nel quale sono presenti trasformazioni geometriche definite <strong>su</strong> un nodo ma che<br />
influiscono <strong>su</strong>ll’intero sottoalbero avente tale nodo come ra<strong>di</strong>ce, come nel caso<br />
del braccio in Figura 6.1.<br />
Per sod<strong>di</strong>sfare tali scopi sono state progettate e realizzate le funzionalità della classe<br />
Group. La gerarchia implementata è mantenuta dagli stessi no<strong>di</strong> <strong>per</strong> mezzo <strong>di</strong><br />
puntatori al padre ed ai figli. Grazie a questa stuttura modulare è quin<strong>di</strong> fac<strong>il</strong>e –<br />
tramite i già citati meto<strong>di</strong> <strong>per</strong> l’aggiunta e la rimozione dei figli e <strong>per</strong> l’impostazione<br />
del padre – unire fra loro vari alberi importati da f<strong>il</strong>e <strong>di</strong>fferenti. Può ad esempio<br />
essere pratico ut<strong>il</strong>izzare nei programmi un gruppo globale nel quale inserire come<br />
figli tutti i modelli 3D caricati <strong>di</strong> volta in volta da vari f<strong>il</strong>e 3DS. Potrebbe anche
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 43<br />
essere altrettanto ut<strong>il</strong>e caricare un’automob<strong>il</strong>e da un f<strong>il</strong>e separato e aggiungerla<br />
come oggetto figlio all’interno <strong>di</strong> un modello <strong>di</strong> <strong>una</strong> città complessa; sarebbe in<br />
tal caso elementare variare <strong>il</strong> modello dell’automob<strong>il</strong>e mantenendo intatta la città<br />
circostante, come mostrato in Figura 6.2.<br />
Per mezzo dei citati meto<strong>di</strong> è possib<strong>il</strong>e anche la creazione <strong>di</strong> grafi, ma l’ut<strong>il</strong>izzo <strong>di</strong> tale<br />
funzionalità è deprecato in quanto induce problemi <strong>di</strong> loop infinito nell’esecuzione<br />
degli algoritmi a cascata. Non viene effettuato automaticamente un controllo <strong>su</strong>lla<br />
presenza <strong>di</strong> cicli – ma si pone tale verifica a carico dell’utente – <strong>per</strong> ovvi motivi <strong>di</strong><br />
<strong>per</strong>formance.<br />
Grazie alle funzionalità riguardanti la gerarchia è stato infine possib<strong>il</strong>e implementare<br />
<strong>una</strong> serie <strong>di</strong> meto<strong>di</strong> orientati agli interi sottoalberi aventi come ra<strong>di</strong>ce <strong>il</strong> nodo <strong>su</strong> cui<br />
vengono invocati. Essi consentono l’applicazione e la mo<strong>di</strong>fica in tempo reale delle<br />
trasformazioni geometriche (cfr. 6.5), <strong>il</strong> culling a più livelli <strong>di</strong> profon<strong>di</strong>tà (cfr. 6.4),<br />
molto <strong>per</strong>formante soprattutto nel caso <strong>di</strong> oggetti dettagliati ovvero con molti vertici<br />
piuttosto vicini fra loro, e l’or<strong>di</strong>namento <strong>di</strong> tutti i no<strong>di</strong> figli in funzione della loro<br />
<strong>di</strong>stanza dal punto <strong>di</strong> vista (cfr. 6.6).<br />
6.3 Boun<strong>di</strong>ng box e centro <strong>di</strong> un oggetto<br />
Appoggiandosi <strong>su</strong>lla gerarchia sono state implementate delle funzionalità <strong>per</strong> calco-<br />
lare e mantenere in memoria anche <strong>una</strong> rappresentazione semplificata dei vari no<strong>di</strong>,<br />
ovvero la boun<strong>di</strong>ng box e <strong>il</strong> centro <strong>di</strong> ciascuno <strong>di</strong> essi. Entrambi i dati sono parti-<br />
colarmente importanti sia <strong>per</strong> <strong>il</strong> culling (presentato in 6.4), che viene eseguito <strong>su</strong>lle<br />
boun<strong>di</strong>ng box, sia <strong>per</strong> le trasformazioni in tempo reale (cfr. 6.5) e l’or<strong>di</strong>namento dei<br />
no<strong>di</strong> (cfr. 6.6) in base alla loro <strong>di</strong>stanza dal punto <strong>di</strong> vista, che fanno uso del centro.<br />
Per boun<strong>di</strong>ng box <strong>di</strong> un oggetto si intende <strong>il</strong> più piccolo parallelepipedo contenente<br />
tutti i <strong>su</strong>oi vertici. Sono tuttavia spesso ut<strong>il</strong>izzati (e denominati ugualmente boun-<br />
<strong>di</strong>ng box) dei parallelepipe<strong>di</strong> non minimi ma rispettanti la proprietà <strong>di</strong> contenenza<br />
e caratterizzati da <strong>una</strong> più rapida calcolab<strong>il</strong>ità.<br />
Nel caso <strong>di</strong> questa <strong>libreria</strong>, appunto <strong>per</strong> motivi <strong>di</strong> velocità computazionale, l’algo-<br />
ritmo sv<strong>il</strong>uppato non calcola <strong>il</strong> parallelepipedo più piccolo fra tutti, ma solamente<br />
<strong>il</strong> minore in volume fra quelli aventi i lati paralleli ai tre assi (cfr. Figura 6.3).<br />
La creazione <strong>di</strong> <strong>una</strong> boun<strong>di</strong>ng box si riduce quin<strong>di</strong> alla estrazione fra tutti i vertici
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 44<br />
Figura 6.2: Con <strong>una</strong> semplice o<strong>per</strong>azione logica si può sostituire l’oggetto Automob<strong>il</strong>e 1<br />
con l’oggetto Automob<strong>il</strong>e 2 lasciando invariato <strong>il</strong> resto della gerarchia
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 45<br />
Figura 6.3: Boun<strong>di</strong>ng box minima (in grigio) e <strong>di</strong> rapida computazione (in nero)<br />
dell’oggetto dei valori minimi e massimi <strong>su</strong>lle tre coor<strong>di</strong>nate; dati questi sei valori è<br />
elementare ricreare <strong>il</strong> parallelepipedo.<br />
Extract Min(Array[0..n-1]):<br />
1: Minimo = Array[0]<br />
2: for i from 1 to n - 1 do<br />
3: if Array[i] < Minimo then Minimo = Array[i] en<strong>di</strong>f<br />
4: endfor<br />
Tabella 6.1: Estrazione del minimo<br />
Trattandosi <strong>di</strong> un semplice algoritmo <strong>di</strong> estrazione <strong>di</strong> minimi e massimi (analogo a<br />
quello nella Tabella 6.1), si può notare fac<strong>il</strong>mente come esso sia linearmente <strong>di</strong>pen-<br />
dente dal numero <strong>di</strong> elementi nell’array, che nel caso della boun<strong>di</strong>ng box equivale<br />
al numero <strong>di</strong> vertici presenti nell’oggetto. Essendo <strong>il</strong> sovraccarico computazionale<br />
<strong>per</strong> la generazione degli otto vertici del parallelepipedo (dati i tre minimi ed i tre<br />
massimi) <strong>di</strong> peso costante, si può <strong>di</strong>re che la complessità dell’algoritmo <strong>per</strong> calcolare
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 46<br />
la boun<strong>di</strong>ng box <strong>di</strong> un oggetto sia<br />
O(6n) + O(c) = O(6n) = O(n) (6.1)<br />
dove n è <strong>il</strong> numero dei vertici e c è la costante <strong>per</strong> la computazione del parallelepipedo<br />
dati i minimi e i massimi. La complessità dell’algoritmo <strong>per</strong> estrarre la boun<strong>di</strong>ng<br />
box <strong>di</strong> un oggetto <strong>di</strong>pende quin<strong>di</strong> linearmente dalla quantità <strong>di</strong> vertici nel modello.<br />
Nella realtà della gerarchia <strong>per</strong>ò non è <strong>su</strong>fficiente o<strong>per</strong>are solo in funzione dei vertici<br />
in quanto la boun<strong>di</strong>ng box <strong>di</strong> un nodo contiene non solo tutti i vertici del nodo<br />
ma anche tutte le boun<strong>di</strong>ng box dei figli. L’algoritmo <strong>di</strong>venta <strong>per</strong>ciò quello esposto<br />
tramite pseudoco<strong>di</strong>ce nella Tabella 6.2.<br />
Calculate Boun<strong>di</strong>ng Box:<br />
1: scorri tutti i vertici ed estrai i valori minimi e massimi delle coor<strong>di</strong>nate<br />
2: for i from 0 to numero <strong>di</strong> figli <strong>di</strong>retti - 1 do<br />
3: figli <strong>di</strong>retti[i].Calculate Boun<strong>di</strong>ng Box<br />
4: endfor<br />
5: for i from 0 to numero <strong>di</strong> figli <strong>di</strong>retti - 1 do<br />
6: if un valore <strong>di</strong> figli[i].Boun<strong>di</strong>ngBox > un massimo then<br />
7: salvo <strong>il</strong> valore aggiornato del massimo<br />
8: en<strong>di</strong>f<br />
9: if un valore <strong>di</strong> figli[i].Boun<strong>di</strong>ngBox < un minimo then<br />
10: salvo <strong>il</strong> valore aggiornato del minimo<br />
11: en<strong>di</strong>f<br />
12: endfor<br />
13: calcolo gli otto vertici del parallelepipedo<br />
Tabella 6.2: Calcolo della boun<strong>di</strong>ng box <strong>per</strong> ogni nodo<br />
Si può <strong>di</strong>mostrare che l’esecuzione <strong>di</strong> questo algoritmo <strong>su</strong>lla ra<strong>di</strong>ce <strong>di</strong> un albero<br />
corrisponde all’esecuzione del metodo Calculate Boun<strong>di</strong>ng Box esclusa la chiamata<br />
a cascata <strong>su</strong>i figli <strong>una</strong> ed <strong>una</strong> sola volta <strong>su</strong> ciascun nodo del <strong>su</strong>o sottoalbero. Questo<br />
equivale a <strong>di</strong>mostrare che <strong>il</strong> ciclo delle righe 2-4 causa <strong>una</strong> scansione dell’albero,<br />
<strong>su</strong>lla cui ra<strong>di</strong>ce è stata invocata Calculate Boun<strong>di</strong>ng Box, <strong>di</strong> complessità lineare <strong>su</strong>l<br />
numero dei no<strong>di</strong> contenuti in tale albero.<br />
Ricordando che ci troviamo in presenza <strong>di</strong> un albero con ra<strong>di</strong>ce, si ha <strong>per</strong> costru-<br />
zione un orientamento degli archi dalla ra<strong>di</strong>ce alle foglie. Ogni nodo dell’albero ha
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 47<br />
quin<strong>di</strong> un solo arco entrante proveniente dal padre (ad eccezione della ra<strong>di</strong>ce, che<br />
non ha padre) e un numero <strong>di</strong> archi uscenti pari a quello dei <strong>su</strong>oi figli (1). La chia-<br />
mata da parte dell’utente del metodo Calculate Boun<strong>di</strong>ng Box avviene, sempre <strong>per</strong><br />
costruzione, <strong>una</strong> sola volta <strong>su</strong>lla ra<strong>di</strong>ce dell’albero (2).<br />
Supponiamo ora che <strong>il</strong> metodo venga eseguito più <strong>di</strong> <strong>una</strong> volta <strong>su</strong> un generico nodo x.<br />
Definendo come p la funzione “padre <strong>di</strong>” si può notare come Calculate Boun<strong>di</strong>ng Box<br />
venga invocata nello pseudoco<strong>di</strong>ce delle righe 2-4 <strong>su</strong> ciascun nodo n solamente dal pa-<br />
dre, ovvero dal nodo p(n), ad eccezione della ra<strong>di</strong>ce <strong>su</strong>lla quale è invocata dall’utente<br />
della <strong>libreria</strong>.<br />
Se x è la ra<strong>di</strong>ce si giunge <strong>su</strong>bito ad un as<strong>su</strong>rdo, in quanto Calculate Boun<strong>di</strong>ng Box<br />
non può essere stata invocata dal nodo padre <strong>di</strong> x (non esiste <strong>per</strong> (1)). Essa è <strong>per</strong>ciò<br />
stata invocata più <strong>di</strong> <strong>una</strong> volta dall’utente, <strong>il</strong> che contrad<strong>di</strong>ce (2).<br />
Se invece x non è la ra<strong>di</strong>ce, <strong>su</strong> <strong>di</strong> esso la procedura è invocata <strong>per</strong> la prima volta da<br />
p1 = p(x), quin<strong>di</strong> <strong>una</strong> seconda volta da p2 = p(x), e così via. Le possib<strong>il</strong>ità sono ora<br />
tre:<br />
• p1 �= p2, <strong>per</strong>ciò <strong>il</strong> nodo x ha due archi entranti, <strong>il</strong> che è as<strong>su</strong>rdo <strong>per</strong>ché viola<br />
(1);<br />
• p1 = p2 ed è la ra<strong>di</strong>ce dell’albero; è un as<strong>su</strong>rdo che Calculate Boun<strong>di</strong>ng Box<br />
venga eseguita due volte <strong>su</strong>lla ra<strong>di</strong>ce, in quanto in tal caso l’utente avrebbe<br />
invocato due volte tale metodo (la ra<strong>di</strong>ce non ha un nodo padre <strong>per</strong> (1)).<br />
Questo viola (2);<br />
• p1 = p2 e non è la ra<strong>di</strong>ce; in tal caso si risale l’albero applicando la presente<br />
<strong>di</strong>mostrazione al nodo p1, finché non si giunge ad uno dei due precedenti<br />
as<strong>su</strong>r<strong>di</strong>.<br />
Si è quin<strong>di</strong> <strong>di</strong>mostrato che la procedura Calculate Boun<strong>di</strong>ng Box venga eseguita al<br />
più <strong>una</strong> volta <strong>su</strong> ciascun nodo dell’albero.<br />
Siccome un albero è <strong>per</strong> definizione un grafo connesso, ovvero un grafo nel quale<br />
esiste un <strong>per</strong>corso fra qualsiasi coppia <strong>di</strong> no<strong>di</strong> a lui appartenenti, <strong>per</strong> ciascun nodo<br />
nell’albero della gerarchia esiste un <strong>per</strong>corso dalla ra<strong>di</strong>ce ad esso [CLR98]. Questo<br />
implica che <strong>per</strong> ogni nodo x si abbia che ra<strong>di</strong>ce = p(p(· · · p(x) · · ·)). Il nodo generico
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 48<br />
x sarà <strong>per</strong>ciò raggiunto sempre dalla chiamata a cascata <strong>di</strong> Calculate Boun<strong>di</strong>ng Box,<br />
tramite <strong>il</strong> cammino dato appunto da ra<strong>di</strong>ce = p(p(· · · p(x) · · ·)).<br />
Questo e la <strong>di</strong>mostrazione precedente assicurano che <strong>su</strong> ciascun nodo dell’albero<br />
Calculate Boun<strong>di</strong>ng Box sia eseguito <strong>una</strong> e <strong>una</strong> sola volta. Ciò significa che la chia-<br />
mata a cascata all’interno <strong>di</strong> Calculate Boun<strong>di</strong>ng Box esegue <strong>una</strong> scansione lineare<br />
dell’albero venendo eseguita esattamente <strong>una</strong> volta <strong>su</strong> ogni nodo.<br />
Analizziamo ora la complessità delle rimanenti righe dello pseudoco<strong>di</strong>ce:<br />
• la complessità <strong>di</strong> esecuzione della riga 1 è<br />
O(n) (6.2)<br />
dove n è <strong>il</strong> numero <strong>di</strong> vertici del nodo <strong>su</strong> cui stiamo eseguendo <strong>il</strong> metodo;<br />
questo poiché si tratta <strong>di</strong> <strong>una</strong> estrazione <strong>di</strong> tre minimi e tre massimi, ovvero<br />
<strong>una</strong> semplice scansione lineare <strong>di</strong> tutti i vertici, come chiarito nell’equazione<br />
6.1;<br />
• la complessità del ciclo delle righe 5-12 è<br />
m�<br />
(O(k)) (6.3)<br />
i=1<br />
con m numero <strong>di</strong> figli del nodo e k costante, poiché le istruzioni eseguite nelle<br />
righe 6-7 e 9-10 prendono tempo costante O(k) ma vengono iterate <strong>una</strong> volta<br />
<strong>per</strong> ciascun figlio;<br />
• la complessità dell’ultima riga è<br />
O(c) (6.4)<br />
con c costante, poiché <strong>il</strong> calcolo <strong>di</strong> otto vertici dati i tre minimi e i tre massimi<br />
è un’o<strong>per</strong>azione dal numero <strong>di</strong> istruzioni fisso.<br />
Da 6.2, 6.3 e 6.4 si può derivare come sommatoria la complessità dell’algoritmo<br />
eseguito <strong>su</strong> un generico nodo x, che è<br />
mx �<br />
O(nx) + (O(k)) + O(c) (6.5)<br />
i=1
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 49<br />
ove nx è <strong>il</strong> numero <strong>di</strong> vertici presenti in x, mx è <strong>il</strong> numero dei <strong>su</strong>oi figli, e O(k) è <strong>il</strong><br />
tempo costante impiegato <strong>per</strong> <strong>il</strong> confronto fra i valori della boun<strong>di</strong>ng box del figlio i-<br />
esimo e i minimi e massimi correntemente memorizzati. O(c) è l’u<strong>su</strong>ale sovraccarico<br />
computazionale <strong>per</strong> la creazione dei vertici del parallelepipedo. Si noti <strong>per</strong>ò come<br />
mx �<br />
i=1<br />
(O(k)) =<br />
mx volte<br />
� �� �<br />
O(k) + · · · + O(k) = O(k · mx) = O(mx) (6.6)<br />
in quanto k è costante. Anche c è costante, <strong>per</strong>ciò O(c) è un termine eliminab<strong>il</strong>e.<br />
Applicando un’ulteriore sommatoria <strong>per</strong> ottenere la complessità dell’esecuzione del-<br />
l’algoritmo <strong>su</strong> tutti i no<strong>di</strong> del sottoalbero otteniamo<br />
M�<br />
(O(nj) + O(mj)) (6.7)<br />
j=1<br />
dove nj è <strong>il</strong> numero <strong>di</strong> vertici nel nodo j-esimo, e mj <strong>il</strong> numero dei <strong>su</strong>oi figli e M<br />
<strong>il</strong> numero totale <strong>di</strong> no<strong>di</strong> presenti nell’albero. Da questa sommatoria, rammentando<br />
che in un albero ciascun nodo ha uno ed un solo padre (ad eccezione della ra<strong>di</strong>ce<br />
che non ha padre) e <strong>per</strong>ciò la somma del numero <strong>di</strong> figli <strong>di</strong> tutti i no<strong>di</strong> equivale al<br />
numero totale <strong>di</strong> no<strong>di</strong> nell’albero meno la ra<strong>di</strong>ce, si giunge alla complessità<br />
O(N) + O(M − 1) = O(N) + O(M) = O(N + M) (6.8)<br />
con N numero totale <strong>di</strong> vertici nell’albero e M numero <strong>di</strong> no<strong>di</strong> nell’albero.<br />
La complessità dell’algoritmo <strong>per</strong> <strong>il</strong> calcolo delle boun<strong>di</strong>ng box dell’intera gerarchia<br />
è quin<strong>di</strong> linearmente <strong>di</strong>pendente sia dal numero <strong>di</strong> vertici che dal numero <strong>di</strong> no<strong>di</strong><br />
presenti nell’albero.<br />
Un ulteriore elemento ut<strong>il</strong>e <strong>per</strong> la rappresentazione semplificata dell’oggetto è <strong>il</strong> <strong>su</strong>o<br />
centro. Sono state implementate due modalità <strong>di</strong> definizione del centro <strong>di</strong> un nodo.<br />
La prima consiste semplicemente in un inserimento manuale delle tre coor<strong>di</strong>nate del<br />
punto tramite meto<strong>di</strong> a<strong>di</strong>biti a tale scopo. La seconda invece consente <strong>di</strong> calcolarlo<br />
automaticamente <strong>per</strong> mezzo <strong>di</strong> <strong>una</strong> me<strong>di</strong>a fra i punti della boun<strong>di</strong>ng box. In tal<br />
caso <strong>il</strong> centro viene quin<strong>di</strong> definito come<br />
P0 + P1 + P2 + P3 + P4 + P5 + P6 + P7<br />
8
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 50<br />
dove gli otto vertici della boun<strong>di</strong>ng box sono i Pi (con i = 0 . . . 7).<br />
Sul centro e <strong>su</strong>lla boun<strong>di</strong>ng box <strong>di</strong> un oggetto si basano alcune funzionalità imple-<br />
mentate nella presente <strong>libreria</strong>, ovvero <strong>il</strong> culling, le trasformazioni geometriche in<br />
tempo reale e l’or<strong>di</strong>namento dei figli. Queste funzionalità saranno presentate <strong>una</strong> ad<br />
<strong>una</strong> nel corso del capitolo.<br />
6.4 Il culling<br />
Il volume <strong>di</strong> spazio visib<strong>il</strong>e dall’utente, denominato frustum 2 <strong>di</strong> vista, è definito <strong>per</strong><br />
mezzo <strong>di</strong> sei piani:<br />
• near e far, che sono collocati <strong>di</strong> fronte all’utente e costituiscono rispettivamente<br />
<strong>il</strong> minimo e <strong>il</strong> massimo fra le <strong>di</strong>stanze visib<strong>il</strong>i da esso (cfr. Figura 6.4);<br />
• left, right, top e bottom, che limitano la visib<strong>il</strong>ità dello spazio a sinistra, destra,<br />
sopra e sotto all’utente.<br />
Solamente la porzione <strong>di</strong> geometria collocata internamente al frustum è visib<strong>il</strong>e, e<br />
<strong>per</strong>ciò solo essa è presente nel prodotto finale della fase <strong>di</strong> rendering, ovvero <strong>il</strong> fra-<br />
me.<br />
È detto culling (in inglese significa selezione) <strong>il</strong> proce<strong>di</strong>mento in base al quale<br />
vengono eliminate porzioni <strong>di</strong> scena totalmente esterne al frustum <strong>di</strong> vista prima che<br />
giungano al termine della pipeline grafica, come spiegato poco più avanti. Grazie al<br />
culling si evita l’inut<strong>il</strong>e sovraccarico computazionale causato dal passaggio <strong>di</strong> questa<br />
geometria nella pipeline grafica in quanto verrebbe comunque <strong>su</strong>ccessivamente scar-<br />
tata; così facendo si alleggerisce molto <strong>il</strong> processo <strong>di</strong> rendering quando l’ambiente<br />
virtuale è articolato e <strong>per</strong>ciò non tutti gli oggetti sono sempre visib<strong>il</strong>i.<br />
Siccome in generale le applicazioni che faranno uso della presente <strong>libreria</strong> necessi-<br />
teranno <strong>di</strong> molti f<strong>il</strong>e 3DS si è posto <strong>il</strong> problema della troppo elevata complessità <strong>di</strong><br />
rendering. Si è <strong>per</strong>ciò ritenuto opportuno che fosse sv<strong>il</strong>uppata la funzionalità del<br />
culling.<br />
È stato <strong>per</strong>ciò implementato un algoritmo <strong>di</strong> culling <strong>su</strong>lle boun<strong>di</strong>ng box,<br />
fondato <strong>su</strong>lla proprietà che esse hanno <strong>di</strong> contenere l’intero sottoalbero <strong>su</strong>lla cui<br />
ra<strong>di</strong>ce sono definite. Il culling è attivab<strong>il</strong>e e <strong>di</strong>sattivab<strong>il</strong>e in tempo reale tramite un<br />
apposito parametro del metodo della <strong>libreria</strong> che invoca <strong>il</strong> rendering OpenGL.<br />
2 Frustum significa “tronco <strong>di</strong> solido”, in questo caso <strong>di</strong> piramide.
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 51<br />
Figura 6.4: Il culling scarta la porzione <strong>di</strong> scena che non cade all’interno del campo <strong>di</strong><br />
vista. La parte <strong>di</strong> scena non scartata è stata scurita<br />
In questa sezione verranno presentati e messi a confronto <strong>il</strong> culling <strong>per</strong> poligono a<br />
basso livello, implementato da OpenGL, e <strong>il</strong> culling <strong>per</strong> oggetto o<strong>per</strong>ante ad un più<br />
alto livello <strong>di</strong> astrazione, che è stato implementato all’interno <strong>di</strong> questo lavoro <strong>di</strong><br />
tesi. Verranno in particolar modo sottolineati i miglioramenti <strong>di</strong> <strong>per</strong>formance che <strong>il</strong><br />
culling <strong>per</strong> oggetto introduce nel rendering.<br />
Il culling OpenGL è collocato in <strong>una</strong> fase già avanzata della pipeline grafica. Riferen-<br />
doci all’immagine 6.5 possiamo osservare in alto <strong>il</strong> <strong>per</strong>corso compiuto da un vertice<br />
(proveniente dal <strong>di</strong>sco Vertex Data) prima <strong>di</strong> giungere alla rasterizzazione (Rasteri-<br />
zation). Ignorando i Valutatori (Evaluators) – che vengono ut<strong>il</strong>izzati solo qualora<br />
<strong>il</strong> vertice sia stato definito matematicamente (ad esempio in <strong>una</strong> spline) – <strong>il</strong> primo<br />
passaggio fondamentale compiuto è denominato O<strong>per</strong>azioni <strong>per</strong> vertice e assemblag-<br />
gio delle primitive. Nel caso della presente <strong>libreria</strong> le primitive sono unicamente<br />
triangoli, come detto nella sezione 5.5.2.<br />
Il culling OpenGL avviene proprio in questa fase, fra le o<strong>per</strong>azioni <strong>su</strong>i vertici e la<br />
ricostruzione dei poligoni poiché<br />
• è effettuato sia <strong>su</strong>i vertici (che vengono scartati oppure no), sia <strong>su</strong>i poligoni, che
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 52<br />
Figura 6.5: La pipeline grafica OpenGL. Informazioni geometriche (Vertex data) e informazioni<br />
raster (Pixel data) dopo varie o<strong>per</strong>azioni computazionalmente costose convergono<br />
a formare <strong>il</strong> frame che verrà vi<strong>su</strong>alizzato (contenuto nel Framebuffer)<br />
possono venire scartati, mantenuti interamente, oppure parzialmente tagliati;<br />
tagliare un poligono significa eliminare alcuni vertici e introdurne <strong>di</strong> nuovi,<br />
con le relative mo<strong>di</strong>fiche <strong>su</strong>i lati (cfr. Figura 6.6);<br />
• è in questo momento che i vertici sono in funzione del Clipping Coor<strong>di</strong>nate<br />
System (Sistema <strong>di</strong> coor<strong>di</strong>nate <strong>di</strong> clipping), un particolare sistema nel quale<br />
<strong>il</strong> campo <strong>di</strong> vista viene trasformato in un parallelepipedo e <strong>il</strong> proce<strong>di</strong>mento <strong>di</strong><br />
culling ri<strong>su</strong>lta molto più fac<strong>il</strong>e che in precedenza poiché non deve più essere<br />
eseguito <strong>su</strong> un frustum, come chiarito poco più avanti.<br />
Prima <strong>di</strong> giungere a questo sta<strong>di</strong>o ciascun vertice è stato infatti mo<strong>di</strong>ficato da:<br />
• la trasformazione del modello, che porta ogni vertice dalle proprie coor<strong>di</strong>na-<br />
te locali alle coor<strong>di</strong>nate globali del mondo; serve <strong>per</strong> posizionare gli oggetti<br />
all’interno del mondo;<br />
• la trasformazione della vista, che porta ogni vertice dalle coor<strong>di</strong>nate del mon-<br />
do alle coor<strong>di</strong>nate della vista; solitamente serve a trasformare <strong>il</strong> punto <strong>di</strong> vista
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 53<br />
Figura 6.6: Culling <strong>di</strong> punti e <strong>di</strong> poligoni: P0 viene mantenuto, P1 è scartato. T0 è<br />
mantenuto interamente, T1 solo parzialmente, T2 è scartato (in grigio le parti mantenute)<br />
nell’origine e ad orientare la <strong>di</strong>rezione dello sguardo <strong>su</strong> uno degli assi del si-<br />
stema <strong>di</strong> riferimento. In questo modo si può o<strong>per</strong>are nelle fasi <strong>su</strong>ccessive in<br />
maniera in<strong>di</strong>pendente dalla posizione del punto <strong>di</strong> vista, poiché dopo questa<br />
trasformazione esso si trova sempre in un punto <strong>di</strong> default;<br />
• la trasformazione della proiezione, che porta ogni vertice dalle coor<strong>di</strong>nate della<br />
vista al sistema <strong>di</strong> coor<strong>di</strong>nate <strong>di</strong> clipping (Clipping Coor<strong>di</strong>nate System); con<br />
questa trasformazione <strong>il</strong> frustum <strong>di</strong> vista <strong>di</strong>venta un parallelepipedo con i lati<br />
paralleli ai tre assi del sistema <strong>di</strong> riferimento globale (cfr. Figura 6.8). Un<br />
parallelepipedo con i lati paralleli agli assi definisce degli intervalli <strong>su</strong> tali<br />
assi poiché i sei piani che lo formano sono definiti come x = xmin e x =<br />
xmax, y = ymin e y = ymax, z = zmin e z = zmax, come <strong>il</strong>lustrato nella<br />
Figura 6.7. Per verificare se un punto sia all’interno oppure all’esterno <strong>di</strong><br />
un frustum è necessario comparare la <strong>su</strong>a posizione con tutti i sei piani che<br />
identificano <strong>il</strong> frustum, se al posto <strong>di</strong> un frustum si ha un parallelepipedo<br />
con i lati paralleli agli assi è <strong>su</strong>fficiente analizzare se le tre coor<strong>di</strong>nate del<br />
punto si trovino all’interno degli intervalli definiti dai piani che formano tale<br />
parallelepipedo.
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 54<br />
Figura 6.7: Un parallelepipedo con i lati paralleli ai tre assi definisce <strong>su</strong> ciascun asse un<br />
intervallo<br />
Figura 6.8: Trasformazione da coor<strong>di</strong>nate della vista a Clipping Coor<strong>di</strong>nate
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 55<br />
Ciò significa che, prima che un modello interamente esterno alla scena venga scar-<br />
tato, sarà necessario che tutti i <strong>su</strong>oi vertici vengano moltiplicati – uno ad uno –<br />
<strong>per</strong>lomeno <strong>per</strong> le matrici associate alle trasformazioni sopracitate. Queste compu-<br />
tazioni sono completamente inut<strong>il</strong>i, in quanto avvengono <strong>su</strong> vertici che non sono<br />
visib<strong>il</strong>i. Le boun<strong>di</strong>ng box forniscono un semplice metodo <strong>per</strong> limitare questi calcoli<br />
<strong>su</strong><strong>per</strong>flui.<br />
È infatti <strong>su</strong>fficiente eseguire tali trasformazioni solamente <strong>su</strong>gli otto vertici del pa-<br />
rallelepipedo, poiché se esso non è nel frustum della vista non lo sarà neppure <strong>il</strong><br />
modello in esso contenuto. Se invece la boun<strong>di</strong>ng box è parzialmente o totalmente<br />
all’interno della scena visib<strong>il</strong>e, <strong>il</strong> contenuto del nodo verrà inviato al motore <strong>di</strong> ren-<br />
dering e <strong>il</strong> culling verrà riproposto <strong>su</strong>i figli, in quanto anche essi sono provvisti <strong>di</strong><br />
<strong>una</strong> propria boun<strong>di</strong>ng box minore o uguale rispetto a quella del nodo padre.<br />
Il sovraccarico introdotto da questa procedura è variab<strong>il</strong>e. Se <strong>il</strong> modello è un sem-<br />
plice cubo all’interno del campo visivo, le trasformazioni fino al Clipping Coor<strong>di</strong>nate<br />
System avranno durata doppia in quanto saranno effettuate due volte, la prima vol-<br />
ta <strong>su</strong>lla boun<strong>di</strong>ng box e la seconda <strong>su</strong>i vertici del cubo. Quando – come accade<br />
solitamente in ambienti immersivi <strong>di</strong> realtà virtuale – i modelli (e i vertici) sono<br />
molti e circondano l’utente dell’ambiente virtuale, in maniera tale che solamente<br />
<strong>una</strong> porzione <strong>di</strong> essi sia visib<strong>il</strong>e in ogni momento, <strong>il</strong> sistema viene alleggerito <strong>di</strong> tutte<br />
le trasformazioni che sarebbero state applicate anche ai vertici non visib<strong>il</strong>i.<br />
L’algoritmo ut<strong>il</strong>izzato <strong>per</strong> <strong>il</strong> culling è presentato nell’Appen<strong>di</strong>ce C. [FAR00, STE02]<br />
6.5 Le trasformazioni geometriche in tempo reale<br />
È importante limitare le trasformazioni geometriche (traslazioni, rotazioni e ri<strong>di</strong>-<br />
mensionamenti) applicate <strong>su</strong>i modelli in tempo reale, in quanto ciasc<strong>una</strong> <strong>di</strong> esse<br />
comporta un sovraccarico computazionale talvolta evitab<strong>il</strong>e. Il metodo <strong>per</strong> evitarlo<br />
è <strong>di</strong>fatti quello <strong>di</strong> calcolare in fase <strong>di</strong> inizializzazione tutte le trasformazioni non va-<br />
riab<strong>il</strong>i nel tempo. Questo è esattamente <strong>il</strong> compito svolto dal loader 3DS e presentato<br />
nella sezione 5.6.2.<br />
Ci sono <strong>per</strong>ò casi particolari in cui emerge <strong>il</strong> bisogno <strong>di</strong> poter ut<strong>il</strong>izzare trasformazioni<br />
in tempo reale <strong>su</strong> alcune parti della scena. La motivazione principale è solitamente<br />
la necessità <strong>di</strong> animare i modelli in tempo reale. A <strong>su</strong>pporto <strong>di</strong> questa funzionalità
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 56<br />
è stata sv<strong>il</strong>uppata <strong>una</strong> parte <strong>di</strong> co<strong>di</strong>ce de<strong>di</strong>cata alla impostazione e applicazione <strong>di</strong><br />
tali trasformazioni in realtime.<br />
Per la definizione <strong>su</strong> ciascun nodo della traslazione, della rotazione e del ri<strong>di</strong>mensio-<br />
namento in realtime sono state implementate due metodologie, entrambe con i propri<br />
pregi. Una metodologia <strong>per</strong>mette <strong>di</strong> definire tutte le trasformazioni con un’unica<br />
matrice, ed è <strong>per</strong>ciò pratica nel caso in cui la matrice associata alla trasformazione<br />
che si desidera sia <strong>di</strong> formato noto e i <strong>su</strong>oi parametri fac<strong>il</strong>mente calcolab<strong>il</strong>i. L’altra<br />
metodologia <strong>per</strong>mette <strong>di</strong> definire le trasformazioni (traslazione, ri<strong>di</strong>mensionamento<br />
e rotazione) <strong>una</strong> ad <strong>una</strong>, ed è ut<strong>il</strong>e poiché non è necessario dover calcolare <strong>di</strong> volta in<br />
volta la matrice associata alla trasformazione; un’ulteriore caratteristica <strong>di</strong> praticità<br />
<strong>di</strong> questo secondo metodo è <strong>il</strong> fatto che la rotazione sia definita <strong>su</strong> un’asse generico,<br />
un metodo <strong>di</strong> definizione in certi casi più flessib<strong>il</strong>e <strong>di</strong> quello u<strong>su</strong>ale che richiede i tre<br />
angoli <strong>di</strong> rotazione <strong>su</strong>gli assi del sistema <strong>di</strong> riferimento.<br />
La prima metodologia <strong>di</strong> definizione ut<strong>il</strong>izza matrici 4 × 4. Tutti i vertici sono<br />
infatti in coor<strong>di</strong>nate omogenee, ovvero nel formato (x, y, z, w) T , ove w è <strong>una</strong> quarta<br />
coor<strong>di</strong>nata introdotta <strong>per</strong> fac<strong>il</strong>itare alcune o<strong>per</strong>azioni (ad esempio la proiezione dei<br />
vertici dalle tre <strong>di</strong>mensioni allo spazio bi<strong>di</strong>mensionale dello schermo) e <strong>per</strong> altri<br />
motivi <strong>di</strong> praticità (grazie alla quarta coor<strong>di</strong>nata è ad esempio possib<strong>il</strong>e eseguire<br />
le traslazioni <strong>per</strong> mezzo <strong>di</strong> matrici, cosa che lavorando con tre sole coor<strong>di</strong>nate non<br />
sarebbe possib<strong>il</strong>e).<br />
Il vertice e la matrice vengono moltiplicati all’interno della pipeline OpenGL in<br />
questa maniera 3<br />
⎛<br />
⎜<br />
⎝<br />
a11 a12 a13 a14<br />
a21 a22 a23 a24<br />
a31 a32 a33 a34<br />
a41 a42 a43 a44<br />
⎞<br />
⎟<br />
⎠ ×<br />
⎛ ⎞<br />
⎜<br />
⎝<br />
x<br />
y<br />
z<br />
w<br />
⎟<br />
⎠ =<br />
⎛<br />
⎜<br />
⎝<br />
3È importante ricordare che le matrici 4 × 4 memorizzate in OpenGL sottoforma <strong>di</strong> array <strong>di</strong> 16<br />
elementi sono in un formato column-major, ovvero i primi 4 elementi corrispondono alla prima<br />
colonna della matrice [NDW94]. Un array <strong>di</strong> 16 elementi del tipo [a0, . . . , a15] rappresenta <strong>per</strong>ciò<br />
la matrice 4 × 4 ⎛<br />
⎞<br />
⎜<br />
⎝<br />
a0 a4 a8 a12<br />
a1 a5 a9 a13<br />
a2 a6 a10 a14<br />
a3 a7 a11 a15<br />
⎟<br />
⎠<br />
x ′<br />
y ′<br />
z ′<br />
w ′<br />
⎞<br />
⎟<br />
⎠
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 57<br />
Per eseguire <strong>una</strong> traslazione (tx, ty, tz) T è quin<strong>di</strong> necessario ut<strong>il</strong>izzare la matrice<br />
⎛<br />
⎞<br />
⎜<br />
⎝<br />
1<br />
0<br />
0<br />
0<br />
1<br />
0<br />
0<br />
0<br />
1<br />
tx<br />
ty<br />
tz<br />
⎟<br />
⎠<br />
0 0 0 1<br />
I valori <strong>di</strong> ri<strong>di</strong>mensionamento <strong>su</strong>i tre assi sono <strong>su</strong>lla <strong>di</strong>agonale, <strong>per</strong> cui la matrice<br />
ut<strong>il</strong>izzab<strong>il</strong>e se i coefficienti sono sx, sy e sz è<br />
⎛<br />
⎞<br />
sx<br />
⎜<br />
0<br />
⎜<br />
⎝ 0<br />
0<br />
sy<br />
0<br />
0<br />
0<br />
sz<br />
0<br />
⎟<br />
0 ⎟<br />
0<br />
⎟<br />
⎠<br />
0 0 0 1<br />
mentre <strong>per</strong> la rotazione si usano le u<strong>su</strong>ali matrici con seno e coseno (ut<strong>il</strong>izzando la<br />
sottomatrice 3 × 3 da a11 a a33), ovvero<br />
⎛<br />
⎞ ⎛<br />
⎞ ⎛<br />
⎞<br />
1<br />
⎜<br />
0<br />
⎜<br />
⎝ 0<br />
0<br />
cos α<br />
sin α<br />
0<br />
− sin α<br />
cos α<br />
0 cos α<br />
⎟ ⎜<br />
0 ⎟ ⎜<br />
⎟ ⎜<br />
0<br />
0<br />
⎟ ⎜<br />
⎠ ⎝ − sin α<br />
0<br />
1<br />
0<br />
sin α<br />
0<br />
cos α<br />
0 cos α<br />
⎟ ⎜<br />
0 ⎟ ⎜<br />
⎟ ⎜<br />
sin α<br />
0<br />
⎟ ⎜<br />
⎠ ⎝ 0<br />
− sin α<br />
cos α<br />
0<br />
0<br />
0<br />
1<br />
0<br />
⎟<br />
0 ⎟<br />
0<br />
⎟<br />
⎠<br />
0 0 0 1 0 0 0 1 0 0 0 1<br />
rispettivamente <strong>per</strong> la rotazione <strong>su</strong>ll’asse x, <strong>su</strong>ll’asse y e <strong>su</strong>ll’asse z. [MOR89]<br />
La seconda metodologia consente invece <strong>di</strong> specificare <strong>una</strong> ad <strong>una</strong> le trasformazioni<br />
desiderate, <strong>per</strong> mezzo <strong>di</strong>:<br />
• un vettore (tx, ty, tz) T nel caso della traslazione, che viene sommato ad ogni<br />
vertice (x, y, z) T <strong>per</strong> ottenere <strong>il</strong> <strong>su</strong>o trasformato (x ′ , y ′ , z ′ ) T = (x+tx, y+ty, z +<br />
tz) T ;<br />
• un angolo α e un asse (ax, ay, az) T nel caso della rotazione, che è <strong>per</strong>ciò definita<br />
come un angolo <strong>di</strong> rotazione <strong>su</strong> un asse arbitrario anziché come tre angoli <strong>di</strong><br />
rotazione <strong>su</strong>i tre assi del sistema <strong>di</strong> riferimento;<br />
• tre coefficienti sx, sy e sz nel caso del ri<strong>di</strong>mensionamento, ut<strong>il</strong>izzati <strong>per</strong> mol-<br />
tiplicare i valori <strong>di</strong> ciascun vertice (x, y, z) T <strong>per</strong> ottenere <strong>il</strong> <strong>su</strong>o trasformato<br />
(x ′ , y ′ , z ′ ) T = (x · sx, y · sy, z · sz) T .
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 58<br />
Non è necessario usare tutte e tre le trasformazioni ogni volta ed è certamente<br />
più <strong>per</strong>formante ut<strong>il</strong>izzare solo le non nulle; la <strong>libreria</strong> applica infatti unicamente<br />
le trasformazioni definite. L’or<strong>di</strong>ne in cui esse vengono eseguite è rigorosamente:<br />
ri<strong>di</strong>mensionamento, rotazione, traslazione. La matrice <strong>di</strong> trasformazione della prima<br />
metodologia, se definita, viene applicata prima <strong>di</strong> queste trasformazioni.<br />
Tutte le trasformazioni avvengono <strong>su</strong>l centro del nodo della gerarchia <strong>su</strong> cui sono de-<br />
finite, tramite <strong>il</strong> classico approccio basato <strong>su</strong>llo spostamento temporaneo del sistema<br />
<strong>di</strong> riferimento spesso usato in computer graphics. Per effettuare tale spostamento<br />
vengono applicate all’oggetto due traslazioni inverse fra loro (la loro somma è <strong>il</strong> vet-<br />
tore nullo), atte a spostare <strong>il</strong> centro del nodo nell’origine del sistema <strong>di</strong> riferimento<br />
globale e viceversa, come <strong>il</strong>lustrato nella Tabella 6.3.<br />
Apply Transformations:<br />
1: Translate(−centrox, −centroy, −centroz)<br />
2: if matrice valida then Apply(matrice) en<strong>di</strong>f<br />
3: if ri<strong>di</strong>mensionamento valido then Scale(sx, sy, sz) en<strong>di</strong>f<br />
4: if rotazione valida then Rotate(angolo, assex, assey, assez) en<strong>di</strong>f<br />
5: if traslazione valida then Translate(tx, ty, tz) en<strong>di</strong>f<br />
6: Translate(centrox, centroy, centroz)<br />
Tabella 6.3: Applicazione delle trasformazioni geometriche <strong>su</strong> un nodo avente come<br />
centro C = (centrox, centroy, centroz) T<br />
È importante osservare come tutte le trasformazioni si applichino all’intero sottoal-<br />
bero avente come ra<strong>di</strong>ce <strong>il</strong> nodo <strong>su</strong> cui sono definite. Esse inoltre si accumulano <strong>di</strong><br />
nodo in nodo, e vengono applicate partendo dalle foglie sino a giungere alla ra<strong>di</strong>ce.<br />
Questo significa che se <strong>su</strong> un nodo è definita <strong>una</strong> trasformazione N e la trasforma-<br />
zione definita <strong>su</strong>l <strong>su</strong>o nodo padre è P , <strong>su</strong>l nodo in questione verrà applicata P N<br />
(ovviamente P può essere a <strong>su</strong>a volta <strong>una</strong> trasformazione composta). L’applicazione<br />
delle trasformazioni avviene prima che venga invocato <strong>il</strong> motore <strong>di</strong> rendering <strong>per</strong> <strong>il</strong><br />
nodo, e prima che la chiamata <strong>di</strong> rendering <strong>di</strong>scenda anche ai figli.<br />
Nel caso della presenza <strong>di</strong> trasformazioni in tempo reale non è garantito <strong>il</strong> corretto<br />
comportamento del culling, poiché la boun<strong>di</strong>ng box può variare continuamente e
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 59<br />
non viene aggiornata in realtime <strong>per</strong> non aumentare drasticamente <strong>il</strong> sovraccarico<br />
computazionale.<br />
6.6 L’or<strong>di</strong>namento dei figli<br />
Quando nella scena sono presenti degli oggetti trasparenti ri<strong>su</strong>lta molto importante<br />
l’or<strong>di</strong>ne nel quale viene eseguito <strong>il</strong> rendering dei modelli. La resa della trasparenza si<br />
basa infatti <strong>su</strong>l blen<strong>di</strong>ng, <strong>una</strong> particolare funzionalità che consente <strong>di</strong> “mescolare” fra<br />
<strong>di</strong> loro <strong>il</strong> colore del pixel da scrivere in <strong>una</strong> locazione e <strong>il</strong> colore del pixel già presente<br />
in tale locazione. La <strong>libreria</strong> sv<strong>il</strong>uppata ut<strong>il</strong>izza <strong>il</strong> formato <strong>di</strong> memorizzazione dei<br />
colori RGBA (acronimo <strong>di</strong> Red, Green, Blue, Alpha) a quattro canali da 8 bit<br />
ciascuno. La particolare tipologia <strong>di</strong> blen<strong>di</strong>ng impiegata nella presente <strong>libreria</strong> è<br />
denominata alpha blen<strong>di</strong>ng in quanto ut<strong>il</strong>izza <strong>il</strong> canale dei colori denominato canale<br />
alpha <strong>per</strong> modulare <strong>il</strong> livello <strong>di</strong> trasparenza dei materiali.<br />
Il blen<strong>di</strong>ng o<strong>per</strong>a <strong>su</strong>i singoli pixel e consiste in <strong>una</strong> somma pesata dei colori ottenuti<br />
<strong>per</strong> <strong>il</strong> medesimo pixel nel corso del rendering; i pesi ut<strong>il</strong>izzati nell’alpha blen<strong>di</strong>ng<br />
non sono costanti ma sono dati dal valore del canale alpha del pixel, che può variare<br />
in funzione del colore RGBA definito <strong>per</strong> i vari poligoni. Se <strong>il</strong> colore <strong>di</strong> un pixel già<br />
presente nel framebuffer è (rd, gd, bd, ad) T e dobbiamo applicare un blen<strong>di</strong>ng con <strong>il</strong><br />
colore (rs, gs, bs, as) T la particolare formula ut<strong>il</strong>izzata nella presente <strong>libreria</strong> ci farà<br />
ottenere ⎛<br />
⎜<br />
⎝<br />
rfinale<br />
gfinale<br />
bfinale<br />
afinale<br />
⎞<br />
⎟<br />
⎠ =<br />
⎛<br />
⎞<br />
⎜<br />
⎝<br />
as · rs + (1 − as) · rd<br />
as · gs + (1 − as) · gd<br />
as · bs + (1 − as) · bd<br />
⎟<br />
⎠<br />
as · as + (1 − as) · ad<br />
come colore finale. Si può fac<strong>il</strong>mente notare <strong>il</strong> peso <strong>di</strong> as <strong>su</strong>l ri<strong>su</strong>ltato finale.<br />
Se come in Figura 6.9 abbiamo due oggetti trasparenti con un valore <strong>di</strong> trasparenza<br />
del 60%, e ci appaiono posti uno <strong>di</strong>etro all’altro, nella zona in cui sono sovrapposti si<br />
vedrà un colore pari al 60% dell’oggetto più vicino a noi sommato al 40% dell’oggetto<br />
co<strong>per</strong>to 4 . Questo è vero se viene eseguito <strong>il</strong> rendering dell’oggetto posto <strong>su</strong>l retro, e<br />
in seguito <strong>il</strong> blen<strong>di</strong>ng con l’oggetto in fronte. Se <strong>per</strong>ò l’or<strong>di</strong>ne della renderizzazione è<br />
4 In realtà questo colore è pari al 60% del reale colore sommato al 40% del colore dello sfondo.
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 60<br />
Figura 6.9: Blen<strong>di</strong>ng errato (in alto) e corretto (in basso) fra due oggetti
CAPITOLO 6. LA GESTIONE DELLA GERARCHIA 61<br />
<strong>il</strong> contrario, <strong>il</strong> colore che erroneamente comparirà sarà <strong>il</strong> 40% del colore dell’oggetto<br />
posto davanti sommato al 60% del colore dell’oggetto <strong>di</strong>etro.<br />
Questo esempio mostra come sia necessario che nel caso in cui vi siano degli oggetti<br />
trasparenti essi siano renderizzati sempre nell’or<strong>di</strong>ne corretto. Il metodo implemen-<br />
tato or<strong>di</strong>na i figli <strong>di</strong> un nodo, consentendo al programmatore <strong>di</strong> scegliere <strong>il</strong> livello<br />
<strong>di</strong> profon<strong>di</strong>tà a cui applicare l’or<strong>di</strong>namento; <strong>il</strong> livello <strong>di</strong> profon<strong>di</strong>tà 1 causa l’or<strong>di</strong>na-<br />
mento dei soli figli <strong>di</strong>retti, <strong>il</strong> livello 2 farà sì che vengano or<strong>di</strong>nati anche i figli dei<br />
figli, e così via.<br />
L’algoritmo ut<strong>il</strong>izzato è un merge sort, <strong>di</strong> complessità O(n log n), e o<strong>per</strong>a in fun-<br />
zione della <strong>di</strong>stanza fra <strong>il</strong> punto <strong>di</strong> vista e <strong>il</strong> centro dell’oggetto or<strong>di</strong>nando i no<strong>di</strong><br />
dal più lontano al più vicino. Un’approfon<strong>di</strong>mento <strong>su</strong> tale algoritmo è presente<br />
nell’Appen<strong>di</strong>ce E. [CLR98]
CAPITOLO 7<br />
La gestione del rendering<br />
7.1 Le funzionalità a <strong>su</strong>pporto del rendering<br />
A fianco delle funzionalità riguardanti la gerarchia nella classe Object – contenente<br />
geometria e materiali – sono anche presenti meto<strong>di</strong> <strong>per</strong> la gestione del rendering.<br />
È importante notare come <strong>il</strong> rendering, orientato alle singole primitive, sia effettuato<br />
da OpenGL. La <strong>libreria</strong> sv<strong>il</strong>uppata nel presente lavoro o<strong>per</strong>a ad un livello <strong>su</strong><strong>per</strong>iore<br />
– orientato agli oggetti – e si occupa <strong>di</strong> impostare tutti i materiali e le texture,<br />
modello dopo modello, ed infine inviare i dati alla <strong>libreria</strong> OpenGL sottostante.<br />
Non è stato <strong>per</strong>ciò implementato un motore <strong>di</strong> rendering, bensì uno strumento <strong>di</strong><br />
automatizzazione <strong>per</strong> l’ut<strong>il</strong>izzo del preesistente motore OpenGL.<br />
I modelli gestib<strong>il</strong>i tramite questa classe si limitano alle mesh <strong>di</strong> triangoli, ovvero<br />
dei reticoli composti unicamente da triangoli; i modelli contenuti all’interno <strong>di</strong> un<br />
f<strong>il</strong>e 3DS sono sempre mesh <strong>di</strong> triangoli (cfr. 5.5.2). I triangoli sono <strong>di</strong>fatti le figure<br />
geometriche gestib<strong>il</strong>i più fac<strong>il</strong>mente dai moderni hardware grafici e solitamente le<br />
librerie che <strong>su</strong>pportano anche poligoni con un numero <strong>di</strong> lati maggiore <strong>di</strong> tre im-<br />
plementano algoritmi <strong>di</strong> tessellazione che li riducano automaticamente a insiemi <strong>di</strong><br />
triangoli prima <strong>di</strong> inviarli alla pipeline grafica.<br />
La classe Object <strong>su</strong>pporta gli u<strong>su</strong>ali colori dei materiali (ambientale, <strong>di</strong>ffusivo, spe-<br />
culare ed emissivo). Supporta inoltre <strong>una</strong> vasta gamma <strong>di</strong> texture, ciasc<strong>una</strong> con <strong>il</strong><br />
proprio particolare effetto visivo, che saranno presentate <strong>una</strong> ad <strong>una</strong> nelle <strong>su</strong>ccessive<br />
sezioni, con le relative modalità <strong>di</strong> applicazione ed esempi dei ri<strong>su</strong>ltati finali. Questa<br />
varietà <strong>di</strong> texture garantisce <strong>una</strong> elevata corrispondenza con la versione originale<br />
del modello importato. Esse sono <strong>di</strong>fatti tutte definite all’origine all’interno del f<strong>il</strong>e<br />
62
CAPITOLO 7. LA GESTIONE DEL RENDERING 63<br />
3DS e da esso vengono caricate <strong>per</strong> mezzo del loader sv<strong>il</strong>uppato. Un semplice me-<br />
todo consente l’attivazione, la <strong>di</strong>sattivazione e la reimpostazione in tempo reale <strong>di</strong><br />
ciasc<strong>una</strong> <strong>di</strong> queste texture, in<strong>di</strong>pendentemente dalla loro presenza all’interno del f<strong>il</strong>e<br />
importato.<br />
Di seguito viene quin<strong>di</strong> presentato l’algoritmo sv<strong>il</strong>uppato <strong>per</strong> poter ut<strong>il</strong>izzare tutte<br />
le texture desiderate contemporaneamente. Esso sfrutta blen<strong>di</strong>ng e stenc<strong>il</strong> buffer<br />
<strong>per</strong> effettuare rendering in più passate.<br />
Sono infine chiarite le modalità <strong>per</strong> mezzo delle quali è possib<strong>il</strong>e ut<strong>il</strong>izzare anche<br />
materiali trasparenti.<br />
7.2 Le texture <strong>su</strong>pportate<br />
Una texture è <strong>una</strong> matrice bi<strong>di</strong>mensionale in cui ciascun elemento contiene la descri-<br />
zione <strong>di</strong> un colore, nel caso della presente <strong>libreria</strong> memorizzato in 32 bit nel formato<br />
RGBA come <strong>il</strong>lustrato nella sezione 6.6. Con i termini “texture” e “mappa” si<br />
identifica <strong>per</strong>ò spesso anche la mappatura della texture, <strong>il</strong> proce<strong>di</strong>mento che consiste<br />
nell’identificare le corrispondenze fra i vertici del modello e gli elementi della tex-<br />
ture (intesa qui come matrice) e nel decidere in base a tali corrispondenze i colori<br />
da assegnare ai pixel durante la fase <strong>di</strong> rendering <strong>di</strong> tale modello. Nel seguito del<br />
capitolo i termini texture e mappa saranno ut<strong>il</strong>izzati in<strong>di</strong>fferentemente con uno o<br />
l’altro significato; l’interpretazione corretta sarà <strong>per</strong>ò <strong>di</strong> volta in volta comprensib<strong>il</strong>e<br />
dal contesto.<br />
Il rendering viene tipicamente eseguito <strong>per</strong> vertice <strong>per</strong>ciò solamente i vertici attraver-<br />
sano la pipeline grafica; <strong>il</strong> colore viene calcolato <strong>su</strong> essi ed interpolato nello spazio<br />
che li <strong>di</strong>vide. Esiste <strong>per</strong>ò un’altra modalità più realistica (e computazionalmente<br />
molto più pesante) <strong>di</strong> rendering: quella <strong>per</strong> pixel; in questa modalità sono tutti i<br />
pixel ad attraversare la pipeline grafica, ed <strong>il</strong> colore <strong>di</strong> ciascuno <strong>di</strong> essi non deriva<br />
quin<strong>di</strong> da <strong>una</strong> interpolazione bensì da <strong>una</strong> vera e propria rasterizzazione 1 .<br />
L’ut<strong>il</strong>izzo delle texture all’interno <strong>di</strong> un motore <strong>di</strong> rendering <strong>per</strong> vertice come quello<br />
OpenGL consente un approccio <strong>di</strong> rendering che si avvicina <strong>per</strong> alcune caratteristiche<br />
1 Per rasterizzazione si intende <strong>il</strong> processo che trasforma <strong>una</strong> scena definita geometricamente <strong>su</strong> un<br />
intervallo continuo (la geometria 3D è definita <strong>su</strong> R 3 ) in <strong>una</strong> matrice <strong>di</strong> pixel dalle <strong>di</strong>mensioni<br />
fissate, quin<strong>di</strong> definita <strong>su</strong> un intervallo <strong>di</strong>screto.
CAPITOLO 7. LA GESTIONE DEL RENDERING 64<br />
a quello <strong>per</strong> pixel. La luminosità viene sempre calcolata <strong>per</strong> vertice (a meno che non<br />
si ut<strong>il</strong>izzi <strong>una</strong> mappa <strong>di</strong> <strong>il</strong>luminazione, come spiegato in 7.2.7), ma la cromaticità<br />
dei pixel deriva dall’interpolazione fra i valori <strong>di</strong> colore presenti nella texture, non<br />
solo quelli definiti <strong>su</strong>i vertici, e consente quin<strong>di</strong> <strong>una</strong> maggiore precisione <strong>su</strong>ll’output<br />
del rendering.<br />
Per <strong>una</strong> migliore resa visiva dei modelli è necessario poter definire <strong>una</strong> moltitu<strong>di</strong>ne<br />
<strong>di</strong> proprietà dei materiali, che talvolta sono ad<strong>di</strong>rittura connesse fra loro. Le tex-<br />
ture forniscono un metodo abbastanza semplice <strong>per</strong> impostare gran parte <strong>di</strong> queste<br />
caratteristiche.<br />
Se l’applicazione <strong>di</strong> alcune texture è banale (ad esempio <strong>una</strong> semplice texture <strong>di</strong><br />
colore), l’ut<strong>il</strong>izzo <strong>di</strong> altre richiede formule più complesse definib<strong>il</strong>i unicamente con<br />
<strong>il</strong> <strong>su</strong>pporto delle estensioni OpenGL; esse sono delle porzioni <strong>di</strong> co<strong>di</strong>ce sv<strong>il</strong>uppanti<br />
funzionalità avanzate non facenti parte del nocciolo OpenGL definito dallo standard<br />
<strong>di</strong> S<strong>il</strong>icon Graphics, ma fornite dalle case produttrici delle schede grafiche all’interno<br />
dei driver delle <strong>per</strong>iferiche. Le estensioni ut<strong>il</strong>izzate in questo lavoro sono<br />
• GL ARB multitexture, che <strong>per</strong>mette <strong>il</strong> multitexturing, ovvero la possib<strong>il</strong>ità <strong>di</strong><br />
ut<strong>il</strong>izzare contemporaneamente più <strong>di</strong> <strong>una</strong> texture <strong>su</strong>llo stesso poligono;<br />
• GL ARB texture env add, che <strong>per</strong>mette <strong>di</strong> sommare <strong>il</strong> colore della texture<br />
con quello del materiale o della texture precedente, anziché sostituirlo oppure<br />
moltiplicarlo secondo le due modalità standard OpenGL;<br />
• GL ARB texture env combine, che <strong>per</strong>mette un controllo molto più avanzato<br />
<strong>su</strong>lle formule che definiscono le o<strong>per</strong>azioni <strong>per</strong> pixel fra i colori delle texture e<br />
dei materiali.<br />
Le tre estensioni OpenGL ut<strong>il</strong>izzate sono presentate in dettaglio nell’Appen<strong>di</strong>ce<br />
B. Se qualche estensione non è presente tutte le funzionalità della <strong>libreria</strong> che<br />
necessitano <strong>di</strong> essa vengono ovviamente <strong>di</strong>sab<strong>il</strong>itate.<br />
Le texture <strong>il</strong> cui <strong>su</strong>pporto è stato implementato all’interno della <strong>libreria</strong> – assieme<br />
alla spiegazione delle modalità con le quali sono applicate dalla <strong>libreria</strong> prima del<br />
rendering – sono introdotte <strong>di</strong> seguito.<br />
Si rammenta infine che tutte queste texture possono essere presenti all’interno dei f<strong>il</strong>e<br />
3DS e, se presenti, vengono importate dal loader e mantenute grazie alle funzionalità
CAPITOLO 7. LA GESTIONE DEL RENDERING 65<br />
della classe Object.<br />
È comunque possib<strong>il</strong>e – in<strong>di</strong>pendentemente dalla loro presenza<br />
nei f<strong>il</strong>e importati – attivarle, <strong>di</strong>sattivarle e ridefinirle in tempo reale grazie ai meto<strong>di</strong><br />
implementati nella <strong>libreria</strong>.<br />
7.2.1 Texture <strong>di</strong> colore <strong>di</strong>ffusivo<br />
È la texture più comune, e viene ut<strong>il</strong>izzata in sostituzione del colore <strong>di</strong>ffusivo del<br />
materiale nel caso in cui si abbiano oggetti non uniformi cromaticamente.<br />
Figura 7.1: La modulazione fra <strong>il</strong> riflesso <strong>di</strong>ffusivo e la texture <strong>di</strong> colore <strong>di</strong>ffusivo (A)<br />
ricrea l’oggetto (B)<br />
La modalità <strong>di</strong> applicazione della texture <strong>di</strong> colore <strong>di</strong>ffusivo non ut<strong>il</strong>izza estensioni.<br />
Il colore <strong>di</strong>ffusivo base del materiale viene sostituito dal colore bianco, in maniera<br />
tale che i riflessi <strong>di</strong>ffusivi <strong>su</strong>gli oggetti possano variare dal bianco al nero. Questi<br />
livelli <strong>di</strong> luminosità vengono quin<strong>di</strong> modulati dal colore della texture <strong>di</strong>ffusiva, così<br />
da riportare <strong>su</strong> essa stessa le varie sfumature delle ombre, come <strong>il</strong>lustrato in Figura<br />
7.1.
CAPITOLO 7. LA GESTIONE DEL RENDERING 66<br />
7.2.2 Mappa <strong>di</strong> riflessione ambientale<br />
Talvolta <strong>per</strong> ricreare l’effetto tipico dei materiali molto luci<strong>di</strong>, specialmente quelli<br />
metallici, è necessario simulare la riflessione dell’ambiente circostante <strong>su</strong> <strong>di</strong> essi.<br />
Questo è fattib<strong>il</strong>e tramite le mappe <strong>di</strong> riflessione ambientale.<br />
Le coor<strong>di</strong>nate <strong>di</strong> texture vengono solitamente assegnate a priori a ciascun vertice;<br />
nel caso del loader 3DS vengono ad esempio importate <strong>una</strong> ad <strong>una</strong> dal f<strong>il</strong>e (cfr.<br />
5.5.2). A <strong>di</strong>fferenza delle altre texture, le coor<strong>di</strong>nate <strong>per</strong> la mappa <strong>di</strong> riflessione<br />
ambientale non sono precalcolate bensì computate <strong>per</strong> ogni vertice in tempo reale<br />
<strong>di</strong>pendentemente dal sistema <strong>di</strong> coor<strong>di</strong>nate <strong>di</strong> vista anziché quello dell’oggetto (cfr.<br />
6.4). Ci sono varie modalità <strong>per</strong> generare delle coor<strong>di</strong>nate <strong>di</strong> riflessione d’ambiente,<br />
le più ut<strong>il</strong>izzate sono:<br />
• <strong>il</strong> cylindrical mapping, in cui la texture dell’ambiente da riflettere viene ap-<br />
plicata alla <strong>su</strong><strong>per</strong>ficie <strong>di</strong> un c<strong>il</strong>indro invisib<strong>il</strong>e che circoscrive <strong>il</strong> modello. Le<br />
coor<strong>di</strong>nate della texture vengono calcolate <strong>per</strong> ogni vertice in base al punto <strong>di</strong><br />
intersezione fra <strong>il</strong> c<strong>il</strong>indro ed <strong>il</strong> vettore normale <strong>su</strong> tale vertice. C’è un evidente<br />
problema quando le normali dei vertici sono parallele all’asse del c<strong>il</strong>indro, in<br />
quanto è un caso particolare <strong>per</strong> <strong>il</strong> quale non esistono intersezioni fra le normali<br />
e <strong>il</strong> c<strong>il</strong>indro (del quale non si considerano le basi);<br />
• lo spherical mapping, sim<strong>il</strong>e al cylindrical mapping, nel quale si ut<strong>il</strong>izzano<br />
ugualmente le normali ma si ricerca la loro intersezione con <strong>una</strong> sfera, elimi-<br />
nando <strong>il</strong> caso particolare presente nella precedente modalità. Non è in realtà<br />
ut<strong>il</strong>izzata <strong>una</strong> sfera bensì la semisfera tagliata dal piano <strong>per</strong>pen<strong>di</strong>colare all’asse<br />
ottico 2 passante <strong>per</strong> <strong>il</strong> centro come <strong>il</strong>lustrato in Figura 7.2;<br />
• <strong>il</strong> cubic mapping, nel quale le texture d’ambiente sono sei anziché <strong>una</strong>, e ven-<br />
gono applicate ciasc<strong>una</strong> ad <strong>una</strong> delle sei facce <strong>di</strong> un cubo, come <strong>il</strong>lustrato in<br />
Figura 7.3.<br />
È molto preciso ma anche molto <strong>di</strong>spen<strong>di</strong>oso computazionalmen-<br />
te; inoltre ancora poche schede lo <strong>su</strong>pportano in hardware, a <strong>di</strong>fferenza dello<br />
spherical mapping.<br />
2 L’asse ottico è la retta passante <strong>per</strong> <strong>il</strong> punto <strong>di</strong> vista ed <strong>il</strong> fuoco (<strong>il</strong> punto <strong>su</strong> cui è concentrato lo<br />
sguardo). [J ÄH93]
CAPITOLO 7. LA GESTIONE DEL RENDERING 67<br />
Figura 7.2: Si nota come l’immagine della texture originale applicata <strong>su</strong> <strong>una</strong> semisfera<br />
(A) appaia come riflessa <strong>su</strong>l modello 3D (B) se lo si inscrive all’interno della semisfera<br />
Figura 7.3: Si nota come l’immagine delle sei texture originali applicate <strong>su</strong> un cubo (A)<br />
appaiano come riflesse <strong>su</strong>l modello 3D (B) se lo si inscrive all’interno del cubo
CAPITOLO 7. LA GESTIONE DEL RENDERING 68<br />
La <strong>libreria</strong> ut<strong>il</strong>izza lo spherical mapping e i meto<strong>di</strong> <strong>di</strong> generazione automatica delle<br />
coor<strong>di</strong>nate già integrati in OpenGL. Sono messe a <strong>di</strong>sposizione dell’utente due ti-<br />
pologie <strong>di</strong> environment mapping, <strong>una</strong> più rapida ma meno accurata dell’altra, come<br />
sarà chiarito nella sezione 7.3.<br />
7.2.3 Texture <strong>di</strong> colore speculare<br />
Come è possib<strong>il</strong>e rimpiazzare <strong>il</strong> colore <strong>di</strong>ffusivo con <strong>una</strong> texture, così è possib<strong>il</strong>e<br />
farlo anche con <strong>il</strong> colore speculare. Il colore speculare è <strong>per</strong>ò spesso molto meno<br />
visib<strong>il</strong>e <strong>di</strong> quello <strong>di</strong>ffusivo, e solitamente gli è cromaticamente molto vicino. Questa<br />
texture è <strong>per</strong>ciò ut<strong>il</strong>e soprattutto nei materiali con riflessi <strong>di</strong> colore <strong>di</strong>fferente da<br />
quello primario del materiale.<br />
Figura 7.4: La modulazione fra <strong>il</strong> riflesso speculare e la texture <strong>di</strong> colore speculare (A)<br />
ricrea l’oggetto (B)<br />
La metodologia <strong>di</strong> applicazione è sim<strong>il</strong>e a quella ut<strong>il</strong>izzata <strong>per</strong> la texture <strong>di</strong> colore<br />
<strong>di</strong>ffusivo. In questo caso è <strong>per</strong>ò <strong>il</strong> colore speculare del materiale anziché quello <strong>di</strong>f-
CAPITOLO 7. LA GESTIONE DEL RENDERING 69<br />
fusivo ad essere sostituito con <strong>il</strong> bianco. La texture è quin<strong>di</strong> ut<strong>il</strong>izzata <strong>per</strong> modulare<br />
l’intensità del riflesso speculare <strong>su</strong>l materiale bianco, come <strong>il</strong>lustrato in Figura 7.4.<br />
7.2.4 Mappa <strong>di</strong> riflessività<br />
Può essere talvolta necessario variare non uniformemente <strong>il</strong> livello <strong>di</strong> riflessività spe-<br />
culare <strong>di</strong> un materiale, ovvero la quantità <strong>di</strong> riflesso speculare visib<strong>il</strong>e (<strong>per</strong> esempio<br />
in un materiale metallico non <strong>per</strong>fettamente lucidato).<br />
Figura 7.5: La riflessività dell’etichetta <strong>su</strong>ll’estintore a destra è stata annullata <strong>per</strong> mezzo<br />
<strong>di</strong> <strong>una</strong> mappa <strong>di</strong> riflessività<br />
La mappa <strong>di</strong> riflessività è <strong>una</strong> texture che viene ut<strong>il</strong>izzata come modulatore <strong>per</strong> <strong>il</strong><br />
colore speculare oppure la texture <strong>di</strong> colore speculare e <strong>per</strong> la mappa <strong>di</strong> riflessione<br />
d’ambiente, se attivata. Se non è usata <strong>per</strong> <strong>il</strong> colore speculare è <strong>per</strong>ò necessaria<br />
l’estensione OpenGL <strong>per</strong> <strong>il</strong> multitexturing (comunque largamente <strong>su</strong>pportata) in<br />
quanto devono essere ut<strong>il</strong>izzate due texture contemporaneamente (cfr. Appen<strong>di</strong>ce<br />
B). Il valore cromatico finale, pixel <strong>per</strong> pixel, è uguale al colore speculare <strong>su</strong>l pixel<br />
(dato dal colore del materiale oppure da quello della texture) moltiplicato <strong>per</strong> <strong>il</strong><br />
colore della mappa <strong>di</strong> riflessività <strong>su</strong>l medesimo pixel.<br />
Nella maggior parte dei casi questa texture è in scala <strong>di</strong> grigi (ovvero i tre canali
CAPITOLO 7. LA GESTIONE DEL RENDERING 70<br />
rosso, verde e blu as<strong>su</strong>mono valori uguali <strong>su</strong>llo stesso pixel) ma è possib<strong>il</strong>e ut<strong>il</strong>izzare<br />
anche texture a colori; in tal caso ciascuno dei canali della mappa andrebbe a mo-<br />
dulare <strong>il</strong> corrispettivo nel colore speculare. Una mappa <strong>di</strong> riflessività con gamma<br />
cromatica variante dal nero al rosso puro eliminerebbe ad esempio i canali verde e<br />
blu dal riflesso speculare del materiale.<br />
7.2.5 Texture <strong>di</strong> colore emissivo<br />
Come <strong>per</strong> gli altri colori – ad esclusione <strong>di</strong> quello ambientale – è possib<strong>il</strong>e modulare<br />
non uniformemente anche <strong>il</strong> colore emissivo. La texture che consente <strong>di</strong> farlo è<br />
denominata anche mappa <strong>di</strong> auto<strong>il</strong>luminazione in quanto definisce <strong>una</strong> luminosità<br />
non riflessa dal materiale bensì introdotta artificialmente nella scena dall’oggetto<br />
stesso. L’artificiosità è data dal fatto che in realtà tale luminosità non interagisce<br />
con gli altri oggetti, ma è visib<strong>il</strong>e solamente <strong>su</strong>l modello che la emette.<br />
Figura 7.6: I fanali <strong>di</strong> un automob<strong>il</strong>e appaiono accesi nell’immagine <strong>di</strong> destra grazie all’uso<br />
<strong>di</strong> <strong>una</strong> texture <strong>di</strong> colore emissivo<br />
Questa texture viene applicata <strong>per</strong> mezzo <strong>di</strong> <strong>una</strong> particolare estensione OpenGL,<br />
GL ARB texture env add, che o<strong>per</strong>a semplicemente sommando pixel <strong>per</strong> pixel <strong>il</strong> co-<br />
lore ri<strong>su</strong>ltante dall’applicazione <strong>di</strong> questa texture al colore già presente <strong>su</strong>l fram-<br />
mento (cfr. Appen<strong>di</strong>ce B). La texture è ut<strong>il</strong>izzata senza ness<strong>una</strong> influenza da parte<br />
delle luci presenti nell’ambiente, in quanto <strong>il</strong> colore che modula è colore emesso e<br />
non riflesso.
CAPITOLO 7. LA GESTIONE DEL RENDERING 71<br />
7.2.6 Bump mapping<br />
Spesso è ut<strong>il</strong>e simulare la ruvi<strong>di</strong>tà <strong>di</strong> <strong>una</strong> <strong>su</strong><strong>per</strong>ficie, ad esempio <strong>su</strong> pavimenti e pareti.<br />
Talvolta è possib<strong>il</strong>e ut<strong>il</strong>izzare texture <strong>di</strong> colore <strong>di</strong>ffusivo con elevato contrasto <strong>per</strong><br />
ottenere un valido effetto <strong>di</strong> questo tipo. Quando <strong>per</strong>ò <strong>su</strong>l materiale in questione<br />
influisce <strong>una</strong> luminosità variab<strong>il</strong>e nel tempo le ombre dei particolari in r<strong>il</strong>ievo devono<br />
spostarsi in realtime in funzione della posizione del punto <strong>di</strong> luce.<br />
È allora possib<strong>il</strong>e<br />
ado<strong>per</strong>are un metodo più valido <strong>per</strong> rappresentare le as<strong>per</strong>ità dei materiali che fa<br />
uso della texture <strong>di</strong> bump mapping, <strong>una</strong> particolare texture che definisce <strong>per</strong> mezzo<br />
<strong>di</strong> livelli <strong>di</strong> grigio le scabrosità presenti <strong>su</strong>lla <strong>su</strong><strong>per</strong>ficie.<br />
Figura 7.7: Una <strong>su</strong><strong>per</strong>ficie senza (a sinistra) e con (al centro e a destra) bump mapping<br />
(si noti nelle ultime due immagini come le ombre dei mattoni in r<strong>il</strong>ievo varino in funzione<br />
della posizione della luce)<br />
Il particolare algoritmo <strong>di</strong> bump mapping implementato nel presente lavoro è deno-<br />
minato embossing 3 e necessità dell’estensione GL ARB multitexturing (cfr. Appen-<br />
<strong>di</strong>ce B). Ut<strong>il</strong>izza infatti la texture <strong>di</strong> bump mapping ed <strong>una</strong> <strong>su</strong>a copia con i colori<br />
invertiti 4 applicandole contemporaneamente <strong>su</strong>l modello lievemente scostate fra loro<br />
in funzione della posizione della luce e quin<strong>di</strong> sommando i loro colori; i coefficien-<br />
3 Emboss significa scolpire, stampare in r<strong>il</strong>ievo.<br />
4 Per invertire un colore si rimpiazza <strong>per</strong> ciascun canale <strong>il</strong> valore presente v con <strong>il</strong> nuovo valore<br />
massimo valore − v. Nel caso della presente <strong>libreria</strong>, siccome si ut<strong>il</strong>izza <strong>il</strong> formato RGBA da 8 bit<br />
<strong>per</strong> canale, <strong>il</strong> massimo valore è 2 8 − 1 = 255 <strong>per</strong>ciò <strong>il</strong> valore invertito è 255 − v.
CAPITOLO 7. LA GESTIONE DEL RENDERING 72<br />
ti <strong>di</strong> scostamento sono calcolati in tempo reale <strong>per</strong> vertice, ut<strong>il</strong>izzando l’algoritmo<br />
presentato nell’Appen<strong>di</strong>ce D.<br />
I ri<strong>su</strong>ltati ottenib<strong>il</strong>i sono buoni solamente <strong>per</strong> materiali rugosi come l’asfalto oppure<br />
la buccia <strong>di</strong> un’arancia, dove le irregolarità <strong>su</strong>lle <strong>su</strong><strong>per</strong>fici sono poco r<strong>il</strong>evanti ma ben<br />
marcate. Per materiali poco scabri come la ceramica decorata sono invece necessari<br />
altri algoritmi <strong>per</strong> pixel non ut<strong>il</strong>izzati nella <strong>libreria</strong> in quanto molto <strong>di</strong>spen<strong>di</strong>osi e<br />
quin<strong>di</strong> poco adatti ad applicazioni realtime.<br />
É stata inoltre implementata un’ulteriore funzione <strong>di</strong> simulazione <strong>di</strong> ruvi<strong>di</strong>tà, atti-<br />
vab<strong>il</strong>e e <strong>di</strong>sattivab<strong>il</strong>e in tempo reale a piacimento, che ut<strong>il</strong>izza la texture <strong>di</strong> bump<br />
mapping <strong>per</strong> modulare la riflessione speculare e la riflessione d’ambiente. Questa<br />
applicazione della texture <strong>di</strong> bump mapping è stata ideata ed implementata <strong>per</strong> far<br />
fronte al basso realismo che si riscontrava nei materiali con molti riflessi speculari<br />
e bump mapping ab<strong>il</strong>itato, che apparivano luci<strong>di</strong> in maniera uniforme nonostante<br />
l’irregolarità della <strong>su</strong><strong>per</strong>ficie. Questa funzionalità non ha alc<strong>una</strong> precisione mate-<br />
matica – a <strong>di</strong>fferenza degli algoritmi <strong>per</strong> pixel – ma è un semplice artifizio visivo<br />
che richiede poche risorse computazionali a fronte <strong>di</strong> un netto aumento del realismo,<br />
come si può notare in Figura 7.8.<br />
7.2.7 Mappa <strong>di</strong> luminosità<br />
Una parte notevole della computazione eseguita durante <strong>il</strong> rendering in tempo reale<br />
è investita nel calcolo della luminosità dei vertici. L’approccio solitamente ut<strong>il</strong>iz-<br />
zato nella grafica in tempo reale, in quanto computazionalmente affrontab<strong>il</strong>e dagli<br />
attuali hardware, è <strong>di</strong>fatti quello <strong>di</strong> calcolare <strong>il</strong> livello <strong>di</strong> luce riflessa <strong>su</strong> ogni verti-<br />
ce e <strong>di</strong> assegnare ai pixel interme<strong>di</strong> un valore <strong>di</strong> luminosità ottenuto interpolando<br />
linearmente questi valori. Le limitazioni dell’<strong>il</strong>luminazione <strong>per</strong> vertice sono legate<br />
alla grandezza dei poligoni: più i poligoni impiegati sono gran<strong>di</strong> minore è <strong>il</strong> realismo<br />
dell’<strong>il</strong>luminazione (come si può constatare nella Figura 7.9), e minore è la possib<strong>il</strong>ità<br />
<strong>di</strong> calcolare in maniera realistica le ombre reciproche fra gli oggetti (del resto calco-<br />
lab<strong>il</strong>i in tempo reale solamente con un grande <strong>di</strong>spen<strong>di</strong>o <strong>di</strong> risorse computazionali).<br />
Se si calcola la luminosità in realtime <strong>il</strong> realismo può aumentare solo se si ut<strong>il</strong>izzano<br />
algoritmi <strong>per</strong> pixel, nei quali cioè <strong>il</strong> livello <strong>di</strong> luce riflessa è calcolata pixel <strong>per</strong> pixel
CAPITOLO 7. LA GESTIONE DEL RENDERING 73<br />
Figura 7.8: Il bump mapping <strong>su</strong> un materiale lucido è quasi im<strong>per</strong>cettib<strong>il</strong>e (A) se non si<br />
ut<strong>il</strong>izza la simulazione <strong>di</strong> ruvi<strong>di</strong>tà (B)
CAPITOLO 7. LA GESTIONE DEL RENDERING 74<br />
senza interpolazioni; la pesantezza <strong>di</strong> calcolo <strong>di</strong> questi algoritmi è già stata esposta<br />
nella sezione 7.2.<br />
Figura 7.9: Nei poligoni l’<strong>il</strong>luminazione calcolata <strong>per</strong> vertice (A) in base ai vettori normali<br />
non è precisa quanto quella calcolata <strong>per</strong> pixel (B)<br />
Se <strong>per</strong> motivi legati alla necessità <strong>di</strong> esecuzione in tempo reale non è quin<strong>di</strong> pos-<br />
sib<strong>il</strong>e abbandonare l’algoritmo <strong>per</strong> vertice in favore <strong>di</strong> un algoritmo <strong>per</strong> pixel più<br />
lento, tuttavia si può talvolta abbandonare l’<strong>il</strong>luminazione in tempo reale. Essa è<br />
necessaria quando le luci o i modelli che devono essere <strong>il</strong>luminati sono in movimen-<br />
to, ma se entrambi non si muovono è possib<strong>il</strong>e adottare un metodo che garantisca<br />
più rapi<strong>di</strong>tà e precisione in fase <strong>di</strong> rendering, ovvero precalcolare la luminosità delle<br />
facce e salvarla in <strong>una</strong> texture ut<strong>il</strong>izzata <strong>per</strong> la mappa <strong>di</strong> luminosità. La mappa <strong>di</strong><br />
luminosità non presenta i problemi sopracitati <strong>per</strong> l’<strong>il</strong>luminazione in tempo reale.<br />
Ut<strong>il</strong>izzare mappe <strong>di</strong> luminosità quando i modelli e le luci non variano la loro po-<br />
sizione reciproca nel tempo può ri<strong>su</strong>ltare spesso più realistico e <strong>su</strong>ggestivo – oltre<br />
che meno pesante <strong>per</strong> <strong>il</strong> motore <strong>di</strong> rendering che non deve calcolare in tempo reale<br />
l’<strong>il</strong>luminazione <strong>per</strong> ciascun vertice – come si può notare in Figura 7.10.
CAPITOLO 7. LA GESTIONE DEL RENDERING 75<br />
Figura 7.10: Illuminazione in tempo reale (a sinistra) e precalcolata (a destra) (si noti la<br />
migliore resa delle ombreggiature nella seconda)<br />
Figura 7.11: La trasparenza <strong>di</strong> un pannello <strong>di</strong> vetro decorato (A) può essere modulata in<br />
maniera non uniforme <strong>per</strong> mezzo <strong>di</strong> <strong>una</strong> mappa <strong>di</strong> opacità (B)
CAPITOLO 7. LA GESTIONE DEL RENDERING 76<br />
7.2.8 Mappa <strong>di</strong> opacità<br />
Alcuni materiali possono essere trasparenti in maniera non uniforme, ad esempio nel<br />
caso <strong>di</strong> oggetti <strong>di</strong> vetro con dei <strong>di</strong>segni decorativi. In tal caso è possib<strong>il</strong>e modulare<br />
<strong>il</strong> canale alpha del materiale <strong>per</strong> mezzo <strong>di</strong> <strong>una</strong> mappa <strong>di</strong> opacità.<br />
L’applicazione <strong>di</strong> questa mappa avviene grazie ad <strong>una</strong> particolare estensione Open-<br />
GL, GL ARB texture env combine, che consente <strong>di</strong> ut<strong>il</strong>izzare <strong>per</strong> <strong>il</strong> materiale i tre<br />
canali cromatici <strong>di</strong> <strong>una</strong> texture ed <strong>il</strong> canale alpha <strong>di</strong> un’altra texture (cfr. Appen<strong>di</strong>ce<br />
B).<br />
7.3 Il rendering multipassata<br />
Le texture sono state presentate <strong>una</strong> ad <strong>una</strong>, ma l’algoritmo implementato nella<br />
presente <strong>libreria</strong> consente <strong>di</strong> ut<strong>il</strong>izzare allo stesso momento tutte quelle desiderate.<br />
L’ut<strong>il</strong>izzo <strong>di</strong> più texture contemporaneamente <strong>su</strong>llo stesso insieme <strong>di</strong> poligoni è de-<br />
nominato multitexturing. La maggior parte delle schede grafiche moderne è in grado<br />
<strong>di</strong> gestire <strong>il</strong> multitexturing, ma <strong>il</strong> numero massimo <strong>di</strong> texture ut<strong>il</strong>izzab<strong>il</strong>i contem-<br />
poraneamente è spesso limitato a due, con alcune eccezioni (alcune schede grafiche<br />
<strong>su</strong>pportano al più quattro texture).<br />
Per poter ut<strong>il</strong>izzare un maggior numero <strong>di</strong> texture contemporaneamente, è stato<br />
necessario implementare un meccanismo a più passate <strong>di</strong> rendering 5 , funzionante<br />
tramite stenc<strong>il</strong> buffer, z-buffer e blen<strong>di</strong>ng (presentati uno ad uno in seguito), in<br />
grado <strong>di</strong> mescolare fra <strong>di</strong> loro in maniera stratificata i ri<strong>su</strong>ltati <strong>di</strong> più rendering.<br />
7.3.1 Lo stenc<strong>il</strong> buffer<br />
Lo stenc<strong>il</strong> buffer è <strong>una</strong> matrice bi<strong>di</strong>mensionale <strong>di</strong> <strong>di</strong>mensioni identiche a quella <strong>su</strong>lla<br />
quale si esegue <strong>il</strong> rendering (<strong>il</strong> frame buffer). Il numero <strong>di</strong> bit <strong>di</strong>sponib<strong>il</strong>i <strong>per</strong> ciascun<br />
elemento dello stenc<strong>il</strong> buffer <strong>di</strong>pende dalla scheda video. Non è, a <strong>di</strong>fferenza del frame<br />
buffer, un buffer visib<strong>il</strong>e. Gli elementi dello stenc<strong>il</strong> buffer sono invece ut<strong>il</strong>izzab<strong>il</strong>i<br />
come flag (<strong>una</strong> <strong>per</strong> pixel) ut<strong>il</strong>i <strong>per</strong> svariate o<strong>per</strong>azioni.<br />
5 Per rendering multipassata si intende l’esecuzione <strong>di</strong> più rendering dello stesso modello (variando<br />
le <strong>su</strong>e caratteristiche <strong>di</strong> materiale) e la fusione dei ri<strong>su</strong>ltati <strong>di</strong> tutti questi rendering <strong>per</strong> ottenere<br />
l’immagine finale.
CAPITOLO 7. LA GESTIONE DEL RENDERING 77<br />
Figura 7.12: Interpretazione grafica dei valori scritti nello stenc<strong>il</strong> buffer dall’algoritmo<br />
implementato durante <strong>il</strong> rendering (0 = nero, 1 = bianco)<br />
Per ciascun pixel scritto <strong>su</strong>l frame buffer è possib<strong>il</strong>e eseguire un’o<strong>per</strong>azione elementa-<br />
re (azzeramento, incremento, decremento) <strong>su</strong>l corrispondente elemento dello stenc<strong>il</strong><br />
buffer.<br />
È possib<strong>il</strong>e eseguire anche l’o<strong>per</strong>azione <strong>di</strong> testing (denominata stenc<strong>il</strong> test),<br />
ovvero decidere se <strong>di</strong>segnare o meno un pixel <strong>su</strong>l frame buffer a seconda del valore<br />
presente al momento del rendering nella locazione corrispondente dello stenc<strong>il</strong> buffer.<br />
L’algoritmo implementato sfrutta queste funzionalità impostando ad uno i valori<br />
dello stenc<strong>il</strong> buffer corrispondenti ai pixel scritti durante <strong>il</strong> primo rendering e a zero<br />
i rimanenti, con effetti analoghi a quelli mostrati nella Figura 7.12, ed ut<strong>il</strong>izzando<br />
lo stenc<strong>il</strong> test <strong>per</strong> i rendering <strong>su</strong>ccessivi, come spiegato dettagliatamente in seguito.<br />
7.3.2 Lo z-buffer<br />
Il depth buffer – denominato anche z-buffer a causa del fatto che in computer gra-<br />
phics solitamente l’asse z sia quello posto a mi<strong>su</strong>rare la profon<strong>di</strong>tà – è come lo<br />
stenc<strong>il</strong> buffer <strong>una</strong> matrice delle <strong>di</strong>mensioni del frame buffer, a<strong>di</strong>bita <strong>per</strong>ò a contene-<br />
re le profon<strong>di</strong>tà degli oggetti renderizzati. Per profon<strong>di</strong>tà <strong>di</strong> un oggetto si intende la<br />
<strong>su</strong>a <strong>di</strong>stanza dal punto <strong>di</strong> vista. Questa <strong>di</strong>stanza è calcolata durante <strong>il</strong> rendering <strong>per</strong><br />
pixel e memorizzata nelle opportune locazioni dello z-buffer. La profon<strong>di</strong>tà è spesso<br />
normalizzata nell’intervallo [0, 1], dove 0 e 1 corrispondono ai limiti posti dai piani<br />
near e far del frustum <strong>di</strong> vista (cfr. 6.4).<br />
È definib<strong>il</strong>e <strong>una</strong> o<strong>per</strong>azione <strong>di</strong> testing (denominata depth test) che ut<strong>il</strong>izzi lo z-<br />
buffer. Per mezzo del depth test è possib<strong>il</strong>e decidere se tenere oppure scartare un<br />
pixel durante la fase <strong>di</strong> rendering. Il metodo più ut<strong>il</strong>izzato (e ado<strong>per</strong>ato anche
CAPITOLO 7. LA GESTIONE DEL RENDERING 78<br />
nell’algoritmo implementato) è quello <strong>di</strong> vi<strong>su</strong>alizzare <strong>per</strong> ogni locazione solamente<br />
<strong>il</strong> pixel con <strong>di</strong>stanza minore fra tutti quelli corrispondenti alla medesima locazione<br />
dello z-buffer, ovvero quello posto <strong>di</strong>nanzi a tutti gli altri rispetto alla posizione<br />
dell’osservatore. I criteri <strong>di</strong> testing sono comunque definib<strong>il</strong>i a piacimento anche in<br />
tempo reale.<br />
7.3.3 Il blen<strong>di</strong>ng<br />
Il blen<strong>di</strong>ng è già stato introdotto nella sezione 6.6.<br />
È un particolare meccanismo che<br />
consente <strong>di</strong> mescolare fra loro, con coefficienti definib<strong>il</strong>i in tempo reale, <strong>il</strong> colore che<br />
deve essere scritto in un pixel e <strong>il</strong> colore già presente in tale pixel.<br />
7.3.4 L’algoritmo ut<strong>il</strong>izzato<br />
L’algoritmo implementato invia gli oggetti al motore <strong>di</strong> rendering OpenGL, un ma-<br />
teriale alla volta. All’interno <strong>di</strong> ciascun materiale è presente <strong>una</strong> lista <strong>di</strong> puntatori<br />
alle facce che lo ut<strong>il</strong>izzano. L’or<strong>di</strong>ne in cui vengono scelti i vari materiali è quello<br />
in cui sono stati inseriti, ad eccezione dei materiali trasparenti che vengono sempre<br />
presi <strong>per</strong> ultimi, come spiegato nella sezione 7.4.<br />
Vi sono sostanziali <strong>di</strong>fferenze fra le impostazioni ut<strong>il</strong>izzate <strong>per</strong> la prima passata<br />
e quelle impiegate <strong>per</strong> tutte le <strong>su</strong>ccessive. Queste <strong>di</strong>fferenze sono dovute al fatto<br />
che al primo passaggio si debba unicamente <strong>di</strong>segnare <strong>il</strong> modello, mentre in tutti i<br />
seguenti sta<strong>di</strong> è necessario un più fine lavoro <strong>di</strong> mescolamento dell’ultimo rendering<br />
con l’oggetto già presente nel frame buffer.<br />
Il rendering viene <strong>di</strong>fatti applicato in maniera stratificata, ed ogni passaggio non<br />
deve sovrascrivere totalmente ciò che è stato fatto in precedenza, ma amalgamarsi<br />
correttamente con esso.<br />
La prima passata<br />
Nel primo passaggio lo z-buffer è ut<strong>il</strong>izzato con la modalità tipica che <strong>per</strong>mette la<br />
vi<strong>su</strong>alizzazione solamente dei pixel più vicini all’osservatore. Così facendo si ottiene<br />
che gli oggetti si coprano fra <strong>di</strong> loro in maniera corretta, ovvero che i più prossimi<br />
all’osservatore nascondano porzioni degli oggetti posti <strong>di</strong>etro. I materiali trasparenti<br />
fanno <strong>una</strong> piccola eccezione, poiché <strong>per</strong> loro <strong>il</strong> buffer viene <strong>di</strong>sab<strong>il</strong>itato in scrittura,
CAPITOLO 7. LA GESTIONE DEL RENDERING 79<br />
in modo che possano passare <strong>il</strong> test <strong>di</strong> profon<strong>di</strong>tà anche i pixel retrostanti ma visib<strong>il</strong>i<br />
a causa della loro non totale opacità.<br />
All’inizio <strong>di</strong> questa fase lo stenc<strong>il</strong> buffer viene impostato totalmente al valore 0;<br />
quin<strong>di</strong> le funzioni OpenGL sono configurate in maniera tale che <strong>per</strong> ogni pixel scritto<br />
<strong>su</strong>l frame buffer venga impostata la locazione corrispondente dello stenc<strong>il</strong> buffer a<br />
1. Questo ci <strong>per</strong>metterà al termine della fase <strong>di</strong> rendering <strong>di</strong> avere uno stenc<strong>il</strong> buffer<br />
composto da 1 e 0 raffiguranti la zona del frame buffer nella quale <strong>il</strong> modello è stato<br />
<strong>di</strong>segnato con <strong>su</strong>ccesso (come <strong>il</strong>lustrato nella Figura 7.12). Avere questi dati nello<br />
stenc<strong>il</strong> buffer è importante <strong>per</strong>ché tutte le altre passate devono intervenire <strong>su</strong> tutti<br />
e soli i pixel <strong>di</strong>segnati in questo passaggio, <strong>per</strong> evitare sbavature causate da pixel<br />
non visib<strong>il</strong>i in tutti i rendering ma solo in alcuni.<br />
Il blen<strong>di</strong>ng è in questo momento <strong>di</strong>sab<strong>il</strong>itato, ad eccezione dei materiali trasparenti<br />
nei quali è ut<strong>il</strong>izzato <strong>per</strong> modellare l’opacità del materiale e non <strong>per</strong> motivi inerenti<br />
l’algoritmo.<br />
Le <strong>su</strong>ccessive passate<br />
In tutti i <strong>su</strong>ccessivi passaggi si fa innanzitutto in modo che i pixel che vengono scritti<br />
si limitino alla zona già ut<strong>il</strong>izzata nella prima passata. Questo è possib<strong>il</strong>e grazie allo<br />
stenc<strong>il</strong> buffer, che a questo punto contiene già un’immagine composta da tanti 1 e<br />
raffigurante la porzione <strong>di</strong> schermo in cui è presente <strong>il</strong> modello. Lo stenc<strong>il</strong> test viene<br />
impostato in maniera tale che solamente i pixel posti in locazioni presenti nella zona<br />
riempita <strong>di</strong> 1 vengano <strong>di</strong>segnati.<br />
C’è <strong>una</strong> piccola variazione nell’ut<strong>il</strong>izzo dello z-buffer: i pixel accettati sono qui tutti<br />
quelli con profon<strong>di</strong>tà minore oppure uguale a quella scritta nel buffer.<br />
È necessario<br />
che sia così poiché sono già presenti i valori impostati nella prima passata che ri<strong>su</strong>lta-<br />
no, <strong>per</strong> le facce visib<strong>il</strong>i, certamente uguali a quelli calcolati in questa fase. Ut<strong>il</strong>izzare<br />
unicamente <strong>il</strong> minore comporterebbe quin<strong>di</strong> scartare anche i pixel in primo piano,<br />
mentre la presenza dell’uguale garantisce che essi vengano accettati. Le facce non<br />
visib<strong>il</strong>i vengono invece correttamente scartate in quanto aventi profon<strong>di</strong>tà maggiore<br />
rispetto ai pixel visib<strong>il</strong>i, con<strong>di</strong>zione non contemplata nella formula impiegata.<br />
Il blen<strong>di</strong>ng è qui ab<strong>il</strong>itato <strong>per</strong> consentire <strong>il</strong> mescolamento con i rendering precedenti.<br />
Le impostazioni del blen<strong>di</strong>ng variano <strong>per</strong>ò a seconda del tipo <strong>di</strong> texture ut<strong>il</strong>izzate<br />
nella passata.
CAPITOLO 7. LA GESTIONE DEL RENDERING 80<br />
I problemi dei materiali trasparenti<br />
Se l’algoritmo funziona molto bene <strong>per</strong> i materiali opachi, non si può <strong>di</strong>re che faccia<br />
lo stesso <strong>per</strong> i materiali trasparenti. Per essi è <strong>di</strong>fatti sempre consigliab<strong>il</strong>e ut<strong>il</strong>izzare<br />
un’unica passata, in quanto <strong>il</strong> blen<strong>di</strong>ng fra le varie fasi non avviene in maniera<br />
corretta.<br />
Negli oggetti non trasparenti sono visib<strong>il</strong>i solamente le facce in primo piano, e <strong>il</strong><br />
blen<strong>di</strong>ng fra le varie passate <strong>di</strong> rendering è possib<strong>il</strong>e <strong>per</strong>ché ogni pixel <strong>su</strong> cui viene<br />
eseguito non è <strong>il</strong> frutto <strong>di</strong> un precedente blen<strong>di</strong>ng fra più facce. Nel caso <strong>di</strong> materiali<br />
trasparenti sono invece visib<strong>il</strong>i tutte le facce dell’oggetto, anche quelle che negli altri<br />
casi sarebbero mascherate in quanto retrostanti, e ciò implica che <strong>il</strong> blen<strong>di</strong>ng fra le<br />
passate causi <strong>una</strong> stratificazione <strong>di</strong> più facce non corrispondenti fra loro, in maniera<br />
erronea.<br />
Questa è <strong>una</strong> limitazione degli algoritmi che eseguono <strong>il</strong> rendering multipassata <strong>su</strong><br />
insiemi <strong>di</strong> poligoni, irrisolvib<strong>il</strong>e se non ut<strong>il</strong>izzando algoritmi <strong>di</strong>fferenti più <strong>di</strong>spen-<br />
<strong>di</strong>osi computazionalmente. Una soluzione a questo problema sarebbe ad esempio<br />
implementare un algoritmo che o<strong>per</strong>i <strong>per</strong> faccia anziché <strong>per</strong> materiale, ma ciò segne-<br />
rebbe un netto calo delle prestazioni in quanto richiederebbe <strong>di</strong> impostare tramite<br />
le funzioni OpenGL tutti gli stati relativi ai materiali <strong>una</strong> volta <strong>per</strong> ogni triangolo,<br />
un’o<strong>per</strong>azione molto pesante.<br />
Si è scelto <strong>per</strong>ciò <strong>di</strong> mantenere questa strategia e <strong>di</strong> consigliare l’ut<strong>il</strong>izzo <strong>di</strong> <strong>una</strong><br />
singola passata nel caso <strong>di</strong> materiali trasparenti.<br />
7.3.5 L’or<strong>di</strong>ne delle texture<br />
Come esposto nelle sezioni precedenti tramite <strong>il</strong> rendering a più passate è possib<strong>il</strong>e<br />
ottenere effetti più realistici grazie all’ut<strong>il</strong>izzo <strong>di</strong> un numero elevato <strong>di</strong> texture <strong>su</strong>llo<br />
stesso poligono. Potendo <strong>per</strong>ò ut<strong>il</strong>izzare al più due texture <strong>per</strong> passata (questo è <strong>il</strong><br />
limite massimo imposto al multitexturing dalla maggior parte delle correnti schede<br />
grafiche) è necessario effettuare <strong>una</strong> selezione fra le varie texture ab<strong>il</strong>itate e definire<br />
<strong>su</strong> <strong>di</strong> esse un or<strong>di</strong>ne temporale <strong>di</strong> ut<strong>il</strong>izzo.<br />
Non esiste <strong>per</strong>ò un or<strong>di</strong>ne univoco <strong>di</strong> applicazione delle varie texture, in quanto i<br />
ri<strong>su</strong>ltati delle varie passate vengono semplicemente sommati pixel <strong>per</strong> pixel fra loro,<br />
e la commutatività della somma non <strong>per</strong>mette <strong>di</strong> ottenere un’or<strong>di</strong>ne <strong>di</strong> esecuzione
CAPITOLO 7. LA GESTIONE DEL RENDERING 81<br />
assoluto fra le varie passate. L’unica eccezione è <strong>il</strong> caso del bump mapping, che deve<br />
essere sempre eseguito <strong>per</strong> primo: questo vincolo è stato imposto dal blen<strong>di</strong>ng e sarà<br />
chiarito in seguito.<br />
La scelta dell’or<strong>di</strong>ne <strong>di</strong> applicazione delle texture è stata <strong>per</strong>ciò effettuata soggettiva-<br />
mente, selezionando <strong>una</strong> fra le varie possib<strong>il</strong>i <strong>per</strong>mutazioni delle passate. L’algoritmo<br />
implementato esegue quin<strong>di</strong> le passate nel seguente or<strong>di</strong>ne:<br />
1. bump mapping, <strong>una</strong> passata <strong>per</strong> ciasc<strong>una</strong> delle luci ut<strong>il</strong>izzab<strong>il</strong>i in OpenGL (se<br />
ovviamente è attivato <strong>il</strong> bump mapping <strong>per</strong> tale luce). Per default è ab<strong>il</strong>itato<br />
<strong>il</strong> bump mapping solamente <strong>su</strong>lla prima luce. Questo passaggio deve essere<br />
eseguito <strong>per</strong> primo <strong>per</strong>ché <strong>il</strong> blen<strong>di</strong>ng fra le passate <strong>di</strong> bump mapping eseguite<br />
<strong>per</strong> le varie luci non deve essere influenzato dalle passate <strong>su</strong>ccessive;<br />
2. colore <strong>di</strong>ffusivo oppure texture <strong>di</strong>ffusiva, e la prima texture attivata (se ve ne<br />
è <strong>una</strong>) fra<br />
• mappa <strong>di</strong> luminosità;<br />
• mappa <strong>di</strong> opacità;<br />
• riflessione ambientale (modalità rapida);<br />
• texture <strong>di</strong> colore emissivo.<br />
Se non sono state attivate ulteriori texture oltre a quelle ut<strong>il</strong>izzate in questa<br />
fase vengono qui renderizzati anche i colori ambientale, speculare ed emissivo;<br />
3. colore speculare oppure texture speculare, con la prima texture attivata (se ve<br />
ne è <strong>una</strong>) fra<br />
• mappa <strong>di</strong> opacità;<br />
• texture <strong>di</strong> bump mapping, <strong>per</strong> la simulazione <strong>di</strong> ruvi<strong>di</strong>tà;<br />
• mappa <strong>di</strong> riflessività;<br />
• riflessione ambientale (modalità rapida), se non è stata già ut<strong>il</strong>izzata nella<br />
fase precedente.<br />
4. texture <strong>di</strong> riflessione ambientale, nella <strong>su</strong>a modalità più precisa ma più lenta,<br />
modulata dalla prima texture attivata (se ve ne è <strong>una</strong>) fra
CAPITOLO 7. LA GESTIONE DEL RENDERING 82<br />
• mappa <strong>di</strong> opacità;<br />
• texture <strong>di</strong> bump mapping, <strong>per</strong> la simulazione <strong>di</strong> ruvi<strong>di</strong>tà;<br />
• texture <strong>di</strong> colore speculare.<br />
5. texture <strong>di</strong> colore emissivo, se attivata ma non già ut<strong>il</strong>izzata nella seconda fase,<br />
modulata dalla mappa <strong>di</strong> opacità se attivata.<br />
Solamente la seconda fase è eseguita sempre, mentre le rimanenti sono attivab<strong>il</strong>i e<br />
<strong>di</strong>sattivab<strong>il</strong>i in tempo reale <strong>per</strong> mezzo della impostazione delle texture da ut<strong>il</strong>izzare<br />
(e delle luci nel caso del bump mapping). Ogni passata introduce <strong>una</strong> maggiore<br />
pesantezza computazionale, a scapito del frame rate ma a giovamento della qualità<br />
visiva.<br />
La <strong>di</strong>fferenza sostanziale fra la riflessione d’ambiente rapida e la riflessione d’ambien-<br />
te lenta è che la seconda è più precisa ma introduce un’ulteriore passata <strong>di</strong> rendering<br />
mentre la prima – se sono attivate poche texture – può venire vi<strong>su</strong>alizzata anche in<br />
un’unica passata, ad esempio assieme alla texture <strong>di</strong> colore <strong>di</strong>ffusivo.<br />
7.4 I materiali trasparenti<br />
Come la presenza <strong>di</strong> più oggetti trasparenti nella scena richiede <strong>una</strong> particolare at-<br />
tenzione, così anche all’interno dello stesso oggetto i materiali trasparenti necessitano<br />
<strong>di</strong> maggiori cure.<br />
Innanzitutto è opportuno renderizzare prima tutte le facce aventi un materiale non<br />
trasparente, e solo in seguito quelle trasparenti. Questo <strong>per</strong>ché <strong>per</strong> i materiali tra-<br />
sparenti si deve <strong>di</strong>sab<strong>il</strong>itare la scrittura <strong>su</strong>llo z-buffer, siccome è necessario che si<br />
vedano anche le facce retrostanti che in un materiale completamente opaco sareb-<br />
bero co<strong>per</strong>te quin<strong>di</strong> invisib<strong>il</strong>i. Or<strong>di</strong>nando i materiali in questa maniera si è invece<br />
certi che le facce non trasparenti non coprano erroneamente frammenti trasparenti<br />
visib<strong>il</strong>i, e che quelle trasparenti vengano renderizzate solamente dove <strong>il</strong> depth te-<br />
st, ab<strong>il</strong>itato solamente in lettura e quin<strong>di</strong> in funzione dei valori inseriti durante <strong>il</strong><br />
rendering dei materiali opachi, venga passato.<br />
Anche all’interno dello stesso materiale è necessaria <strong>una</strong> accortezza: or<strong>di</strong>nare in<br />
tempo reale le facce in maniera tale che <strong>il</strong> rendering avvenga sempre dalla più lontana
CAPITOLO 7. LA GESTIONE DEL RENDERING 83<br />
alla più vicina.<br />
È opport<strong>una</strong> questa o<strong>per</strong>azione affinché <strong>il</strong> blen<strong>di</strong>ng fra le facce<br />
dell’oggetto avvenga correttamente, come già chiarito nella sezione 6.6.<br />
All’interno della <strong>libreria</strong> la procedura <strong>di</strong> gestione del rendering implementata si<br />
preoccupa automaticamente <strong>di</strong> invocare innanzitutto <strong>il</strong> rendering delle facce non<br />
trasparenti e solo in seguito quello delle facce trasparenti. Tutte le facce <strong>di</strong> ciascun<br />
materiale trasparente vengono inoltre or<strong>di</strong>nate fra loro dalla più lontana alla più<br />
vicina senza che sia necessario l’intervento dell’utente. Così come <strong>per</strong> l’or<strong>di</strong>namen-<br />
to degli oggetti, anche l’algoritmo <strong>per</strong> l’or<strong>di</strong>namento delle facce è un merge sort,<br />
presentato nell’Appen<strong>di</strong>ce E.
CAPITOLO 8<br />
Demo e Benchmark<br />
8.1 Il programma <strong>di</strong>mostrativo<br />
Parallelamente allo sv<strong>il</strong>uppo del presente lavoro <strong>di</strong> tesi è stato creato un programma<br />
<strong>di</strong>mostrativo volto al testing delle varie funzionalità della <strong>libreria</strong> implementata.<br />
Al termine del lavoro si è quin<strong>di</strong> giunti ad avere anche un completo applicativo <strong>di</strong><br />
testing.<br />
Questo applicativo è composto da vari scenari tri<strong>di</strong>mensionali, ciascuno opport<strong>una</strong>-<br />
mente selezionato <strong>per</strong> collaudare un particolare gruppo <strong>di</strong> funzionalità. L’interazione<br />
con la <strong>libreria</strong> avviene tramite la pressione <strong>di</strong> vari tasti, ma è opportuno notare come<br />
<strong>il</strong> gestore degli eventi relativi ai tasti premuti invochi <strong>di</strong>rettamente le procedure della<br />
presente <strong>libreria</strong>. Si sottolinea quin<strong>di</strong> come le funzionalità visib<strong>il</strong>i e testab<strong>il</strong>i tramite<br />
pulsanti all’interno del programma <strong>di</strong>mostrativo siano le stesse funzionalità ut<strong>il</strong>iz-<br />
zab<strong>il</strong>i tramite chiamate a meto<strong>di</strong> dagli sv<strong>il</strong>uppatori che faranno uso della presente<br />
<strong>libreria</strong>.<br />
Gli ambienti virtuali ut<strong>il</strong>izzati sono:<br />
• <strong>una</strong> vasta area rurale composta da molti poligoni <strong>su</strong>d<strong>di</strong>visi in un gran numero<br />
<strong>di</strong> no<strong>di</strong> della gerarchia. Questo test è ut<strong>il</strong>e <strong>per</strong> collaudare la gerarchia ed <strong>il</strong><br />
culling (cfr. 6.4) che <strong>su</strong> <strong>di</strong> essa si basa. Sono stati inseriti dei modelli in movi-<br />
mento all’interno <strong>di</strong> questo ambiente <strong>per</strong> verificare <strong>il</strong> corretto funzionamento<br />
delle procedure <strong>per</strong> aggiungere e rimuovere no<strong>di</strong> dalla gerarchia (cfr. 6.1) e <strong>per</strong><br />
impostare in tempo reale le trasformazioni geometriche (cfr. 6.5). Sul modello<br />
della zona rurale sono inoltre presenti varie texture (cfr. 7.2).<br />
muoversi liberamente nell’ambiente virtuale;<br />
84<br />
È possib<strong>il</strong>e
CAPITOLO 8. DEMO E BENCHMARK 85<br />
• <strong>una</strong> stanza con 4 pareti laterali <strong>di</strong> mattoni e pavimento e soffitto in cemento<br />
rugoso. Questo test è volto a collaudare <strong>il</strong> bump mapping (cfr. 7.2.6), in quan-<br />
to è possib<strong>il</strong>e spostare <strong>il</strong> punto <strong>di</strong> luce ed osservare gli effetti <strong>di</strong> tali spostamenti<br />
<strong>su</strong>lle sei pareti che compongono la stanza.<br />
anche all’interno <strong>di</strong> questo ambiente virtuale;<br />
È possib<strong>il</strong>e muoversi liberamente<br />
• <strong>una</strong> stanza piastrellata con <strong>una</strong> lastra <strong>di</strong> vetro semitrasparente sospesa al cen-<br />
tro. Questo test è volto a collaudare la trasparenza e l’or<strong>di</strong>namento degli<br />
oggetti (cfr. 6.6). Sul vetro viene proiettato un f<strong>il</strong>mato ut<strong>il</strong>izzando le funzioni<br />
<strong>per</strong> l’impostazione delle texture in tempo reale (cfr. 7.1). Si può infine decide-<br />
re se ab<strong>il</strong>itare <strong>una</strong> mappa <strong>di</strong> opacità (cfr. 7.2.8) <strong>per</strong> modellare la trasparenza<br />
del pannello;<br />
• un modello <strong>di</strong> un ambiente caricato da un f<strong>il</strong>e BSP (cfr. 9.2) che ut<strong>il</strong>izza<br />
mappe <strong>di</strong> luminosità (cfr. 7.2.7) ed un modello <strong>di</strong> <strong>una</strong> teiera importato da un<br />
f<strong>il</strong>e 3DS <strong>per</strong> verificare la fac<strong>il</strong>e integrab<strong>il</strong>ità fra modelli importati da formati<br />
<strong>di</strong>fferenti, grazie alla separazione delle classi Group e Object dal formato <strong>di</strong><br />
importazione, come spiegato nel capitolo 4.<br />
Nell’Appen<strong>di</strong>ce G sono presenti vari screenshot della demo implementata.<br />
8.2 Benchmark<br />
Sono stati eseguiti vari test <strong>per</strong> verificare <strong>il</strong> corretto comportamento della <strong>libreria</strong> e<br />
<strong>per</strong> stimare la velocità del rendering. I due test più significativi <strong>per</strong> questo secondo<br />
parametro sono stati effettuati <strong>su</strong> cinque macchine presentate in or<strong>di</strong>ne crescente <strong>di</strong><br />
potenza:<br />
1. un Athlon 1GHz con 256Mb <strong>di</strong> RAM; la scheda video è <strong>una</strong> Savage Twister K<br />
integrata con 32Mb <strong>di</strong> RAM con<strong>di</strong>visa, la risoluzione dello schermo è 800×600;<br />
2. un Pentium 3 800MHz con 256Mb <strong>di</strong> RAM; la scheda video è <strong>una</strong> Matrox<br />
G450 con 32Mb <strong>di</strong> RAM de<strong>di</strong>cata, la risoluzione dello schermo è 1024 × 768;<br />
3. un Pentium 4 1.8GHz con 512Mb <strong>di</strong> RAM; la scheda video è <strong>una</strong> nVi<strong>di</strong>a<br />
Quadro 2 EX con 32Mb <strong>di</strong> RAM de<strong>di</strong>cata, la risoluzione dello schermo è<br />
1280 × 1024;
CAPITOLO 8. DEMO E BENCHMARK 86<br />
4. un Pentium 4 3.2GHz con 1Gb <strong>di</strong> RAM; la scheda video è <strong>una</strong> nVi<strong>di</strong>a Quadro<br />
FX 1000 con 128Mb <strong>di</strong> RAM de<strong>di</strong>cata, la risoluzione dello schermo è 1280 ×<br />
1024;<br />
5. un doppio Xeon a 2.4GHz l’uno con 1Gb <strong>di</strong> RAM; la scheda video è <strong>una</strong> nVi<strong>di</strong>a<br />
Quadro 4 900 XGL con 128Mb <strong>di</strong> RAM de<strong>di</strong>cata, la risoluzione dello schermo<br />
è 1280 × 1024.<br />
Il primo test mette a confronto le <strong>per</strong>formance della <strong>libreria</strong> con <strong>il</strong> culling (cfr. 6.4)<br />
ab<strong>il</strong>itato e <strong>di</strong>sab<strong>il</strong>itato <strong>su</strong> un modello rappresentante <strong>una</strong> vasta area rurale (cfr.<br />
Figura 8.1). Il modello è composto da 23519 facce triangolari memorizzate in <strong>una</strong><br />
gerarchia formata da 2902 no<strong>di</strong>. I ri<strong>su</strong>ltati del test, esposti in frame <strong>per</strong> secondo,<br />
sono i seguenti:<br />
Culling ab<strong>il</strong>itato Culling Disab<strong>il</strong>itato<br />
Athlon 1GHz 20fps circa 8fps<br />
P3 800MHz fra i 25fps e i 30fps 14fps<br />
P4 1.8GHz fra i 28fps e i 33fps 22fps<br />
P4 3.2GHz fra gli 80fps e i 130fps 42fps<br />
Doppio Xeon 2.4GHz fra gli 80fps e i 150fps 44fps<br />
I frame <strong>per</strong> secondo sono variab<strong>il</strong>i quando <strong>il</strong> culling è ab<strong>il</strong>itato in quanto <strong>di</strong>pendono<br />
dalla <strong>per</strong>centuale <strong>di</strong> geometria che viene scartata prima <strong>di</strong> essere inviata alla pipeline<br />
grafica, come spiegato nella sezione 6.4.<br />
Per <strong>il</strong> secondo test è stato invece ut<strong>il</strong>izzato <strong>il</strong> modello 3D <strong>di</strong> <strong>una</strong> teiera già visto più<br />
volte nei capitoli precedenti, composto da 1024 facce. Su <strong>di</strong> esso è stato applicato un<br />
numero via via crescente <strong>di</strong> texture in maniera tale da poter analizzare le variazioni<br />
indotte dall’aumento del numero <strong>di</strong> passate <strong>di</strong> rendering da eseguire (cfr. 7.3) nel<br />
frame rate. I ri<strong>su</strong>ltati sono i seguenti:<br />
1 passata 2 passate 3 passate 4 passate<br />
Athlon 1GHz 30fps 19fps 12fps 11fps<br />
P3 800MHz 44fps 28fps 16fps 15fps<br />
P4 1.8GHz 44fps 29fps 22fps 21fps<br />
P4 3.2GHz 264fps 186fps 142fps 133fps<br />
Doppio Xeon 2.4GHz 507fps 340fps 184fps 164fps
CAPITOLO 8. DEMO E BENCHMARK 87<br />
Figura 8.1: Un modello 3DS rappresentante <strong>una</strong> vasta zona rurale
CAPITOLO 8. DEMO E BENCHMARK 88<br />
Il rendering multipassata non è <strong>una</strong> caratteristica fondamentale della <strong>libreria</strong>, bensì<br />
un’ut<strong>il</strong>ità aggiuntiva che è stata implementata allo scopo <strong>di</strong> migliorare <strong>il</strong> fotoreali-<br />
smo dell’immagine finale, ove l’hardware e la complessità dell’ambiente virtuale lo<br />
<strong>per</strong>mettono. Solitamente l’applicazione <strong>di</strong> molte texture <strong>per</strong> aumentare <strong>il</strong> realismo<br />
avviene <strong>su</strong> piccoli oggetti <strong>su</strong>i quali è concentrata l’attenzione o <strong>su</strong>i quali si vuole<br />
ricreare un particolare effetto visivo, pressoché mai essa avviene <strong>su</strong>ll’intero mondo<br />
virtuale.<br />
Due considerazioni emergono da questi test:<br />
• è possib<strong>il</strong>e con <strong>una</strong> passata <strong>di</strong> rendering ut<strong>il</strong>izzare la <strong>libreria</strong> anche <strong>su</strong> hardware<br />
dalle me<strong>di</strong>o/basse prestazioni nella grafica 3D (come la Savage Twister K<br />
integrata) raggiungendo sod<strong>di</strong>sfacenti frame rate che non scendono <strong>di</strong> molto<br />
sotto al limite minimo <strong>per</strong>cettib<strong>il</strong>e dall’uomo, fissato fra i 20 e i 30 frame al<br />
secondo;<br />
• l’ut<strong>il</strong>izzo <strong>di</strong> quattro passate <strong>di</strong> rendering <strong>su</strong> un singolo oggetto <strong>di</strong> <strong>di</strong>mensioni<br />
limitate è possib<strong>il</strong>e <strong>su</strong>lle macchine potenti attualmente in commercio come <strong>il</strong><br />
Pentium 4 3.2GHz oppure <strong>il</strong> doppio Xeon, e consente <strong>di</strong> ottenere un frame rate<br />
ampiamente <strong>su</strong><strong>per</strong>iore ai 20/30fps.<br />
Un computer con la potenza del Pentium 4 3.2GHz oppure <strong>il</strong> doppio Xeon ut<strong>il</strong>izzati<br />
<strong>per</strong> questo benchmark possono ri<strong>su</strong>ltare effettivamente piuttosto cari <strong>per</strong> un uso<br />
domestico, ma sono un investimento affrontab<strong>il</strong>e <strong>per</strong> un’ente come ITIA avvezzo<br />
all’acquisto delle costose macchine SGI. Se a questo si aggiunge la <strong>di</strong>fferenza <strong>di</strong><br />
prezzo fra OpenGL (gratuita) e le onerose librerie a pagamento precedentemente<br />
ut<strong>il</strong>izzate da ITIA, fra cui Vega e Performer, <strong>il</strong> risparmio a livello aziendale appare<br />
molto evidente.
CAPITOLO 9<br />
Conclusioni e sv<strong>il</strong>uppi futuri<br />
9.1 Conclusioni<br />
Inizialmente era stato posto l’obiettivo <strong>di</strong> realizzare <strong>una</strong> <strong>libreria</strong> <strong>basata</strong> <strong>su</strong> OpenGL<br />
<strong>per</strong> <strong>il</strong> caricamento e la gestione <strong>di</strong> modelli tri<strong>di</strong>mensionali. Il progetto iniziale era<br />
incentrato <strong>su</strong>ll’importazione dei modelli presenti nei f<strong>il</strong>e 3DS esportati da Autodesk<br />
3DStu<strong>di</strong>o.<br />
Durante <strong>il</strong> lavoro è venuta gradualmente alla luce <strong>una</strong> infrastruttura <strong>di</strong> classi molto<br />
flessib<strong>il</strong>i; tali classi sono in grado non solo <strong>di</strong> importare e gestire efficacemente tutte<br />
le proprietà dei modelli e della gerarchia presenti all’interno <strong>di</strong> un f<strong>il</strong>e 3DS, ma<br />
anche <strong>di</strong> <strong>per</strong>mettere all’utente della <strong>libreria</strong> <strong>di</strong> intervenire in tempo reale <strong>su</strong> tali<br />
proprietà. Questa flessib<strong>il</strong>ità lascia inoltre spazio a<strong>per</strong>to allo sv<strong>il</strong>uppo <strong>di</strong> altri loader<br />
che carichino modelli 3D da formati <strong>di</strong>fferenti da 3DS e li gestiscano <strong>per</strong> mezzo delle<br />
classi già implementate nel presente lavoro <strong>di</strong> tesi.<br />
Sin dall’inizio del lavoro è stata data un’elevata importanza alla fac<strong>il</strong>ità <strong>di</strong> integra-<br />
zione della presente <strong>libreria</strong> all’interno <strong>di</strong> più gran<strong>di</strong> applicativi <strong>di</strong> realtà virtuale<br />
basati <strong>su</strong> OpenGL. A <strong>di</strong>mostrazione del raggiungimento <strong>di</strong> questo scopo è stato<br />
sv<strong>il</strong>uppato un programma <strong>di</strong>mostrativo in OpenGL nel quale <strong>il</strong> Loader 3DS è sta-<br />
to integrato fac<strong>il</strong>mente e senza turbare <strong>il</strong> rendering globale dell’ambiente virtuale;<br />
alcuni screenshot <strong>di</strong> tale programma sono presenti nell’Appen<strong>di</strong>ce G.<br />
La <strong>libreria</strong> è stata infine corredata <strong>di</strong> <strong>una</strong> documentazione dettagliata fornita <strong>di</strong><br />
in<strong>di</strong>ce analitico, ad uso degli sv<strong>il</strong>uppatori dell’ITIA a cui è stata consegnata. Tale<br />
documentazione contiene <strong>una</strong> spiegazione <strong>di</strong> tutti i meto<strong>di</strong> implementati or<strong>di</strong>nati <strong>per</strong><br />
classe <strong>di</strong> appartenenza (Loader3DS, Group e Object). Per ciascun metodo è chiarita<br />
all’interno della documentazione la metodologia d’uso, i parametri necessari in input<br />
e l’output ottenib<strong>il</strong>e, oltre a precisazioni <strong>su</strong>lle funzionalità del metodo ove necessario.<br />
89
CAPITOLO 9. CONCLUSIONI E SVILUPPI FUTURI 90<br />
9.2 Sv<strong>il</strong>uppi futuri<br />
L’interfaccia implementata dalla classe Loader e presentata nella sezione 5.1 e le<br />
classi Group (cfr. Capitolo 6) e Object (cfr. Capitolo 7) in<strong>di</strong>pendenti dal formato<br />
<strong>di</strong> provenienza dei modelli 3D hanno lasciato ampio spazio <strong>per</strong> la creazione <strong>di</strong> nuovi<br />
loader che importino f<strong>il</strong>e da formati <strong>di</strong>fferenti dal 3DS.<br />
Figura 9.1: Un’ambientazione caricata <strong>per</strong> mezzo del loader <strong>di</strong> f<strong>il</strong>e BSP<br />
È già in fase <strong>di</strong> sv<strong>il</strong>uppo un loader <strong>di</strong> f<strong>il</strong>e BSP (Binary Space Partition), un formato<br />
ut<strong>il</strong>izzato dal famoso gioco Quake III della ID Software. All’interno <strong>di</strong> un f<strong>il</strong>e BSP<br />
è memorizzata <strong>una</strong> geometria rappresentante degli ambienti (muri, porte, . . . ) cor-<br />
redata <strong>di</strong> texture <strong>di</strong> colore <strong>di</strong>ffusivo (cfr. 7.2.1) e mappe <strong>di</strong> luminosità (cfr. 7.2.7).<br />
La versione ancora in fase <strong>di</strong> sv<strong>il</strong>uppo del loader BSP è stata ut<strong>il</strong>izzata <strong>per</strong> ottenere<br />
l’immagine 9.1.<br />
Il progetto <strong>di</strong> questo loader BSP è tuttora a<strong>per</strong>to e continuerà presso l’ITIA anche<br />
in seguito ed al <strong>di</strong> fuori della tesi.
A.1 Introduzione<br />
APPENDICE A<br />
Il formato 3DS<br />
Il formato 3DS è un formato binario. Un f<strong>il</strong>e 3DS è composto da blocchi ni<strong>di</strong>ficati<br />
denominati chunk, come <strong>il</strong>lustrato nella Figura A.1.<br />
Figura A.1: La struttura a blocchi dei f<strong>il</strong>e 3DS<br />
Ogni chunk è formato da un header contenente un <strong>su</strong>o identificativo a 16 bit e la<br />
lunghezza in byte del chunk:<br />
struct chunk_header {<br />
};<br />
unsigned short int ID;<br />
unsigned int size;<br />
L’header è seguito dal contenuto del chunk, la cui lunghezza in byte è<br />
chunk_header.size - sizeof(chunk_header)<br />
91
APPENDICE A. IL FORMATO 3DS 92<br />
Nel corso <strong>di</strong> questa Appen<strong>di</strong>ce verrà presentato solamente l’insieme dei chunk che<br />
sono caricati dalla classe Loader3DS (cfr. 5.3), <strong>una</strong> sottoparte dell’insieme <strong>di</strong> tutti<br />
i chunk re<strong>per</strong>ib<strong>il</strong>i in un f<strong>il</strong>e 3DS, assieme al loro identificativo a 16 bit. I chunk<br />
scartati contengono <strong>di</strong>fatti informazioni non r<strong>il</strong>evanti <strong>per</strong> la presente <strong>libreria</strong>, ad<br />
esempio dati riguardanti le luci e le telecamere oppure le animazioni. I chunk <strong>di</strong><br />
interesse <strong>per</strong> la <strong>libreria</strong> sono presentati nella Figura A.2.<br />
Si può fac<strong>il</strong>mente osservare come essi si <strong>su</strong>d<strong>di</strong>vidano in due gran<strong>di</strong> gruppi: i chunk<br />
dell’e<strong>di</strong>tor e i chunk del keyframer. L’e<strong>di</strong>tor e <strong>il</strong> keyframer sono due sottoparti <strong>di</strong><br />
3DStu<strong>di</strong>o che interagiscono strettamente ma sono concettualmente separate. L’e-<br />
<strong>di</strong>tor è ut<strong>il</strong>izzato <strong>per</strong> creare gli oggetti, che possono essere modelli 3D, luci oppure<br />
telecamere.<br />
È ut<strong>il</strong>izzato anche <strong>per</strong> creare i materiali, impostare le loro texture e as-<br />
segnare ai modelli i vari materiali. Il keyframer è invece ut<strong>il</strong>izzato <strong>per</strong> gestire l’intera<br />
scena, posizionare i modelli dell’e<strong>di</strong>tor in funzione del sistema <strong>di</strong> riferimento globale,<br />
creare fra loro <strong>una</strong> gerarchia, impostare animazioni mo<strong>di</strong>ficando le trasformazioni<br />
geometriche che intervengono <strong>su</strong>i vari oggetti in funzione del tempo. I contenuti dei<br />
due chunk rispecchiano questa <strong>su</strong>d<strong>di</strong>visione.<br />
Sono considerati anche altri due chunk, RGB e AMOUNTOF, che possono essere<br />
presenti in varie parti del f<strong>il</strong>e. [PVVF97]<br />
A.2 I chunk<br />
RGB (0x0011)<br />
Contiene un colore in formato RGB (Red Green Blue), con ciascuno dei tre canali<br />
memorizzato in un singolo byte.<br />
AMOUNTOF (0x0030)<br />
Contiene un intero <strong>di</strong> due byte ut<strong>il</strong>izzato <strong>per</strong> vari scopi.<br />
MAIN (0x4D4D)<br />
Corrisponde all’intero f<strong>il</strong>e, e contiene un chunk <strong>di</strong> tipo EDITOR ed un chunk <strong>di</strong> tipo<br />
KEYFRAMER.
APPENDICE A. IL FORMATO 3DS 93<br />
MAIN (0x4D4D)<br />
+-EDITOR (0x3D3D)<br />
| +-EDITOR_MATERIAL (0xAFFF)<br />
| | +-EDITOR_MATERIAL_NAME (0xA000)<br />
| | +-EDITOR_MATERIAL_AMBIENT (0xA010)<br />
| | +-EDITOR_MATERIAL_DIFFUSE (0xA020)<br />
| | +-EDITOR_MATERIAL_SPECULAR (0xA030)<br />
| | +-EDITOR_MATERIAL_GLOSSINESS (0xA040)<br />
| | +-EDITOR_MATERIAL_SHININESS (0xA041)<br />
| | +-EDITOR_MATERIAL_TRANSPARENCY (0xA050)<br />
| | +-EDITOR_MATERIAL_2_SIDED (0xA081)<br />
| | +-EDITOR_MATERIAL_EMISSION (0xA084)<br />
| | +-EDITOR_MATERIAL_TEXTURE_DIFFUSE (0xA200)<br />
| | +-EDITOR_MATERIAL_TEXTURE_OPACITY (0xA210)<br />
| | +-EDITOR_MATERIAL_TEXTURE_BUMP (0xA230)<br />
| | +-EDITOR_MATERIAL_TEXTURE_SPECULAR (0xA204)<br />
| | +-EDITOR_MATERIAL_TEXTURE_SHININESS (0xA33C)<br />
| | +-EDITOR_MATERIAL_TEXTURE_SELF_ILLUMINATION (0xA33D)<br />
| | +-EDITOR_MATERIAL_TEXTURE_ENVIRONMENT (0xA220)<br />
| | +-EDITOR_MATERIAL_TEXTURE_FILE (0xA300)<br />
| | +-EDITOR_MATERIAL_TEXTURE_U_SCALING (0xA354)<br />
| | +-EDITOR_MATERIAL_TEXTURE_V_SCALING (0xA356)<br />
| | +-EDITOR_MATERIAL_TEXTURE_U_OFFSET (0xA358)<br />
| | +-EDITOR_MATERIAL_TEXTURE_V_OFFSET (0xA35A)<br />
| +-EDITOR_OBJECT (0x4000)<br />
| +-EDITOR_OBJECT_MESH (0x4100)<br />
| +-EDITOR_OBJECT_MESH_VERTICES (0x4110)<br />
| +-EDITOR_OBJECT_MESH_FACES (0x4120)<br />
| +-EDITOR_OBJECT_MESH_MATERIAL (0x4130)<br />
| +-EDITOR_OBJECT_MESH_TEXTURE_COORDS (0x4140)<br />
| +-EDITOR_OBJECT_MESH_SMOOTHING_GROUPS (0x4150)<br />
| +-EDITOR_OBJECT_MESH_LOCAL_AXES (0x4160)<br />
+-KEYFRAMER (0xB000)<br />
+-KEYFRAMER_OBJECT (0xB002)<br />
+-KEYFRAMER_OBJECT_FATHER (0xB010)<br />
+-KEYFRAMER_OBJECT_NAME (0xB011)<br />
+-KEYFRAMER_OBJECT_PIVOT_OFFSET (0xB013)<br />
+-KEYFRAMER_OBJECT_TRANSLATION (0xB020)<br />
+-KEYFRAMER_OBJECT_ROTATION (0xB021)<br />
+-KEYFRAMER_OBJECT_SCALING (0xB022)<br />
+-KEYFRAMER_OBJECT_NUMBER (0xB030)<br />
Figura A.2: I chunk caricati dalla classe Loader3DS
APPENDICE A. IL FORMATO 3DS 94<br />
EDITOR (0x3D3D)<br />
Contiene i chunk che definiscono i materiali e gli oggetti presenti nella scena. Contie-<br />
ne anche i chunk che definiscono le telecamere e le luci, ma questi vengono ignorati<br />
dal loader in quanto non interessanti ai fini dell’applicazione.<br />
EDITOR MATERIAL (0xAFFF)<br />
Questo chunk corrisponde ad un particolare materiale e contiene i chunk con prefisso<br />
EDITOR MATERIAL che definiscono le proprietà del materiale (non tutti i chunk<br />
sono obbligatori).<br />
EDITOR MATERIAL NAME (0xA000)<br />
Contiene <strong>una</strong> stringa terminata dal carattere nullo, che corrisponde al nome del<br />
materiale definito nel chunk padre <strong>di</strong> tipo EDITOR MATERIAL.<br />
EDITOR MATERIAL AMBIENT (0xA010)<br />
Contiene un chunk RGB al cui interno è memorizzato <strong>il</strong> colore ambientale del<br />
materiale.<br />
EDITOR MATERIAL DIFFUSE (0xA020)<br />
Contiene un chunk RGB al cui interno è memorizzato <strong>il</strong> colore <strong>di</strong>ffusivo del materiale.<br />
EDITOR MATERIAL SPECULAR (0xA030)<br />
Contiene un chunk RGB al cui interno è memorizzato <strong>il</strong> colore speculare del mate-<br />
riale.<br />
EDITOR MATERIAL GLOSSINESS (0xA040)<br />
Contiene un chunk AMOUNTOF al cui interno è memorizzato <strong>il</strong> livello <strong>di</strong> atte-<br />
nuazione dei riflessi speculari <strong>su</strong>lla <strong>su</strong><strong>per</strong>ficie. Una maggiore attenuazione comporta<br />
riflessi piccoli dai contorni più marcati, <strong>una</strong> minore attenuazione al contrario implica<br />
riflessi speculari più estesi e più sfocati.
APPENDICE A. IL FORMATO 3DS 95<br />
EDITOR MATERIAL SHININESS (0xA041)<br />
Contiene un chunk AMOUNTOF al cui interno è memorizzato <strong>il</strong> livello <strong>di</strong> specularità<br />
del materiale, ut<strong>il</strong>izzab<strong>il</strong>e come modulatore del colore speculare.<br />
EDITOR MATERIAL TRANSPARENCY (0xA050)<br />
Contiene un chunk AMOUNTOF al cui interno è memorizzato <strong>il</strong> livello <strong>di</strong> opacità<br />
del materiale. Maggiore è questo livello, minore è la trasparenza.<br />
EDITOR MATERIAL 2 SIDED (0xA081)<br />
È un chunk vuoto la cui presenza è ut<strong>il</strong>izzata come flag. Se presente ogni poligono<br />
che usa questo materiale è considerato come composto da due facce sovrapposte,<br />
ciasc<strong>una</strong> delle due avente le normali invertite rispetto all’altra.<br />
EDITOR MATERIAL EMISSION (0xA084)<br />
Contiene un chunk AMOUNTOF al cui interno è memorizzato <strong>il</strong> livello <strong>di</strong> emissione<br />
del materiale, ut<strong>il</strong>izzab<strong>il</strong>e come moltiplicatore del colore <strong>di</strong>ffusivo <strong>per</strong> ottenere <strong>il</strong><br />
colore emissivo.<br />
EDITOR MATERIAL TEXTURE DIFFUSE (0xA200)<br />
EDITOR MATERIAL TEXTURE OPACITY (0xA210)<br />
EDITOR MATERIAL TEXTURE BUMP (0xA230)<br />
EDITOR MATERIAL TEXTURE SPECULAR (0xA204)<br />
EDITOR MATERIAL TEXTURE SHININESS (0xA33C)<br />
EDITOR MATERIAL TEXTURE SELF ILLUMINATION (0xA33D)<br />
EDITOR MATERIAL TEXTURE ENVIRONMENT (0xA220)<br />
Contengono i chunk identificati dal prefisso EDITOR MATERIAL TEXTURE. Cia-<br />
scuno <strong>di</strong> loro identifica un particolare tipo <strong>di</strong> texture, fac<strong>il</strong>mente intuib<strong>il</strong>e dal nome<br />
stesso del chunk.
APPENDICE A. IL FORMATO 3DS 96<br />
EDITOR MATERIAL TEXTURE FILE (0xA300)<br />
Contiene <strong>il</strong> nome del f<strong>il</strong>e contenente la texture, sotto forma <strong>di</strong> stringa terminata da<br />
un carattere nullo.<br />
EDITOR MATERIAL TEXTURE U SCALING (0xA354)<br />
EDITOR MATERIAL TEXTURE V SCALING (0xA356)<br />
Contengono <strong>il</strong> valore <strong>di</strong> scaling della texture <strong>su</strong>lle <strong>su</strong>e due coor<strong>di</strong>nate. Questo va-<br />
lore viene impiegato negli oggetti che ut<strong>il</strong>izzano questa texture come moltiplicatore<br />
<strong>per</strong> le coor<strong>di</strong>nate <strong>di</strong> texture re<strong>per</strong>ib<strong>il</strong>i nel chunk EDITOR OBJECT MESH TEX-<br />
TURE COORDS.<br />
EDITOR MATERIAL TEXTURE U OFFSET (0xA358)<br />
EDITOR MATERIAL TEXTURE V OFFSET (0xA35A)<br />
Contengono <strong>il</strong> valore <strong>di</strong> offset della texture <strong>su</strong>lle <strong>su</strong>e due coor<strong>di</strong>nate. Questo valore<br />
viene impiegato negli oggetti che ut<strong>il</strong>izzano questa texture sommandolo alle coor<strong>di</strong>-<br />
nate <strong>di</strong> texture re<strong>per</strong>ib<strong>il</strong>i in EDITOR OBJECT MESH TEXTURE COORDS.<br />
EDITOR OBJECT (0x4000)<br />
Identifica un oggetto della scena. Contiene <strong>una</strong> stringa terminata dal carattere<br />
nullo che memorizza <strong>il</strong> nome dell’oggetto. A questa fanno seguito un chunk EDI-<br />
TOR OBJECT MESH oppure altri chunk se l’oggetto è <strong>una</strong> luce o <strong>una</strong> telecamera.<br />
Questi ultimi due casi sono <strong>per</strong>ò ignorati dal loader, in quanto irr<strong>il</strong>evanti ai fini del<br />
caricamento dei modelli 3D.<br />
EDITOR OBJECT MESH (0x4100)<br />
Identifica <strong>una</strong> mesh <strong>di</strong> triangoli. Contiene i chunk identificati dal prefisso EDI-<br />
TOR OBJECT MESH.
APPENDICE A. IL FORMATO 3DS 97<br />
EDITOR OBJECT MESH VERTICES (0x4110)<br />
Contiene un intero <strong>di</strong> 2 byte che in<strong>di</strong>ca <strong>il</strong> numero <strong>di</strong> vertici presenti in questo chunk.<br />
Sono quin<strong>di</strong> memorizzate tante triplette (x, y, z) <strong>di</strong> floating point da 4 byte l’uno<br />
quante in<strong>di</strong>cate nell’intero da 2 byte.<br />
EDITOR OBJECT MESH FACES (0x4120)<br />
Contiene un intero <strong>di</strong> 2 byte che in<strong>di</strong>ca <strong>il</strong> numero <strong>di</strong> facce presenti in questo chunk.<br />
Sono quin<strong>di</strong> memorizzati, <strong>per</strong> ogni faccia, i 3 vertici che la compongono (ciascuno<br />
sotto forma <strong>di</strong> intero da 2 byte) e ulteriori 2 byte ut<strong>il</strong>izzati come insieme <strong>di</strong> flag.<br />
Nella presente applicazione si ut<strong>il</strong>izzano solo i primi 3 byte <strong>di</strong> tale flag (flag & 0x01,<br />
flag & 0x02 e flag & 0x04) nella modalità wireframe come in<strong>di</strong>catori della visib<strong>il</strong>ità<br />
dei tre segmenti che compongono la faccia triangolare.<br />
EDITOR OBJECT MESH MATERIAL (0x4130)<br />
Contiene <strong>una</strong> stringa terminata dal carattere nullo che corrisponde al nome del mate-<br />
riale re<strong>per</strong>ib<strong>il</strong>e in EDITOR MATERIAL NAME. A questa stringa fanno seguito un<br />
intero da 2 byte che in<strong>di</strong>ca <strong>il</strong> numero <strong>di</strong> facce che ut<strong>il</strong>izzano questo materiale, ed in se-<br />
guito tanti in<strong>di</strong>ci da 2 byte all’array re<strong>per</strong>ib<strong>il</strong>e in EDITOR OBJECT MESH FACES<br />
quanti in<strong>di</strong>cati dall’intero da 2 byte.<br />
EDITOR OBJECT MESH TEXTURE COORDS (0x4140)<br />
Contiene un intero <strong>di</strong> 2 byte che in<strong>di</strong>ca <strong>il</strong> numero <strong>di</strong> coor<strong>di</strong>nate <strong>di</strong> texture (uguale al<br />
numero <strong>di</strong> vertici) presenti in questo chunk. Sono quin<strong>di</strong> memorizzate tante coppie<br />
(u, v) <strong>di</strong> floating point da 4 byte l’uno quante in<strong>di</strong>cate nell’intero da 2 byte.<br />
EDITOR OBJECT MESH SMOOTHING GROUPS (0x4150)<br />
Gli smoothing groups sono gruppi <strong>di</strong> facce fra le quali vengono interpolate le nor-<br />
mali. Questo chunk contiene tanti interi da 4 byte quante sono le facce in EDI-<br />
TOR OBJECT MESH FACES. Ciascuno <strong>di</strong> questi interi è ut<strong>il</strong>izzab<strong>il</strong>e come insie-<br />
me <strong>di</strong> 32 flag da un bit; un bit i-esimo impostato a 1 in<strong>di</strong>ca che <strong>il</strong> numero dello<br />
smoothing group a cui appartiene la faccia corrispondente è i.
APPENDICE A. IL FORMATO 3DS 98<br />
EDITOR OBJECT MESH LOCAL AXES (0x4160)<br />
Contiene quattro triplette (x, y, z) <strong>di</strong> floating point da 4 byte l’uno. Le prime tre<br />
triplette costituiscono la terna d’assi del sistema <strong>di</strong> riferimento locale dell’oggetto,<br />
la quarta <strong>il</strong> centro <strong>di</strong> tale sistema <strong>di</strong> riferimento.<br />
KEYFRAMER (0xB000)<br />
Contiene i chunk che definiscono la gerarchia e le animazioni sotto forma <strong>di</strong> tra-<br />
sformazioni geometriche in funzione del tempo. Ai fini della presente <strong>libreria</strong> ci si<br />
interessa solamente della gerarchia, mentre <strong>per</strong> le animazioni si leggono solamente<br />
le trasformazioni geometriche del primo fotogramma e si ignorano le <strong>su</strong>ccessive.<br />
KEYFRAMER OBJECT (0xB002)<br />
Contiene un nodo della gerarchia. Al <strong>su</strong>o interno sono presenti i chunk contrad<strong>di</strong>-<br />
stinti dal prefisso KEYFRAMER OBJECT.<br />
KEYFRAMER OBJECT FATHER (0xB010)<br />
Contiene <strong>una</strong> stringa terminata dal carattere nullo che memorizza <strong>il</strong> nome del no-<br />
do. Per gli oggetti tale stringa corrisponde a quella re<strong>per</strong>ib<strong>il</strong>e in uno dei chunk<br />
EDITOR OBJECT. Per i gruppi la stringa è invece “$$$DUMMY”, mentre <strong>il</strong> reale<br />
nome del gruppo è re<strong>per</strong>ib<strong>il</strong>e nel seguente chunk KEYFRAMER OBJECT NAME.<br />
Seguono 4 byte <strong>di</strong> dati ignorati, ed infine un intero da 2 byte che corrisponde al<br />
numero re<strong>per</strong>ib<strong>il</strong>e in KEYFRAMER OBJECT NUMBER del nodo padre (oppure<br />
-1 se <strong>il</strong> nodo è figlio della ra<strong>di</strong>ce).<br />
KEYFRAMER OBJECT NAME (0xB011)<br />
Contiene <strong>una</strong> stringa terminata dal carattere nullo che memorizza <strong>il</strong> nome del<br />
gruppo. Non è presente negli oggetti.<br />
KEYFRAMER OBJECT PIVOT OFFSET (0xB013)<br />
Contiene <strong>una</strong> tripletta (x, y, z) <strong>di</strong> floating point da 4 byte ciascuno. Tale tripletta<br />
identifica lo scostamento del centro del sistema <strong>di</strong> riferimento locale dell’oggetto dal<br />
centro della <strong>su</strong>a boun<strong>di</strong>ng box.
APPENDICE A. IL FORMATO 3DS 99<br />
KEYFRAMER OBJECT TRANSLATION (0xB020)<br />
Contiene 20 byte <strong>di</strong> dati ignorati, quin<strong>di</strong> <strong>una</strong> tripletta (x, y, z) che identifica <strong>il</strong> vettore<br />
<strong>di</strong> traslazione che influisce <strong>su</strong>l nodo. I rimanenti dati fino al termine del chunk sono<br />
ignorati in quanto nel presente lavoro non ci si interessa dell’animazione dell’oggetto.<br />
KEYFRAMER OBJECT ROTATION (0xB021)<br />
Contiene 20 byte <strong>di</strong> dati ignorati, quin<strong>di</strong> un floating point da 4 byte ed <strong>una</strong> tripletta<br />
(x, y, z) che identificano l’angolo e l’asse della rotazione che influisce <strong>su</strong>l nodo. I<br />
rimanenti dati fino al termine del chunk sono ignorati in quanto nel presente lavoro<br />
non ci si interessa dell’animazione dell’oggetto.<br />
KEYFRAMER OBJECT SCALING (0xB022)<br />
Contiene 20 byte <strong>di</strong> dati ignorati, quin<strong>di</strong> <strong>una</strong> tripletta (x, y, z) che identifica i tre<br />
coefficienti del ri<strong>di</strong>mensionamento che influisce <strong>su</strong>l nodo. I rimanenti dati fino al<br />
termine del chunk sono ignorati in quanto nel presente lavoro non ci si interessa<br />
dell’animazione dell’oggetto.<br />
KEYFRAMER OBJECT NUMBER (0xB030)<br />
Contiene un intero da 2 byte che memorizza <strong>il</strong> numero del nodo, ut<strong>il</strong>e <strong>per</strong> identificarlo<br />
come padre nei <strong>su</strong>oi no<strong>di</strong> figli.
B.1 Introduzione<br />
APPENDICE B<br />
Le estensioni OpenGL<br />
Le estensioni OpenGL sono funzioni non definite all’interno del nocciolo standard<br />
OpenGL <strong>di</strong> S<strong>il</strong>icon Graphics. Esse sono invece fornite dai singoli produttori <strong>di</strong> hard-<br />
ware all’interno dei driver delle schede grafiche, e potenziano l’insieme <strong>di</strong> funzionalità<br />
base OpenGL.<br />
Ogni estensione è identificata da un nome. Una estensione <strong>il</strong> cui nome inizia <strong>per</strong><br />
GL ARB è <strong>una</strong> estensione che è stata approvata dall’ARB (cfr. 3.1.4) e in quanto<br />
tale deve obbligatoriamente essere fornita all’interno <strong>di</strong> ogni driver <strong>di</strong> scheda grafica<br />
che <strong>su</strong>pporti OpenGL. Le estensioni aventi come prefisso GL EXT sono estensioni<br />
molto <strong>di</strong>ffuse ma non ancora approvate formalmente dall’ARB; si consiglia comunque<br />
ai produttori <strong>di</strong> schede grafiche <strong>di</strong> includerle all’interno dei driver. Esistono infine<br />
<strong>una</strong> moltitu<strong>di</strong>ne <strong>di</strong> estensioni realizzate dalle singole case produttrici <strong>di</strong> hardware, ad<br />
esempio nVi<strong>di</strong>a (GL NV ) e S<strong>il</strong>icon Graphics (GL SGIS). La provenienza <strong>di</strong> ciasc<strong>una</strong><br />
estensione è quin<strong>di</strong> ricavab<strong>il</strong>e semplicemente osservando <strong>il</strong> prefisso del <strong>su</strong>o nome.<br />
B.2 Elenco delle estensioni presenti<br />
È possib<strong>il</strong>e ottenere l’elenco delle estensioni presenti nel proprio driver interrogando<br />
OpenGL <strong>per</strong> mezzo della procedura glGetString. Una chiamata a<br />
glGetString(GL_EXTENSIONS);<br />
restituisce un puntatore ad <strong>una</strong> stringa contenente i nomi <strong>di</strong> tutte le estensioni<br />
fornite all’interno del driver, separate fra loro da spazi.<br />
100
APPENDICE B. LE ESTENSIONI OPENGL 101<br />
B.3 Ut<strong>il</strong>izzare le estensioni OpenGL<br />
Per ut<strong>il</strong>izzare le estensioni OpenGL è necessario includere la <strong>libreria</strong> glext.h che defi-<br />
nisce tutte le macro C necessarie. All’interno della stessa <strong>libreria</strong> sono anche definite<br />
le funzioni aggiuntive introdotte dalle varie estensioni, sotto forma <strong>di</strong> puntatori.<br />
Le modalità <strong>di</strong> ut<strong>il</strong>izzo <strong>di</strong> questi puntatori variano <strong>di</strong>pendentemente dal sistema ope-<br />
rativo ut<strong>il</strong>izzato. In ambiente Linux/Unix è possib<strong>il</strong>e ut<strong>il</strong>izzare tali puntatori senza<br />
istanziarli. In ambiente Windows è invece necessario istanziarli con la locazione <strong>di</strong><br />
memoria corretta; <strong>per</strong> fare ciò è possib<strong>il</strong>e ut<strong>il</strong>izzare wglGetProcAddress che riceve<br />
come input <strong>il</strong> nome della procedura <strong>di</strong> cui si vuole ottenere <strong>il</strong> puntatore e restitui-<br />
sce tale puntatore.<br />
<strong>il</strong>lustrato nel seguente esempio:<br />
È necessario effettuare un cast <strong>su</strong>l puntatore restituito, come<br />
glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)<br />
wglGetProcAddress("glActiveTextureARB");<br />
I tipi da ut<strong>il</strong>izzare <strong>per</strong> <strong>il</strong> cast sono definiti nel f<strong>il</strong>e glext.h.<br />
È <strong>su</strong>fficiente osservare<br />
all’interno <strong>di</strong> tale f<strong>il</strong>e <strong>il</strong> tipo della procedura <strong>per</strong> la quale si vuole ottenere <strong>il</strong> puntatore<br />
e ut<strong>il</strong>izzare tale tipo <strong>per</strong> <strong>il</strong> cast.<br />
Se non è presente <strong>una</strong> funzione <strong>per</strong> la quale si vuole ottenere un puntatore wglGet-<br />
ProcAddress restituisce un puntatore nullo; analogamente anche sotto Linux/Unix<br />
<strong>il</strong> puntatore è istanziato dal sistema a NULL. Questo implica che sia sempre neces-<br />
sario controllare la presenza <strong>di</strong> <strong>una</strong> estensione con glGetString(GL EXTENSIONS)<br />
prima <strong>di</strong> cercare <strong>di</strong> ut<strong>il</strong>izzare <strong>una</strong> funzione ad essa collegata.<br />
Il f<strong>il</strong>e glext.h è scaricab<strong>il</strong>e dai siti dei vari produttori <strong>di</strong> schede grafiche, ad esempio<br />
http://oss.sgi.com/projects/ogl-sample/registry/<br />
oppure fac<strong>il</strong>mente re<strong>per</strong>ib<strong>il</strong>e con <strong>una</strong> ricerca <strong>su</strong>i principali motori <strong>di</strong> ricerca.<br />
B.4 Le estensioni ut<strong>il</strong>izzate nella presente <strong>libreria</strong><br />
Il presente lavoro fa uso, se sono <strong>di</strong>sponib<strong>il</strong>i, <strong>di</strong> tre estensioni OpenGL:<br />
• GL ARB multitexture;<br />
• GL ARB texture env add;
APPENDICE B. LE ESTENSIONI OPENGL 102<br />
• GL ARB texture env combine.<br />
Se <strong>una</strong> <strong>di</strong> esse non è <strong>di</strong>sponib<strong>il</strong>e vengono <strong>di</strong>sab<strong>il</strong>itate tutte le funzionalità della<br />
presente <strong>libreria</strong> che fanno uso <strong>di</strong> tale estensione.<br />
GL ARB multitexture<br />
Questa estensione aggiunge al nocciolo OpenGL funzionalità <strong>per</strong> <strong>il</strong> multitexturing,<br />
ovvero la possib<strong>il</strong>ità <strong>di</strong> ut<strong>il</strong>izzare contemporaneamente più <strong>di</strong> <strong>una</strong> texture <strong>su</strong>llo stesso<br />
poligono. Fra le procedure introdotte da questa estensione quelle ut<strong>il</strong>izzate all’inter-<br />
no della presente <strong>libreria</strong> sono due: glActiveTextureARB e glMultiTexCoord2fARB.<br />
OpenGL è <strong>una</strong> macchina a stati, <strong>per</strong>ciò è possib<strong>il</strong>e impostare le modalità <strong>di</strong> ut<strong>il</strong>izzo<br />
della texture semplicemente mo<strong>di</strong>ficando gli stati OpenGL. Quando si ut<strong>il</strong>izzano più<br />
texture allo stesso momento ri<strong>su</strong>lta <strong>per</strong>ò <strong>di</strong>ffic<strong>il</strong>e configurare <strong>per</strong> mezzo delle funzioni<br />
base ciasc<strong>una</strong> texture in<strong>di</strong>pendentemente dalle altre. La procedura glActiveTextu-<br />
reARB serve a selezionare la texture attiva, ovvero quella <strong>per</strong> la quale avvengono le<br />
mo<strong>di</strong>fiche degli stati. Tale texture può essere selezionata con le costanti introdotte<br />
da glext.h, ovvero GL TEXTURE0 ARB, GL TEXTURE1 ARB, e così via.<br />
Se non si ut<strong>il</strong>izza <strong>il</strong> multitexturing è possib<strong>il</strong>e definire <strong>per</strong> ogni vertice la relati-<br />
va coor<strong>di</strong>nata <strong>di</strong> texture ut<strong>il</strong>izzando la procedura glTexCoord2f del nocciolo base<br />
OpenGL. Quando si ut<strong>il</strong>izza <strong>il</strong> multitexturing è possib<strong>il</strong>e ut<strong>il</strong>izzare la procedura<br />
glMultiTexCoord2fARB <strong>per</strong> associare a ciascun vertice <strong>una</strong> coor<strong>di</strong>nata <strong>di</strong> texture<br />
separata <strong>per</strong> ogn<strong>una</strong> delle texture ut<strong>il</strong>izzate. glMultiTexCoord2fARB funziona in<br />
maniera analoga a glTexCoord2f ma riceve come parametro aggiuntivo <strong>una</strong> fra le<br />
costanti GL TEXTUREn ARB sopracitate. [GF98]<br />
GL ARB texture env add<br />
In fase <strong>di</strong> rendering viene effettuata <strong>una</strong> modulazione fra <strong>il</strong> colore del materiale <strong>di</strong><br />
un poligono e i colori delle varie texture definite <strong>su</strong>l medesimo poligono. Il nocciolo<br />
OpenGL consente <strong>di</strong> definire la modalità in base alla quale avviene tale modulazione<br />
tramite le costanti<br />
• GL DECAL e GL REPLACE, che <strong>per</strong>mettono <strong>di</strong> sostituire <strong>il</strong> colore già presen-<br />
te <strong>su</strong>l frammento (dato dal colore del materiale oppure dal colore della texture<br />
precedente) con quello della texture corrente;
APPENDICE B. LE ESTENSIONI OPENGL 103<br />
• GL MODULATE e GL BLEND, che <strong>per</strong>mettono <strong>di</strong> eseguire <strong>una</strong> moltiplica-<br />
zione fra <strong>il</strong> colore presente <strong>su</strong>l frammento e quello della texture corrente;<br />
Questa estensione aggiunge la possib<strong>il</strong>ità <strong>di</strong> ut<strong>il</strong>izzare <strong>una</strong> quinta costante, GL ADD,<br />
che consente <strong>di</strong> sommare fra loro pixel <strong>per</strong> pixel <strong>il</strong> colore presente <strong>su</strong>l frammento e<br />
quello della texture corrente. [GF99]<br />
GL ARB texture env combine<br />
Questa estensione consente un maggiore controllo <strong>su</strong>lle equazioni che definiscono la<br />
modulazione pixel <strong>per</strong> pixel che avviene fra <strong>il</strong> colore del materiale <strong>di</strong> un poligono e<br />
<strong>il</strong> colore delle texture del poligono stesso.<br />
Vengono fornite nuove costanti <strong>per</strong> poter definire con precisione gli o<strong>per</strong>an<strong>di</strong> e gli<br />
o<strong>per</strong>atori da ut<strong>il</strong>izzare <strong>per</strong> ottenere <strong>il</strong> colore RGBA finale partendo da quello del<br />
materiale e quello della texture (oppure delle texture se si ut<strong>il</strong>izza anche l’esten-<br />
sione <strong>per</strong> <strong>il</strong> multitexturing).<br />
È possib<strong>il</strong>e definire sia le o<strong>per</strong>azioni che intervengono<br />
<strong>su</strong>l colore (COMBINE RGB) sia quelle che influiscono solamente <strong>su</strong>l canale alpha<br />
(COMBINE ALPHA).<br />
Gli o<strong>per</strong>an<strong>di</strong> possono essere selezionati fra:<br />
• GL TEXTURE, ovvero <strong>il</strong> colore della texture corrente;<br />
• GL CONSTANT ARB, ovvero un colore costante definib<strong>il</strong>e tramite le proce-<br />
dure OpenGL;<br />
• GL PRIMARY COLOR ARB, ovvero <strong>il</strong> colore del materiale;<br />
• GL PREVIOUS ARB, ovvero <strong>il</strong> colore già presente <strong>su</strong>l frammento;<br />
Per tutti questi o<strong>per</strong>an<strong>di</strong> è possib<strong>il</strong>e decidere se selezionare <strong>il</strong> colore, <strong>il</strong> <strong>su</strong>o com-<br />
plementare, <strong>il</strong> valore del canale alpha oppure <strong>il</strong> complementare <strong>di</strong> tale valore. Gli<br />
o<strong>per</strong>atori che si possono ut<strong>il</strong>izzare sono i già citati REPLACE, MODULATE e ADD;<br />
in aggiunta si può usare ADD SIGNED (come ADD ma al ri<strong>su</strong>ltato viene sottratta<br />
la metà del valore massimo), INTERPOLATE (<strong>una</strong> somma pesata <strong>per</strong> la quale sono<br />
necessari tre o<strong>per</strong>an<strong>di</strong>: <strong>il</strong> terzo viene ut<strong>il</strong>izzato come peso) e SUBTRACT (<strong>il</strong> valore<br />
del primo o<strong>per</strong>ando meno quello del secondo).<br />
Le specifiche <strong>per</strong> questa estensione sono re<strong>per</strong>ib<strong>il</strong>i in [PGFH01].
C.1 Introduzione<br />
APPENDICE C<br />
Il frustum culling<br />
Il frustum culling è un processo volto a decidere se dei punti siano all’interno oppure<br />
all’esterno del frustum <strong>di</strong> vista (cfr. 6.4). Nella presente <strong>libreria</strong> <strong>il</strong> frustum culling è<br />
stato ut<strong>il</strong>izzato assieme alle boun<strong>di</strong>ng box (cfr. 6.3) <strong>per</strong> alleggerire le computazioni<br />
che avvengono in fase <strong>di</strong> rendering: è possib<strong>il</strong>e applicare <strong>il</strong> frustum culling <strong>su</strong>lle<br />
boun<strong>di</strong>ng box <strong>di</strong> tutti gli oggetti della scena <strong>per</strong> scoprire quali siano gli oggetti<br />
visib<strong>il</strong>i e quali siano quelli <strong>su</strong>i quali non è necessario eseguire <strong>il</strong> rendering, in quanto<br />
non visib<strong>il</strong>i.<br />
L’algoritmo implementato o<strong>per</strong>a in due fasi: la prima è necessaria <strong>per</strong> ottenere i sei<br />
piani che formano <strong>il</strong> frustum <strong>di</strong> vista a partire dalla matrice <strong>di</strong> trasformazione del<br />
modello e della vista e dalla matrice <strong>di</strong> trasformazione della proiezione (cfr. 6.4),<br />
la seconda consiste nella vera e propria o<strong>per</strong>azione <strong>di</strong> culling e si basa <strong>su</strong>l frustum<br />
calcolato nella prima fase.<br />
C.2 Il calcolo del frustum<br />
Per <strong>il</strong> calcolo del frustum si ut<strong>il</strong>izzano la matrice <strong>di</strong> trasformazione del modello e<br />
della vista M (in OpenGL le due trasformazioni sono unite in un’unica matrice) e<br />
la matrice <strong>di</strong> trasformazione della proiezione P (cfr. 6.4). Esse sono fac<strong>il</strong>mente ot-<br />
tenib<strong>il</strong>i interrogando OpenGL con l’apposita funzione glGetFloatv ut<strong>il</strong>izzando come<br />
parametri GL MODELVIEW MATRIX e GL PROJECTION MATRIX. [NDW94]<br />
Da queste due matrici è possib<strong>il</strong>e ottenere<br />
104
APPENDICE C. IL FRUSTUM CULLING 105<br />
⎛<br />
⎜<br />
C = P M = ⎜<br />
⎝<br />
m11 m12 m13 m14<br />
m21 m22 m23 m24<br />
m31 m32 m33 m34<br />
m41 m42 m43 m44<br />
che corrisponde alla matrice <strong>per</strong> trasformare ciascun vertice dal <strong>su</strong>o sistema <strong>di</strong> ri-<br />
ferimento locale al Clipping Coor<strong>di</strong>nate System (cfr. 6.4). Il vertice in coor<strong>di</strong>nate<br />
omogenee (x, y, z, w) T viene trasformato da questa matrice in<br />
⎛<br />
⎜<br />
⎝<br />
x ′<br />
y ′<br />
z ′<br />
w ′<br />
⎞<br />
⎟<br />
⎠<br />
⎞<br />
⎟<br />
⎠ =<br />
⎛<br />
⎞<br />
⎜<br />
⎝<br />
m11<br />
m21<br />
m31<br />
m12<br />
m22<br />
m32<br />
m13<br />
m23<br />
m33<br />
m14<br />
m24<br />
m34<br />
⎟<br />
⎠<br />
m41 m42 m43 m44<br />
×<br />
⎛ ⎞<br />
⎜<br />
⎝<br />
x<br />
y<br />
z<br />
⎟<br />
⎠<br />
⎛<br />
w<br />
⎞<br />
=<br />
⎜<br />
⎝<br />
x · m11 + y · m12 + z · m13 + w · m14<br />
x · m21 + y · m22 + z · m23 + w · m24<br />
x · m31 + y · m32 + z · m33 + w · m34<br />
x · m41 + y · m42 + z · m43 + w · m44<br />
⎟<br />
⎠<br />
In OpenGL <strong>il</strong> frustum della vista viene trasformato nel Clipping Coor<strong>di</strong>nate System<br />
in un cubo <strong>di</strong> lato 2 centrato <strong>su</strong>ll’origine, i cui vertici sono <strong>per</strong>ciò tutte le triplette<br />
<strong>di</strong> coor<strong>di</strong>nate ottenib<strong>il</strong>i ut<strong>il</strong>izzando i valori 1 e −1.<br />
(x ′ , y ′ , z ′ , w ′ ) T = (x ′ /w ′ , y ′ /w ′ , z ′ /w ′ , 1) T<br />
sia all’interno <strong>di</strong> questo cubo solamente se vale<br />
⎧<br />
⎪⎨ −1 < x<br />
⎪⎩<br />
′ /w ′ < 1<br />
−1 < y ′ /w ′ < 1<br />
−1 < z ′ /w ′ < 1<br />
ovvero ⎧ ⎪⎨<br />
−w ′ < x ′ < w ′<br />
−w<br />
⎪⎩<br />
′ < y ′ < w ′<br />
−w ′ < z ′ < w ′<br />
È quin<strong>di</strong> evidente che un vertice
APPENDICE C. IL FRUSTUM CULLING 106<br />
Ponendo queste <strong>di</strong>sequazioni in funzione <strong>di</strong> (x, y, z, w) T anziché (x ′ , y ′ , z ′ , w ′ ) T <strong>per</strong><br />
mezzo <strong>di</strong> <strong>una</strong> sostituzione si ottiene ad esempio <strong>per</strong> −w ′ < x ′ :<br />
−(x · m41 + y · m42 + z · m43 + w · m44) < x · m11 + y · m12 + z · m13 + w · m14<br />
ovvero<br />
0 < x · (m41 + m11) + y · (m42 + m12) + z · (m43 + m13) + w · (m44 + m14)<br />
che è la <strong>di</strong>sequazione <strong>di</strong> uno semispazio. Siccome nella presente <strong>libreria</strong> tutti i vertici<br />
sono nel formato (x, y, z, 1) T si giunge a<br />
0 < x · (m41 + m11) + y · (m42 + m12) + z · (m43 + m13) + (m44 + m14)<br />
dove si possono identificare<br />
a = (m41 + m11), b = (m42 + m12), c = (m43 + m13), d = (m44 + m14)<br />
come i coefficienti <strong>di</strong> un piano<br />
ax + by + cz + d = 0<br />
In maniera analoga si possono ottenere i coefficienti <strong>di</strong> tutti i sei piani che definiscono<br />
<strong>il</strong> volume <strong>di</strong> spazio del frustum <strong>di</strong> vista, che ri<strong>su</strong>ltano essere quelli in<strong>di</strong>cati nella<br />
Tabella C.1 (<strong>per</strong> i piani <strong>di</strong> clipping si veda 6.4).<br />
Tutti i piani vengono quin<strong>di</strong> normalizzati; i loro coefficienti vengono cioè tutti <strong>di</strong>visi<br />
<strong>per</strong> la norma del vettore (a, b, c) T ottenendo<br />
(a ′ , b ′ , c ′ , d ′ ) T �<br />
a<br />
= √<br />
a2 + b2 + c2 ,<br />
b<br />
√<br />
a2 + b2 + c2 ,<br />
c<br />
√<br />
a2 + b2 + c2 ,<br />
�T d<br />
√<br />
a2 + b2 + c2 C.3 Il frustum culling<br />
Un vertice (x0, y0, z0, 1) T è nel semispazio positivo rispetto ad un piano ax+by+cz+d<br />
se si ha che<br />
a · x0 + b · y0 + c · z0 + d > 0<br />
In maniera analoga <strong>una</strong> boun<strong>di</strong>ng box è nel semispazio positivo rispetto ad un piano<br />
se tutti i <strong>su</strong>oi otto vertici sono nel semispazio positivo rispetto a tale piano.
APPENDICE C. IL FRUSTUM CULLING 107<br />
Piano <strong>di</strong> clipping Diseguaglianza Coefficienti<br />
left −w ′ < x ′ a = m41 + m11<br />
b = m42 + m12<br />
c = m43 + m13<br />
d = m44 + m14<br />
right x ′ < w ′ a = m41 − m11<br />
b = m42 − m12<br />
c = m43 − m13<br />
d = m44 − m14<br />
bottom −w ′ < y ′ a = m41 + m21<br />
b = m42 + m22<br />
c = m43 + m23<br />
d = m44 + m24<br />
top y ′ < w ′ a = m41 − m21<br />
b = m42 − m22<br />
c = m43 − m23<br />
d = m44 − m24<br />
21ck −w ′ < z ′ a = m41 + m31<br />
b = m42 + m32<br />
c = m43 + m33<br />
d = m44 + m34<br />
front z ′ < w ′ a = m41 − m31<br />
b = m42 − m32<br />
c = m43 − m33<br />
d = m44 − m34<br />
Tabella C.1: I coefficienti dei sei piani che formano <strong>il</strong> frustum <strong>di</strong> vista (cfr. Figura<br />
C.1), espressi in funzione del Clipping Coor<strong>di</strong>nate System
APPENDICE C. IL FRUSTUM CULLING 108<br />
Figura C.1: I sei piani che definiscono <strong>il</strong> volume del frustum <strong>di</strong> vista<br />
Come si può notare dalle equazioni della sezione C.2 un punto è all’interno del<br />
frustum <strong>di</strong> vista solamente se si trova all’interno dell’intersezione fra i semispazi<br />
positivi <strong>di</strong> tutti i sei piani che formano <strong>il</strong> frustum. Una boun<strong>di</strong>ng box è all’interno<br />
del frustum <strong>di</strong> vista (parzialmente o totalmente) solamente se almeno uno dei <strong>su</strong>oi<br />
vertici è all’interno del frustum.<br />
L’algoritmo implementato <strong>per</strong> <strong>il</strong> frustum culling scarta tutte le boun<strong>di</strong>ng box che si<br />
trovano nel semispazio negativo rispetto ad uno qualsiasi dei sei piani che formano<br />
<strong>il</strong> frustum. Questo algoritmo non esclude <strong>per</strong>ciò le boun<strong>di</strong>ng box esterne al frustum<br />
ma non completamente all’interno <strong>di</strong> uno dei sei semispazi negativi, come <strong>il</strong>lustrato<br />
nella Figura C.2.<br />
In questo ultimo caso sarebbe infatti necessario impiegare anche un algoritmo <strong>di</strong><br />
collision detection fra la boun<strong>di</strong>ng box ed <strong>il</strong> frustum. Un algoritmo <strong>di</strong> questo tipo<br />
non consiste nell’in<strong>di</strong>viduazione della posizione <strong>di</strong> un punto rispetto ad un piano,<br />
calcolab<strong>il</strong>e tramite la risoluzione <strong>di</strong> un’equazione <strong>per</strong> mezzo dell’algoritmo <strong>di</strong> fru-<br />
stum culling sopra presentato; un algoritmo <strong>di</strong> collision detection comporta invece<br />
la risoluzione <strong>di</strong> sistemi <strong>di</strong> equazioni <strong>per</strong> in<strong>di</strong>viduare l’esistenza <strong>di</strong> uno o più punti <strong>di</strong><br />
intersezione fra la boun<strong>di</strong>ng box dell’oggetto ed <strong>il</strong> frustum <strong>di</strong> vista, e risolvere questi<br />
sistemi è evidentemente più costoso computazionalmente rispetto alla risoluzione <strong>di</strong><br />
<strong>una</strong> sola <strong>di</strong>sequazione.
APPENDICE C. IL FRUSTUM CULLING 109<br />
Figura C.2: Solamente i poligoni completamente all’interno <strong>di</strong> uno semispazio negativo<br />
vengono eliminati. Per questo motivo la boun<strong>di</strong>ng box B0 viene scartata dal frustum<br />
culling, mentre B1 viene mantenuta
D.1 Introduzione<br />
APPENDICE D<br />
Il bump mapping<br />
Le <strong>su</strong><strong>per</strong>fici da modellare possono talvolta non essere <strong>per</strong>fettamente liscie, ed ai fini<br />
<strong>di</strong> un rendering realistico può essere ut<strong>il</strong>e rappresentare rugosità e scanalature. È<br />
possib<strong>il</strong>e farlo in maniera precalcolata ut<strong>il</strong>izzando texture <strong>di</strong>ffusive ad alto contra-<br />
sto (cfr. 7.2.1). Quando <strong>per</strong>ò le luci che influiscono <strong>su</strong>lla <strong>su</strong><strong>per</strong>ficie si muovono è<br />
necessario che le ombre causate dai particolari in r<strong>il</strong>ievo si spostino in tempo reale<br />
in funzione della posizione della luce. In questi casi è possib<strong>il</strong>e fare uso del bump<br />
mapping (cfr. 7.2.6).<br />
Il bump mapping, traducib<strong>il</strong>e in italiano come mappatura dei r<strong>il</strong>ievi, è <strong>una</strong> tecnica<br />
ut<strong>il</strong>izzata in computer graphics <strong>per</strong> simulare dei <strong>di</strong>slivelli oppure delle as<strong>per</strong>ità <strong>su</strong><br />
<strong>una</strong> <strong>su</strong><strong>per</strong>ficie. Esistono vari algoritmi <strong>per</strong> <strong>il</strong> bump mapping, ma lo scopo comune<br />
<strong>di</strong> tutti è quello <strong>di</strong> mo<strong>di</strong>ficare la riflessione della <strong>su</strong><strong>per</strong>ficie come se <strong>su</strong> <strong>di</strong> essa fossero<br />
realmente presenti i <strong>di</strong>slivelli e le scabrosità.<br />
Ci sono vari mo<strong>di</strong> <strong>per</strong> mo<strong>di</strong>ficare la riflessione <strong>di</strong> <strong>una</strong> <strong>su</strong><strong>per</strong>ficie:<br />
• mo<strong>di</strong>ficare i vettori normali alla <strong>su</strong><strong>per</strong>ficie pixel <strong>per</strong> pixel. Questo implica<br />
impiegare algoritmi <strong>di</strong> sha<strong>di</strong>ng <strong>per</strong> pixel anziché <strong>per</strong> vertice non ancora com-<br />
putazionalmente affrontab<strong>il</strong>i all’interno <strong>di</strong> programmi <strong>di</strong> grafica in tempo reale<br />
(cfr. 7.2);<br />
• mo<strong>di</strong>ficare i vettori normali alla <strong>su</strong><strong>per</strong>ficie vertice <strong>per</strong> vertice. Il realismo <strong>di</strong><br />
questa soluzione è legato al numero <strong>di</strong> poligoni che compongono <strong>il</strong> model-<br />
lo. Non bisogna comunque <strong>di</strong>menticare che aumentare <strong>il</strong> numero <strong>di</strong> poligoni<br />
significa anche aumentare la pesantezza computazionale del rendering;<br />
110
APPENDICE D. IL BUMP MAPPING 111<br />
• sfruttare o<strong>per</strong>azioni fra le texture come avviene nell’embossing, l’algoritmo im-<br />
plementato all’interno della presente <strong>libreria</strong>; l’embossing verrà spiegato nella<br />
sezione D.3.<br />
D.2 La texture <strong>di</strong> bump mapping<br />
La texture <strong>di</strong> bump mapping consiste in <strong>una</strong> immagine in scala <strong>di</strong> grigi (i cui valori<br />
<strong>per</strong> ogni pixel variano nell’intervallo [0, 1], ovvero fra <strong>il</strong> nero ed <strong>il</strong> bianco) che viene<br />
interpretata come <strong>una</strong> mappa <strong>di</strong> altitu<strong>di</strong>ne: <strong>il</strong> bianco in<strong>di</strong>ca l’altitu<strong>di</strong>ne più elevata,<br />
<strong>il</strong> nero quella meno elevata ed i valori interme<strong>di</strong> sono rappresentati dai vari valori <strong>di</strong><br />
grigio.<br />
I <strong>di</strong>slivelli fra due zone sono tanto più gran<strong>di</strong> quanto maggiore è la <strong>di</strong>stanza fra i<br />
due valori cromatici dei pixel che le rappresentano. Una texture <strong>di</strong> bump mapping<br />
<strong>per</strong> <strong>il</strong> pianeta Terra è fornita come esempio nella Figura D.1.<br />
Figura D.1: Una texture <strong>di</strong> bump mapping <strong>per</strong> <strong>il</strong> pianeta Terra
APPENDICE D. IL BUMP MAPPING 112<br />
D.3 L’embossing<br />
L’embossing è un algoritmo <strong>di</strong> bump mapping che funziona tramite <strong>una</strong> semplice<br />
o<strong>per</strong>azione <strong>di</strong> somma fra texture, come chiarito poco avanti. Ha <strong>il</strong> <strong>di</strong>fetto <strong>di</strong> mo<strong>di</strong>fi-<br />
care solamente la riflessione <strong>di</strong>ffusiva della <strong>su</strong><strong>per</strong>ficie <strong>su</strong> cui è applicato, senza poter<br />
mo<strong>di</strong>ficare la riflessione speculare (<strong>per</strong> quest’ultima è necessario un algoritmo <strong>per</strong><br />
pixel); d’altra parte ha <strong>il</strong> grosso vantaggio <strong>di</strong> essere comunque parecchio realistico<br />
(cfr. 7.2.6) ed al tempo stesso molto veloce: questo è ciò che conta in particolar<br />
modo nelle applicazioni <strong>di</strong> grafica in tempo reale, e <strong>per</strong> questo motivo all’interno<br />
della presente <strong>libreria</strong> è stato adottato l’embossing.<br />
Il punto <strong>di</strong> partenza <strong>per</strong> effettuare l’embossing è ovviamente la texture <strong>di</strong> bump<br />
mapping. Viene creata <strong>una</strong> copia <strong>di</strong> questa texture con i colori invertiti; <strong>per</strong> inverso<br />
<strong>di</strong> un colore c definito <strong>su</strong>ll’intervallo [0, 1] si intende <strong>il</strong> valore 1 − c. I valori <strong>di</strong><br />
entrambe le texture vengono poi <strong>di</strong>mezzati, in maniera tale da portare tutti i pixel<br />
dall’intervallo [0, 1] all’intervallo [0, 0.5].<br />
Se a questo punto si esamina <strong>una</strong> sezione delle due texture rappresentando con<br />
<strong>di</strong>versi livelli <strong>di</strong> altitu<strong>di</strong>ne i colori delle due texture, è evidente che sommandole si<br />
ottiene <strong>una</strong> texture <strong>di</strong> colore grigio (0.5) uniforme (cfr. Figura D.2).<br />
Figura D.2: La somma fra la texture <strong>di</strong> bump mapping e la <strong>su</strong>a inversa genera <strong>una</strong> texture<br />
uniforme grigia<br />
L’effetto cromatico che si nota <strong>su</strong> <strong>una</strong> <strong>su</strong><strong>per</strong>ficie con <strong>di</strong>slivelli che viene influenzata
APPENDICE D. IL BUMP MAPPING 113<br />
da <strong>una</strong> luce è lo schiarimento delle zone <strong>di</strong> <strong>di</strong>slivello orientate verso la luce stessa<br />
e lo oscuramento delle zone opposte. Se nella Figura D.2 spostiamo la texture <strong>di</strong><br />
bump mapping mantenendo immutata la posizione della <strong>su</strong>a inversa, otteniamo che<br />
la somma non è più un valore costante, bensì la sezione <strong>di</strong> <strong>una</strong> texture <strong>su</strong>lla quale è<br />
presente l’effetto che desideriamo ottenere <strong>su</strong>lla <strong>su</strong><strong>per</strong>ficie soggetta a bump mapping.<br />
Figura D.3: Se la texture <strong>di</strong> bump mapping viene scostata rispetto alla <strong>su</strong>a inversa la<br />
loro somma genera due <strong>di</strong>slivelli <strong>di</strong> colore, uno più scuro ed uno più chiaro<br />
È quin<strong>di</strong> evidente come sia <strong>su</strong>fficiente ut<strong>il</strong>izzare questa somma fra la texture <strong>di</strong> bump<br />
mapping invertita e la texture <strong>di</strong> bump mapping originale <strong>per</strong> simulare la ruvi<strong>di</strong>tà<br />
<strong>di</strong> <strong>una</strong> <strong>su</strong><strong>per</strong>ficie, mo<strong>di</strong>ficando <strong>su</strong> ogni vertice in tempo reale le coor<strong>di</strong>nate della<br />
texture <strong>di</strong> bump mapping originale in maniera da scostarla <strong>di</strong> poco verso <strong>il</strong> punto<br />
<strong>di</strong> luce. I coefficienti <strong>di</strong> scostamento della texture <strong>di</strong> bump mapping sono calcolab<strong>il</strong>i<br />
in funzione <strong>di</strong> tre versori:<br />
• <strong>il</strong> versore inverso rispetto alla <strong>di</strong>rezione della luce. Si possono avere luci <strong>di</strong><br />
posizione, collocate in un punto preciso del mondo virtuale, ed in tal caso<br />
bisogna calcolare <strong>per</strong> ciascun vertice <strong>di</strong> ogni faccia <strong>il</strong> vettore che va dal vertice<br />
al punto dove è collocata la luce, quin<strong>di</strong> normalizzarlo.<br />
È possib<strong>il</strong>e ut<strong>il</strong>izzare<br />
anche luci <strong>di</strong>rezionali, ed in tal caso è <strong>su</strong>fficiente invertire <strong>il</strong> vettore <strong>di</strong> <strong>di</strong>rezione<br />
della luce, avendo sempre cura <strong>di</strong> normalizzarlo;<br />
• i due versori <strong>di</strong> avanzamento della texture. Le texture sono bi<strong>di</strong>mensionali, e <strong>su</strong>
APPENDICE D. IL BUMP MAPPING 114<br />
<strong>di</strong> esse è definito un sistema <strong>di</strong> riferimento a due assi. I versori <strong>di</strong> avanzamento<br />
servono a stimare la <strong>di</strong>rezione nel mondo tri<strong>di</strong>mensionale nella quale sono<br />
orientati i due assi del sistema <strong>di</strong> riferimento della texture. Questa stima deve<br />
essere calcolata <strong>per</strong> ogni vertice, e la metodologia impiegata nella presente<br />
<strong>libreria</strong> è presentata in seguito.<br />
Versori <strong>di</strong> avanzamento della texture<br />
I versori <strong>di</strong> avanzamento <strong>di</strong> texture vengono calcolati <strong>su</strong>i tre vertici <strong>di</strong> ciasc<strong>una</strong> fac-<br />
cia. I software <strong>di</strong>mostrativi che fanno uso dell’embossing ut<strong>il</strong>izzano solitamente dei<br />
modelli predefiniti <strong>per</strong> i quali i versori <strong>di</strong> avanzamento delle texture sono precalco-<br />
lati. Questo non è ovviamente possib<strong>il</strong>e all’interno della presente <strong>libreria</strong>, in quanto<br />
non si conoscono a priori i modelli <strong>per</strong> i quali verrà ut<strong>il</strong>izzato <strong>il</strong> bump mapping. È<br />
stato <strong>per</strong>ciò necessario ideare un algoritmo <strong>per</strong> calcolare <strong>una</strong> stima atten<strong>di</strong>b<strong>il</strong>e della<br />
<strong>di</strong>rezione <strong>di</strong> avanzamento delle coor<strong>di</strong>nate <strong>di</strong> texture.<br />
Figura D.4: Un triangolo con le coor<strong>di</strong>nate <strong>di</strong> texture dei vari vertici<br />
Ut<strong>il</strong>izzando come esempio <strong>il</strong> triangolo della Figura D.4, ed in particolar modo <strong>il</strong> lato
APPENDICE D. IL BUMP MAPPING 115<br />
che va da P 0 a P 1, è necessario in<strong>di</strong>viduare <strong>una</strong> valida stima della <strong>di</strong>rezione spaziale<br />
verso la quale avanzano le due coor<strong>di</strong>nate della texture.<br />
È evidente come all’interno delle equazioni da ut<strong>il</strong>izzare dovranno trovare posto i<br />
due coefficienti<br />
∆u = u1 − u0<br />
∆v = v1 − v0<br />
che rappresentano la <strong>di</strong>fferenza fra le coor<strong>di</strong>nate <strong>di</strong> texture <strong>su</strong>i due vertici.<br />
Dovrà anche trovare posto <strong>il</strong> vettore<br />
p = P 1 − P 0 = (p1x − p0x, p1y − p0y, p1z − p0z)<br />
che è invece <strong>il</strong> vettore che va da P 0 = (p0x, p0y, p0z) T a P 1 = (p1x, p1y, p1z) T , ed<br />
in<strong>di</strong>ca la <strong>di</strong>rezione verso la quale le coor<strong>di</strong>nate <strong>di</strong> texture avanzano <strong>di</strong> (∆u, ∆v).<br />
Questo non è <strong>per</strong>ò <strong>su</strong>fficiente, in quanto sono necessari anche due coefficienti che<br />
rappresentino l’atten<strong>di</strong>b<strong>il</strong>ità della stima. Per ottenere questi coefficienti è stato<br />
<strong>su</strong>fficiente osservare i casi limite:<br />
• quando ∆u = 0 si ha che la stima <strong>per</strong> l’avanzamento della coor<strong>di</strong>nata v è al<br />
massimo dell’atten<strong>di</strong>b<strong>il</strong>ità, a meno che non si abbia anche ∆v = 0. Lo stesso<br />
vale <strong>per</strong> <strong>il</strong> caso ∆v = 0 e la coor<strong>di</strong>nata u;<br />
• quando |∆u| = |∆v| la stima è al minimo dell’atten<strong>di</strong>b<strong>il</strong>ità, in quanto <strong>il</strong> vettore<br />
<strong>di</strong> <strong>di</strong>rezione spaziale in<strong>di</strong>ca un avanzamento <strong>di</strong>agonale <strong>su</strong>lla texture, dal quale<br />
è impossib<strong>il</strong>e estrarre i due versori paralleli agli assi u e v del sistema <strong>di</strong><br />
riferimento della texture.<br />
Si è <strong>per</strong>ciò scelto <strong>di</strong> ut<strong>il</strong>izzare come valore <strong>di</strong> atten<strong>di</strong>b<strong>il</strong>ità<br />
a = |(|∆u| − |∆v|)|<br />
che rispetta i casi limite analizzati e varia linearmente nei casi interme<strong>di</strong>, in funzione<br />
della <strong>di</strong>fferenza fra |∆u| e |∆v|.<br />
I due vettori calcolati come stima dell’avanzamento nello spazio delle coor<strong>di</strong>nate <strong>di</strong><br />
texture sono <strong>per</strong>ciò<br />
u = ∆ua · p
APPENDICE D. IL BUMP MAPPING 116<br />
v = ∆va · p<br />
Questi vettori sono calcolati <strong>per</strong> tutti i tre vertici <strong>di</strong> ciasc<strong>una</strong> faccia.<br />
Questi vettori non sono <strong>per</strong>ò quelli finali. Per ogni smoothing group (cfr. A.2)<br />
viene infatti calcolata <strong>una</strong> me<strong>di</strong>a dei vettori relativi a ciascun vertice del modello<br />
appartenente a tale smoothing group (ogni vertice può <strong>di</strong>fatti appartenere a più <strong>di</strong><br />
<strong>una</strong> faccia); questo vettore me<strong>di</strong>o viene normalizzato <strong>per</strong> ottenere un versore, ed è<br />
infine assegnato al relativo vertice come versore <strong>di</strong> avanzamento della coor<strong>di</strong>nata <strong>di</strong><br />
texture.<br />
Il coefficienti <strong>di</strong> scostamento della texture <strong>di</strong> bump mapping<br />
Una volta calcolati i versori <strong>di</strong> avanzamento delle coor<strong>di</strong>nate <strong>di</strong> texture ci ritroviamo<br />
dalla situazione presentata in Figura D.4 a quella in Figura D.5. A questo punto è<br />
possib<strong>il</strong>e calcolare lo scostamento da applicare alla texture <strong>di</strong> bump mapping, che<br />
<strong>di</strong>penderà dalla posizione della luce.<br />
Figura D.5: Sono stati i calcolati i versori <strong>di</strong> avanzamento delle coor<strong>di</strong>nate <strong>di</strong> texture <strong>per</strong><br />
<strong>il</strong> triangolo <strong>di</strong> Figura D.4 (sono mostrati solo quelli <strong>per</strong> P 0)<br />
Riferendoci all’immagine D.5 possiamo osservare la modalità ut<strong>il</strong>izzata <strong>per</strong> <strong>il</strong> calcolo
APPENDICE D. IL BUMP MAPPING 117<br />
dello scostamento della texture <strong>su</strong>lla coor<strong>di</strong>nata u. La metodologia <strong>per</strong> <strong>il</strong> calcolo<br />
dello scostamento <strong>su</strong>lla coor<strong>di</strong>nata v è la stessa.<br />
Come si nota è necessario calcolare <strong>il</strong> versore con <strong>di</strong>rezione uguale a quella del-<br />
la luce e verso opposto.<br />
È innanzitutto necessario ricavare <strong>il</strong> vettore (x, y, z, w)T<br />
rappresentante la luce ut<strong>il</strong>izzando la funzione OpenGL<br />
glGetLightfv(GL_LIGHT_n, GL_POSITION, light)<br />
dove n corrisponde al numero della luce <strong>per</strong> cui si vuole ottenere <strong>il</strong> vettore 1 , mentre<br />
light è un array <strong>di</strong> 4 floating point che conterrà tale vettore come output.<br />
Figura D.6: È necessario calcolare <strong>il</strong> versore con <strong>di</strong>rezione uguale a quella della luce e<br />
verso opposto. Calcolando la norma della <strong>su</strong>a proiezione <strong>su</strong>l versore <strong>di</strong> avanzamento della<br />
coor<strong>di</strong>nata <strong>di</strong> texture si ottiene lo scostamento da applicare<br />
1 In OpenGL è possib<strong>il</strong>e ut<strong>il</strong>izzare più <strong>di</strong> <strong>una</strong> luce contemporaneamente. Il limite degli hardware<br />
attuali è solitamente posto ad otto luci, <strong>per</strong> cui n solitamente può as<strong>su</strong>mere i valori fra 0 e 7<br />
compresi.
APPENDICE D. IL BUMP MAPPING 118<br />
Il vettore della luce restituito da glGetLightfv è espresso in funzione del sistema <strong>di</strong><br />
riferimento della vista, mentre i vettori <strong>di</strong> avanzamento delle coor<strong>di</strong>nate <strong>di</strong> texture<br />
sono espressi in coor<strong>di</strong>nate locali dell’oggetto (cfr. 6.4).<br />
È quin<strong>di</strong> necessario mol-<br />
tiplicare <strong>il</strong> vettore della luce appena ottenuto <strong>per</strong> l’inversa della matrice relativa<br />
alla trasformazione del modello e della vista. Tale matrice inversa è calcolata con <strong>il</strong><br />
metodo del determinante, già chiarito nella sezione 5.6.1. Così facendo si ottiene <strong>il</strong><br />
vettore (x ′ , y ′ , z ′ , w ′ ) T rappresentante la luce in funzione del sistema <strong>di</strong> riferimento<br />
locale dell’oggetto.<br />
Sempre riferendoci alla Figura D.6, <strong>di</strong>pendentemente dal valore <strong>di</strong> w ′ si possono<br />
avere due casi:<br />
• se w ′ = 0 la luce è <strong>di</strong> tipo <strong>di</strong>rezionale (ovvero i raggi luminosi sono tutti paralleli<br />
come provenienti da <strong>una</strong> sorgente posta a <strong>di</strong>stanza infinita).<br />
È <strong>su</strong>fficiente<br />
normalizzare (−x ′ , −y ′ , −z ′ ) T <strong>per</strong> ottenere <strong>il</strong> versore con <strong>di</strong>rezione uguale a<br />
quella della luce e verso opposto;<br />
• se w ′ �= 0 la luce è <strong>di</strong> tipo posizionale (ovvero i raggi luminosi sono tutti<br />
provenienti da <strong>una</strong> sorgente puntiforme).<br />
È necessario normalizzare <strong>il</strong> vettore<br />
(x ′ − p0x, y ′ − p0y, z ′ − p0z) T <strong>per</strong> ottenere <strong>il</strong> versore con <strong>di</strong>rezione uguale a<br />
quella della luce e verso opposto (si rammenta che P 0 = (p0x, p0y, p0z) T ).<br />
A questo punto, in<strong>di</strong>pendentemente dalla tipologia <strong>di</strong> luce che stiamo considerando, è<br />
stato ottenuto <strong>il</strong> versore in<strong>di</strong>cato nella Figura D.6 con la lettera ˆ l. Come scostamento<br />
da applicare alla texture <strong>di</strong> bump mapping <strong>su</strong>lla coor<strong>di</strong>nata u è <strong>su</strong>fficiente ut<strong>il</strong>izzare<br />
la norma della proiezione <strong>di</strong> ˆ l <strong>su</strong>l versore û. Il calcolo <strong>di</strong> questo valore consiste in un<br />
semplice prodotto scalare fra i due versori, ovvero ˆ l · û. Per ottenere lo scostamento<br />
<strong>su</strong>lla coor<strong>di</strong>nata v si devono eseguire tutti i passi appena presentati sostituendo<br />
semplicemente <strong>il</strong> versore û con <strong>il</strong> versore ˆv.<br />
È infine possib<strong>il</strong>e ut<strong>il</strong>izzare un coefficiente <strong>di</strong> attenuazione dello scostamento. Non<br />
esiste un valore univoco <strong>per</strong> tale coefficiente ma è necessario decidere empiricamen-<br />
te <strong>il</strong> valore da impiegare <strong>di</strong>pendentemente da quanto si vuole che sia evidente e<br />
marcata l’ombreggiatura generata dal bump mapping. Nel presente lavoro si ut<strong>il</strong>iz-<br />
za come coefficiente 0.01, ma esso è <strong>di</strong>chiarato con <strong>una</strong> <strong>di</strong>rettiva del preprocessore<br />
C (#define BUMP_LEVEL 0.01) ed è quin<strong>di</strong> fac<strong>il</strong>mente mo<strong>di</strong>ficab<strong>il</strong>e da parte degli<br />
utenti della <strong>libreria</strong> intervenendo <strong>su</strong>l f<strong>il</strong>e che contiene tale <strong>di</strong>rettiva.
APPENDICE D. IL BUMP MAPPING 119<br />
Si ha quin<strong>di</strong> che i coefficienti <strong>di</strong> scostamento <strong>su</strong> e sv <strong>per</strong> ciascun vertice P <strong>su</strong>l quale<br />
sono stati calcolati come versori <strong>di</strong> avanzamento delle coor<strong>di</strong>nate <strong>di</strong> texture ûp e ˆvp<br />
e <strong>per</strong> <strong>il</strong> quale <strong>il</strong> versore avente come <strong>di</strong>rezione quella della luce ma verso opposto è<br />
ˆ lp sono<br />
[GOL99]<br />
<strong>su</strong> = BUMP LEVEL · ûp · ˆ lp<br />
sv = BUMP LEVEL · ˆvp · ˆ lp
APPENDICE E<br />
L’algoritmo <strong>di</strong> or<strong>di</strong>namento<br />
E.1 Introduzione<br />
All’interno del presente lavoro <strong>di</strong> tesi è stato necessario implementare un algorit-<br />
mo <strong>di</strong> or<strong>di</strong>namento <strong>per</strong> motivi legati alla trasparenza e chiariti nelle sezioni 6.6 e<br />
7.4. L’algoritmo implementato nella presente <strong>libreria</strong> è ut<strong>il</strong>izzab<strong>il</strong>e <strong>per</strong> or<strong>di</strong>nare in<br />
funzione della <strong>di</strong>stanza dal punto <strong>di</strong> vista<br />
• i triangoli che compongono un singolo modello tri<strong>di</strong>mensionale;<br />
• i figli <strong>di</strong> un nodo della gerarchia.<br />
L’algoritmo funziona in due passi <strong>su</strong>ccessivi: innanzitutto è necessario calcolare la<br />
<strong>di</strong>stanza che intercorre fra ciascun poligono oppure ciascun figlio <strong>di</strong> un nodo della<br />
gerarchia ed <strong>il</strong> punto <strong>di</strong> vista, quin<strong>di</strong> si può applicare un or<strong>di</strong>namento dal più lontano<br />
<strong>di</strong> essi al più vicino. Di seguito sono presentate le due modalità <strong>per</strong> <strong>il</strong> calcolo della<br />
<strong>di</strong>stanza rispettivamente fra <strong>il</strong> punto <strong>di</strong> vista ed un poligono e fra <strong>il</strong> punto <strong>di</strong> vista<br />
ed un nodo della gerarchia. Viene quin<strong>di</strong> presentato l’algoritmo <strong>di</strong> or<strong>di</strong>namento, che<br />
è un merge sort.<br />
E.2 Distanza fra un poligono ed <strong>il</strong> punto <strong>di</strong> vista<br />
Come spiegato nella sezione 6.4 le due trasformazioni del modello e della vista ser-<br />
vono a portare <strong>il</strong> punto <strong>di</strong> vista nell’origine degli assi e ad orientare la <strong>di</strong>rezione della<br />
vista <strong>su</strong> un’asse. Nel caso <strong>di</strong> OpenGL queste due trasformazioni sono unite nella<br />
120
APPENDICE E. L’ALGORITMO DI ORDINAMENTO 121<br />
Figura E.1: Sistema <strong>di</strong> riferimento globale (A) e sistema <strong>di</strong> riferimento della vista (B).<br />
La trasformazione della vista porta <strong>il</strong> punto <strong>di</strong> vista nell’origine degli assi ed orienta la<br />
<strong>di</strong>rezione della vista lungo l’asse z<br />
matrice denominata ModelView, e orientano la vista <strong>su</strong>ll’asse z nel verso dei valori<br />
crescenti, come si può notare nella Figura E.1. [NDW94]<br />
Questo significa che trasformando un poligono con la matrice ModelView è poi<br />
elementare calcolare la <strong>su</strong>a <strong>di</strong>stanza dal punto <strong>di</strong> vista, in quanto <strong>il</strong> punto <strong>di</strong> vista<br />
sarà collocato nell’origine.<br />
Il metodo <strong>per</strong> <strong>il</strong> calcolo della <strong>di</strong>stanza <strong>di</strong> <strong>una</strong> faccia triangolare dal punto <strong>di</strong> vista<br />
implementato nella presente <strong>libreria</strong> ut<strong>il</strong>izza <strong>per</strong> mi<strong>su</strong>rare tale <strong>di</strong>stanza <strong>il</strong> punto<br />
ottenuto dalla me<strong>di</strong>a dei tre vertici della faccia. Se i tre vertici sono P0, P1 e P2 <strong>il</strong><br />
punto me<strong>di</strong>o ut<strong>il</strong>izzato è<br />
Pm = P0 + P1 + P2<br />
3<br />
Per <strong>di</strong>minuire <strong>il</strong> numero <strong>di</strong> calcoli eseguiti, la matrice ModelView viene applicata<br />
solo in seguito a questa me<strong>di</strong>a, e solamente al punto me<strong>di</strong>o Pm. La <strong>di</strong>stanza della<br />
faccia che si sta considerando è quin<strong>di</strong> calcolata come<br />
dove Pm = (mx, my, mz) T .<br />
d =<br />
�<br />
m 2 x + m 2 y + m 2 z
APPENDICE E. L’ALGORITMO DI ORDINAMENTO 122<br />
E.3 Distanza fra un nodo della gerarchia ed <strong>il</strong> punto <strong>di</strong> vista<br />
Come spiegato nella sezione 6.3 ad ogni nodo della gerarchia è assegnata <strong>una</strong> boun-<br />
<strong>di</strong>ng box, con un relativo centro. Si può quin<strong>di</strong> applicare quanto detto nella sezione<br />
E.2 a tale centro.<br />
Se <strong>il</strong> centro del nodo <strong>di</strong> cui si vuole calcolare la <strong>di</strong>stanza dal punto <strong>di</strong> vista è C =<br />
(xc, yc, zc) T ad esso viene innanzitutto applicata la matrice delle trasformazioni del<br />
modello e della vista M ottenendo<br />
C ′ = MC = (x ′ c, y ′ c, z ′ c) T<br />
ed infine si computa la <strong>di</strong>stanza del nodo come<br />
d = � (x ′ c) 2 + (y ′ c) 2 + (z ′ c) 2<br />
E.4 L’algoritmo <strong>di</strong> or<strong>di</strong>namento<br />
L’algoritmo <strong>di</strong> or<strong>di</strong>namento implementato all’interno della presente <strong>libreria</strong> è un<br />
merge sort, e or<strong>di</strong>na array <strong>di</strong> floating point (rappresentanti le <strong>di</strong>stanze dal punto <strong>di</strong><br />
vista dei vari poligoni oppure dei figli <strong>di</strong> un nodo) dal maggiore al minore. Ai fini<br />
della <strong>libreria</strong> è <strong>di</strong>fatti necessario avere poligoni e no<strong>di</strong> or<strong>di</strong>nati dal più lontano al più<br />
vicino, <strong>per</strong> motivi legati alla trasparenza e spiegati in 6.6.<br />
MergeSort(Array, from, to):<br />
1: if from < to then<br />
2: m = from+to<br />
2<br />
3: MergeSort(Array, from, m)<br />
4: MergeSort(Array, m+1, to)<br />
5: Merge(Array, from, m, to)<br />
6: en<strong>di</strong>f<br />
Tabella E.1: Merge Sort<br />
L’algoritmo implementato si basa <strong>su</strong> un approccio <strong>di</strong>vide et im<strong>per</strong>a, cioè <strong>una</strong> metodo-<br />
logia che <strong>su</strong>d<strong>di</strong>vide ricorsivamente <strong>il</strong> problema in più sottoproblemi <strong>di</strong> meno <strong>di</strong>ffic<strong>il</strong>e
APPENDICE E. L’ALGORITMO DI ORDINAMENTO 123<br />
risoluzione, sino ad un caso base risolvib<strong>il</strong>e elementarmente. [SED93] L’algoritmo è<br />
presentato in pseudoco<strong>di</strong>ce nella tabella E.1.<br />
Come si nota dallo pseudoco<strong>di</strong>ce MergeSort si appoggia <strong>su</strong> un’altra procedura de-<br />
nominata Merge. Lo pseudoco<strong>di</strong>ce <strong>di</strong> Merge è presentato nella tabella E.2. Ci sono<br />
dei requisiti <strong>per</strong> l’input inviato a Merge: i due sottoarray Array[from..middle]<br />
e Array[middle+1..to] devono essere già or<strong>di</strong>nati. Se queste specifiche <strong>su</strong>ll’input<br />
sono rispettate l’output <strong>di</strong> Merge sarà l’intero array Array[from..to] or<strong>di</strong>nato.<br />
Merge(Array, from, middle, to):<br />
1: k = from<br />
2: i = from<br />
3: j = middle+1<br />
4: wh<strong>il</strong>e (i ≤ middle) ∨ (j ≤ to) do<br />
5: if (i > middle) then<br />
6: Temp[k] = Array[j]<br />
7: j = j+1<br />
8: else if (j > to) then<br />
9: Temp[k] = Array[i]<br />
10: i = i+1<br />
11: else<br />
12: if Array[i] > Array[j] then<br />
13: Temp[k] = Array[i]<br />
14: i = i+1<br />
15: else<br />
16: Temp[k] = Array[j]<br />
17: j = j+1<br />
18: en<strong>di</strong>f<br />
19: en<strong>di</strong>f<br />
20: k = k+1<br />
21: endwh<strong>il</strong>e<br />
22: for i from from to to do<br />
23: Array[i] = Temp[i]<br />
24: endfor<br />
Tabella E.2: Merge<br />
Come si può notare dallo pseudoco<strong>di</strong>ce Merge non o<strong>per</strong>a in place, ovvero necessita<br />
<strong>di</strong> un array <strong>di</strong> <strong>su</strong>pporto <strong>su</strong>l quale salvare temporaneamente i dati che vengono or<strong>di</strong>-
APPENDICE E. L’ALGORITMO DI ORDINAMENTO 124<br />
nati. Questo sovrapprezzo <strong>di</strong> memoria è <strong>per</strong>ò ampiamente ricompensato dalla bassa<br />
complessità dell’algoritmo che è O(n log n), a fronte <strong>di</strong> un ut<strong>il</strong>izzo della memoria che<br />
è comunque O(n), dove n è <strong>il</strong> numero degli elementi presenti nell’array da or<strong>di</strong>nare.<br />
[CLR98, SED93]
APPENDICE F<br />
I quaternioni e la rotazione<br />
F.1 Introduzione<br />
I quaternioni furono inventati da Sir W<strong>il</strong>liam Rowan Ham<strong>il</strong>ton (*1809 – †1865)<br />
nel 1843. L’obiettivo <strong>di</strong> Ham<strong>il</strong>ton era generalizzare i numeri complessi alle tre <strong>di</strong>-<br />
mensioni, ovvero numeri nella forma a + ib + jc dove a, b, c ∈ R e i 2 = j 2 = −1.<br />
Una delle motivazioni <strong>di</strong> Ham<strong>il</strong>ton <strong>per</strong> la ricerca <strong>di</strong> numeri complessi tri<strong>di</strong>mensio-<br />
nali era trovare <strong>una</strong> rappresentazione delle rotazioni nello spazio tramite numeri<br />
complessi, dove <strong>una</strong> moltiplicazione potesse corrispondere ad <strong>una</strong> rotazione ed un<br />
ri<strong>di</strong>mensionamento.<br />
Nell’Ottobre del 1843, mentre passeggiava <strong>su</strong>l Royal Canal a Dublino, Ham<strong>il</strong>ton si<br />
rese conto che sono necessari quattro numeri <strong>per</strong> descrivere <strong>una</strong> rotazione seguita<br />
da un ri<strong>di</strong>mensionamento: un numero <strong>per</strong> <strong>il</strong> coefficiente <strong>di</strong> ri<strong>di</strong>mensionamento, un<br />
numero <strong>per</strong> i gra<strong>di</strong> <strong>di</strong> rotazione ed i rimanenti due <strong>per</strong> descrivere <strong>il</strong> piano nel quale<br />
<strong>il</strong> vettore deve essere ruotato 1 . Ham<strong>il</strong>ton nominò quin<strong>di</strong> quaternioni i numeri com-<br />
plessi quadri<strong>di</strong>mensionali da lui ideati, esprimendoli nella forma ix + jy + kz, dove<br />
i 2 = j 2 = k 2 = ijk = −1, ij = k e ji = −k. [KDL98]<br />
La modalità spesso ut<strong>il</strong>izzata <strong>per</strong> definire <strong>una</strong> rotazione fa uso dei tre angoli <strong>di</strong><br />
Eulero, scomponendo ciasc<strong>una</strong> rotazione in <strong>una</strong> combinazione <strong>di</strong> tre rotazioni <strong>su</strong>i<br />
tre assi del sistema <strong>di</strong> riferimento. La rotazione <strong>per</strong> mezzo dei quaternioni è invece<br />
definita con un angolo <strong>di</strong> rotazione ed un asse generico. La <strong>di</strong>fferenza fra le due<br />
modalità è visib<strong>il</strong>e in Figura F.1.<br />
1 Il piano xy può essere ruotato in un piano qualsiasi dello spazio xyz tramite i due angoli <strong>di</strong> rotazione<br />
<strong>su</strong>gli assi x e y.<br />
125
APPENDICE F. I QUATERNIONI E LA ROTAZIONE 126<br />
Figura F.1: Rotazione con i tre angoli <strong>di</strong> Eulero (A) e con un angolo ed un asse generico<br />
(B)<br />
Figura F.2: Una doppia rotazione <strong>di</strong> 90 ◦ eseguita <strong>su</strong> (A) causa la sovrapposizione <strong>di</strong> due<br />
assi (B) con la <strong>per</strong><strong>di</strong>ta <strong>di</strong> un grado <strong>di</strong> libertà
APPENDICE F. I QUATERNIONI E LA ROTAZIONE 127<br />
Il metodo degli angoli <strong>di</strong> Eulero soffre del problema del Gimbal Lock, ovvero <strong>una</strong><br />
<strong>per</strong><strong>di</strong>ta <strong>di</strong> uno dei tre gra<strong>di</strong> <strong>di</strong> libertà rotazionale. La <strong>per</strong><strong>di</strong>ta <strong>di</strong> un grado <strong>di</strong> libertà<br />
avviene quando <strong>una</strong> rotazione <strong>di</strong> 90 ◦ va a sovrapporre fra loro due assi del sistema<br />
<strong>di</strong> riferimento, come <strong>il</strong>lustrato in Figura F.2. In questo caso si viene a ricreare <strong>una</strong><br />
situazione <strong>per</strong> la quale eseguire <strong>una</strong> rotazione <strong>su</strong> uno dei due assi coincidenti sia<br />
equivalente ad eseguirla <strong>su</strong>ll’altro, <strong>per</strong> cui i due assi identificano lo stesso grado <strong>di</strong><br />
libertà. La rotazione con i quaternioni non soffre <strong>di</strong> Gimbal Lock. [BOB98]<br />
F.2 Matematica base dei quaternioni<br />
I quaternioni sono rappresentati solitamente come [s, v] con s ∈ R, v ∈ R 3 . Sono<br />
<strong>per</strong>ciò composti da <strong>una</strong> parte scalare s ed <strong>una</strong> parte vettoriale v. L’insieme dei<br />
quaternioni è denominato H.<br />
Moltiplicazione fra quaternioni<br />
Dati due quaternioni q, q ′ ∈ H con q = [s, v] e q ′ = [s ′ , v ′ ], <strong>il</strong> loro prodotto è definito<br />
come<br />
qq ′ = [ss ′ − v · v ′ , v × v ′ + sv ′ + s ′ v]<br />
dove · e × sono rispettivamente i prodotti scalare e vettoriale in R 3 .<br />
Moltiplicazione fra un quaternione ed uno scalare<br />
La moltiplicazione fra uno scalare s ed un quaternione q è definita come [s, 0]q.<br />
Quaternione coniugato<br />
Dato un quaternione q = [s, v] è detto <strong>su</strong>o coniugato, e denominato q ∗ , <strong>il</strong> quaternione<br />
q ∗ = [s, v] ∗ = [s, −v].<br />
Norma <strong>di</strong> un quaternione<br />
La funzione || · || : H ↦→ R è definita come ||q|| = √ qq ∗ . Questa funzione è chiamata<br />
norma, <strong>per</strong>ciò ||q|| è la norma <strong>di</strong> q.<br />
Viene denominato ˚ H l’insieme <strong>di</strong> tutti i quaternioni aventi norma non nulla.
APPENDICE F. I QUATERNIONI E LA ROTAZIONE 128<br />
Inverso <strong>di</strong> un quaternione<br />
Dato un quaternione q ∈ ˚ H è definito come <strong>su</strong>o inverso, e denotato q −1 , <strong>il</strong> quater-<br />
nione<br />
q −1 = q∗<br />
||q|| 2<br />
Ogni quaternione in ˚ H ha un inverso, come <strong>di</strong>mostrato in [KDL98].<br />
F.3 Rotazione con i quaternioni<br />
Con i pre<strong>su</strong>pposti matematici esposti in F.2, è possib<strong>il</strong>e ut<strong>il</strong>izzare i quaternioni <strong>per</strong><br />
ruotare un vettore.<br />
Rappresentiamo un vettore v con un quaternione nella forma p = [0, v]. Dato un<br />
asse <strong>di</strong> rotazione normalizzato n ed un angolo θ, definiamo<br />
Si ha allora che<br />
q = [cos θ, sin θn]<br />
p ′ = qpq −1<br />
equivale a p ruotato <strong>su</strong>ll’asse n <strong>di</strong> un angolo 2θ. Per <strong>una</strong> prova formale <strong>di</strong> questo si<br />
rimanda a [KDL98].<br />
È possib<strong>il</strong>e <strong>di</strong>mostrare che dato un quaternione p = [0, v], <strong>il</strong> quaternione p ′ = qpq −1<br />
sarà nella forma p ′ = [0, v ′ ] (si veda [KDL98]).<br />
Per ruotare <strong>il</strong> vettore v <strong>di</strong> un angolo θ <strong>su</strong>ll’asse n è <strong>per</strong>ciò <strong>su</strong>fficiente inserirlo<br />
all’interno <strong>di</strong> un quaternione p = [0, v], calcolare<br />
p ′ = [cos θ θ<br />
, sin<br />
2 2<br />
ed estrarre dal quaternione p ′ <strong>il</strong> vettore v ′ .<br />
θ θ<br />
· n]p[cos , sin<br />
2 2 · n]−1 = [0, v ′ ]
APPENDICE G<br />
Screenshot della demo realizzata<br />
G.1 Demo 1: la gerarchia e le trasformazioni geometriche<br />
in tempo reale<br />
Figura G.1: Un modello rappresentante <strong>una</strong> vasta area rurale. Esso è composto da 23519<br />
facce triangolari memorizzate in <strong>una</strong> gerarchia formata da 2902 no<strong>di</strong> (cfr. Capitolo 6)<br />
129
APPENDICE G. SCREENSHOT DELLA DEMO REALIZZATA 130<br />
Figura G.2: Un nodo della gerarchia viene aggiunto e mo<strong>di</strong>ficato senza influenzare <strong>il</strong> resto<br />
del modello (cfr. Capitolo 6)<br />
Figura G.3: I due mezzi appaiono in movimento <strong>su</strong>lla strada grazie all’applicazione in<br />
tempo reale <strong>di</strong> <strong>una</strong> traslazione variab<strong>il</strong>e nel tempo (cfr. 6.5)
APPENDICE G. SCREENSHOT DELLA DEMO REALIZZATA 131<br />
G.2 Demo 2: bump mapping<br />
Figura G.4: Quando la luce si sposta le ombre <strong>su</strong> un pavimento con bump mapping<br />
ab<strong>il</strong>itato variano (cfr. 7.2.6)
APPENDICE G. SCREENSHOT DELLA DEMO REALIZZATA 132<br />
Figura G.5: Quando la luce si sposta le ombre <strong>su</strong> un muro <strong>di</strong> mattoni con bump mapping<br />
ab<strong>il</strong>itato variano (cfr. 7.2.6)
APPENDICE G. SCREENSHOT DELLA DEMO REALIZZATA 133<br />
G.3 Demo 3: trasparenza e mo<strong>di</strong>fica delle texture in tempo<br />
reale<br />
Figura G.6: Un pannello semitrasparente posto al centro <strong>di</strong> <strong>una</strong> stanza rivestita <strong>di</strong><br />
piastrelle (cfr. 6.6)<br />
Figura G.7: La texture del pannello trasparente viene mo<strong>di</strong>ficata in tempo reale in<br />
maniera da simulare la proiezione <strong>di</strong> <strong>una</strong> animazione <strong>su</strong> <strong>di</strong> esso (cfr. 7.2)
APPENDICE G. SCREENSHOT DELLA DEMO REALIZZATA 134<br />
Figura G.8: La trasparenza del pannello è uniforme nell’immagine a sinistra, modulata<br />
in maniera non uniforme <strong>per</strong> mezzo <strong>di</strong> <strong>una</strong> mappa <strong>di</strong> opacità nel pannello <strong>di</strong> destra (cfr.<br />
7.2 e 7.2.8)<br />
G.4 Demo 4: mappe <strong>di</strong> luminosità ed integrazione fra modelli<br />
importati da formati <strong>di</strong>fferenti<br />
Figura G.9: Nella scena <strong>di</strong> sinistra l’<strong>il</strong>luminazione è calcolata in tempo reale, nella scena<br />
<strong>di</strong> destra sono sfruttate le mappe <strong>di</strong> luminosità (cfr. 7.2.7)
APPENDICE G. SCREENSHOT DELLA DEMO REALIZZATA 135<br />
Figura G.10: L’ambiente è stato importato da un f<strong>il</strong>e BSP (cfr. 9.2) mentre la teiera è<br />
stata importata da un f<strong>il</strong>e 3DS (cfr. 3.4). Come si può notare l’in<strong>di</strong>pendenza dal formato <strong>di</strong><br />
provenienza delle classi Group e Object (cfr. Capitolo 4) consente <strong>una</strong> totale integrazione<br />
fra modelli provenienti da tipi <strong>di</strong> f<strong>il</strong>e <strong>di</strong>fferenti
Bibliografia<br />
[ABA96] Marco Abate. Geometria. McGraw-H<strong>il</strong>l, 1996.<br />
[BAC00] Anders Backman. Virtual reality, 2000.<br />
(http://www.cs.umu.se/kurser/TDBD12/HT00/lectures/introduction.pdf, 21 Novembre 2003).<br />
[BEI03] Klaus-Peter Beier. Virtual reality: A short introduction, 2003.<br />
(http://www-vrl.umich.edu/intro/, 10 Novembre 2003).<br />
[BOB98] Nick Bobick. Rotating objects using quaternions, 1998.<br />
(http://www.gama<strong>su</strong>tra.com/features/19980703/quaternions 01.htm, 23 Novembre 2003).<br />
[CLR98] Thomas H. Cormen, Charles E. Leiserson e Ronald L. Rivest. Intro-<br />
duction to Algorithms. McGraw-H<strong>il</strong>l, 1998.<br />
[COH00] Jonathan Cohen. History of virtual reality, 2000.<br />
(http://www.cs.jhu.edu/˜cohen/VW2000/Lectures/History.color.pdf, 06 Novembre 2003).<br />
[ECK98] Bruce Eckel. Thinking in C++, 2nd E<strong>di</strong>tion. Prentice Hall, 1998.<br />
[EG01] Wolfgang F. Engel e Amir Geva. Beginning Direct3D Game Program-<br />
ming. Prima Tech, 2001.<br />
[FAR00] Paul A. Farrell. OpenGL rendering pipeline, 2000.<br />
(http://www.cs.kent.edu/ farrell/graphics/<strong>opengl</strong>/<strong>opengl</strong>prog1.2/<strong>opengl</strong>/render.html, 26 Dicembre 2003).<br />
[GF98] Michael Gold e Tom Frisinger. GL ARB multitexture, 1998.<br />
(http://oss.sgi.com/projects/ogl-sample/registry/ARB/multitexture.txt, 27 Gennaio 2004).<br />
[GF99] Michael Gold e Tom Frisinger. GL ARB texture env add, 1999.<br />
(http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture env add.txt, 27 Gennaio 2004).<br />
136
BIBLIOGRAFIA 137<br />
[GOL99] Michael I. Gold. Emboss bump mapping, 1999.<br />
(http://develo<strong>per</strong>.nvi<strong>di</strong>a.com/object/emboss bump mapping, 12 Novembre 2003).<br />
[HR94] David Halliday e Robert Resnick. Fisica 2. Ambrosiana, 1994.<br />
[ISO85] ISO. The graphical kernel system (GKS), 1985. Technical Report ISO<br />
7942.<br />
[ISO88A] ISO. The graphical kernel system for three <strong>di</strong>mensions (GKS-3D), 1988.<br />
Technical Report ISO 8805.<br />
[ISO88B] ISO. The graphical kernel system (GKS) language bin<strong>di</strong>ngs, 1988.<br />
Technical Report ISO 8651.<br />
[ISO89] ISO. Programmer’s hierarchical interactive graphics system (PHIGS),<br />
1989. Technical Report ISO 9592.<br />
[JÄH93] Bernd Jähne. Digital Image Processing. Springer-Verlag, 1993.<br />
[KDL98] Martin Koch, Erik B. Dam e Martin L<strong>il</strong>lholm. Quaternions, interpolation<br />
and animation, 1998.<br />
[LAF99] Susan Laflin. History of computer graphics, 1999.<br />
(http://www.cs.bham.ac.uk/˜slb/sem307/g11.html, 04 Dicembre 2003).<br />
[MOR89] Michael E. Mortenson. Computer Graphics: An introduction to the<br />
Mathematics and Geometry. Industrial Press Inc, 1989.<br />
[NDW94] Jackie Neider, Tom Davis e Mason Woo. OpenGL Programming Guide.<br />
Ad<strong>di</strong>son-Wesley, 1994.<br />
[OPE03] OpenGL.org. OpenGL overview, 2003.<br />
(http://www.<strong>opengl</strong>.org/about/overview.html, 05 Dicembre 2003).<br />
[PGFH01] Bimal Poddar, Michael Gold, Tom Frisinger e Rick Hammerstone.<br />
GL ARB texture env combine, 2001.<br />
(http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture env combine.txt, 27 Gennaio 2004).
BIBLIOGRAFIA 138<br />
[PVVF97] Jim Pitts, Martin van Velsen e Robin Fercoq. 3D-Stu<strong>di</strong>o F<strong>il</strong>e Format<br />
(.3ds), 1997.<br />
(http://thork<strong>il</strong>dsen.no/faqsys/docs/3ds2.txt, 13 Settembre 2003).<br />
[SAA95] Janne Saarela. What is GKS (the Graphical Kernel System), 1995.<br />
(http://wwwasdoc.web.cern.ch/wwwasdoc/gks html3/node6.html, 05 Dicembre 2003).<br />
[SED93] Robert Sedgewick. Algoritmi in C++. Ad<strong>di</strong>son-Wesley, 1993.<br />
[SIC58] Francesco Sicar<strong>di</strong>. Enciclope<strong>di</strong>a U.T.E.T., voce Luce, 1958.<br />
[SMI95] Terry Smith. An introduction to PHIGS, 1995.<br />
(http://terrysmith.net/archives/collegehomepage/research/phigs/phigs.html, 05 Dicembre 2003).<br />
[STE01] Karl Steiner. History of ve, 2001.<br />
(http://www.cs.unt.edu/ steiner/4330-VR/lecture1.html, 03 Novembre 2003).<br />
[STE02] James Stewart. The OpenGL pipeline, 2002.<br />
(http://www.cs.queen<strong>su</strong>.ca/home/jstewart/454/notes/pipeline/, 26 Dicembre 2003).