10.11.2012 Visualizzazioni

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 ...

SHOW MORE
SHOW LESS

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).

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!