Il raytracing unito ai metodi di
Monte Carlo, ha raggiunto un elevato grado realismo; soprattutto grazie
all'utilizzo di modelli fisici sempre più accurati e sempre meno
basati su metodi empirici. Questo lavoro nel suo piccolo seppur solo di
implementazione (infatti è finalizzato alla creazione di
software), ha lo scopo di esplorare le estensioni principali del
raytracing per la sintesi di immagini sintetiche realistiche. Per
questione di sintesi verranno presentati le estensioni
storiche del raytracing, accenando alle altre.
1.- IL RAYTRACING CLASSICO
Il raytracing puro è una tecnica per la generazione di immagini
fotorealistiche al calcolatore partendo da una descrizione formale di
una scena tridimensionale; ed è stato introdotto nel 1980 da
Turner Whitted. Ancora
oggi riveste un ruolo importante grazie ai vantaggi rispetto alle
metodologie a scansione lineare:
1) La geometria può essere procedurale senza il bisogno di
triangolarizzazioni;
2) Le ombre posso essere calcolate in modo preciso senza un elevato
consumo di memoria e di tempo di cpu, rispetto a tecniche classiche
come: pojection plane shadow, shadow map, e alle
stencil volume shadow;
3) L'elevata precisione, determinata a pixel;
4) Riflessioni e rifrazioni perfette;
L'idea alla base del raytracing è che il percorso della luce
può essere seguito in senso
contrario; dall'osservatore alla sorgente luminosa. La correttezza di
tale idea è dovuta a due proprietà della luce:
1) La luce si muove in modo rettilineo nello spazio
vuoto;
2) La simmetria o reciprocità; se il senso di percorrenza della
luce è invertito (cioè si inverte la direzione di uscita
con quella di entrata), il valore del BRDF non cambia.
Infatti nel raytracing, per ogni pixel dello schermo o dell'immagine,
si "lanciano" dei raggi, e si verifica l'eventuale
intersezione più vicina con gli oggetti presenti nella scena.
Ogni
raggio ha la seguente forma:
r ( O, D ) = O + D t
dove:
O è la posizione di lancio del raggio ( il raggio si dice
primario se la posizione di lancio coincede con quella
dell'osservatore);
D è la direzione del raggio;
Una volta trovata un'intersezione con un oggetto ad un certo punto
x
con normale N, si calcola l'illuminazione in quel punto usando un BRDF
f basandosi sulle proprietà
del materiale dell'oggetto
intersecato.
Per esempio ecco una formula generale per il calcolo
dell'intensità luminosa diretta:
illuminazione = f ( x, w, w' ) ( n . w' )
dove:
w' è il vettore
normalizzato che congiunge il punto x con la posizione
della
luce;
w è il vettore normalizzato
ottenuto dalla riflessione w' rispetto ad n;
Può accadere che degli oggetti (occlusori) si frappongano tra
x
e i raggi luminosi della sorgente creando così ombra. I punti
d'ombra sono privi di illuminazione; quindi il calcolo
dell'intensità luminosa va effettuata solo nei punti liberi
dagli occlusori. Tale verifica si effettua facendo un test di
intersezione con un raggio dove O corrisponde al punto
x, e con D
corrispondente al vettore
w'. Una
nota particolare va in caso di sorgenti luminose continue (una linea,
un rettangolo, una sfera), in quel caso la sorgente va campionata in
tanti punti di emissione secondo la distribuzione di emissione
per raggiungere migliori risultati.
Nel caso in cui l'oggetto con intersezione
x, abbia
proprietà
speculari viene calcolato il contributo speculare. Ricorsivamente si
ripete la procedura utilizzando come nuova O il punto e
x e come nuova
D il raggio D riflesso o rifratto (a seconda del tipo di superficie
speculare).
Una delle prime estensioni effettuate al raytracing fu il raytracing
distribuito introdotto da Robert L. Cook, Thomas Porter e Loren
Carpenter nel 1984. Il raytracing distribuito consiste nella
sovracampionatura dei pixel, così facendo si possono ottenere
molti effetti tra i quali: anti-aliasing, profondità di campo,
riflessioni fuzzy (sovracampionatura delle riflessioni), sfuocatura di
movimento (integrazione del tempo).

fig. 1.1- Un tipico esempio di raytracing.
Ecco un frammento di pseudo-codice per capire la procedura, la funzione
Render illumina un determinato pixel ( i , j ) dell'immagine:
Function Render ( raggio )
Begin
esiste:= TrovaInteresezione ( raggio );
colore:= Nero;
if ( esiste )
then
Begin
colore:=
CalcolaIntensitaLuminosa ( x, n );
if ( speculare )
then
Begin
colore:= colore + Render ( raggio riflesso
/ raggio rifratto );
end
end
ret
colore;
end
2. - IL PATH TRACING
Il Path Tracing, introdotto da James T. Kaijya nel 1984, è un
estensione del raytracing che permette di ottenere effetti di
illuminazione globale come color bleeding (riflessi diffusi) o
caustiche (anche se queste necessitano un gran numero di campioni per
essere rappresentate). L'idea alla
base
è molto semplice, ogni qual volta che si interseca una
superficie lambertiana o diffusa in un punto
x, si lancia un nuovo
raggio, che parte da
x, in una
direzione casuale dell'emisfero
determinato dalla normale
n in
x. Ad ogni nuova
intersezione si calcola
l'illuminazione locale e la si somma a quella del pixel corrente. Il
procedimento termina perchè in genere si forza ad un numero
determinato di rimbalzi, o si effettua la roulette russa.
La procedura crea praticamente un percorso, e maggiore è il
numero di percorsi fatti per pixel maggiormente il valore in quel pixel
convergerà al calcolo dell'integrale della Rendering Equation di
Kaijya (il rumore è molto elevato utilizzando meno di 100
percorsi per pixel). Il punto di partenza dei percorsi non è
sempre lo stesso ma varia, infatti si sceglie in genere una posizione
casuale all'interno dell'intorno della posizione standard di partenza
del raytracing.
Da notare che nel Path Tracing non si campiona ogni direzione
dell’emisfero di
x
ma solo una direzione casuale, perché
altrimenti la complessità sarebbe esponenziale, e il calcolo
dell'illuminazione di una semplice scena quale una Cornell Box sarebbe
proibitivo.
fig. 2.1 - Un esempio di pathtracing,
100 campioni/pixel.
Ecco un frammento di pseudo-codice come
per il caso del pathtracing:
Function ColoraPixel (
raggio )
Begin
colore:= Nero;
for i:= 0 to
nCampioni Do
Begin
colore:= colore + Render ( raggio
);
end
colore:= colore / nCampioni
end
Function Render ( raggio )
Begin
esiste:= TrovaInteresezione ( raggio );
colore:= Nero;
if ( esiste ) then
Begin
colore:=
CalcolaIntensitaLuminosa ( x, n );
if ( speculare ) then
Begin
colore:= colore + Render ( raggio riflesso / raggio rifratto );
end
colore:= colore + Render ( raggio random nell'emisfero
della normale);
end
ret
colore;
end
Per dovere di cronoca è da citare
altre due metodologie che hanno fatto storia (che non verranno trattare
per questione di tempo) Bidirectional Pathtracing introdotto da Eric P.
Lafortune e da Yves D. Willems nel 1993, e il Metropolis Light Trasport
introdotto da Eric Veach e Leonidas J. Guibas nel 1997. Entrambe le due
tecniche si basano sullo stesso concetto di potenziamento del path
tracing; ossia campionare percorsi non solo dall'oggetto alla luce ma
anche dalla luce e dall'oggetto. Infatti molti percorsi sono molto
più facili da campionari dalla luce, in particolar modo le
caustiche; infatti nel path tracing tradizionale se si vogliono
ottenere delle caustiche di buona qualità si deve forzare in
modo costoso perchè un percorso includa l'attraversamento di
superfici speculari per poi terminare su una luce (infatti usando solo
percorsi random la qualità è molto bassa).
La differenza dei due metodi è la strategia di campionamento
adottata; infatti il Bidirectional Pathtracing utilizza come nel caso
del Pathtracing per il campionamento una strategia di Monte Carlo,
mentre il Metopolis Light Transport (MLT) utilizza la strategia di
Metropolis come dice il nome stesso.Tale strategia consente al MLT di
produrre immagini di qualità superiori al Bidirectional
Pathtracing di base, in quanto per valutare l'illuminazione genera una
distribuzione dei campioni proporzionale all'integrale della Rendering
Equation che è sconosciuto.
3. -
IL PHOTON MAPPING
Il Photon Mapping, introdotto da Henrik Wann Jensen tra il 1995 e il
1996, è un algoritmo che estende il raytracing e l'idea del
Pathtracing di
Kaijya, in particolar modo può essere visto come un
Bidirectional
Pathtracing con cache. Infatti anche in questo caso, invece di
effettuare solo il percorso inverso della
luce cioè dall'oggetto alla sorgente luminosa, si traccia anche
il
percorso naturale della luce; ossia dalla sorgente luminosa agli
oggetti.
I percorsi "vengono salvati" (in realtà non si conserva
informazione del percorso ma dei punti del percorso) in una struttura
chiamata
mappa dei fotoni per
evitare ogni volta il lancio dei fotoni. La mappa dei fotoni è
un KD-tree (fig.3.1), e la scelta per tale struttura è dovuto al
fatto che è molto efficiente per la localizzazione di n punti
vicini rispetto ad un punto di riferimento. Ogni qual volta che si
salva un fotone nella mappa dei fotoni si salva la sua posizione,
direzione di arrivo e la potenza luminosa che trasporta.
fig.3.1- Visualizzazione di Photon Map con OpenGL: a) Photon Map
Diretta
b) Photon Map Indiretta, c) Photon Map Caustiche.
L'algoritmo di Jensen è un algoritmo a due passate. La prima
passata è il lancio dei fotoni (che rappresentano il flusso di
energia) dalle sorgenti presenti nella scena; per ogni sorgente vengono
lanciati un determinato numero di fotoni che trasportano una
quantità di potenza, pari alla potenza della sorgente luminosa
divisa per il numero dei fotoni emessi. I fotoni possono essere
lanciati da qualsiasi tipo di sorgente luminosa (fig.3.2),
infatti
basta conoscere la funzione di distribuzione dei fotoni di un
determinato tipo di sorgente.
fig.3.2- I tipi di luce possibili con
il
Photon Mapping.
Ogni fotone lanciato può essere perso (cioè non collide
con nessun oggetto della scena e scappa) o può collidere; in
questo caso vi sono varie possibilità (fig.3.3):
1) il fotone viene assorbito e viene salvato nella mappa dei fotoni;
2) il fotone viene riflesso diffusamente e la sua collsione attuale
viene salvata nella mappa dei fotoni;
3) il fotone viene riflesso in modo speculare.
La natura reale dei fotoni consente loro infiniti rimbalzi a seguito di
una collisione, però nel nostro modello ciò sarebbe
impraticabile, infatti la passata di lancio dei fotoni non potrebbe
terminare. Quindi ad ogni rimbalzo si decide con il meccanismo della
roulette russa che farne del fotone (fig.3.4): assorbirlo, rifletterlo
in
modo diffuso o speculare. Se il fotone viene riflesso si scala la sua
potenza per la capacità di riflessione diffusa o speculare del
materiale dell'oggetto con cui è avvenuta la collisione.
fig.3.3- un esempio di percorso dei fotoni.
|
fig.3.4- la roulette russa
semplificata.
|
Nella seconda passata viene calcolata l'illuminazione per un
determinato punto; riflessioni e rifrazioni vengono gestite come in un
normale Raytracer, mentre il calcolo dell'intensità luminosa
diretta, indiretta e delle caustiche vengono calcolate tramite la stima
di densità (una tecnica nata in ambito statistico).
La stima di densità può essere vista come una
descritizzazione dell'equazione dell'intensità riflessa (il cui
dominio di integrazione è una semisfera, vedi fig.3.5)::
fig.3.5 – la semisfera di integrazione.
La stima di
densità ha la seguente forma:
dove:

