Introduzione
Il rendering 3D in realnulltime consiste nel far generare al Computer immagini tridimensionali
molto rapidamente. Un’immagine appare sullo schermo, l’osservatore la vede ed interaginull
sce, influendo tramite questo feedback su quello che sarà generato successivamente. Quenull
sto ciclo di azione, reazione e rendering avviene ad una velocità sufficiente da fare in modo
che l’osservatore non distingua le singole immagini ma veda un unico movimento che lo
immerga in un processo dinamico e realistico.
La frequenza con cui queste immagini sono visualizzate viene misurata in fps (frame per
second). Da 5fps a 15fps si parla di interattività, mentre superata la frequenza di 25null30fps si
può parlare effettivamente di realnulltime, con una soglia ottimale fissata a 60fps. Visto che 60
immagini al secondo corrispondono a poco più di 16 millisecondi disponibili per generare
ogni frame, risulta evidente come sia poco il tempo a disposizione per creare un’immagine
che riproduca in modo convincente la realtà, senza considerare che non tutto il tempo a
disposizione può essere dedicato alla componente visiva.
Sebbene l’hardware dedicato alla grafica tridimensionale fosse disponibile da molti anni per
le workstation professionali, è solo in tempi relativamente recenti che l’uso di questi
acceleratori 3D si è ampiamente diffuso anche a livello consumer. L’introduzione da parte
di 3DFX della scheda Voodoo nel 1996 ha dato inizio a questa era. Con il passare degli
anni la potenza computazionale delle schede è aumentata in modo vertiginoso, secondo un
tasso di crescita tuttora ineguagliato da qualsiasi settore informatico; grazie infatti al continull
nuo raffinamento dei processi produttivi è stato possibile stipare una sempre maggiore
quantità di transistor per mm² il che, unito all’intrinseco parallelismo offerto dai calcoli inenull
renti la generazione di scene tridimensionali, ha permesso di creare schede grafiche costinull
tuite da migliaia di unità di calcolo parallelo.
Lo straordinario sviluppo hardware è stato trainato dal mercato videoludico che in questi
anni ha sorpassato l’industria dell’intrattenimento per eccellenza, ovvero Hollywood, alnull
meno per quanto riguarda l’home video. Questo avanzamento tecnologico ha anche
alimentato la ricerca nel campo della grafica interattiva, con la scoperta di nuove tecniche
atte ad incrementare sia la velocità di rendering sia la qualità visiva.
Nonostante il livello di realismo della grafica realnulltime continui a progredire ogni anno, la
fruizione dei contenuti è continuata a restare prettamente bidimensionale. Lo schermo su
cui vengono visualizzate le immagini infatti è (e lo rimarrà almeno per il medio periodo)
5
6
Introduzione
bidimensionale, rappresentando in un certo senso l’ultimo ostacolo per offrire una
immersività veramente convincente (almeno sotto l’aspetto visivo).
Una tecnica per superare questo limite è nota sin dall’ottocento ed è chiamata stereoscopia,
il cui obbiettivo è sostanzialmente quello di fornire in forma artificiale la visione binoculare,
ciò che consente alla nostra vista di percepire la realtà a tre dimensioni. Gli occhi vedono
infatti la stessa scena ma da posizioni differenti; le due immagini vengono così interpretate
dal cervello per estrapolare la profondità basandosi sulle differenze di posizionamento degli
oggetti nelle rispettive "inquadrature". Per riprodurre lo stesso effetto è necessario produrre
due immagini per ogni frame (una per l’occhio sinistro e una per l’occhio destro) e tramite
qualche accorgimento (di solito degli appositi occhiali) far sì che ogni occhio veda soltanto
l’immagine che gli compete.
Il cinema ha tentato di percorrere questa strada già negli anni a cavallo tra le due guerre
mondiali, mentre la massima diffusione la si ottenne negli anni 50null60. I risultati però,
soprattutto a livello qualitativo, non furono entusiasmanti e la tecnologia fu praticamente
abbandonata. Con il passare degli anni il sistema di riproduzione è migliorato e il recente
successo di pellicole 3D come Avatar testimoniano l’apprezzamento del pubblico. Anche
nel rendering tridimensionale la stereoscopia sta quindi tornando di attualità.
Il lavoro svolto si è prefisso come obbiettivo la realizzazione di un motore grafico autonull
nomo che offrisse una riproduzione realistica e immersiva di una scena virtuale (creata tranull
mite un programma di modellazione tridimensionale) dal punto di vista visivo, sonoro e
della gestione dei movimenti dell’utente all’interno dell’ambiente simulato.
Per quanto riguarda il primo aspetto si è fatto uso della stereoscopia, generando quindi per
ogni fotogramma una coppia di immagini riprodotte da un sistema di proiezione basato su
occhiali e proiettori con filtri Infitec. Per potenziare l’effetto che ne deriva si è anche
implementato l’headnulltracking in modo da conoscere la posizione dell’osservatore relativa
allo schermo e ricalcolare la proiezione prospettica corretta per ogni occhio istante per
istante. Dotare il motore grafico di un approccio al rendering di tipo deferred shading al
posto del tradizionale forward shading, di una struttura dati e di un sistema di partizionanull
mento spaziale studiati per adattarsi al meglio ad esso, ha permesso inoltre di realizzare e
gestire in realnulltime effetti di postnullprocessing computazionalmente molto intensivi (in
particolare la Screen Space Ambient Occlusion, ma anche l’AntinullAliasing e il
DepthnullOfnullField) in combinazione con un dettaglio poligonale particolarmente elevato
(>500.000 triangoli) e decine di luci calcolate dinamicamente, in grado di aumentare in
modo significativo la verosimiglianza dell’output. Il tutto è stato implementato tramite
linguaggio C, OpenGL 2.0 e shaders in formato GLSL, generando un’esperienza coinvolnull
gente in grado fornire i corretti stimoli sensoriali comportando un affaticamento visivo
contenuto. Sul fronte sonoro sono state utilizzate le librerie OpenAL per generare l’audio
posizionale e gestire l’effetto doppler, mentre i movimenti sono stati resi in modo naturale
7
Introduzione
con una velocità di spostamento e accelerazione dell’osservatore coerenti con quelle di un
uomo, contribuendo così alla fruizione di una esperienza pressoché completa.
Nel primo capitolo vengono illustrati i dati forniti al motore grafico come input, nello
specifico il file contenente le impostazioni input.log, il modello da renderizzare nel formato
OBJ/MTL, i tipi di texture ed il loro utilizzo, gli effetti sonori ed infine gli shaders utilizzati
per effettuare il rendering. Si conclude effettuando una panoramica sullo schema di
funzionamento generale dell’applicativo, rimandando per l’approfondimendo dei vari elenull
menti ai capitoli successivi dedicati ad ognuno di essi.
Nel capitolo 2 vengono descritte le possibili interazioni con l’operatore, da quelle basilari
riguardanti l’interfaccia di caricamento (comprese le operazioni che precedono la fase di
rendering vera e propria come la scelta della risoluzione e posizione iniziale da acquisire in
caso di attivazione dell’headnulltracking) a quelle riguardanti la navigazione realistica
all’interno del modello renderizzato, scendendo nel dettaglio di come avviene il controllo
sulla velocità di spostamento e rotazione nelle varie fasi che compongono i movimenti, fino
allo spostamento delle luci, la selezione degli oggetti e la scelta degli effetti grafici da applinull
care.
Nel capitolo 3 si descrive la fase di caricamento del modello tridimensionale e relativa
traduzione in un formato più adatto in grado di velocizzare questo stadio durante le esecunull
zioni successive alla prima. Viene anche presentata la risultante struttura dati in memoria,
esponendo i vantaggi che derivano dalla sua particolare organizzazione con riferimenti
specifici alle modalità di gestione da parte dell’hardware grafico dei dati di volta in volta
richiesti.
Nel capitolo 4 viene introdotta la stereoscopia. Si inizia con brevi cenni storici e si prosegue
con il funzionamento teorico della visione binoculare; si passa quindi alle tecniche di
rendering disponibili per realizzarla. Successivamente viene descritta in dettaglio la tecnica
utilizzata e la relativa variante rispetto al metodo da cui deriva, per concludere con una
breve panoramica dei sistemi di proiezione disponibili sul mercato, compreso ovviamente
quello utilizzato durante lo sviluppo.
Nel capitolo 5 viene descritto il sistema per tracciare la posizione dell’osservatore nello spanull
zio (headnulltracking). Inizialmente si effettua una descrizione dell’hardware impiegato, nel
caso specifico il controller della console Nintendo Wii e una serie di led a raggi infrarossi
alimentati a batteria. Vengono quindi presentati i principali metodi di calcolo della posinull
zione dell’osservatore, con particolare dettaglio per quello effettivamente utilizzato, seguiti
dall’implementazione all’interno del programma.
Nel capitolo 6 vengono analizzate le principali tecniche di partizionamento spaziale,
indispensabili per ridurre il numero di poligoni da renderizzare. In questo capitolo vengono
presentate tutte le tecniche principali, soffermandosi in particolare su quella poi effettivanull
mente utilizzata e sulla particolare ottimizzazione ideata. Vengono inoltre mostrati i vari tipi
di volumi di bound. Infine viene presentato il particolare algoritmo di frustum culling
8
Introduzione
impiegato che, attraverso la struttura di partizionamento menzionata in precedenza, pernull
mette di fornire una buona approssimazione dell’insieme di oggetti visibili nella scena,
mantenendo allo stesso tempo un costo computazionale particolarmente basso utile a
valorizzare la caratteristiche positive del deferred shading.
Nel capitolo 7 viene presentato il motore di rendering vero e proprio; si parte dalla descrinull
zione del metodo classico (forward shading) per poi arrivare a parlare del nuovo sistema
chiamato deferred shading. Segue una disamina dei relativi vantaggi e svantaggi rispetto alla
tecnica tradizionale. Infine viene descritta la sua realizzazione, con particolare dettaglio
riguardante la fase di postnullprocessing.
Nel capitolo 8 si analizza la parte audio del lavoro svolto, partendo da una breve spieganull
zione teorica della propagazione del suono nello spazio e dell’effetto doppler, descrivendo
poi la struttura dati utilizzata per concludere infine con i dettagli implementativi.
Nel capitolo 9 vengono presentate le conclusioni, facendo riferimento sia ai risultati ottenull
nuti sotto il profilo visivo che prestazionale sia alle possibili estensioni del progetto per
migliorarlo ed eventualmente aggiungere nuove funzionalità.
CAPITOLO 1
Dati di Input e struttura generale
Affinché sia possibile renderizzare un modello poligonale occorre prima caricarlo in memonull
ria; lo stesso bisogna farlo per quanto riguarda texture, effetti sonori, shaders, ecc...
In questo primo capitolo verranno esaminati i tipi di dati che è necessario fornire al motore
grafico per renderizzare correttamente la scena prescelta, concludendo con una breve
descrizione della struttura generale del programma in cui vengono elencati i vari stadi di
funzionamento, rimandando l’approfondimento di ognuno di essi all’interno dei capitoli
successivi.
1.1 File di log
Ogni programma ha bisogno di un file di configurazione nel quale si impostano i valori dei
diversi parametri di funzionamento e questo non fa eccezione. Il file in questione si chiama
input.log ed è essenzialmente un file di testo per il quale sono definite delle regole sintattinull
che precise. Nel caso queste siano violate, l’esecuzione viene interrotta. Analizziamo ora in
dettaglio la struttura di tale file. E’ composto da una sequenza di elementi formati da:
# descrizione del parametro
Valore del parametro
E’ possibile che un parametro sia composto da più valori numerici, per cui il campo valore
sarà distribuito su più righe, una per ognuno di essi. E’ anche possibile che la descrizione
stessa del parametro richieda troppi caratteri per risultare facilmente leggibile se scritta su di
una sola riga. In questo caso, per ogni riga di commento deve essere ripetuto il carattere #,
pena l’interpretazione da parte del programma di trovarsi già sul valore del parametro in
questione.
Esaminiamo ora i vari parametri ed il loro significato tramite un file di esempio. Nella tanull
bella seguente a sinistra ci saranno i vari parametri, mentre sulla destra il relativo significato.
9
10
1. Dati di Input e struttura generale
Nei campi multivalore, gli assegnamenti possibili sono indicati e separati da uno “/”. Alnull
cuni sono richiesti soltanto se altri parametri assumono un determinato valore; per esempio
la dislocazione del Wii Remote è richiesta soltanto se è stato attivato l’headnulltracking. Quenull
sta situazione nella tabella è rappresentata indicando il valore richiesto tra parentesi. Con il
termine Wii Remote si intende il controller della console Nintendo Wii utilizzato per
l’headnulltracking (paragrafo 5.1).
# tracking della posizione
NO_WIIMOTE / WIIMOTE
stringa per attivare o meno l’headnulltracking
# modalità di visualizzazione
19.7 (WIIMOTE)
distanza (in cm) tra i due led a infrarossi (paragrafo 5.2)
MONO / STEREO
stringa di selezione per l’attivazione della modalità clasnull
sica o stereoscopica
1
distanza (in cm) di near plane per il frustum
6000
distanza (in cm) di far plane per il frustum
30.0
larghezza (in cm) dello schermo su cui verrà effettuato
il rendering
1680
risoluzione orizzontale desktop
7.0 (STEREO)
distanza (in cm) tra gli occhi dell’osservatore
100 (NO_WIIMOTE)
distanza (in cm) tra osservatore e schermo
0.0 5.0 3.0 (WIIMOTE)
coordinate (in cm) della posizione del Wii Remote rifenull
rite al centro dello schermo
15 (WIIMOTE)
inclinazione (in gradi) del Wii Remote rispetto al suolo
# coordinate centro schermo x/z
526
coordinata x della posizione dello schermo nello spazio
del modello
720
coordinata z della posizione dello schermo nello spazio
del modello
# coordinata y del suolo
500
coordinata y del suolo per identificare la altezza del ternull
reno nello spazio del modello
# altezza centro schermo oppure altezza operatore
170
altezza dell’osservatore o altezza centro schermo (in
cm) rispettivamente con headnulltracking disattivato
(NO_WIIMOTE) e con headnulltracking attivatW o ( IIMOTE)
# clock_per_sec
1000
parametro di configurazione per la gestione dei tempi
del compilatore C. Sulle macchine Windows/x86 è
solitamente 1000
11
1. Dati di Input e struttura generale
# velocità di spostamento
0.5
velocità massima (in metri/sec) degli spostamenti
dell’osservatore
# velocità di rotazione
24
velocità massima di rotazione (in gradi/sec)
dell’osservatore, per il tronco e per la testa
# numero luci
1
indica il numero di luci presenti nella scena
# parametri delle luci
1.0 1.0 1.0 1.0
valori RGBA dell’intensità della componente ambiennull
tale luce nnullesima
1.0 1.0 1.0 1.0
valori RGBA dell’intensità della componente diffusiva
luce nnullesima
1.0 1.0 1.0 1.0
valori RGBA dell’intensità della componente speculare
luce nnullesima
1.0
coefficiente di attenuazione costante. E’ usato solo dunull
rante l’emulazione della fixed pipeline di rendering
0.0
coefficiente di attenuazione lineare. E’ usato solo dunull
rante l’emulazione della fixed pipeline di rendering
0.01
coefficiente di attenuazione quadratica. E’ usato solo
durante l’emulazione della fixed pipeline di rendering
4.0
esponente per attenuazione della luce. 1 identifica una
attenuazione lineare. E’ usato soltanto nel deferred
shading
0.0 1.0 0.0
direzione del fascio di luce. E’ valido solo nel caso di
luci spot
1.0
esponente per caratterizzare la curva di illuminazione
all’interno del cono di influenza della luce spot
30.0
angolo tra la direzione del fascio di luce e il bordo del
cono di influenza. Un angolo di 180 gradi identifica una
luce omnidirezionale (point light)
540.0 30.0 25.0 1.0
Se il quarto valore è 1.0 allora i primi tre rappresentano
le coordinate spaziali della posizione della luce nello
spazio del modello (point light), altrimenti sono le
coordinate del versore indicante la direzione della luce
(directional light)
50
dimensione (in cm) della sfera di influenza della luce.
Nel caso di spot light, è la distanza tra la posizione della
luce e la base del cono di influenza
12
1. Dati di Input e struttura generale
# numero effetti sonori
1
indica il numero di effetti sonori da attivare nella scena
# parametri degli effetti sonori
Footsteps.wav
nome del campione
0 / 1
indica se riprodurre in loop continuo il suono (1) o solnull
tanto una volta dopo la sua attivazione (0)
1.0
pitch: serve per distorcere il tono del suono. Con il vanull
lore 1.0 lo si lascia inalterato
1.0
gain: è possibile aumentare o diminuire il volume
dell’effetto sonoro. Con il valore 1.0 lo si lascia inaltenull
rato
500.0 600.0 435.0
posizione del suono nello spazio del modello. Per il
primo campione non viene indicato, in quanto lo si
considera collegato all’osservatore (paragrafo 8.5)
# tracciamento mouse
0 / 1 (MONO)
flag che segnala se utilizzare la posizione del puntatore
del mouse per identificare la distanza di messa a fuoco
(paragrafo 7.6.3)
# parametri per il DepthnullofnullField
100
distanza di messa a fuoco
0.8
coefficiente per calcolare infocusStart (paragrafo 7.6.2)
2.4
coefficiente per calcolare infocusEnd (paragrafo 7.6.2)
0.5
coefficiente per calcolare outfocusStart (paragrafo 7.6.2)
10.0
coefficiente per calcolare outfocusEnd (paragrafo 7.6.2)
# modello da caricare
Modello.obj
nome del file OBJ contenente i dati geometrici
Modello.mtl
nome del file MTL contenente la descrizione dei matenull
riali utilizzati e le relative texture
Figura 1.1: struttura file input.log
1.2 Formato modello
Sono molti i formati commerciali disponibili per memorizzare e di conseguenza leggere i
dati geometrici e materiali di una scena tridimensionale: 3DS, OBJ, MAX, DXF, ecc…
La scelta del formato da utilizzare è ricaduta su OBJ: è di tipo aperto e, nonostante
l’anzianità, offre una compatibilità pressoché totale con tutti i più famosi programmi di monull
dellazione tridimensionale tra cui 3DStudioMax, Maya e Cinema4D. Rispetto ad altri fornull
mati più ricchi (ad esempio quello proprietario utilizzato da 3DStudioMax), permette di
memorizzare soltanto i dati riguardanti la geometria e non, per esempio, le luci presenti
nella scena. Questo fatto rende la distribuzione più complessa, ma facilità l’interoperabilità
13
1. Dati di Input e struttura generale
tra gruppi di lavoro che usano software differenti. Creato inizialmente da Wavefront
Tecnologies per il suo pacchetto Advanced Visualizer, OBJ è stato man mano adottato da
altre software house diventando un formato accettato pressoché universalmente. La sua
ampia diffusione è dovuta sicuramente anche alla sua semplicità: può essere infatti visto
come un semplice file di testo ASCII organizzato in modo molto semplice. Nonostante si
possano immagazzinare superfici parametriche complesse come per esempio NURBS,
tratteremo soltanto il caso di semplici triangoli, perché è il formato più facile da gestire dai
moderni acceleratori 3D senza eccessivi rallentamenti.
Le specifiche prevedono la presenza opzionale di un file MTL in cui vengono definiti uno
o più materiali, i quali includono il colore, texture, normal map, ecc…
Per una disamina completa del formato si può far riferimento a [OBJ Specification URL] e
[MTL Specification URL].
Struttura OBJ
Un file OBJ ha la seguente struttura interna che se ripete:
# modello “xyz”
mtllib ./modello.mtl
g
v -526.517395 762.574097 -509.566772
v -526.517273 762.574097 -510.439453
….
v -527.735229 762.574097 -509.566772
# n vertices
vt 0.849249 0.348760 0.000000
vt 0.879550 0.306468 0.000000
…
vt 0.605932 0.770549 0.000000
# n texture vertices
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
…
vn 0.839457 0.417385 0.347997
# n vertex normals
g gruppo_1
usemtl mat_1_gruppo_1
f 2/2/2 3/1/3 1/3/1
f 2/5/2 4/4/4 3/6/3
…
f 2390/3642/2390 3304/3639/3304 3233/3640/3233
# n faces
14
1. Dati di Input e struttura generale
dove le righe che cominciano per # sono commenti e vengono ignorati dal parser preposto
al caricamento. Il significato delle varie parole chiave è descritto nella tabella di figura 1.2.
mtllib ./modello.mtl
specificato all’inizio della descrizione dell’OBJ,
identifica il file MTL in cui sono definiti tutti i
materiali relativi al modello in questione
g gruppo_1
gruppo di appartenenza: serve per raggruppare gli
insiemi di vertici, normali, coordinate texture e
facce
v x y z
coordinate spaziali del vertice
vt u, v [w]
coordinate della texture del vertice
vn x y z
coordinate della normale del vertice
f n1/n4/n7 n2/n5/n8 n3/n6/n9
triangolo composto da vertici che hanno coordinate
spaziali n1/n2/n3, coordinate texture n4/n5/n6,
coordinate delle normali n7/n8/n9
usemtl mat_1_gruppo_1
nome del materiale da usare per i triangoli specifinull
cati successivamente
Figura 1.2: struttura file OBJ
A causa della loro struttura a lista, i file OBJ indicizzano i dati geometrici secondo la loro
posizione assoluta. Prendendo ad esempio le coordinate spaziali dei vertici, se il gruppo_1
avesse 620 vertici ed il gruppo_2 ne avesse altri 340, al primo gruppo sarebbero assegnati i
vertici dal numero 1 al 620, mentre al secondo dal numero 621 al 960.
Questa caratteristica porta con se un grosso vantaggio. Si consideri un oggetto composto
da una mesh chiusa e convessa. Indicando con n il numero di triangoli da cui è composta, il
numero di vertici risulta n*3. In realtà quelli distinti sono molti di meno, grazie al fatto che
ogni triangolo condivide i vertici con i triangoli adiacenti. Se prendiamo per esempio un
cubo, questo ha 6 facce scomponibili in 12 triangoli comportando la presenza di ben 36
vertici, mentre i vertici distinti sono soltanto 8. Codificare le informazioni in questo modo
comporta una notevole riduzione del traffico dati in input, che si traduce in un caricamento
più veloce da parte del programma.
Ad ogni gruppo inoltre è possibile assegnare un numero arbitrario di materiali, in modo da
simulare il più fedelmente possibile oggetti reali composti da leghe differenti.
Struttura MTL
Come per i file OBJ, anche gli MTL hanno una struttura a lista che si ripete:
# materiale modello “xyz”
newmtl mat_1_gruppo_1
Ka 0.6 0.6 0.6
15
1. Dati di Input e struttura generale
Kd 0.6 0.6 0.6
Ks 0.9 0.9 0.9
d 1.0
Ns 750.0
map_Kd texture1.jpg
dove le righe che cominciano per # sono nuovamente commenti e vengono ignorati dal
parser preposto al caricamento. Il significato delle varie parole chiave è il seguente:
newmtl nomemateriale
specificato all’inizio della descrizione dell’MTL,
assegna il nome al materiale
Ka r g b
coefficienti di riflessione ambientale in valori comnull
presi tra 0 e 1
Kd r g b
coefficienti di riflessione diffusiva in valori comnull
presi tra 0 e 1
Ks r g b
coefficienti di riflessione speculare in valori comnull
presi tra 0 e 1
d n
percentuale di trasparenza relativa alla superficie rinull
volta verso l’osservatore; 1 è 100% (opaco), mentre
0 è 0% (trasparente)
Ns n
esponente per l’equazione della riflessione specunull
lare; i valori validi vanno da 0 a 1000
map_Kd nometexture
texture da applicare all’oggetto in questione
Figura 1.3: struttura file MTL
Unità di misura
Per offrire una visione realistica occorre che le dimensioni degli oggetti rispecchino le
controparti reali una vola riprodotti sullo schermo. Per consentire ciò, è necessario intronull
durre una sorta di unità di misura, definendo il rapporto tra le dimensioni all’interno del
modello virtuale e mondo reale. Sotto questo aspetto il motore grafico considera un metro
come corrispondente a 100 unità, la quale coincide quindi con il centimetro. Questo valore
è controllato dal parametro UNITA_DI_MISURA e quindi facilmente modificabile.
1.3 Texture
Quando si applica una immagine ad una geometria tridimensionale, questa viene chiamata
texture. Il texture mapping è fondamentale nei moderni motori grafici, visto la drammatica
differenza di realismo che si ottiene fra visualizzare geometrie senza e con texture map (finull
gura 1.4). Analogamente al caso dei dati geometrici, anche per quanto riguarda le texture ci
sono molti formati disponibili. Per capire l’importanza di uno di questi in particolare, è
necessario fare un premessa. Ogni oggetto con texture, come ogni altro della scena, può esnull
16
1. Dati di Input e struttura generale
sere visto a differenti distanze rispetto al punto di vista dell’osservatore. A prescindere dal
fatto che sia quest’ultimo o l’oggetto a muoversi, in una scena dinamica la texture deve vanull
riare le sue dimensioni in accordo con quelle della proiezione dell’oggetto sullo schermo.
Figura 1.4: differenza tra una semplice geometria senza texture e con texture
Quando una texture viene rimpicciolita, molti texel possono ritrovarsi a coprire lo stesso
pixel. Per ottenere il valore corretto per ognuno di essi bisogna tenere conto quindi di tutti i
texel in grado di influenzarlo. Risulta effettivamente difficile però quantificare esattamente
questa influenza, perlomeno in realnulltime. A causa di tale limitazione, sono diversi gli apnull
procci utilizzati, tra cui l’interpolazione bilineare e altri filtraggi più efficaci. L’idea che sta
alla base di tutte queste tecniche è quella di catturare più sample per ogni pixel, in modo da
approssimare meglio i diversi texel che, come spiegato in precedenza, dovrebbero contrinull
buire a definirne il valore.
Esiste tuttavia anche un altro approccio al problema: tentare di ridurre il numero di texel
che si sovrappongono ad uno stesso pixel cercando quindi di riportarsi il più possibile nella
situazione ideale in cui ad ogni texel corrisponde un unico pixel. Il più popolare fra questi
metodi è chiamato Mipmapping [L. Williams 1983], ed è implementato perfino nelle più
moderne schede 3D. Quando un filtro di questo tipo viene utilizzato, prima della fase di
rendering la texture originale viene usata per formare una lista di texture sempre più
piccole. L’immagine originale (livello 0) viene ridotta ad un area di ¼ attraverso un filtro di
downsampling, che spesso consiste nel calcolare il valore del nuovo texel come la media di
quelli adiacenti. Questa nuova texture viene chiamata livello 1. Il processo è applicato
ricorsivamente fino ad ottenere una texture in cui una dimensione sia composta da un texel
soltanto. La struttura risultante viene spesso indicata come catena di Mipmapping.
Tramite una soluzione del genere è sempre possibile scegliere la texture della dimensione
più adeguata alla proiezione della geometria sottostante. Le performance dell’algoritmo
17
1. Dati di Input e struttura generale
dipendono comunque molto dalla bontà con cui viene effettuato il filtraggio della texture
originale per andare a creare i vari livelli che compongono la relativa catena. Anche in quenull
sto caso ad un filtraggio migliore corrispondono tempi di calcolo più elevati.
Figura 1.5: rappresentazione piramidale di una catena di Mipmapping
Questa premessa sulla natura del Mipmapping è utile per capire l’importanza di poter carinull
care in memoria una texture che possa già contenere al suo interno tutti i vari livelli della
relativa catena. Un formato di questo tipo è il DDS (Direct Draw Surface) introdotto con le
librerie DirectX7, ma col tempo divenuto di utilizzo comune anche per quanto riguarda le
API OpenGL. Per approfondire [DDS Texture Reference URL].
Il motore grafico è realizzato utilizzando la libreria SOIL (appendice A) che permette il
caricamento di file BMP, PNG, JPG, TGA, PSD, HDR e, appunto, DDS. Quello che
differenzia questa libreria da tutte le altre testate è la possibilità di immagazzinare direttanull
mente nella memoria dell’hardware grafico l’intera catena di Mipmapping anche se comnull
pressa secondo gli standard DXT1/2/3/4/5 senza ulteriori elaborazioni, il che rende le
operazioni di caricamento anche di centinaia di megabyte di texture estremamente rapide.
1.4 Campioni audio
L’audio (capitolo 8) è gestito tramite la libreria multipiattaforma OpenAL (appendice B).
L’unico tipo di campioni audio gestito di default, almeno fino alla versione qui utilizzata, è
il Pcm, che nella piattaforma windows corrisponde solitamente a file con estensione Wav.
L’utilizzo di formati compressi come Ogg, Mp3, ecc… sarebbe stato possibile utilizzando
librerie esterne che permettessero di decomprimere i campioni in Pcm da caricare
successivamente in OpenAL, ma si è deciso di utilizzare esclusivamente il formato nativo.
L’obbiettivo principale per quanto riguarda gli effetti sonori era fornire un suono
tridimensionale di tipo posizionale, e questo si può ottenere soltanto se i campioni non
18
1. Dati di Input e struttura generale
sono stereofonici. In quest’ultimo caso infatti, OpenAL provvede a disabilitare ogni calcolo
interno e restituisce la semplice riproduzione stereofonica.
Come si può dedurre dalla tabella in figura 1.1 il numero di effetti sonori che possono esnull
sere caricati non ha limitazioni, tranne naturalmente la quantità di memoria disponile nel
sistema.
1.5 Shaders
Gli algoritmi che istruiscono l’hardware grafico programmabile sono codificati attraverso
shaders. L’api grafica utilizzata è OpenGL, la quale ha aperto la pipeline grafica per offrire
la programmabilità del vertex processor e del fragment processor a partire dalla versione
2.0 grazie all’utilizzo di un linguaggio di shading ad alto livello chiamato GLSL (OpenGL
Shading Language).
I diversi file contenenti il codice hanno estensione vs e fs, rispettivamente per i programmi
dedicati al vertex processor e al fragment processor, e sono semplici file di testo ASCII;
una delle peculiarità del linguaggio di shading GLSL (a differenza, per esempio, di HLSL
utilizzato da DirectX) è infatti quella di poter utilizzare direttamente i sorgenti, senza quindi
richiedere nessuna forma di prenullcompilazione. Questo comporta vantaggi sotto due aspetti:
il primo è prestazionale, in quanto ogni produttore di hardware grafico ha la opportunità di
ottenere le migliori performance possibili utilizzando uno specifico compilatore per il
proprio hardware e di migliorarle con il tempo grazie alle continue ottimizzazioni lato
compilatore (distribuite tramite il driver grafico), senza che lo sviluppatore debba mai ritocnull
care il codice. Il secondo aspetto riguarda la manutenzione e portabilità di quest’ultimo, che
risulta facilitata in quanto si tratta di codice sorgente. Per ulteriori approfondimenti
[Shreiner, Woo, Neider, Davis 2007].
Si è inoltre scelto di utilizzare un file diverso per ogni tipologia di shader in modo da facilinull
tarne ulteriormente la manutenzione, anche se ciò a comportato una certa ripetizione di alnull
cune funzioni. Il codice di quelli più significativi e la relativa gestione verrà analizzata
all’interno del capitolo 7.
1.6 Struttura generale
Nei capitoli successivi verranno analizzate le varie caratteristiche del motore grafico, sia
sotto l’aspetto teorico sia da quello della relativa integrazione a livello di codice. Prima di
procedere in tal senso è però utile fornire un diagramma che presenti la struttura generale
del programma e relativo flusso di esecuzione, mostrando i diversi stadi che compongono
la pipeline di elaborazione tramite la quale vengono generati i fotogrammi in realnulltime.
19
1. Dati di Input e struttura generale
Figura 1.6: struttura generale del programma (sinistra),
dettaglio degli stadi interni alle display (destra)
L’esecuzione può essere suddivisa in tre fasi distinte:
- Loop di rendering per visualizzare il menu iniziale che interroga l’utente sulla scelta
della coppia risoluzione e profondità di colore, da abbinare alla visualizzazione a
schermo intero o in finestra (capitolo 2)
- Lettura del file di input.log per caricare i dati di input (ed eventuale calcolo della
posizione iniziale dell’osservatore in modalità headnulltracking) con la conseguente
creazione della particolare struttura dati realizzata per contenerli (capitolo 3). E’ in
questa fase che avviene il partizionamento spaziale con la relativa connessione alla
struttura dati principale (capitolo 6): come verrà analizzato meglio in seguito si è
scelto di utilizzare la Bounding Volume Hierarchy (BVH). Questa struttura è
essenzialmente un albero binario i cui nodi rappresentano volumi di bound (BV)
che racchiudono ricorsivamente gli elementi geometrici che compongono la scena,
per la cui creazione è stata sviluppata una variante di un algoritmo bottomnullup
descritto in [S. M. Omohundro 1989]. Sempre per motivi legati all’efficienza come
BV è stato scelto il volume più semplice possibile, la sfera, il quale comporta in ogni
caso problematiche non banali riguardo alla sua generazione [J. Ritter 1990]. Sucnull
cessivamente vengono eseguite una serie di inizializzazioni, tra cui quelle riguardanti
gli shaders GLSL sia per la parte forward che deferred (capitolo 7), VBO (capitolo
3) e FBO (capitolo 7)