Raytracing

Il ray tracing è una tecnica di rendering in grado di produrre immagini virtuali con un elevato livello di realismo, pur basandosi su un principio molto semplice. L'idea è quella di seguire il percorso della luce all'interno della scena, che parte da una sorgente luminosa e interagisce con l'ambiente circostante (attraverso fenomeni fisici come rifrazione, riflessione, diffusione....) prima di raggiungere il nostro occhio, rendendo quindi visibili gli oggetti.
In realtà, a livello computazionale è molto più efficiente seguire questo percorso in direzione opposta, immaginando che il raggio di luce parta dal nostro occhio, poichè solo una piccola parte dei raggi emessi da una sorgente luminosa raggiunge effettivamente l'occhio. Questo approccio prende in particolare il nome di backward ray tracing.
Per creare un immagine digitale 2D formata da pixel, un raggio di questo tipo (detto primary o view ray) viene creato per ciascuno dei pixel. Se tale raggio interseca (visibility problem) un oggetto della scena, è possibile quindi calcolare l'illuminazione di tale oggetto nel punto di intersezione (procedimento che prende il nome di shading) ed assegnare il colore risultante al pixel d'interesse.

Shading

Il modo in cui viene calcolata l'illuminazione di un punto della scena dipende principalmente dalle proprietà del materiale di cui è composto l'oggetto che stiamo guardando, che determinano il modo in cui la luce interagisce con esso. Dal punto di vista della riflessione, possiamo identificare tre tipi di riflessione:

Chiaramente, gli oggetti reali esibiscono sempre una componente di riflessione specualare ed una di riflessione diffusa. Alcuni modelli empirici utilizzati per simulare l'illuminazione di oggetti reali funzionano combinando opportunamente l'illuminazione che si avrebbe da una superficie perfettamente speculare con quella ottenibile da una perfettamente diffusa (vedi il modello di Phong).
Il programma prevede tre tipi di oggetti, a seconda del modo in cui interagiscono con la luce:

Fonti luminose

Sono previsti due tipi di fonti luminose:

Oltre alle proprietà sopra descritte, ogni fonte luminosa è definita da colore ed intensità.

Square rolloff

Per le luci sferiche , l'illuminazione dipende anche dalla distanza a cui un oggetto si trova. Più precisamente, si può considerare una luce sferica puntiforme come una fonte luminosa isotropa, che emette luce in maniera uguale in tutte le direzioni. In tal caso, si può applicare la seguente legge di proporzionalità:
\begin{equation} I = \frac{P}{4\pi r^{2} } \end{equation}
Dove \(I\) è l'intensità luminosa, \(r\) è la distanza dalla sorgente e \(P\) è la potenza totale.

Illuminazione su superfici lambertiane

La legge di Lambert afferma che l'illuminamento prodotto da una sorgente su una superficie è direttamente proporzionale all'intensità luminosa della sorgente e al coseno dell'angolo che la normale alla superficie forma con la direzione dei raggi luminosi.
\begin{equation} E = I\cdot \cos \alpha = I \cdot \textbf{n} \boldsymbol{\cdot}\textbf{l} \end{equation}
Dove \(\textbf{n} \) è il versore normale alla superficie, mentre \(\textbf{l} \) è il versore della direzione dei raggi luminosi. .Più precisamente, per una luce puntiforme \begin{equation} \textbf{l} = \frac{\textbf{P}_{light} - \textbf{P}_{hit}} {\left \| \textbf{P}_{light} - \textbf{P}_{hit}\right \|} \end{equation} dove \(\textbf{P}_{hit} \) è il punto considerato sulla superficie, mentre \( \textbf{P}_{light}\) è il punto che identifica la posizione di una sorgente luminosa puntiforme. Per una luce distante, invece, la direzione è una proprietà intrinseca della sorgente luminosa.
L'intensità luminosa che compare nella formula, \( I \), è calcolata per le sorgenti puntiformi utilizzando la legge inversa del quadrato descritta precedentemente, mentre per le luci distanti si utilizza direttamente l'intensità luminosa alla sorgente.
L'intensità luminosa della superficie dipende poi, ovviamente, anche da quanta della luce ricevuta viene riflessa nelle varie direzioni e da quanta viene invece assorbita. Il rapporto tra la quantità di luce emessa e quella ricevuta è detta albedo. Quindi, l'ammontare totale di energia luminosa riflessa dalla superficie diffondente è dato da:
\begin{equation} F_{tot} = albedo \cdot E = albedo \cdot I\cdot \cos \alpha \end{equation}
Poichè questa energia viene distribuita uniformemente su un emisfero centrato sul punto osservato ed orientato nella direzione della normale alla superficie, per ottenere la quantità di luce riflessa nella direzione della visuale bisogna dividere per \( \pi \).
\begin{equation} L = \frac{F_{tot}}{\pi} \end{equation}
Come anticipato, la quantità di luce riflessa è indipendente dalla direzione della visuale.