è il flusso di energia da la fotone p.
r è il raggio
della sfera in cui sono contenuti gli n fotoni
della stima (fig.3.6).
fig.3.6 – gli n fotoni vicini al punto
x
sulla superficie.
NOTA: Nella stima di
densità la proiezione dell’area dell’angolo solido
dell'equazione
dell’intensità riflessa, viene sostituita dall’area della del
cerchio
con il raggio di ricerca degli n fotoni vicini.
La stima di densità è valida in quanto tra radiazione e
flusso sussiste la seguente relazione:
Sostituendo tale relazione all'equazione dell’intensità
riflessa si ottiene:
Per migliorare la qualità dei risultati, si può calcolare
il termine dell'illuminazione indiretta diffusa con il Final Gathering.
Il Final Gathering consiste nel calcolare l'intensità luminosa
(tramite stima di densità) di tutti i punti visibili da punto
x
preso in esame (cioè campionare attorno al suo emisfero) e
quindi farne la media. E' una procedura molto costosa, che può
essere velocizzata utilizzando delle cache (fig.7). L'uso di cache
è giustificato dal fatto che la luce indiretta diffusa al
contrario di quella speculare, cambia lentamente nello spazio, e quindi
si possono riutilizzare i valori vicini tramite interpolazione. Questa
idea sviluppata da Ward, è alla base del famoso software
Radiance.
fig. 3.7- I punti di calcolo
dell'illuminazione indiretta.
Un altro metodo per migliorare i risultati è quello di
utilizzare un Raytracer per il calcolo dell'illuminazione diretta,
quindi la stima di densità viene utilizzata in "modo puro" solo
per il calcolo delle caustiche che non necessitano particolari
condizioni. Per la realizzazione della divisione del calcolo
dell'illuminazione nelle tre componenti viste ora (diretta, indiretta,
caustiche) vi è la necessità di avere tre Photon Map, una
per i fotoni diretti, uno per quelli indiretti, e uno per le caustiche.
Questa strategia risulta ottimale in quanto, non vi sono interferenze
di altre tipi di illuminazione durante la stima di densità;
diminuendo significatamente il rumore.
4. -
LA STRUTTURA DEL RAYTRACER
Il raytracer è stato sviluppato con il paradigma ad oggetti ed
implementato in C++ utilizzando le OpenGL come libreria di
previsualizzazione, e Diretc3DX come librerie di
supporto per i calcoli vettoriali e matriciali. Il raytracer lavora
fondamentalmente con i seguenti oggetti:
i materiali, le luci, gli oggetti tridimensionali; il tutto contenuto e
gestito nelle varie classi Scena che si differenziano per funzioni
peculiari particolari. Nella scrittura del codice si è sfruttato
molto l'ereditarietà, e i meccanismi di casting grazie ai quali
l’aggiunta di nuovi tipi di luci, materiali e oggetti risulta molto
facile.
4.1 GLI OGGETTI 3D
Gli oggetti tridimensionali del raytracer non sono altro che
descrizioni formali, e fanno tutti capo ad una classe base Oggetto, che
definisce i metodi comuni che verranno utilizzati dalle varie classi
Scena. Questi metodi sono:
1)
CheckRay() per
calcolare l'intersezione dell'oggetto con un raggio;
2)
C_Normale() per
calcolare la normale in un punto dell'oggetto;
3)
CaricaOggetto() per
caricare da file la descrizione dell'oggetto;
4)
ChiSono() per sapere
con quale specializzazione di Oggetto si stà lavorando;
5)
ApplicaTrasformazioni()
per effettuare traslazioni e rotazioni dell'oggetto.
Oltre a metodi in Oggetto vengono definite delle variabili comuni quali
il nome dell'oggetto, il nome del materiale a cui va associato, il tipo
di texture mapping, ed infine la posizione rispetto all'origine e la
rotazione rispetto al centro dell'oggetto.
La maggior parte degli oggetti specialistici hanno una descrizione
formale molto semplice: nel caso del Cubo (che è in
realtà un parallelepipedo) si tiene conto solo delle estensioni
nelle tre dimensioni, per la sfera solo del raggio, mentre per il piano
non si ha bisogno di registrare niente dato che la posizione e la
normale (rappresentata dal vettore di rotazione) sono già
presenti in Oggetto.
L'oggetto Mesh invece è una mesh triangolare rappresentata a
lista di vertici. Per velocizzare il test di intersezione
mesh-raggio (infatti l'algoritmo di forza bruta effettua il test
triangolo-raggio per ogni triangolo della mesh, ed è molto
oneroso dal punto di vista computazionale) viene utilizzata una
suddivisione spaziale. Nello specifico si utilizza un octree e quindi
viene effettuato il test triangolo-raggio solo per i triangoli
contenuti nelle regioni di spazio candidate, selezionate dal test
octree-raggio (un test ricorsivo cubo-raggio), l'utilizzo dell'octree
ha velocizzato di circa otto volte il test mesh-raggio; anche se
l'utilizzo dei BSP sarebbe ottimale.
-Il grafico UML della gerarchia di
Oggetto.
4.2 LE LUCI
Gli oggetti luce sono descrizioni formali di fonti luminose, grazie
alle quali ed a un modello di shading si possono illuminare gli oggetti
presenti nella scena. Sono strutturati come gli oggetti 3D, in poche
parole c'è una classe astratta Luce che definisce i metodi e le
caratteristiche comuni.
Le caratteristiche comuni sono proprietà fisiche quali: il
colore diffuso, il colore speculare, la potenza in Watt della luce, il
nome, il tipo di luce specializzante, se è abilitata a calcolare
ombre. Le caratteristiche specializzanti sono caratteristiche di natura
geometrica che definiscono il tipo di luce.
I metodi delle classi figlie sono rivolti alla creazione delle ombre,
infatti ogni tipo di luce avendo caratteristiche geometriche differenti
hanno bisogno di metodi specifici per tale calcolo.
I metodi comuni sono:
1)
BRDF_Blinn() per
calcolare l'intensità luminosa con il BRDF di Blinn.
2)
CaricaLuce() per
caricare da file la descrizione della luce;
3)
ChiSono() per sapere
con quale specializzazione di Luce si stà lavorando;
4)
SparaFotone() per
sparare un insieme di fotoni nella scena;
5)
FotonePath() per
tracciare il percorso di un fotone.
Le tipologie di luci presenti sono abbastanza standard (point light,
directional light, spot light, le hemisphere light presenti nelle
pipeline di lighting di DirectX e OpenGL) e implementano il modello
della luce di Jim Blinn (che si differenzia da quello di Phong per un
migliore calcolo del fattore speculare).
-Il grafico UML della gerarchia di Luce
Gli unici tipi di luce un po' ricercati sono la LLineare (il limite a
infinito del numero di point light lungo una linea) e la LArea (il
limite a infinito del numero di point light distribuite uniformemente
su una superifice); queste due tipologie di luce sono molto
pesanti dal punto di vista computazionale, ma rappresentano meglio le
fonti di luci presenti in natura (infatti una LLineare può
essere vista come un neon e una LArea come una finestra fig.4.1). Per
effettuare il calcolo del modello di riflessione di Blinn e del calcolo
delle ombre per la LLineare e per la LArea è stato deciso di
campionarle con point light. Si potrebbe migliorare il calcolo del
modello di riflessione, che è un integrale curvilineo nel caso
di LLineare, e superificiale nel caso di LArea) svolgendolo in modo
analitico, anzichè in modo numerico; ma lascio ciò a
future implementazioni.

fig.4.1.a- Una luce LPunto.
|

fig.4.1.b- Una luce LArea.
|
I fotoni generati tramite la funzione SparaFotone vengono salvati in
un'istanza della classe MappaFotoni, che
è un KD-tree bilanciato. MappaFotoni svolge le normali
operazioni di un KD-tree cioè bilanciamento di un insieme di
punti, inserimento di un punto, e ricerca degli n-vicini. In più
calcola l'illuminazione in un punto con il metodo della stima di
densità.
4.3 I MATERIALI
I materiali nei programmi professionali di rendering quali fra tutti
RenderMan, MentalRay, BMRT e LightFlow, vengono rappresentati con veri
e propri linguaggi ad alto livello e spesso visualizzati come grafi.
Purtroppo per questioni di complessità e di tempo ciò non
è stato possibile, e quindi i materiali hanno opzioni fissate.
Per quanto riguarda le proprietà fisiche i materiali hanno i
seguenti attributi: un colore diffuso, uno speculare (entrambi una
tripla RGB che assume valori da 0.0 a 1.0), un fattore di lucentezza,
un indice di rifrazione, un indice di trasparenza.
Infine un materiale può contenere texture, nello specifico tre
texture. La prima è una texture diffusa che viene moltiplicata
con il colore diffuso, la seconda è una texture di
rugosità per effettuare la perturbazione delle normali e quindi
il bump mapping. Infine la terza texture è una texture di
luminosità ossia è una fotografia alla quale viene
applicata la convoluzione tra la mappa di radiazione e la funzione di
riflessione della luce diffusa (utilizzando armoniche sferiche per
abbattere la complessità); questa tecnica di Image Based
Lighting consente di immergere la scena all'interno delle fotografie.
-Il grafico UML di Materiali.
4.4 LA SCENA
La scena è stata suddivisa in una gerarchia di classi, dove ogni
classe svolge delle funzioni logiche determinate; questo è stato
fatto essenzialmente per avere una migliore pulizia del codice.
Alla radice della gerarchia abbiamo la classe base Scena che incorpora
gli Oggetti 3D, le Luci, i Materiali, e la Telecamera. Scena svolge
solo la funzione di calcolo dell'intersezione degli oggetti con il
raggio tramite la funzione Intersezioni(). Oltre a trovare quale
è l'intersezione più vicina (nel caso ci sia)
Intersezioni() calcola la normale in quel punto e le coordinate di
mapping.
L'immediata classe che eredita direttamente da Scena è
ScenaLoader che svolge la funzione di caricare separatamente Luci,
Oggetti 3D, e Materiali della scena.
La classe successiva che eredita da SceneLoader è
ScenaRaytracer, essa prepara il setup delle matrici di proiezione e di
vista, dell'immagine e dello z-buffer. Inoltre crea immagini sintetiche
implementando l'algoritmo del Raytracing e del PathTracing presentati
precedentemente.
Spesso il rendering di scene complesse può richiedere svariati
minuti, quindi è stata inserita ScenaGL una classe di
previsualizzazione via OpenGL derivata da ScenaRaytracer; questo
è stato fatto per sfruttare la stessa pipeline di lighting, e
quindi per avere risultati uguali, anzichè usare la pipeline di
rendering di OpenGL. ScenaGL oltre che a renderizzare gli oggetti
presenti nella scena, effettua la triangolazione degli oggetti
parametrici quali sfere, piani, e cubi.
L'ultima classe che eredita da ScenaGL è ScenaGI. ScenaGI
interfacciandosi con le classi MappaFotoni, e
IrradianceCache crea immagini sintetiche implementando l'algoritmo del
Raytracing combinato con il Photon Mapping e il Final Gathering. Seppur
l'IrradianceCache sia un banale array di valori di intensità
luminosa, è stata creata una classe a parte per poter facilitare
la lettura e scrittura del codice.
-Il grafico UML della gerarchia di
scena.
5. - TEMPI DI RENDERING E CONCLUSIONI
Per valutare le prestazioni del Raytracer sono stati effettuati vari
rendering della cornell-box di riferimento (una stanza con due sfere
speculari e una rettangolare posizionata nel centro della cornellbox).
Di seguito vengono riportate le immagini renderizzate a risoluzione di
400x300, e i rispettivi tempi di rendering. La macchine utilizzata
è un Intel Pentium 4 a 2.8Ghz, 1Gb di ram a 400Mhz, e con
sistema
operativo Windows XP con Service Pack1. Il codice è stato
compilato utilizzando il compilatore di MS Visual C++ 6.0 con Service
Pack 5. Si potrebbe migliorare i tempi globali effettuando rendering
distribuito in quanto ogni tecnica (Raytracing classico, Pathtracing,
Photon Mapping) è possibile eseguirla in parallelo.