Riflessione speculare

Usando la legge della riflessione, date la direzione incidente \( \textbf{l} \) e la normale \( \textbf{n} \) (si assume entrambi siano vettori di norma unitaria) è facile calcolare la direzione della riflessione:

\begin{equation}\textbf{r} = 2(\textbf{n}\cdot \textbf{i})\textbf{n} - \textbf{i} \end{equation}




A livello implementativo, quando la direzione della visuale interseca una superficie riflettente, calcoliamo la direzione di riflessione e generiamo un nuovo "raggio", avente come origine il punto di intersezione e come direzione quella di riflessione. Questo raggio può potenzialmente intersecare a sua volta una superficie riflettente, di conseguenza il processo è ricorsivo. Potenzialmente, una scena potrebbe causare una ricorsione infinita, o comunque generare un numero così elevato di riflessioni da rendere la computazione molto lenta (senza particolari miglioramenti dal punto di vista del realismo dell'immagine ottenuta). Per questo motivo, si definisce una costante che limita il numero massimo di livelli che può raggiungere questo procedimento ricorsivo (le immagini dimostrative sono state generate usando come limite 5 livelli).




Rifrazione

Quando un raggio di luce "passa" da un mezzo trasparente ad un altro, la sua direzione viene alterata. La nuova direzione dipende dalla direzione incidente e dagli indici di rifrazione dei due mezzi. L'indice di rifrazione è un numero adimensionale definito come il rapporto tra la velocità della luce nel vuoto e la velocità di fase della radiazione che attraversa il mezzo:
\begin{equation} \eta = \frac{c}{v} \end{equation}
Per ricavare la direzione di rifrazione si utilizza la legge di Snell:
\begin{equation} \frac{\sin{\theta_1}}{\sin{\theta_2}} = \frac{\eta_2}{\eta_1} \end{equation}
dove \( \theta_1 \) è l'angolo di incidenza, mentre \( \theta_2 \) è l'angolo di rifrazione.

Data la direzione incidente \( \textbf{i} \) e quella della normale \( \textbf{n} \), con alcuni passaggi si ricava la direzione del raggio rifratto:
\begin{equation} \textbf{t} = \eta \textbf{i} + (\eta c - \sqrt{h} )\textbf{n} \\ \end{equation}
\begin{equation} \text{dove} \quad \eta = \frac{\eta_1}{\eta_2} ; \quad c = \textbf{n} \cdot \textbf{i} = \cos{\theta_1} ; \quad h = 1 - \eta^2 (1-c^2) \end{equation}
Quando passando da un mezzo ad un altro l'indice di rifrazione aumenta, se l'angolo di incidenza supera l' angolo critico, si verifica un fenomeno detto riflessione interna totale: la luce viene completamente riflessa e non si ha rifrazione. L'angolo critico si ottiene partendo dalla legge di Snell ed imponendo \begin{equation} \theta_2 = \frac{\pi}{2} \Rightarrow \sin{\theta_2} = 1 \Rightarrow \theta_{crit} = \arcsin{(\frac{\eta_1}{\eta_2})} \end{equation}
Si ha quindi riflessione interna totale quando
\begin{equation} \theta_1 > \theta_{crit} \end{equation}
che è analogo a verificare \( h < 0 \)

Legge di Fresnel

Gli oggetti trasparenti esibiscono in realtà sia rifrazione che riflessione. La quantità di luce che viene riflessa o rifratta dipende dall'angolo di incidenza. All'aumentare dell'angolo di incidenza la quantità di luce rifratta diminuisce sempre più, fino a diventare nulla nel caso della riflessione totale interna. Precisamente, la frazione di luce che viene riflessa si può calcolare usando la legge di Fresnel:
\begin{equation} R = \frac{I_r}{I_i} \end{equation}
\(R \) è il coefficiente di riflessione, rapporto tra l'intensità della radiazione riflessa \((I_r)\) e della radiazione incidente \((I_i)\).
Questo viene separato in due componenti con polarizzazione perpendicolare tra loro:
\begin{equation} R_s = (\frac{\eta_1 \cos{\theta_1} - \eta_2 \cos{\theta_2}} {\eta_1 \cos{\theta_1} + \eta_2 \cos{\theta_2}})^2 \quad R_p = (\frac{\eta_1 \cos{\theta_2} - \eta_2 \cos{\theta_1}} {\eta_1 \cos{\theta_2} + \eta_2 \cos{\theta_1}})^2 \end{equation}
Per ottenere il coefficiente di riflessione effettivo per una luce "naturale" (che viene solitamente descritta come non polarizzata), si calcola una media delle due componenti:
\begin{equation} R_{eff} = \frac{R_s + R_p}{2} \end{equation}
La frazione di luce rifratta si calcola semplicemente come:


\begin{equation} T_{eff} = 1 - R_{eff} \end{equation}
Questi due sono i coefficienti che utilizziamo nella pratica per "pesare" le due componenti di rifrazione e di riflessione.
Anche calcolare l'illuminazione di una superficie trasparente, avendo sempre una componente riflettente, è un procedimento ricorsivo. Per oggetti geometrici molto semplici, come le sfere visibili nell'immagine seguente, il limite di 5 livelli che imponiamo alla ricorsione è sufficiente per ottenere ottimi risultati. Tuttavia, lo stesso non si può dire nel caso di oggetti trasparenti complicati, come un oggetto ottenuto tramite incollamento di più superfici (di Bézier o spline, ad esempio) e triangolazione.

Superfici di Bézier

Una superficie di Bézier di bigrado (m,n) è definita da una griglia bidimensionale di (m+1)*(n+1) punti di controllo \( \{ \textbf{P}_{i,j} \} \), che costituiscono il cosiddetto poliedro di controllo. Come superficie parametrica, una superficie di Bézier è una funzione di due parametri \( (u, v) \), dove il valore della superficie nel punto \( \textbf{P}(u,v) \) è così calcolabile:
\begin{equation} \textbf{P}(u,v) = \sum_{i=0}^{m} \sum_{j=0}^{n} B_i^m(u) B_j^n(v) \textbf{P}_{i,j} \quad\quad u, v \in [0,1] \end{equation}

Dove \( B_i^m(u) \) è un polinomio di Bernstein, così definito in generale:
\begin{equation} B_i^m(u) = \binom{m}{i}u^i(1-u)^{n-i} \end{equation}

Come le curve di Bézier, le superfici godono di diverse proprietà utili: Oltre che utilizzando l'equazione parametrica illustrata sopra, è possibile calcolare un punto di una superficie di Bèzier anche applicando due volte l'algoritmo di de Casteljau per le curve di Bézier. Infatti, data una coppia di parametri \( (\bar{u},\bar{v}) \) si può procedere così: Sebbene l'algoritmo di de Casteljau sia più lento del metodo "diretto" per calcolare un punto su una curva di Bézier, è numericamente più stabile e permette di calcolare al tempo stesso il vettore tangente alla curva. Applicato alle superfici di Bézier, questo ci permette di evitare di dover calcolare separatamente uno dei due vettori tangenti (a seconda di quale parametro "fissiamo" per primo), necessari a calcolare il vettore normale alla superficie.

Triangolazione di superfici

Calcolare direttamente l'intersezione di una retta con una superficie di Bézier è difficile e computazionalmente inefficiente, per cui solitamente queste vengono triangolate prima di farne un rendering tramite ray tracing. Per triangolare una superficie di Bézier, è più semplice triangolare il suo dominio (il quadrato unitario, normalmente), suddividendolo prima in rettangoli e successivamente suddividendo ogni rettangolo in due triangoli. Per semplicità, il programma di rendering sviluppato prevede una suddivisione uniforme e uguale in entrambe le direzioni \( u \) e \( v \). Poichè l'effettiva forma ed estensione della porzione di superficie su cui ogni triangolo viene mappato è ignorata, questo approccio può essere inefficiente o dare risultati esteticamente meno piacevoli rispetto ad un algoritmo "adattivo".




Curve B-Spline

Le curve B-Spline offrono diversi vantaggi rispetto alle curve di Bézier, di cui rappresentano una generalizzazione. Infatti, le curve di Bézier possiedono alcune importanti limitazioni: Il motivo per cui le curve B-Spline presentano questi vantaggi rispetto alle curve di Bézier, deriva dal fatto che le prime sono in realtà curve composite, ossia curve ottenute tramite incollamento di più segmenti di curve. Ciascuna di queste è una curva polinomiale, con un suo grado e un insieme di punti di controllo. Questo permette alle curve B-Spline di godere delle proprietà desiderabili di cui abbiamo discusso sopra.
Una curva B-Spline è definita da: Per modificare l'aspetto di una curva B-Spline, possiamo agire su ognuno di questi parametri: la posizione dei punti di controllo, il valore dei nodi o il grado della curva.
Se non viene imposta alcuna restrizione sui nodi della curva, questa in generale non passerà per nessuno dei suoi punti di controllo, nemmeno il punto iniziale o quello finale (come invece accade per le curve di Bézier). La molteplicità di un nodo è il numero di volte che questo occorre all'interno del vettore dei nodi. Se si vuole che la curva passi per il primo e l'ultimo punto di controllo, è necessario che il primo e l'ultimo nodo abbiano molteplicità \( p+1 \). Curve B-Spline aventi questa proprietà vengono chiamate curve clamped.
L'equazione parametrica di una curva B-Spline è:
\begin{equation} \textbf{P}(u) = \sum_{i=0}^n N_{i,p}(u)\textbf{P}_i \end{equation}
Le funzioni \( N_{i,p}(u) \) sono le B-Spline basis functions e vengono usate come coefficienti per i punti di controllo, così come nelle curve di Bèzier venivano usati i polinomi di Bernstein \( B_{i}^p(u) \).
Queste vengono definite ricorsivamente come segue:
\begin{equation} N_{i,0}(u) = \begin{cases} 1, & \text{se $u_i \leq u < u_{i+1} $}\\ 0, & \text{altrimenti} \end{cases} \end{equation}


\begin{equation} N_{i,p}(u) = \frac{u-u_i}{u_{i+p}-u_{i}}N_{i,p-1}(u) + \frac{u_{i+p+1}-u}{u_{i+p+1}-u_{i+1}}N_{i+1,p-1}(u) \end{equation}

Dalla definizione si ricavano le seguenti proprietà (una speculare all'altra), che sono esattamente ciò che permette di avere una forma di controllo locale: Da queste proprietà si deriva immediatamente la proprietà riguardante la modifica dei punti di controllo: Un'altra proprietà importante riguarda la continuità di una curva B-Spline, nei punti di "incollamento" tra le varie curve componenti (knot points) Quindi, la molteplicità di un nodo influenza la continuità della curva.
Aumentando la molteplicità di un nodo è in realtà possibile anche far sì che la curva passi per un determinato punto di controllo. Infatti, vale la seguente proprietà: Ne consegue che, in corrispondenza di un nodo di molteplicità \( p \), solo una delle basis function sarà non nulla. Più precisamente, il valore dell'unica funzione non nulla sarà esattamente \( 1 \), per cui si avrà che la curva passa per uno dei suoi punti di controllo. Un caso particolare è proprio quello delle curve clamped, nominate poco sopra, che passano per il primo e l'ultimo punto di controllo.

Superfici B-Spline

Una superficie B-Spline è definita a partire dalle stesse funzioni \( N_{i,p}(u) \), similarmente a come avviene per le superfici di Bézier. In questo caso, le informazioni necessarie sono: Con questi dati, l'equazione parametrica della superficie è:
\begin{equation} \textbf{P}(u,v) = \sum_{i=0}^m \sum_{j=0}^n N_{i,p}(u) N_{j,q}(v) \textbf{P}_{i,j} \end{equation}

Superficie B-Spline di bigrado \((3,3)\), con \(m=4\) e \(n=4\)

La stessa superficie, con bigrado aumentato a \((4,4)\)


















Interpolazione con curve e superfici B-Spline

Interpolazione con curve
Supponiamo di avere \( n+1 \) punti nello spazio \( D_0, ..., D_n \) e di volerli interpolare mediante una curva B-Spline di grado \( p \) (il grado viene dato come input). In questa formulazione del problema, i parametri per l'interpolazione \( t_0, t_1, ..., t_n \) non sono forniti dall'utente e vanno quindi generati mediante qualche tecnica, ad esempio in maniera uniforme oppure basandosi sulla distanza tra i punti da interpolare (chord length method).
Per la definizione di una curva B-Spline è necessario avere anche un vettore di nodi. Anche questo può essere generato in maniera uniforme, oppure appoggiandosi sui valori dei parametri calcolati precedentemente. A questo punto rimangono solo da determinare gli \( n+1 \) punti di controllo \( P_i \) tali che:
\begin{equation} \textbf{D}_k = \textbf{P}(t_k) = \sum_{i=0}^n N_{i,p}(t_k)\textbf{P}_i \quad 0 \leq k \leq n \end{equation}

Abbiamo quindi \( (n+1) \) equazioni, che possiamo riscrivere come sistema utilizzando le seguenti matrici "formali" di punti:
\( NP=D \)
ossia
\begin{equation} \begin{bmatrix} N_{0, p}(t_0) & \ldots & N_{n, p}(t_0) \\ \vdots & \ddots & \vdots \\ N_{0, p}(t_n) & \ldots & N_{n, p}(t_n) \end{bmatrix} \begin{bmatrix} \textbf{P}_0 \\ \vdots \\ \textbf{P}_n \end{bmatrix} = \begin{bmatrix} \textbf{D}_0 \\ \vdots \\ \textbf{D}_n \end{bmatrix} \end{equation}

Scrivendo al posto di ogni punto le sue coordinate affini come vettore riga, nel caso di punti nello spazio tridimensionale abbiamo in pratica 3 sistemi lineari da risolvere (risolvendo per colonna), ciascuno in \( n+1 \) equazioni ed \( n+1 \) incognite. La determinazione dei punti di controllo quindi si riduce alla risoluzioni di questi sistemi lineari.
Interpolazione con superfici
Per l'interpolazione tramite superfici, il ragionamento visto nel caso delle curve si estende abbastanza facilmente. In questo caso ci viene data una matrice di \( (m+1) \) righe ed \( (n+1) \) colonne di punti \( D_{i,j} \) nello spazio, che vogliamo interpolare utilizzando una superficie B-Spline di bigrado \( (p,q \) definita da \( (m+1)(n+1) \) punti di controllo.
Vanno quindi determinati \( m + 1 \) parametri \( s_0, s_1, ..., s_m \) nella direzione \( u \) e \( n + 1 \) parametri \( t_0, t_1, ..., t_n \) nella direzione \( v \), così da imporre:
\begin{equation} \textbf{D}_{c,d} = \textbf{P}(s_c,t_d) = \sum_{i=0}^m \sum_{j=0}^n N_{i,p}(s_c) N_{j,q}(t_d) \textbf{P}_{i,j} \quad 0 \leq c \leq m \quad 0 \leq d \leq n \end{equation}

Manipolando questa espressione otteniamo
\begin{equation} \textbf{D}_{c,d} = \sum_{i=0}^m N_{i,p}(s_c) \textbf{Q}_{i,d} \quad \end{equation}
dove
\begin{equation} \textbf{Q}_{i,d} = \sum_{j=0}^n N_{j,q}(t_d) \textbf{P}_{i,j} \end{equation}
\(\textbf{Q}_{i,d}\) è il punto su una curva B-Spline, valutata in \( t_d \), di grado \(q\) e definita dalla riga \(i\) dei punti di controllo da determinare.
\(\textbf{D}_{c_d}\) è il punto su una curva B-Spline, valutata in \(s_c\), di grado \(p\) e definita dalla colonna \(d\) dei punti di controllo \(\textbf{Q}\).
In questo modo, possiamo determinare la \(i\)-esima colonna dei punti di controllo "intermedi" \(\textbf{Q}\) a partire dalla \(i\)-esima colonna dei punti dati \(\textbf{D}\) e dai parametri \( s_0, s_1, ..., s_m \), facendo un'interpolazione tramite curve B-Spline. Una volta ottenuti i punti \( \textbf{Q} \), per ottenere la \(i-esima\) riga degli effetti punti di controllo \(\textbf{P}\) si fa un'altra interpolazione tramite curve B-Spline, questa volta con una curva di grado q, utilizzando come punti l'\(i\)-esima riga dei punti \(\textbf{Q}\) ed i parametri \( t_0, t_1, ..., t_n \).