|
Immagine calcolata utilizzando
il code-path Raytracing Classico.
Tempo di calcolo: 10 s
|

|
Immagine calcolata utilizzando
il code-path Pathtracing, 100 campioni/pixel.
Tempo di calcolo:
2000 s |

|
Immagine calcolata utilizzando
il code-path Photon Mapping con stima di densità per
l'illuminazione diretta
e indiretta, utilizzando 500 fotoni
nella stima e un milione di fotoni nella Photon Map.
Tempo di calcolo: 140
s
|

|
Immagine
calcolata utilizzando il
code-path Photon Mapping con Final Gathering (400
campioni)
utilizzando 500 fotoni nella stima di densità e
con circa centomila fotoni nella Photon Map.
Tempo di calcolo: 200 s |
6. - ESTENSIONI PER IL FUTURO
Il software prodotto ha implementato solo tecniche base che si fermano
al 1996, da allora sono state scritte molte pubblicazioni, che hanno
aumentato l'espressività e la qualità dei metodi di Monte
Carlo, e in particolar modo del Photon Mapping. Per esempio sono state
introdotte tecniche efficienti per la realizzazione dei cosidetti
partecipating media (nebbia, fumo,
fuoco, etc...) e per la valutazione del BSSRDF, che ha reso possibile
di
realizzare in modo fisicamente corretto il rendering di materiali
traslucenti quali pelle, marmi, etc... Inoltre passi da giganti
sono stati fatti anche
nell'Image Based Rendering (IBL), migliorando tempi e qualità
delle prime tecniche.
BIBLIOGRAFIA
Per
la realizzazione del progetto mi sono avvalso dei seguenti testi:
Jensen, Henrik Wann, “Realistic
Image Synthesis Using Photon Mapping” . 2001, A K Peters.
Akenine-Möller,
Tomas e
Haines, Eric "Real-Time
Rendering Second Edition". 2002, A K Peters.
Shirley, Peter “Realistic
Ray Tracing”. 2000, A K Peters.