Sei sulla pagina 1di 62

I.T.I.S. G.

Marconi
Esame di Stato

RENDERING 3D

Massimo Perini
Classe 5Ci

Anno scolastico 2013-2014

Indice
Premessa

La grafica 3D

Pipeline di elaborazione 3D

2.1

Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2

Elaborazione dei vertici . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.1

Geometria proiettiva . . . . . . . . . . . . . . . . . . . . . . . . .

2.2.2

Quaternioni di Hamilton . . . . . . . . . . . . . . . . . . . . . . .

2.3

Rasterizzazione dei triangoli . . . . . . . . . . . . . . . . . . . . . . . . .

12

2.4

Elaborazione dei frammenti . . . . . . . . . . . . . . . . . . . . . . . . . .

13

2.5

Unione dei frammenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

Illuminazione

15

3.1

Introduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

3.2

Percorsi di luce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

3.3

Equazione di rendering . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

3.4

Metodi risolutivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

18

3.5

Implementazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

21

La scheda video

23

4.1

Componenti principali . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

4.2

La GPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

24

4.3

CPU e GPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

4.4

La GPU allinterno del computer . . . . . . . . . . . . . . . . . . . . . . .

27

4.5

Comunicazione tra CPU e GPU . . . . . . . . . . . . . . . . . . . . . . .

27

4.5.1

Problemi di sincronizzazione . . . . . . . . . . . . . . . . . . . . .

28

Architettura di una GPU . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

4.6

iv | Indice
4.7

Unified Shader Architecture . . . . . . . . . . . . . . . . . . . . . . . . .


4.7.1 Architettura di ununit di elaborazione . . . . . . . . . . . . . . .
4.7.2 GPU attuali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Calcolo distribuito
5.1 MPI . . . . . . . . . . . . . . . . .
5.2 Comunicazione tra processi . . . . .
5.2.1 Comunicazione punto-punto
5.2.2 Comunicazione collettiva . .
5.2.3 Esempio . . . . . . . . . .
5.3 Topologie virtuali . . . . . . . . . .
5.4 Open MPI . . . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

API grafiche
6.1 OpenGL . . . . . . . . . . . . . . . . . . .
6.1.1 Specifiche . . . . . . . . . . . . . .
6.2 GLUT . . . . . . . . . . . . . . . . . . . .
6.3 GLSL . . . . . . . . . . . . . . . . . . . .
6.4 Confronto tra Direct3D e OpenGL . . . . .
6.4.1 Portabilit . . . . . . . . . . . . . .
6.4.2 Semplicit di utilizzo . . . . . . . .
6.4.3 Prestazioni . . . . . . . . . . . . .
6.4.4 Estensibilit . . . . . . . . . . . . .
6.4.5 Mercato attuale . . . . . . . . . . .
6.5 Progettazione di un motore di rendering 3D
6.5.1 Il formato Wavefront .obj . . . . . .
6.5.2 Scelta del linguaggio . . . . . . . .
6.5.3 Class Diagram semplificato . . . .
6.5.4 Esempio . . . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

33
33
34

.
.
.
.
.
.
.

35
35
36
36
38
38
39
40

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

41
41
41
42
42
43
43
44
45
45
46
46
46
48
49
50

Bibliografia

51

Sitografia

53

Licenza

55

Premessa

La grafica 3D ha come scopo il ricreare immagini fotorealistiche. Per raggiungere questo


fine, essa coinvolge in modo approfondito molte discipline, anche diverse fra loro, come
la fisica e la fotografia. Questa tesina non mira a descrivere il processo di generazione
delle immagini in relazione ad ogni singola materia coinvolta, ma desidera offrire unidea
complessiva dellintero processo.

Capitolo 1
La grafica 3D
Lobiettivo finale della sintesi di immagini tramite calcolatore quello di offrire allosservatore la percezione di osservare unimmagine fotografica riprodotta sullo schermo video
o su un altro dispositivo di output. Il procedimento di generazione dellimmagine, detto
rendering, consiste in una sequenza di operazioni che trasformano il modello matematico
della scena artificiale da visualizzare, nel quale ogni oggetto descritto attraverso le sue
propriet geometriche e fisiche, in una immagine discreta. Per poter quindi giungere a questo risultato, necessario completare tre fasi distinte: modellazione degli oggetti, rendering
e riproduzione dellimmagine attraverso un dispositivo. Nella fase di modellazione si deve
descrivere la scena da visualizzare, specificando gli oggetti, le sorgenti luminose, i materiali,
i punti di vista. Oggetti tridimensionali semplici possono essere rappresentati con equazioni
operanti su un sistema di riferimento cartesiano tridimensionale (ad esempio una sfera o
un cubo). Unaltra tecnica utilizzata per la creazione di oggetti tridimensionali si avvale di
algoritmi applicati a linee, come potrebbe essere unestrusione di una faccia piana descritta
da segmenti 2D. La tecnica pi efficiente, e tuttora pi diffusa, tuttavia la modellazione
poligonale, che opera su superfici organizzate in maglie pi o meno dettagliate di facce poligonali. Una superficie, perci, viene scomposta in facce formate da vertici e segmenti. Si
formano cos poligoni di forme diverse, anche se quelle pi comuni sono i triangoli e i quadrilateri. Queste superfici possono solo approssimare la forma delloggetto finale se siamo
in presenza di un basso livello di poligoni (Low Poly). Un modello poligonale sfaccettato pu essere comunque raffinato con algoritmi che consentono di rappresentare superfici
curve: questa tecnica chiamata superfici di suddivisione. Lalgoritmo pi utilizzato in
questo tipo di modellazione lalgoritmo Catmull-Clark, il quale prevede che il modello
venga raffinato con un processo di interpolazione iterativa: la sua superficie viene cos resa
sempre pi densa di poligoni, che approssimeranno meglio curve ideali derivate matemati-

2 | La grafica 3D
camente dai vari vertici del modello.
La grafica 3D si occupa anche della gestione dellilluminazione. Tutte le superfici, infatti,
devono essere illuminate per poter essere visibili. Una corretta gestione dellilluminazione
permette di decidere parametri come il colore di una luce, il suo tipo e il suo valore di decadenza, la sua potenza e la tipologia di ombre che emana. Lilluminazione necessaria anche
perch gioca un ruolo fondamentale nella creazione di due effetti che rendono realistica
la scena: ombreggiatura e ombre portate. Lombreggiatura permette di dare allimmagine
finale 2D una sensazione di profondit. Le ombre portate, invece, permettono di legare
loggetto alla superficie su cui posizionato. Poich i fotoni rimbalzano su ogni superficie
verso cui sono diretti e ad ogni rimbalzo generalmente aumentano di numero e diminuiscono la loro energia, per calcolare unimmagine ancora pi fotorealistica, possibile simulare
questo comportamento al computer. Tale simulazione, tuttavia, pi accurata e pi rallenta
il processo di generazione dellimmagine bidimensionale. Oltre alla gestione della luce, la
grafica 3D deve anche simulare le propriet fisiche delle facce delloggetto. Questo insieme
di propriet, che viene applicato ad una o pi facce, viene chiamato materiale. Un materiale
permette di descrivere, per esempio, il colore (o i colori), la riflessione della luce e/o il riflesso degli oggetti circostanti, la trasparenza, la rifrazione e la rugosit della superficie. I colori
vengono spesso definiti mediante texture, ovvero immagini 2D che si applicano al modello
grazie a vari tipi di proiezione. La grafica 3D si occupa anche di alcuni effetti fotografici,
come ad esempio la messa a fuoco degli oggetti (profondit di campo). Questa tecnica viene utilizzata per rafforzare lillusione della profondit della scena. Per il computer non ci
sarebbero, infatti, problemi a tenere a fuoco tutti gli oggetti di una scena, ma questo comportamento non sarebbe realistico. Unaltra tecnica fondamentale per la computer grafica
lAnti-Aliasing. Questa procedura necessaria poich il computer, in presenza di linee oblique, potrebbe non riprodurle in modo corretto. Questo effetto si verifica perch limmagine
suddivisa in pixel. LAnti-Aliasing tenta di nascondere questo problema, modificando in
parte il colore dei pixel vicini e sfumando cos la linea. Questo effetto, sebbene molto utile
per ottenere immagini fotorealistiche, aumenta di molto il tempo di elaborazione, poich
ogni immagine deve essere calcolata ad una risoluzione maggiore.

Capitolo 2
Pipeline di elaborazione 3D
2.1

Introduzione

Il compito di ogni sistema grafico 3D quello di generare unimmagine da una scena, nella
grafica real-time anche 60 volte al secondo. La scena contiene tutti gli elementi descritti
in precedenza (ovvero oggetti 3D composti da poligoni, linee e punti, luci e materiali) e la
posizione dello spettatore. La maggior parte delle GPU lavora esclusivamente con triangoli,
perci il loro primo compito quello di trasformare i poligoni pi complessi in triangoli. Lo
sviluppatore usa le librerie grafiche (OpenGL o DirectX) per fornire alla pipeline i poligoni,
un vertice alla volta.
I vertici sono definiti dai valori in virgola mobile (float) della loro posizione, espressa con le
coordinate cartesiane x, y e z. Lo stesso avviene per il punto di vista, al quale si aggiungono
la rotazione sui tre assi ed ulteriori caratteristiche (ad esempio messa a fuoco).
Di seguto verranno descritte le diverse fasi della pipeline di rendering 3D eseguite dalla
GPU.

2.2

Elaborazione dei vertici

Quando viene creato un oggetto, le sue coordinate sono riferite solo ad esso e non sono
presenti altri oggetti nella scena. Per esempio, un cubo viene descritto con coordinate che
rappresentano la dimensione delle facce del solido, ma non la sua reale posizione nello spazio o la sua reale rotazione allinterno di una scena 3D comprendente anche altri oggetti. Si
parla quindi di sistema di riferimento locale. Per poter passare ad un sistema di riferimento
globale, che tenga anche conto degli altri oggetti presenti nella scena e delle indicazioni

4 | Pipeline di elaborazione 3D
di traslazione, rotazione e scalatura, occorre trasformare le coordinate dei vertici dei poligoni. Le coordinate devono essere modificate anche per tenere conto della posizione e
dellorientamento del punto di vista. Ad esempio, se il punto di vista trasla a destra, la GPU
lo interpreta come se gli oggetti della scena dovessero traslare a sinistra. Una volta fatto
questo, necessario trasformare le coordinate in modo che esse siano coerenti con la vista
prospettica; ovvero che vengano modificate seguendo le regole della prospettiva ( tuttavia
possibile creare proiezioni di altre tipologie). Questi motivi obbligano la GPU ad effettuare
operazioni di traslazione, rotazione e scalatura sui triangoli, manipolandone i vertici. Queste operazioni vengono svolte mediante prodotti tra matrici, che generalmente provocano
milioni di operazioni in virgola mobile al secondo. Oltre ai valori di posizione dei vertici,
anche le normali, ossia i vettori perpendicolari a ciascuna faccia, e le texture sono processate. Al termine di questo passaggio, i triangoli sono posti in un sistema di riferimento 3D in
cui lo spettatore posizionato nellorigine degli assi ed allineato con lasse z.

Figura 1: Processo di elaborazione dei vertici. Fonte: matrix44.net

Ogni vertice definito da una matrice colonna formata da 4 valori: x, y, z, w. Questi valori,
nella geometria proiettiva, prendono il nome di coordinate omogenee. Attraverso luso
delle coordinate omogenee, possibile proiettare un oggetto tridimensionale su un piano
proiettivo a coordinate omogenee. Indichiamo questo piano come piano di vista, mentre
chiamiamo centro di prospettiva il punto dal quale si osserva loggetto.

2.2 Elaborazione dei vertici | 5


Per poter ottenere le coordinate cartesiane del vertice, necessario eseguire le seguenti
divisioni:
x
y
z
y=
z=
w
w
w
La prima operazione della pipeline generare le coordinate globali del vertice. Questo processo avviene utilizzando le operazioni di traslazione, rotazione e scalatura. E possibile
eseguire queste operazioni mediante le matrici di:
x=

Traslazione:

0
T =
0

0
1
0
0

0
0
1
0

Rotazione su X:

1
0
0
0

0 cos() sin() 0

Rx =
0 sin() cos() 0

0
0
0
1
Rotazione su Y :

cos( )

0
Ry =
sin( )

0 sin( ) 0

1
0
0

0 cos( ) 0

0
0
1

Rotazione su Z:

cos() sin() 0 0

sin() cos() 0 0

Rz =

0
0
1
0

0
0
0 1

6 | Pipeline di elaborazione 3D
Scalatura:

sx 0

0 sy
S=
0 0

0 0

0
0
sz
0

La matrice finale di tutte le operazioni da eseguire sul vertice sar quindi il prodotto delle
precedenti matrici, ovvero T Rx Ry Rz S

sx cos()cos( )
sy sin()cos( )
sz sin( )
x
sx cos()sin( )sin() + sx sin()cos() sy cos()cos() sy sin()sin( )sin() sz cos( )sin() y

=
sx sin()sin() sx cos()sin( )cos() sy sin()sin( )cos() + sy sin()cos() sz cos( )cos() z
0
0
0
1

Per esempio, prendiamo in considerazione il seguente cubo.

Figura 2: Cubo con coordinate locali. Fonte: matrix44.net


Se volessimo spostare il cubo di 2 unit sullasse X e ruotarlo di 30 gradi sempre sullo stesso
asse, la matrice W diventerebbe:

1+3
2

1 3
2
0

1+ 3
2
1+ 3
2

1
2
3
2

2.2 Elaborazione dei vertici | 7


Risolvendo il prodotto tra la matrice W e i vettori colonna corrispondenti ad ogni punto del
cubo (es. V4 )

1+3
2

1 3
2
0

1+ 3
2
1+ 3
2

1
2
3
2

2
3
1
23+1


1
1 = 2
4+ 3
1
1 2
1
1
1

si ottiene:

Figura 3: Cubo con coordinate globali (calcolato con Matlab)

In seguito necessario eseguire le trasformazioni dovute al movimento del punto di vista. Queste operazioni sono le stesse eseguite in precedenza, con la differenza che vengono
usati i valori di spostamento / rotazione del punto di vista e vengono utilizzate le matrici
inverse moltiplicate nellordine opposto (ad esempio, se il punto di vista si muove a sinistra, gli oggetti devono muoversi a destra). Come ultima operazione necessario simulare
la distorsione dovuta alleffetto della prospettiva, che ci permette di valutare le distanze in
unimmagine 2D. La matrice prospettica provoca la deformazione causata dal frustum, cio
dal tronco di piramide che rappresenta linquadratura del punto di vista. In una proiezione
prospettica, le rette parallele diventano incidenti allinfinito e quindi si ha una deformazione
dellimmagine che permette, ad esempio, di rappresentare gli oggetti pi vicini di dimensioni maggiori rispetto agli oggetti piu lontani. La distorsione prospettica viene realizzata

8 | Pipeline di elaborazione 3D
utilizzando la seguente matrice:

1
tan

1
tan0

0
0

B+F
BF

2BF
BF
0

In essa, langolo tra lasse Z (direzione del punto di vista) e il bordo destro dello schermo, e langolo tra lo stesso asse e la parte superiore dello schermo. F la distanza
minima visibile dal punto di vista (vengono mostrati gli oggetti solo oltre quella distanza) e
B la distanza massima visibile dal punto di vista.

2.2.1

Geometria proiettiva

Poich il display in 2D e la scena in 3D, deve essere eseguita una proiezione su un piano
2D di un modello 3D. La geometria euclidea descrive le forme per come sono, pertanto le
propriet di un oggetto non vengono cambiate da trasformazioni rigide. La geometria proiettiva, invece, la parte della matematica che studia le proiezioni e descrive come appaiono
gli oggetti nella realt. Pensiamo, ad esempio, ad una strada dritta e piana: i suoi margini
possono essere considerati linee parallele, la cui distanza, per la geometria euclidea, rimane costante. Tuttavia nella nostra esperienza vediamo queste linee avvicinarsi sempre di
pi allaumentare della distanza. La geometria proiettiva, pertanto, ci consente di descrivere
questo tipo di fenomeno. Come la geometria euclidea, anche quella proiettiva include alcuni
assiomi. I principali sono:
Due punti distinti generano un segmento
Due linee distinte si intersecano in un punto
Notiamo che non vengono fatte eccezioni per le linee parallele. Infatti si chiamano punti di
fuga i punti dove le linee parallele del modello sembrano incontrarsi quando proiettate su
un piano. Questo fatto in contrasto con la geometria euclidea, la quale non ammette che le
linee parallele si incontrino. Per passare alla geometria proiettiva, basta prendere un punto
definito nella geometria euclidea e aggiungere unulteriore dimensione che definisce il livello di scalatura. Ad esempio, un punto nello spazio viene definito nella geometria proiettiva
da P = (x, y, z, w). La geometria euclidea non contempla che due linee parallele si incontrino in un punto infinito proprio perch non ammette il concetto di scalatura. Se w = 1,
otteniamo lo spazio euclideo scalato di 1; se w = 2, otteniamo di nuovo lo spazio euclideo

2.2 Elaborazione dei vertici | 9


ma raddoppiato di dimensioni. Non possiamo utilizzare w = 0 perch non riusciremmo a
distinguere le distanze con un fattore di scalatura pari a 0. Se vogliamo quindi un cubo in
prospettiva possiamo definire la faccia frontale con w = 1 e la faccia posteriore con w = 2.
E possibile quindi proiettare tutte le facce del cubo nello spazio euclideo (w = 1), dividendo
tutte le coordinate per w. In questo modo le coordinate della faccia posteriore saranno dimezzate. Poich la scalatura varia linearmente, possiamo poi unire le facce con delle linee.
Riassumendo, la geometria proiettiva ci consente di variare la scalatura dello spazio ad ogni
punto grazie ai vari valori di w. Possiamo poi tornare allo spazio euclideo a 3 dimensioni
dividendo le tre coordinate per w. Per effettuare quindi una proiezione sullo schermo, basta
eseguire una proiezione parallela (ovvero togliere la dimensione z). Esiste tuttavia un altro
modo per descrivere la geometria proiettiva. Pensiamo alle coordinate omogenee come se
(x, y, z) definissero una direzione e w definisse la profondit/scalatura lungo quella direzione. Quando abbiamo detto, in precedenza, che due linee parallele nella geometria euclidea
non si incontrano, intendevamo affermare che non importa quanto lontano si vada: poich le
linee mantengono sempre la stessa distanza luna dallaltra, esse non si incontreranno mai,
anche se hanno in comune la stessa direzione.
Al piano euclideo, aggiungiamo quindi un punto infinito nella stessa direzione di ogni possibile coppia di linee parallele. Con laggiunta dei punti infiniti, esso forma un piano proiettivo. Ogni punto infinito viene perci definito come punto in comune tra due linee parallele.
Tutte le rette, pertanto, hanno un punto in comune: o quello dellintersezione, dotato di
direzione e di scalatura, o quello infinito, dotato di una direzione e con infinita profondit/scalatura. Un punto infinito e uno finito descrivono una linea, mentre due punti infiniti
definiscono una linea che contiene solo punti infiniti. Il punto di fuga , pertanto, la proiezione di un punto infinito condiviso da due linee parallele. E possibile rappresentare i
punti allinfinito ponendo w = 0 poich, nella geometria proiettiva, se le linee parallele si
incontrano allinfinito, non c distanza tra di loro. Un punto (x, y, z, 0) quindi un punto
allinfinito in direzione x, y, z. Se w invece un altro valore, il punto rappresenta un punto
finito ad un dato livello di scalatura. Infatti, mettendo a sistema le equazioni di due rette
parallele distinte rappresentate in coordinate non omogenee, esso non otterrebbe soluzione.
Se le guardiamo invece come equazioni omogenee, con tutti i termini associati ad un asse,
la soluzione esiste in w = 0.

2.2.2

Quaternioni di Hamilton

Possiamo notare come le rotazioni attraverso le matrici siano particolarmente complesse.


Per questa ragione, per rappresentare le rotazioni nella grafica 3D, vengono molto spesso

10 | Pipeline di elaborazione 3D
usati i quaternioni di Hamilton, cio numeri con tre parti immaginarie ed una reale. Questo ci consente di rappresentare sinteticamente rotazioni su un asse e di eseguire in modo
semplice e veloce rotazioni complesse. Lutilizzo di questo insieme numerico permette anche una maggiore efficienza per quanto riguarda la definizione di rotazioni nello spazio. I
quaternioni sono un insieme numerico in cui un valore viene rappresentato da:
a + bi + c j + dk
In questa rappresentazione, a, b, c, d sono numeri reali e i, j, k sono simboli letterali. Nei
quaternioni valgono le relazioni:
i2 = j2 = k2 = i jk = 1
Esse implicano anche:
ij = k
jk = i
ki = j
ji = k
k j = i
ik = j
Dati i due quaternioni:
p = p0 + p1 i + p2 j + p3 k
q = q0 + q1 i + q2 j + q3 k
sono definite le seguenti operazioni:
p + q = (p0 + q0 ) + (p1 + q1 )i + (p2 + q2 ) j + (p3 + q3 )k

pq = (p0 q0 p1 q1 p2 q2 p3 q3 ) + (p0 q1 + p1 q0 + p2 q3 p3 q2 )i+


+(p0 q2 + p2 q0 + p3 q1 p1 q3 ) j + (p0 q3 + p3 q0 + p1 q2 p2 q1 )k

2.2 Elaborazione dei vertici | 11


Un quaternione possiede anche un inverso, ricavabile tramite la relazione:
q1 =

q
|q|2

con q coniugato di q:
q = q0 q1 i q2 j q3 k
Notiamo che la formula del prodotto tra quaternioni molto simile a quella del prodotto di
due numeri complessi. Mentre laddizione gode della propriet commutativa e associativa,
la moltiplicazione non possiede la propriet commutativa, ma solo quella associativa. Per
questo i quaternioni fanno parte dellalgebra non commutativa. Questo insieme numerico ci
consente di memorizzare un asse, definito dalle componenti immaginarie, e quanto il punto
ruoter su quellasse (valore ricavato dato dalla componente reale). La rotazione avviene in
senso orario se il nostro punto di vista condivide la direzione del vettore che indica lasse.
Dati quindi un punto p (x, y, z) e un quaternione q, per far ruotare il punto baster eseguire
il prodotto
p0 = qpq1
In esso, il quaternione q definito come:
 
 
 
 

q = cos
+ sin
ux i + sin
uy j + sin
uz k
2
2
2
2
E inoltre possibile effettuare velocemente concatenazioni di rotazioni. Ruotare usando q1
e poi usando q2 uguale a ruotare usando q3 = q2 q1 . Infatti

Dimostrazione.
p0 = q1 pq1
1
p00 = q2 p0 q1
2
1
= q2 (q1 p q1
1 ) q2
1
= (q2 q1 ) p (q1
1 q2 ) per la propriet associativa del prodotto

= (q2 q1 ) p (q2 q1 )1
Quindi, con q3 = q2 q1
p00 = q3 pq1
3

12 | Pipeline di elaborazione 3D

E anche possibile passare da un quaternione ad una matrice di rotazione. Ad esempio, dato


il quaternione a = q0 + q1 i + q2 j + q3 k, la corrispondente matrice di rotazione sar:

1 2(q22 + q23 ) 2(q1 q2 q0 q3 ) 2(q0 q2 + q1 q3 )

2(q1 q2 + q0 q3 ) 1 2(q21 + q23 ) 2(q2 q3 q0 q1 )

2(q q q q ) 2(q q + q q ) 1 2(q2 + q2 )


0 2
0 1
2 3
1 3
2
1
0
0
0

2.3

Rasterizzazione dei triangoli

I triangoli vengono rasterizzati in frammenti (pixel candidati). Ogni triangolo rasterizzato


indipendentemente dagli altri, perci questa una fase che viene svolta in parallelo. Nelle
GPU moderne, i triangoli che non sono inclusi nel campo visivo o che sono nascosti da altri
triangoli non vengono rasterizzati, in modo da aumentare le prestazioni. Il frammento viene
generato solo se il suo centro allinterno del triangolo.

Figura 4: Processo di rasterizzazione. Fonte: cs.cmu.edu


Per conoscere quale triangolo posto davanti e quanto un oggetto nasconda un altro, viene
utilizzato lo z-value, valore che prende il nome dallasse z (profondit). Il metodo di confronto tra i diversi z-value consiste nellassegnare per ogni frammento un numero in base a
quanto loggetto distante dal punto di vista. Pi vicino al punto di vista, e pi il numero
basso. Per esempio uno z-buffer (memoria che contiene gli z-value) da 16 bit assegnerebbe il numero -32768 ad un frammento che si trovi pi vicino possibile al punto di vista e

2.4 Elaborazione dei frammenti | 13


32767 ad un oggetto che si trovi il pi lontano possibile. Per ogni frammento creato, il suo
z-value viene confrontato con quello dei frammenti che occupano le stesse coordinate x e y
e il frammento con lo z-value minore viene renderizzato. Poich lo z-buffer viene utilizzato
prima che gli oggetti siano interamente rasterizzati, le parti della scena nascoste non devono
essere renderizzate, consentendo cos un incremento di prestazioni.

2.4

Elaborazione dei frammenti

Dopo la rasterizzazione dei triangoli, si procede a calcolare un colore per ogni frammento
in modo parallelo, poich loperazione non dipende da altri frammenti. Se richiesto, per il
calcolo del colore vengono utilizzate texture, ovvero immagini che vengono proiettate sul
modello per migliorarne la resa visiva. Il calcolo del colore comprende anche il calcolo per
la proiezione delle texture e coinvolge la normale del triangolo, calcolata grazie alle normali di ogni vertice. La GPU procede, quindi, con il calcolo del colore di ogni triangolo
sommando i contributi dati dalle sorgenti luminose della scena. Questa fase pu essere programmata in modo da ottenere un controllo totale sul processo con cui la GPU colora i pixel.
Generalmente si implementano equazioni che consentono di fornire una resa fotorealistica
del colore. Una di queste lequazione Phong. In questo caso, lequazione da calcolare per
ogni frammento :
Colore(RGB) = ka ia +

(kd (Lm N)id ) + Ks (Rm V )a is

mluci

dove:
Lm il vettore che congiunge il punto della superficie con la sorgente luminosa
N la normale nel punto di cui si calcola il colore sulla superficie
Rm la direzione che un raggio perfettamente riflesso prenderebbe a partire da questo
punto
V la direzione verso lo spettatore
Per ogni luce:
is lintensit (RGB) del componente speculare della luce
id lintensit (RGB) del componente diffusivo della luce

14 | Pipeline di elaborazione 3D
ia la costante corrispondente alla luce ambientale. Viene a volte calcolata come
somma dei contributi forniti dalle varie sorgenti luminose
Per il materiale:
Kd la costante di riflessione diffusiva, ovvero la percentuale di luce entrante
che viene diffusa (riflettenza Lambertiana)
Ka la costante di riflessione dambiente, ovvero la percentuale di riflessione
della luce ambienteale presente in ogni punto della scena
N la normale della superficie
Ks la costante di riflessione speculare, ovvero la percentuale di luce entrante
che viene riflessa
a la costante di lucentezza del materiale, che determina in quale modo la luce
viene riflessa
In questo modo lintensit della componente diffusiva varia a seconda della direzione della
superficie, mentre lintensit della luce ambientale costante.

2.5

Unione dei frammenti

I frammenti sono quindi memorizzati nel framebuffer (memoria video). Nelle GPU moderne, le informazioni relative al colore vengono compresse per ridurre la banda utilizzata. Le
GPU pi vecchie eseguivano il test con lo z-buffer in questa fase.

Capitolo 3
Illuminazione
3.1

Introduzione

Nella fase di rendering si genera limmagine rappresentante la scena. Uno dei componenti pi importanti per una resa fotorealistica dellimmagine il calcolo dellilluminazione.
Molti sono i procedimenti disponibili, ma generalmente esistono due categorie di rendering,
relative ad altrettanti modelli di trasporto della luce: illuminazione locale e illuminazione
globale. Nellilluminazione locale, i singoli oggetti vengono visualizzati tenendo conto
unicamente della loro interazione ottica con le sorgenti luminose della scena, come se si
trovassero isolati in un spazio vuoto. In questo caso, nellimmagine non sono visibili ombre
proiettate, riflessioni o rifrazioni di alcun tipo. Nellilluminazione globale, invece, viene
simulata la propagazione dellenergia luminosa nellambiente della scena. In questo caso
saranno visibili tutti gli effetti ottici, rappresentabili utilizzando le equazioni che descrivono
il trasporto della luce, come, ad esempio le ombre, i riflessi, le rifrazioni.
Sebbene sia un calcolo semplificato, lilluminazione locale permette di visualizzare abbastanza bene le forme degli oggetti. Considerando che i tempi di rendering per il modello
locale sono assai ridotti rispetto al modello globale, lilluminazione locale molto utilizzata
nelle applicazioni interattive (real-time). Ad esempio i software per la modellazione interattiva di una scena utilizzano la visualizzazione con illuminazione locale. Combinandola
con altre tecniche di resa realistica delle immagini, lilluminazione locale utilizzata per
il rendering nei videogiochi, nei simulatori di realt virtuale, nel Computer Aided Design
(CAD) e in tutte le applicazioni interattive di grafica computazionale.
Il modello di illuminazione pi utilizzato attualmente per generare immagini, per, lilluminazione globale, poich consente di simulare correttamente fenomeni luminosi presenti
nella realt. Eseguire il rendering fotorealistico di una scena con illuminazione globale vuol

16 | Illuminazione
dire calcolare lenergia luminosa che raggiunge losservatore, supposto che costui si trovi
in una posizione in cui la scena sia visibile. Quindi, preso un punto qualsiasi della scena,
necessario calcolare lenergia che emette il punto in direzione dellosservatore (la quantit
di luce che vede losservatore in quel punto). Lespressione di questa quantit verr formulata dallequazione di rendering. Avendo come obiettivo la misurazione di questa energia
al fine di riprodurre unimmagine sintetica, necessario interporre un sensore discreto tra
losservatore e la scena, ovvero uno schermo costituito da pixel (picture element). Poich
losservatore vede infiniti punti della scena attraverso un singolo pixel, sar necessario calcolare lenergia luminosa complessiva emessa da ogni pixel, ovvero il flusso luminoso che
passa attraverso esso.

3.2

Percorsi di luce

Osserviamo che la luce, raggiunta una superficie, pu essere riflessa specularmente o diffusamente
la riflessione diffusa avviene quando un singolo raggio di luce incidente la superficie
A in un punto x non viene riflesso con una direzione specifica, bens viene diffuso in
molte direzioni casuali
la riflessione speculare si ha quando un singolo raggio di luce incidente la superficie A
in un punto x produce un singolo raggio riflesso con direzione determinata dalle leggi
fisiche.

Figura 5: Riflessione diffusa. Fonte: fedoa.unina.it

3.3 Equazione di rendering | 17

Figura 6: Riflessione speculare. Fonte: fedoa.unina.it


Questo comportamento ambivalente nella riflessione della luce dovuto alla natura microscopica del materiale che costituisce la superficie delloggetto. Ad esempio, i materiali
metallici levigati tendono a comportarsi specularmente, mentre i materiali porosi diffondono la luce senza alcuna riflessione. Pertanto, la luce che proviene da una superficie A e
che raggiunge una superficie B pu essere originata da un fenomeno speculare o diffusivo e
altres pu proseguire dalla superficie B specularmente o diffusamente.

3.3

Equazione di rendering

La prima equazione di rendering introdotta nella letteratura della Grafica Computazionale


stata quella di Kajiya del 1986, meglio nota come equazione di rendering di Kajiya:
0

I(x, x ) = g(x, x )[(x, x ) +

(x, x0 , x00 )I(x0 , x00 ) dx00 ]

dove:
I(x, x0 ) lintensit della luce che passa dal punto x al punto x0 (intensit di trasporto)
g(x, x0 ) la funzione di visibilit tra x e x0 . Se tra x e x0 non possibile tracciare
un raggio di luce diretto, ovvero un segmento che non interseca altre superfici, allora
g(x, x0 ) = 0 . Se invece possibile, g varia come linverso del quadrato della distanza
tra i due punti (legge fisica di decadenza della luce).
(x, x0 ) lemittanza trasferita da x0 a x ed relativa allintensit di tutta la luce emessa
da x0 in direzione di x

18 | Illuminazione
(x, x0 , x00 ) il termine diffusivo rispetto alle direzioni x0 e x00 e consiste nellintensit
di energia proveniente dal punto x00 e diffusa verso x dal un punto x0
Lintegrale definito su A, cio su tutti i punti di tutte le superfici nella scena. Dal punto
di vista fisico, lequazione vuole rappresentare lintensit di trasporto luminoso dal punto
x0 al punto x, che risulta essere uguale alla quantit di luce emessa da x0 verso x sommata
alla quantit di luce proveniente da tutte le altre superfici nella scena e diffusa da x0 verso
x. E possibile notare come lequazione di rendering sia riconducibile a unequazione di
Fredholm del secondo tipo, ovvero:
Z

a(x) = b(x) +

K(x, y)a(y) dy
A

con b(x) e K(x, y) funzioni date, A dominio di integrazione e a(x)funzione incognita. Nel
considerare lequazione di Kajiya si pu osservare che:
non ha una soluzione esplicitamente calcolabile. Gran parte dei metodi di risoluzione
impongono ipotesi restrittive che implicano risultati poco accurati, ovvero risultati
che producono immagini di scarsa qualit visiva. Molti algoritmi utilizzano il metodo
Monte Carlo per la valutazione dellintegrale
questa formulazione indipendente dal punto di vista dellosservatore, poich il punto
x0 un punto qualsiasi della scena. Pi in generale il problema dellilluminazione
globale pu essere affrontato in maniera sia indipendente sia dipendente dal punto di
vista dellosservatore.
Un approccio molto utilizzato nella Grafica Computazionale per risolvere questequazione
quello di tracciare dei raggi a partire dal piano dellimmagine, costruendo un percorso di
oggetto in oggetto fino ad ottenere una stima del valore del pixel. La complessit dipende
dal numero di percorsi tracciati.

3.4

Metodi risolutivi

Lintroduzione di metodi stocastici per la soluzione del problema dellilluminazione globale motivata dalla necessit di rappresentare scene in cui sono presenti superfici di varia
natura. Volendo infatti superare le limitazioni di altri metodi di calcolo, appare necessario
introdurre un metodo che permetta la valutazione delle equazioni di Fredholm del secondo tipo. Sono perci presenti molti algoritmi basati sul metodo Monte Carlo per il calcolo

3.4 Metodi risolutivi | 19


dellilluminazione globale. Partendo dallequazione di Fredholm del secondo tipo generica,
posto x0 = x e x1 = y, mediante procedimenti algebrici si perviene alla forma:
Z

a(x0 ) = b(x0 ) +

n
n=1 D

K(xk1, xk )

b(xn )dx1:n

k=1

che risulta essere una somma infinita di integrali. Applicando il metodo Monte Carlo si pu
stimare il valore di a in un punto x0 come:
1 N K(x0 , yi )a(yi )
[
a(x0 ) = b(x0 ) +
N i=1
p1 (yi )
dove p1 (y) una funzione di densit di probabilit su dominio D con la quale generiamo N
campioni yi . Attraverso ulteriori procedimenti algebrici, possibile arrivare alla forma:
1 N K(x0 , yi )
[
a(x
0 ) = b(x0 ) +
p1(yi)
N1 i=1

1
b(yi ) +
N2

!
K(yi , z j )
(b(z j ) + ...)

j=1 p2 (z j |yi )
N2

Poich siamo interessati a valutare questultimo stimatore in un tempo finito, necessario introdurre un criterio di arresto per la sommatoria. Per ovviare alla distorsione che si
introdurrebbe nellinterruzione arbitraria dopo un certo numero di iterazioni, opportuno
utilizzare il concetto di assorbimento per determinare se un certo termine della somma debba
essere valutato oppure se occorra interrompere il procedimento.
Definizione. Si consideri un procedimento iterativo infinito. Sia u una variabile casuale
uniforme in [0, 1]. Se alliterazione i la variabile u(i) minore di un certo coefficiente ,
detto di assorbimento, allora il procedimento si interrompe in quella iterazione; altrimenti,
il procedimento continua con literazione successiva.
Nel nostro caso, presa una variabile casuale u uniforme, la sommatoria si interrompe al
passo i se u(i) < ; altrimenti, si procede con loperazione di somma. Questa procedura
garantisce che la stima con assorbimento non cambi il valore atteso dellesperimento.
Si pu notare che il numero di campioni richiesti per la stima di ogni termine della somma
cresce molto rapidamente. Per stimare, ad esempio, la somma dei primi due termini sono
necessari N1 N2 nuovi campioni. Generando nuovi campioni ad ogni passo, si costruisce
un albero di campioni che si ramifica per ogni elemento. Scendendo nelle ramificazioni
di tale albero, i termini pi bassi contribuiscono sempre meno alla stima di a(x0 ). Se si
procedesse a troncare questi termini dopo un fissato numero di iterazioni, si introdurrebbe
per una distorsione nella valutazione.

20 | Illuminazione

Figura 7: Albero per la valutazione di a(x0 )


Un approccio per ovviare a questa distorsione pu essere quello di valutare un solo campione per ogni termine di ciascun ramo dellalbero, ovvero generare una Catena di Markov
(cammino casuale).

Figura 8: Esempio di cammino casuale


In tal caso la stima diverrebbe:
0

00

K(x0 , x ) 0
K(x0 , x )K(x , x )
[
a(x
b(x ) + 0 0 00 00 0 b(x00 ) + ...
0 ) = b(x0 ) +
0
0
p (x )
p (x )p (x |x )
Ci si aspetta che la varianza associata a questa stima sia molto alta, poich risente dellapprossimazione di una sommatoria di N numeri con un solo valore. Ma poich in questo
modo sono stati generati molti meno campioni per la valutazione dellintero albero, si pu
cercare di ottenere una stima pi accurata generando altri cammini casuali. Generando
Ncamm cammini casuali, originati in a(x0 ), e poi calcolando la media delle stime ottenute,
lo stimatore diventa:

[
a(x
0) =

Ncamm
1
K(x0 , x0 ) 0
K(x0 , x0 )K(x0 , x00 ) 00
(b(x
)
+
b(x
)
+
b(x ) + ...)
0

Ncamm i=1
p0 (x0 )
p0 (x0 )p00 (x00 |x0 )

3.5 Implementazione | 21
Esistono molti algoritmi basati sui cammini casuali. Uno di quelli pi utilizzati consente di calcolare i cammini casuali partendo dal punto di vista dello spettatore (quindi dai
pixel mostrati a schermo) fino alla sorgente luminosa. Si procede quindi eseguendo un
campionamento nellarea dei pixel e si stimer la radianza nei punti scelti.

3.5

Implementazione

Lalgoritmo genera un certo numero di cammini casuali dai pixel dellimmagine fino alla
sorgente luminosa. Ogni cammino deve eseguire una sequenza di operazioni indipendenti,
pertanto lesecuzione si presta molto bene alla suddivisione in thread indipendenti e, quindi,
al calcolo mediante GPU (algoritmo di tipo General Purpose Graphics Processing Unit o
GPGPU). Ogni thread di un blocco, infatti, deve accedere ai dati relativi ad un punto diverso del modello. Si pu quindi affermare che i metodi stocastici garantiscono una buona
resa grafica e che si otterr un miglioramento prestazionale sensibile dovuto alla loro implementazione su GPU. Di seguito viene descritto in pseudocodice lalgoritmo per il calcolo
dellilluminazione globale tramite il metodo dei percorsi dallosservatore alla luce.
E innanzitutto necessario definire:
x il punto da cui si parte per calcolare la radianza;
theta la direzione verso la quale si vuole calcolare la radianza;
r la funzione di raycasting (descritta dalla fisica);
L la radianza in x con direzione theta;
emit la funzione che restituisce la radianza emessa da x;
trova_theta una funzione che identifica la direzione del raggio che dal punto x
raggiunge losservatore;
nuova_direzione una funzione che calcola una nuova direzione per il percorso di
luce. Se il materiale diffusivo si utilizzer un metodo casuale, se speculare, si
useranno le leggi ottiche della riflessione/rifrazione;
eps_rel la massima accuratezza relativa a L
tol la tolleranza richiesta

22 | Illuminazione
Pseudocodice
do {
maxdiff =0;
f o r ( i = 0 ; i < n u m _ p i x e l ; i ++)
{
theta=trova_theta ( osservatore , pixel );
x= r ( o s s e r v a t o r e , t h e t a ) ;
throughput =0;
while ( assorbimento )
{
theta_lux= trova_theta (x , luce ) ;
lux=r (x , theta_lux ) ;
L= e m i t ( l u x , t h e t a _ l u x ) * BRDF( x , t h e t a _ l u x , t h e t a )
* cos ( x , t h e t a _ l u x ) ;
t h r o u g h p u t = t h r o u g h p u t +L ;
theta =nuova_direzione ( diffusiva o speculare ) ;
x= r ( x , t h e t a ) ;
}
i f a b s ( t h r o u g h p u t p i x e l [ i ] ) > m a x d i f f
{
m a x d i f f = a b s ( t h r o u g h p u t p i x e l [ i ] ) ;
}
p i x e l [ i ]= t h r o u g h p u t ;
}
}
w h i l e ( m a x d i f f <max ( e p s _ r e l , t o l ) ) ;

Capitolo 4
La scheda video
4.1

Componenti principali

La scheda video il componente hardware pi importante per il processo di rendering 3D,


nonch quello che svolge la maggior parte delle operazioni. La scheda video consente di
creare immagini a partire dai dati binari elaborati dalla CPU. La CPU manda informazioni
alla scheda video, che crea limmagine e invia i colori dei pixel allo schermo. I componenti
principali della scheda video sono:
la memoria video (o, come viene pi frequentemente chiamata, framebuffer): contiene i dati di ogni pixel (posizione e colore) e pu memorizzare, per quanto riguarda
il rendering 3D, informazioni sulla scena da renderizzare, come le texture. Funziona
a frequenze elevate ed possibile leggere e scrivere contemporaneamente (dual porting). La sua dimensione varia generalmente tra i 512 Mb e gli 8 Gb. Anche parte
della RAM di sistema pu essere usata come framebuffer, specialmente se la scheda
video non dedicata, cio nel computer non presente un componente hardware apposito, ma integrato nel processore. La memoria video basata su banchi SDRAM,
generalmente DDR (SDRAM che trasmette dati sia sul fronte di salita che su quello
di discesa del clock). Pi grande il framebuffer e maggiore la risoluzione gestibile,
la quantit di colori e le texture memorizzabili
il RAMDAC: il componente che deve leggere il framebuffer e convertirlo in un segnale RGB da inviare al monitor. E necessario per trasformare in formato analogico
i dati memorizzati in formato digitale dalla GPU. Ogni colore corrisponde ad un certo voltaggio. Visto che per rappresentare un colore viene usata la combinazione dei

24 | La scheda video
3 segnali RGB, ci sono 3 DAC che si occupano di effettuare questa operazione. La
frequenza con cui la transcodifica viene effettuata definita come refresh rate
il processore grafico o GPU: lunit che esegue i calcoli. Per la scheda video svolge
il ruolo che ha la CPU allinterno del computer
La seguente tabella illustra la risoluzione e i colori gestibili dalla scheda video in base al
variare della dimensione del framebuffer.
Memoria video
1 MB
2 MB
4 MB
6 MB
8 MB

4.2

Risoluzione
800x600
1024x768
800x600
1024x768
1024x768
1280x1024
1600x1200

Prof. Colore
16 bit
8 bit
24 bit
8 bit
24 bit
24 bit
24 bit

Num. Colori
65536
256
16,7 milioni
256
16,7 milioni
16,7 milioni
16,7 milioni

La GPU

Il processore grafico (Graphic Processing Unit o GPU) un circuito elettronico realizzato


appositamente per monitorare e modificare il contenuto della memoria grafica e accelerare la costruzione delle immagini da visualizzare tramite lo schermo. Sebbene esso operi
a frequenze minori della CPU, pi veloce ad eseguire le operazioni per cui stato appositamente progettato. Le prime schede grafiche senza GPU contribuivano a rallentare il
sistema su cui erano installate. La CPU, infatti, doveva svolgere tutto il lavoro di elaborazione dellimmagine e i continui trasferimenti di dati nel bus intasavano le altre attivit.
Questo problema fu risolto dal processore grafico. Grazie alla GPU, il processore del PC
non deve pi compiere tutti i calcoli per fornire alla scheda limmagine da inviare al monitor, ma solamente fornire alla scheda una serie di istruzioni che poi il chip elabora da solo.
Grazie al supporto del processore grafico, non solo la CPU svolge meno lavoro, ma anche i
bus dei dati sono meno congestionati, ottenendo quindi un doppio beneficio. La GPU attualmente viene utilizzata soprattutto nella grafica 3D. Nella grafica 2D, infatti, i dati vengono
elaborati dalla CPU e allocati dalla GPU nel framebuffer. Quando invece viene elaborata
unimmagine 3D, la CPU del computer si occupa del calcolo delle coordinate geometriche
dei vertici dei poligoni e lascia alla GPU il compito di riempire le facce, il calcolo delle

4.3 CPU e GPU | 25


ombre, degli effetti grafici e la generazione dellimmagine finale, evitando pesanti operazioni di calcolo. La GPU, inoltre, essendo progettata specificatamente per questo compito,
lo svolge in modo pi efficiente. E, infatti, specializzata nelleseguire calcoli matematici e
geometrici complessi velocemente e su grandi quantit di dati. Per questo motivo, alcune
GPU hanno pi transistor delle attuali CPU. I maggiori produttori di GPU sono Nvidia e
Ati (AMD). Ogni produttore ha aggiunto caratteristiche proprietarie e ottimizzazioni alle
sue GPU. Le pi famose sono CUDA (NVidia) e TressFX (Ati). Alcuni programmi sono
inoltre sviluppati in modo da funzionare meglio sulle GPU di una specifica marca, poich
utilizzano le caratteristiche proprietarie (ad esempio PhysiX, la tecnologia di simulazione
della fisica per GPU creata da NVidia).

Figura 9: GPU Nvidia (sinistra) e AMD Ati (destra). Fonte: trustedreviews.com

4.3

CPU e GPU

La differenza principale tra CPU e GPU dipende dal ruolo per cui sono state progettate
e, quindi, dal modo in cui gestiscono la latenza ed il throughput. La latenza il tempo
trascorso da quando qualcosa accade al momento in cui i suoi effetti sono percepibili: ad
esempio il tempo tra larrivo del segnale di movimento del mouse e leffetto del cursore che
si sposta. Il throughput , invece, il rapporto tra il lavoro svolto e il tempo impiegato: ad
esempio quanti triangoli vengono processati al secondo. Le principali differenze tra CPU e
GPU sono:
La CPU un processore:
intollerante alla latenza
a bassa latenza e basso throughput

26 | La scheda video
permette il parallelismo sulle attivit da svolgere (task)
con cores multi-thread
con un numero non elevato di thread in esecuzione (decine)
La GPU un processore:
tollerante alla latenza
ad alta latenza ed alto throughput
permette il parallelismo sui dati
con cores SIMD (Single Instruction Multiple Datas)
con un numero molto elevato di thread in esecuzione (decine di migliaia)
Le GPU sono quindi create per lavori che prevedono una tolleranza sul tempo di latenza
come, ad esempio, la generazione delle immagini in tempo reale:

Figura 10: Comunicazione tra CPU e GPU nel rendering real-time. Fonte: NVidia
Per essere efficiente, la GPU deve avere un alto throughput, ovvero processare milioni di
pixel per ogni frame in poco tempo. La CPU, invece, stata creata per minimizzare la
latenza. Per questo, a differenza della GPU, necessaria una grande memoria cache, e,
perci, la GPU pu dedicare pi spazio ai processori di calcolo e incrementare il throughput.

Figura 11: CPU e GPU a confronto. Fonte: NVidia

4.4 La GPU allinterno del computer | 27

4.4

La GPU allinterno del computer

La GPU un coprocessore separato, generalmente connesso al North Bridge del computer.


Il programma eseguito dalla CPU invia la scena e le texture alla GPU, che si occupa di
renderizzarle. La GPU, inoltre, capace di generare segnali VGA, DVI, o HDMI dalla
memoria video.

Figura 12: GPU e gli altri componenti hardware. Fonte: meseec.ce.rit.edu

4.5

Comunicazione tra CPU e GPU

La CPU e la GPU allinterno del PC lavorano in parallelo. Per poter comunicare utilizzano
una memoria speciale chiamata command buffer. Se questo buffer vuoto, la GPU attender
input da parte della CPU. Se il command buffer pieno, invece, la CPU limitata dalla GPU
e attender fino a quando non potr inserire nel buffer il comando da far elaborare alla GPU.
Bisogna ricordare che un programma che utilizza la GPU non segue il modello di esecuzione
sequenziale.

28 | La scheda video
Nellesempio seguente di programma in esecuzione sulla CPU:
Istruzione 1
Chiamata alle API per disegnare un oggetto
Istruzione 2
Loggetto pu non essere disegnato tra listruzione 1 e 2, perch la chiamata delle API non
fa altro che aggiungere listruzione di disegno nel command buffer, senza dare garanzie in
merito a quando loggetto venga effettivamente disegnato dalla GPU.

4.5.1

Problemi di sincronizzazione

Questo fatto crea problemi di sincronizzazione. Nella figura seguente, ad esempio, la CPU
non pu sovrascrivere i dati fino a quando la GPU non ha eseguito il comando in nero, che
fa riferimento a quei dati:

Figura 13: Comandi presenti nel buffer


Le API perci implementano un sistema a semaforo che evita questo tipo di problemi. Se la
CPU tenta di modificare un dato referenziato da un comando GPU in attesa, dovr attendere
fino a quando la GPU non avr finito. Questo, tuttavia, non favorevole per quanto riguarda
le performance. Per evitare questo ulteriore problema, la soluzione migliore allocare un
nuovo blocco di dati e inizializzarlo, in modo da consentire alla CPU di lavorare su questultimo e alla GPU di cancellare il vecchio blocco quando ha finito di utilizzarlo. Le API
moderne svolgono questa operazione automaticamente.

4.6 Architettura di una GPU | 29

4.6

Architettura di una GPU

Fino ad una decina di anni fa, le GPU erano dotate di unit apposite per ogni fase della
pipeline grafica. Di seguito viene presa, ad esempio, la serie NVidia GeForce 6, risalente al
2004.

Figura 14: Archittettura della serie NVidia GeForce 6. Fonte: NVidia


Il processo di rendering inizia quando la GPU riceve comandi, le texture e i dati dei vertici
dalla CPU attraverso il buffer condiviso. I comandi vengono quindi parserizzati. Il passaggio successivo coinvolge lunit di fetch dei vertici, che viene utilizzata per leggere i vertici
referenziati dai comandi di rendering. I comandi e i vertici vengono quindi trasferiti alle
successive fasi della pipeline.
Il vertex processor (o vertex shader) consente di eseguire delle istruzioni per ogni vertice
delloggetto. Queste istruzioni consistono generalmente in trasformazioni geometriche o algebriche su ogni vertice. La serie GeForce 6 consente al programma eseguito su ogni vertice

30 | La scheda video
di caricare delle texture. Lunit di elaborazione dei vertici lavora in singola precisione e il
numero dipende dalla fascia in cui si colloca la scheda video (da due a sei). Poich il vertex
processor deve riuscire ad accedere alle texture, esso viene connesso ad una memoria cache.
Laccesso a questa memoria viene condiviso con lunit di elaborazione dei frammenti. E
anche presente una vertex cache che memorizza le informazioni sui vertici sia prima che
dopo la loro elaborazione, in modo da ridurre la necessit di fetch. Questo significa che se
lo stesso vertice presente due volte in una chiamata di render, le istruzioni di elaborazione
del vertice non devono essere eseguite unaltra volta, ma viene invece utilizzato il vertice
presente in questa memoria.

Figura 15: Vertex processor. Fonte: NVidia


I vertici sono quindi raggruppati in primitive. I blocchi di Cull/Clip/Setup eseguono operazioni sulle primitive, consentendo la rimozione di quelle che non sono visibili (es. escono
dalla visuale dello spettatore) e preparando i dati per la rasterizzazione. Il blocco di rasterizzazione calcola quali pixel sono coperti da ogni primitiva e utilizza lo z-cull block per
scartare velocemente i frammenti che sono coperti da frammenti pi vicini. Se consideriamo i frammenti come pixel candidati, essi subiranno diversi test e, se riescono a superarli,
trasporteranno informazioni relative alla profondit e al colore dei pixel nel framebuffer
(o su altre destinazioni di rendering). La figura illustra seguente il fragment processor (o
pixel shader). Lunit di elaborazione dei frammenti opera con lo scopo di applicare una

4.6 Architettura di una GPU | 31


serie di istruzioni (shader) su ogni frammento in modo indipendente. I dati delle texture
sono memorizzati nella cache in modo da ridurre i requisiti di banda e migliorare le performance. Lunit di elaborazione del frammento opera su un quadrato composto da quattro
pixel (quads) alla volta. Il fragment processor lavora in modo sigle-instruction-multipledata (SIMD), ovvero ogni fragment processor lavora su un frammento alla volta in modo
concorrente.

Figura 16: Fragment processor. Fonte: NVidia


Lunit di fragment processor utilizza lunit di fetch delle texture per eseguire il fetch dei
dati dalla memoria, filtrando opzionalmente i dati prima di inviarli al fragment processor.
Lunit di caricamento delle texture supporta molti formati di immagini, le quali possono
anche essere filtrate utilizzando filtri bilineari, trilineari o anisotropici. Tutti i dati binari
vengono poi utilizzati dal fragment processor in formato floating point a 32 o 16 bit. Una
texture viene quindi vista come un array di dati 2D o 3D che possono essere letti dallunit
delle texture. Il fragment processor possiede due shader fp32. I frammenti vengono guidati attraverso entrambe le unit di shader e attraverso il branch processor, prima di poter
proseguire attraverso la pipeline. Questo accade una volta per ogni ciclo di clock. E possibile eseguire almeno otto operazioni matematiche nel pixel shader per ogni ciclo di clock,
o quattro operazioni matematiche se avviene un fetch delle texture. I frammenti lasciano
lunit di fragment-processing dopo essere stati rasterizzati e sono quindi inviati allunit di

32 | La scheda video
z-compare e blend, che esegue test di profondit e altre operazioni. Il colore finale viene
quindi scritto sulla memoria di destinazione (generalmente il framebuffer). La memoria
partizionata in quattro parti indipendenti. La GPU utilizza moduli DRAM standard invece
di tecnologie personalizzate di RAM per poter ridurre i costi. La creazione di partizioni pi
piccole e indipendenti consente al sistema di gestione della memoria di operare in modo efficiente senza badare a quanto grandi o piccoli siano i blocchi di dati che vengono trasferiti.
Tutte le superifici renderizzate vengono quindi memorizzate nella DRAM, mentre le texture
e i dati in input possono essere anche memorizzati nella memoria di sistema. Le quattro partizioni di memoria danno alla GPU un ampio (256 bit) e flessibile sistema di gestione della
stessa, che consente accessi ad essa relativamente piccoli (32 byte). Ci permette alla GPU
di avvicinarsi al limite fisico di trasferimento dei dati, ovvero 35 GB/sec. Poich lhardware
grafico sta diventando sempre pi programmabile, anche applicazioni diverse dalla pipeline standard iniziano a diventare popolari per lesecuzione sulla GPU. La figura sottostante
mostra in modo semplificato lutilizzo della GPU per la pipeline grafica. In questo modo
una GPU pu essere vista come una grande quantit di unit di elaborazione a singola precisione, che pu essere sfruttata per applicazioni che richiedano una grande dose di calcoli,
anche se non hanno nulla a che fare con la grafica 3D.

Figura 17: Pipeline di rendering 3D con la serie GeForce 6. Fonte: NVidia

4.7 Unified Shader Architecture | 33

4.7

Unified Shader Architecture

LUnified Shading Architecture unarchitettura che consente di fare in modo che tutte le
unit computazionali di una GPU possano gestire ogni tipo di processo di shading. Per
questo larchitettura include anche ununit per il bilanciamento del carico dinamico, che
permette di distribuire il processo di shading su pi unit elaborazionali. Questa architettura
permette un utilizzo pi flessibile dellhardware di rendering. Per esempio, se presente
un grande carico di lavoro riguardante lelaborazione dei frammenti, il sistema pu allocare
la maggior parte delle unit di elaborazione per eseguire il fragment shader. Questa nuova
architettura stata introdotta da NVidia nella serie GeForce 8 e da AMD/Ati con la scheda
Radeon HD 2000. E stata inoltre utilizzata per le GPU di PS3 e Xbox 360. Di seguito
rappresentata larchitettura della serie GeForce 8:

Figura 18: Archittettura della GPU Nvidia GeForce serie 8. Fonte: NVidia

4.7.1

Architettura di ununit di elaborazione

Ununit di elaborazione composta dai seguenti elementi:


memoria cache
8 thread processor dotati di:
calcolo in virgola mobile in singola precisione a 32 bit (standard IEEE 754,
ovvero segno - esponente - mantissa)

34 | La scheda video
calcolo su interi a 32 o 64 bit
registri da 16K a 32 bit
2 SFU (Special Function Units), che permettono operazioni come seno, coseno, logaritmo e potenza
unit per il calcolo in doppia precisione a 64 bit (standard IEEE 754)
16KB di memoria condivisa

4.7.2

GPU attuali

LUnified Shading Architecture viene utilizzata anche per le GPU pi recenti, che hanno
subito un aumento smisurato della potenza e delle unit di calcolo. Ad esempio, la scheda
NVidia GeForce Titan, attuale modello di fascia alta di NVidia, possiede:
7,1 miliardi di transistor
2688 core
224 unit per lelaborazione delle texture
per una potenza complessiva di 4494 Gigaflops.

Figura 19: Architettura della GPU NVidia GeForce Titan. Fonte: NVidia

Capitolo 5
Calcolo distribuito
Come stato visto precedentemente, per il rendering 3D ed il calcolo di effetti come lilluminazione globale richiede una grande potenza di elaborazione. Anche utilizzando algoritmi di tipo GPGPU, il tempo generalmente necessario per il rendering di una scena varia
dalle decine di minuti alle ore di calcolo. Nel caso di video, la situazione, ovviamente, peggiora molto. Per questo, nelle grandi aziende di grafica 3D, si ricorre generalmente a reti di
computer per poter eseguire un calcolo distribuito. Uno dei metodi utilizzati per distribuire
il calcolo su pi computer sfruttare la specifica MPI.

5.1

MPI

MPI lacronimo di Message Passing Interface. Si tratta di una libreria per lo scambio di
messaggi tra diversi processi. MPI , tuttavia, solamente la specifica di una interfaccia, non
la sua implementazione. Esistono, invece, numerose implementazioni di MPI e la pi nota
Open MPI. Lutilizzo principale di MPI nel campo della computazione parallela e distribuita. Per realizzare unelaborazione in modo distribuito, necessaria una comunicazione
tra i vari processi. Esistono due tecniche per effettuarla:
shared-memory: il programma non si deve preoccupare dellesistenza degli altri processi e pu accedere ad una memoria che idealmente condivisa tra tutti i processi. Il componente che realizza larchitettura di shared-memory dovr occuparsi della
comunicazione tra processi tramite messaggi
message-passing: il programma deve farsi carico della comunicazione tra i vari processi. Non c un concetto di memoria condivisa, ma ogni processo pu accedere
unicamente alla propria memoria privata.

36 | Calcolo distribuito
MPI il metodo pi utilizzato per la tecnica di message-passing e, nelle proprie specifiche,
prevede la definizione di una serie di primitive per la comunicazione tra processi. MPI
quindi uno strato middelware, che si colloca tra il programma ed il sistema operativo,
consentendo lo scambio di messaggi.

5.2

Comunicazione tra processi

Consideriamo un sistema distribuito costituito da una serie di nodi connessi tramite una rete
di comunicazione. Su ogni nodo sono presenti uno o pi processi, che vengono eseguiti in
maniera concorrente.

Figura 20: Sistema distribuito. Fonte: simionato.org


MPI consente la comunicazione tra i diversi processi. Deve quindi esserci innanzitutto un
modo per identificare ciascun processo. Il codice numerico che identifica ogni processo
viene chiamato ranking. In MPI, ciascun processo fa parte di un gruppo e ha associato un
ranking, numero naturale che va da 0 ad N-1, dove N il numero di processi del gruppo.

5.2.1

Comunicazione punto-punto

Una delle funzioni pi importanti tra quelle messe a disposizione da MPI la comunicazione
punto-punto.

5.2 Comunicazione tra processi | 37


Per compiere questa operazione, vengono fornite le seguenti funzioni:
MPI_Send ( buf , c o u n t , d a t a t y p e , d e s t , t a g , comm )
MPI_Recv ( buf , c o u n t , d a t a t y p e , s o u r c e , t a g , comm , s t a t u s )
Si tratta di due funzioni bloccanti, perci lesecuzione del programma prosegue solamente
quando un messaggio stato inviato o ricevuto.

Figura 21: Comunicazione punto-punto. Fonte: simionato.org


Per quanto riguarda la funzione Send, non detto che il programma si blocchi fino a quando
il messaggio stato consegnato. Infatti in MPI si distinguono due modalit:
modalit buffered: il controllo ritorna al programma appena il dato da inviare stato
copiato in un buffer. Ci quindi non significa assolutamente che sia stato gi inviato
e ricevuto
modalit sincrona: la funzione termina solamente quando la funzione Receive ha
iniziato la ricezione.
Il funzionamento di default dipende dallimplementazione di MPI, ma possibile forzarlo
tramite le funzioni MPI_Bsend e MPI_Ssend. MPI mette poi a disposizione delle chiamate

38 | Calcolo distribuito
non bloccanti. In questo caso le funzioni ritornano immediatamente, sebbene i dati non siano ancora stati inviati o ricevuti. Il vantaggio delle chiamate non bloccanti lincremento
di performance. Il contenuto dei messaggi che viene effettivamente inviato sui canali di comunicazione dipende dalla specifica implementazione di MPI. Ogni implementazione deve,
tuttavia, garantire il rispetto dellordine di arrivo dei messaggi.

5.2.2

Comunicazione collettiva

Nellambito di una comunicazione parallela spesso utile inviare un messaggio a tutti i


membri del gruppo. Spesso, per, quella che si vuole realizzare non una semplice comunicazione broadcast, ma qualcosa di pi articolato. In molte situazioni, infatti, si vogliono
inviare dati diversi a seconda del destinatario, o si desidera che tutti i nodi inviino un messaggio diverso ad un nodo radice. Immaginiamo, ad esempio, che si voglia applicare un
algoritmo su ogni elemento di una matrice. Sar quindi utile inviare dal nodo root una parte
della matrice ad ogni processo. Successivamente, ogni processo effettuer le computazioni necessarie e dovr rispedire i dati elaborati alla radice. MPI mette a disposizione delle
funzioni per rispondere a tutte queste esigenze.
broadcast: MPI_Bcast(buf,count,datatype,root,comm)
scatter: funzione analoga a quella broadcast, tuttavia il messaggio inviato non lo
stesso, poich si vuole inviare un messaggio diverso per ogni nodo. La funzione
MPI_Scatter (sendbuf, sendcount, sendtype,recvbuf,recvcount,recvtype,root,comm)
gather: compie loperazione inversa della funzione Scatter. In questo caso, tutti i
processi inviano un risultato alla root. La funzione MPI_Gather(sendbuf,sendcount,
sendtype,recvbuf,recvcount,recvtype,root,comm)

5.2.3

Esempio

Supponiamo di voler realizzare delle computazioni su ogni riga di una matrice. Un possibile
esempio potrebbe essere il sottrarre ad ogni elemento la media dei valori della corrispondente riga. Per risolvere questo problema, possiamo dividere la matrice orizzontalmente
in n parti, ed inviarne ciascuna ad un processo. Terminata la computazione, ogni processo
invier al nodo radice la riga con i dati elaborati.

5.3 Topologie virtuali | 39

Figura 22: Esempio di elaborazione distribuita


E possibile trovare il codice sorgente dellesempio, soggetto a licenza Open Source CPAL
1.0, allindirizzo http://git.io/-1z3Fg
Il codice deve essere compilato ed eseguito su sistemi aventi OpenMPI installato. La compilazione deve essere effettuata tramite compilatore mpic++ e lesecuzione deve avvenire
mediante il comando mpirun.

5.3

Topologie virtuali

Con il termine di topologia reale, si intende il modo in cui i vari nodi sono collegati fisicamente, mentre con topologia virtuale definisce un particolare assegnamento di etichette
ai vari nodi. Assegnare una topologia virtuale in MPI implica unicamente un diverso assegnamento del ranking ai vari processi. Un meccanismo di questo tipo pu essere utile in
vari casi. Ad esempio, se si ha una topologia reale particolare, pu essere utile assegnare il
ranking in maniera da rifletterla. Ci pu servire ad incrementare le performance. Se i nodi
sono collegati tramite una rete ad anello, infatti, costruendo una topologia virtuale adeguata
ogni nodo comunicher unicamente con il vicino, ottimizzando le prestazioni. La funzione
per creare un nuova topologia cartesiana la seguente:
M P I _ C a r t _ c r e a t e ( cmm_old , ndims , dims , p e r i o d s , r e o r d e r , comm_crt )
Quindi, se vogliamo costruire un anello, useremo le seguenti funzioni:
MPI_Comm ring ;
int dims []={ N };
int periods []={1};
MPI_Cart_create ( MPI_COMM_WORLD ,1 , dims , periods ,1 ,& ring );

40 | Calcolo distribuito
Per una mesh bidimensionale, invece:
MPI_Comm mesh ;
int dims []={ N , M };
int periods []={0 ,0};
MPI_Cart_create ( MPI_COMM_WORLD ,2 , dims , periods ,1 ,& mesh );

Figura 23: Esempi di topologie virtuali: anello e mesh. Fonte: simionato.org

5.4

Open MPI

Come detto precedentemente, la specifica MPI non definisce le tecniche di comunicazione


tra i processi, che dipendono invece dalla sua implementazione. Ad esempio, se prendiamo
in considerazione la sua implementazione pi diffusa, OpenMpi, e supponiamo che i nodi
siano connessi tramite una rete Ethernet, il protocollo utilizzato di default TCP. Viene perci stabilita una connessione TCP tra i nodi che vogliono comunicare. In questo modo, si
suppone che la trasmissione sia affidabile (ci si affida in questo senso a TCP) e perci il protocollo non prevede acknowledge o timeout. Sempre in merito al modulo TCP, per linvio
dei messaggi viene adottata la seguente scelta: se la dimensione del messaggio da inviare
inferiore a 64 Kb, allora esso viene spedito immediatamente. Se, invece, superiore a 64
Kb, viene inviato un messaggio di notifica al destinatario, il quale poi eseguir una chiamata alla funzione Receive. Ci consente di inviare una notifica al mittente con la richiesta
dei dati. Per quanto riguarda, invece, la comunicazione collettiva, esistono diversi moduli.
Il pi semplice si limita ad eseguire una serie di operazioni di Send/Receive punto-punto.
Tuttavia, di default, Open MPI adotta delle soluzioni molto pi articolate e complesse, in
grado di garantire maggiori performance.

Capitolo 6
API grafiche
Le API (Application Programmer Interfaces) sono un insieme di procedure disponibili al
programmatore, raggruppate per formare un set di strumenti per ladempimento di un determinato compito. Le API grafiche 3D sono state create per semplificare la gestione della
pipeline di rendering 3D e fornire un modo astratto di accedere allhardware.

6.1

OpenGL

OpenGL (Open Graphics Library) una specifica che definisce, per pi linguaggi e pi
piattaforme, delle API, le quali consentono la creazione di applicazioni che producano grafica 3D e 2D. Linterfaccia consiste in pi di 250 funzioni che possono essere utilizzate per
disegnare scene 3D complesse a partire da semplici primitive. OpenGL stata sviluppata
da Silicon Graphics ed molto utilizzata nellindustria dei videogiochi (dove compete con
Microsoft Direct3D), nei programmi CAD, nella realt virtuale e nella visualizzazione di
grafici 3D.

6.1.1

Specifiche

OpenGL una specifica, ovvero un semplice documento che descrive un set di funzioni
e come esse devono lavorare. Le aziende produttrici di hardware sviluppano spesso nuove funzioni per OpenGL, che devono essere testate in modo approfondito prima di esservi
incluse. Implementazioni di OpenGL esistono per Mac OS X, Windows, Linux, molti sistemi basati su Unix e console Nintendo e Sony. Altre implementazioni, generalmente Open
Source, consentono di portare OpenGL su molte piattaforme che non sono state supportate
dai loro produttori. La specifica OpenGL attualmente gestita dallOpenGL Architecture

42 | API grafiche
Review Board (ARB), formata nel 1992. ARB formata da un insieme di aziende interessate a creare delle API ben progettate e supportate da molte piattaforme. I membri sono, ad
esempio, produttori di schede video, come ATI, NVidia o Intel, e produttori di computer,
come Apple, IBM e Dell. Microsoft, uno dei membri fondatori, ha lasciato ARB nel Marzo
2003. A causa dei diversi interessi delle aziende facenti parte di ARB, OpenGL diventata
unAPI ad utilizzo generico. OpenGL ha due scopi principali:
facilitare linterfacciamento con diverse GPU, presentando al programmatore una
singola ed uniforme API
evitare le difficolt causate dalle differenze tra le diverse piattaforme hardware
Le operazioni principali di OpenGL consistono nel trasformare primitive, ad esempio punti,
in pixel. La maggior parte dei comandi OpenGL consente, o di fornire le primitive alla pipeline di elaborazione 3D, o di configurare il modo in cui la pipeline processa queste primitive. Prima dellintroduzione di OpenGL 2.0, ogni passaggio della pipeline era configurabile
con molti limiti, mentre con OpenGL 2.0 alcune fasi sono completamente programmabili
mediante il linguaggio GSGL.

6.2

GLUT

GLUT (OpenGL Utility Toolkit) una liberia di strumenti per i programmi OpenGL, il cui
scopo principale gestire lI/O. Le funzioni consentono la definizione della finestra, il suo
controllo e il monitoraggio di tastiera, mouse e gamepad. Sono anche previste le routine
per il disegno delle primitive e un supporto limitato per le finestre di pop-up. GLUT stato scritto da Mark J. Kilgard mentre lavorava per la Silicon Graphics. Gli scopi principali
di GLUT sono di rendere il codice portabile (GLUT cross-platform) e di consentire che
OpenGL venga imparato ed utilizzato in modo pi semplice. GLUT, inoltre, non richiede la
conoscenza delle API per la gestione delle finestre del sistema operativo. Tutte le funzioni di
GLUT iniziano con il prefisso glut (ad esempio glutPostRedisplay). Esistono anche alternative a GLUT come freeglut. Freeglut un clone di GLUT ma ha il vantaggio di permettere
allutente di modificare e ridistribuire la libreria.

6.3

GLSL

GLSL (OpenGL Shading Language) conosciuto anche come GLslang un linguaggio ad


alto livello per la programmazione degli shader per i linguaggi C e C++. E stato creato per

6.4 Confronto tra Direct3D e OpenGL | 43


consentire agli sviluppatori un controllo della pipeline grafica a basso livello. Con lavanzare delle tecnologie delle schede grafiche, sono state aggiunte sempre pi caratteristiche
per consentire la programmazione di vertex e fragment shader. Originariamente gli shader
erano scritti in Assembly, linguaggio non intuitivo e complesso. OpenGL ARB ha quindi
creato il linguaggio OpenGL Shading Language, in modo da consentire un metodo intuitivo
per la programmazione della pipeline di rendering 3D. Alcuni tra i benefici di GLSL sono:
compatibilit su pi piattaforme tra cui Linux, Mac OS X e Windows
possibilit di scrivere shader per tutte le schede video che supportano GLSL
creazione di codice ottimizzato per larchitettura della scheda video, poich ogni
produttore include nel driver un compilatore GLSL
Gli shader non sono applicazioni stand-alone, poich richiedono che il software che li utilizza usi OpenGL e abbia il supporto per OpenGL Shading Language. Gli shader sono una
serie di stringhe inviate dallapplicazione al driver della scheda video per la compilazione,
e possono essere creati runtime o letti da un file.
GLSL, sebbene simile al linguaggio C, utilizza tipi di variabili diverse da quelle dei normali
linguaggi di programmazione (ad esempio, per indicare una matrice di 4 elementi si utilizza
vec4) e impiega funzioni particolari che generalmente riguardano operazioni matematiche
utilizzate nella grafica 3D.

6.4

Confronto tra Direct3D e OpenGL

Direct3D (componente di DirectX) lAPI che gestisce la grafica 3D in modo proprietario


su sistemi Microsoft Windows. Questa API implementata, come OpenGL, nei driver della
GPU. OpenGL una specifica che prevede un numero di funzioni per il rendering della
grafica 2D e 3D ed implementata in quasi tutti i sistemi operativi, tra cui Android e iOS
(nei sistemi mobile presente OpenGL ES).

6.4.1

Portabilit

Direct3D implementata solo nei sistemi operativi Microsoft e nella famiglia di console
Xbox. Alcune funzionalit sono state implementate tramite Wine su Linux, ma questo lavoro difficile a causa della forte dipendenza tra Direct3D e le altre parti del sistema operativo

44 | API grafiche
Windows. Microsoft ha anche iniziato un progetto di porting di Direct3D su sistemi operativi Mac OS X, ma stato abbandonato. La specifica OpenGL, invece, stata implementata
su unampia variet di piattaforme, tra cui Windows, Linux, Mac OS X, altri sistemi operativi basati su UNIX e console Nintendo e Sony. Tutti i sistemi operativi, tranne Windows,
utilizzano OpenGL come API grafica 3D primaria. Anche Microsoft ha implementato i driver OpenGL in Windows, senza per fornire supporto diretto. Microsoft intende, infatti,
utilizzare OpenGL solo per poter supportare una maggiore quantit di hardware. In termini di portabilit, Direct3D una scelta che limita molto. Se per i computer la quantit di
utilizzatori di sistemi non Windows bassa, per il settore console il contrario.

6.4.2

Semplicit di utilizzo

Alla sua nascita, Direct3D era piuttosto difficile da utilizzare. Richiedeva, infatti, molte operazioni complesse per svolgere funzioni usate frequentemente. Ad esempio, con
OpenGL il procedimento per abilitare lalpha blending veniva svolto con la funzione glEnable(GL_BLEND), mentre con Direct3D era necessario creare un buffer, riempirlo con le
istruzioni corrette e inviarlo al driver. Per questo motivo, molti programmatori hanno chiesto a Microsoft di abbandonare Direct3D in favore di OpenGL. Con il passare del tempo
e lo sviluppo di altre versioni, la situazione per Direct3D per migliorata. Sebbene attualmente entrambe siano API ben sviluppate, esse seguono diversi paradigmi. Direct3D
basata su COM (Component Object Model), uno standard utilizzato da Microsoft per definire oggetti che possono interagire con altri oggetti. Lutilizzo di questo framework, tuttavia,
rende il codice C++ particolare. Per esempio, le funzioni per acquisire un valore ritornano
un HRESULT che indica se la funzione stata eseguita correttamente. OpenGL , invece, una specifica basata sul linguaggio di programmazione C. E stato sviluppato pensando
ad una macchina a stati finiti, ma le versioni pi recenti lhanno trasformato in un sistema
basato su oggetti. Sebbene sia stato progettato per il linguaggio C/C++, possibile implementare OpenGL anche in linguaggi. Direct3D stata progettata per essere uninterfaccia
verso lhardware 3D e, per questo, le sue funzioni dipendono da quelle messe a disposizione
dalla scheda video. OpenGL, invece, stata progettata per essere un sistema di rendering
3D accelerato grazie allhardware. Le due API sono diventate sempre pi simili nelle funzionalit offerte, anche se continuano ad esistere differenze. Con Direct3D lapplicazione
deve gestire le risorse hardware, mentre OpenGL le gestisce direttamente. OpenGL, perci,
rende pi facile scrivere unapplicazione corretta ma, in caso di bug di implementazione, il
programmatore pu fare molto poco. Poich OpenGL nasconde i dettagli dellhardware, il

6.4 Confronto tra Direct3D e OpenGL | 45


programmatore non pu conoscere le risorse che ha a disposizione e deve, perci, affidarsi
totalmente ad OpenGL.

6.4.3

Prestazioni

Dopo la conferma di Direct3D e OpenGL come API grafiche di riferimento, Microsoft e


SGI (Silicon Graphics) hanno dato origine alla Guerra delle API, discutendo soprattutto
su quale dei due software offrisse migliori performance. Microsoft aveva dichiarato che
Direct3D era lAPI pi veloce a causa di test di performance da loro realizzati. Questi test
sono per stati smentiti alla conferenza SIGGRAPH del 1996 (Special Interest Group on
Computer Graphics), durante la quale SGI ha sfidato Microsoft con la propria implementazione di OpenGL chiamata CosmoGL: in varie demo essa aveva uguagliato o superato le
prestazioni di Direct3D. Per SGI, in questo modo si era dimostrato che le inferiori prestazioni erano dovute alla pessima implementazione di OpenGL da parte di Microsoft, e non
a reali difetti di OpenGL. Fino a Direct3D 9, le prestazioni della libreria Microsoft sono
state inferiori, poich per disegnare i vertici era necessario che la CPU passasse in modalit
kernel per comunicare con i driver. OpenGL, invece, possiede porzioni di codice eseguiti in
modalit utente, che permettono di limitare il numero di passaggi in modalit kernel. Questo problema stato risolto da Direct3D 10 e, attualmente, non ci sono particolari differenze
di prestazioni tra OpenGL e Direct3D.

6.4.4

Estensibilit

Il sistema di estensioni di OpenGL , probabilmente, la differenza pi sostanziale tra le due


API. OpenGL include un meccanismo per cui ogni driver pu informare le API riguardo alle estensioni che mette a disposizione. Esse comprendono, ad esempio, nuove funzionalit
o nuovi modi di trasferire i dati alla GPU. In questo modo, le nuove funzionalit possono
essere esposte velocemente, ma pu sorgere confusione se diverse aziende implementano estensioni simili. Molte di queste estensioni sono periodicamente standardizzate dalla
OpenGL Architecture Review Board e altre sono diventate una parte del core di OpenGL.
Direct3D, invece, non consente ai produttori di GPU lutilizzo di funzioni particolari senza
che Microsoft non le abbia implementate.

46 | API grafiche

6.4.5

Mercato attuale

OpenGL, da sempre, viene utilizzata pi di Direct3D nel mercato della grafica professionale, mentre Direct3D viene utilizzata soprattutto nei videogiochi per computer. Attualmente,
alcune schede video professionali supportano solo OpenGL, anche se molti dei maggiori
produttori consentono lutilizzo sia di OpenGL che di Direct3D. La ragione per cui OpenGL preferita nel mercato professionale soprattutto storica. Molte applicazioni, infatti,
erano scritte originariamente in IRIS GL per poter lavorare con le workstation SGI. Laltra
ragione che Direct3D stata progettata come unAPI per consentire un accesso a basso
livello allhardware, caratteristica molto importante per lo sviluppo di videogiochi. OpenGL , invece, unAPI molto pi generica, quindi fornisce caratteristiche non indirizzate
ad un particolare tipo di utilizzatori. Uno svantaggio di OpenGL quello di richiedere di
tenere sotto controllo tutte le diverse implementazioni: chi utilizza OpenGL, perci, deve testare tutto quello che fa su hardware e sistemi operativi diversi. Va detto anche che
OpenGL, non consentendo di sapere quali tecnologie utilizza la scheda video, rischia di
rendere il programma pi lento, poich possono venire utilizzate funzioni che lhardware
non supporta.

6.5
6.5.1

Progettazione di un motore di rendering 3D


Il formato Wavefront .obj

Uno dei formati pi utilizzati per la descrizione di scene 3D Wavefront .obj. Wavefront
.obj un file di testo che segue uno specifico standard. Esso descrive:
i vertici di ogni faccia tramite le loro coordinate sui tre assi (x, y e z)
le coordinate delle texture utilizzando lo standard UVW
le coordinate dei vettori normali
I commenti vengono scritti anteponendo un #. Un file Wavefront pu fare anche riferimento
ad uno o pi file mtl, che descrivono le caratteristiche di ogni materiale. Un esempio di file
Wavefront .obj il seguente:

mtllib strada . mtl


o Cube .1 _0

6.5 Progettazione di un motore di rendering 3D | 47


v -32.6316 8.79239 -15.4159
v -32.6316 8.79239 -16.7159
v -61.9316 8.79239 -16.7159
v -61.9316 8.79239 -15.4159
# ...
vt 0.00000 0.00000
vt 0.00000 0.09731
vt 0.89220 0.09731
# ...
vn 0.367004 -0.85476 0.367004
vn 0.85476 -0.367004 0.367004
vn 0.85476 -0.367004 -0.367004
# ...
usemtl Mat2
f 2/4/4 6/3/3 5/2/2 1/1/1
usemtl Mat1
f 6/3/3 14/6/6 13/5/5 5/2/2
f 14/6/6 22/8/8 21/7/7 13/5/5
# ...
o Cube .2 _0
# ...
La prima riga indica il file .mtl contenente la descrizione dei materiali da utilizzare. La
seconda riga indica che loggetto che verr descritto in seguito si chiama Cube.1_0 . Due
oggetti diversi non possono avere lo stesso nome. Le righe che iniziano con v descrivono la
posizione dei vertici. La prima coordinata corrisponde al valore di x, la seconda a quello di y
e la terza a z. Le righe inizianti con vt descrivono le coordinate u (primo valore), v (secondo
valore) e w (terzo valore, se omesso 0). Questi valori consentono una corretta mappatura
delle texture sulle facce. Le righe che iniziano con vn indicano le coordinate del vettore
normale in un punto. Il vettore normale indica la direzione verso cui rivolto il punto e
viene utilizzato per il calcolo dellilluminazione. Le righe che iniziano con usemtl indicano
il materiale (che deve essere descritto nel file .mtl) da utilizzare per ogni faccia; nel caso
non sia descritto quale materiale utilizzare viene utilizzato quello della faccia precedente.

48 | API grafiche
Le righe che iniziano con la lettera f descrivono una faccia; la lettera viene seguita da n
valori che seguono la forma:
f vertice/texture/normale
dove il numero al posto di vertice, texture e normale indica li-esima informazione descritta
precedentemente (gli indici partono da 1). Ad esempio, i valori 2/4/4 indicano che per
quella faccia necessario utilizzare il secondo vertice, la quarta coordinata texture e la
quarta normale: tutte informazioni definite precedentemente. Una riga che inizia con f ha,
perci, almeno 3 di questi elementi, poich impossibile formare una faccia con meno di 3
vertici. La numerazione di vertici, coordinate e normali non ricomincia quando si descrive
un nuovo oggetto e, ovviamente, pi facce che condividono lo stesso vertice, coordinata o
normale utilizzano lo stesso indice. Un esempio di file .mtl il seguente:
newmtl Mat1
Kd 0.800000 0.800000 0.800000
Ks 0.200000 0.200000 0.200000
Ns 50.781250
map_Kd imgTest . jpg
# ...
newmtl Mat1
La prima riga descrive il nome del materiale (che viene utilizzato dallindicazione usemtl
del file Wavefront). Non possono esserci pi materiali con lo stesso nome. La riga che
inizia con Kd indica il colore e lintensit della componente diffusa. I valori corrispondono
alla quantit di rosso, verde e blu e vanno da 0 ad 1. Lo stesso principio viene utilizzato
per la componente speculare, che viene identificata dalle righe che iniziano con Ks. Valori
pari a 0 0 0 per la componente speculare o diffusiva indicano lassenza di tale componente.
Le righe che cominciano con Ns indicano il peso della componente speculare rispetto a
quella diffusiva, che pu andare da 0 a 1000. Le righe che iniziano con map_ indicano il
percorso di una texture da applicare su una determinata componente. Nel caso, ad esempio,
di map_Kd, la riga indica la texture da applicare per la componente diffusiva del materiale.

6.5.2

Scelta del linguaggio

La scelta del linguaggio di programmazione di cruciale importanza per il buon funzionamento di un motore di rendering. Come visto anche nei capitoli precedenti, le prestazioni
sono uno degli elementi da tenere in forte considerazione quando si tratta di unoperazione

6.5 Progettazione di un motore di rendering 3D | 49


impegnativa per lhardware come il rendering 3D. Le prestazioni diventano, poi, il fattore
pi importante quando si parla di grafica in tempo reale (come, ad esempio, nei videogiochi),
poich, altrimenti, si otterrebbero molti lag. Questo aspetto fa prediligere un linguaggio
compilato rispetto ad uno interpretato. La preferenza andata al linguaggio di programmazione C++ poich le librerie OpenGL sono nate con il linguaggio C, poich disponibile
unampia documentazione per il loro utilizzo con tale linguaggio e poich un linguaggio ad
oggetti permette di semplificare la gestione del codice.

6.5.3

Class Diagram semplificato

Figura 24: Class Diagram di un motore di rendering 3D

50 | API grafiche

6.5.4

Esempio

E possibile trovare il codice sorgente di un motore di rendering 3D basato su OpenGL allindirizzo http://git.io/3DEngine
Il motore sfrutta le librerie Qt, che, pertanto, devono essere installate per consentire la
corretta compilazione del codice.

Bibliografia
Hees H., 3D Computer Graphics, PediaPress Ed., Mainz (Germania), 2006, pp. 1-365
Newman W., Sproull R., Principi di COMPUTER GRAPHICS, McGraw-Hill Ed.,
Milano, 1987, pp. 1-566

Sitografia
download.nvidia.com/developer/cuda/seminar/TDCI_Arch.pdf
http.developer.nvidia.com/GPUGems2/gpugems2_chapter30.html
meseec.ce.rit.edu/551-projects/fall2010/1-2.pdf
research.nvidia.com/sites/default/files/publications/04085637.pdf
simionato.org/MPI.pdf
www.cse.ohio-state.edu/ crawfis/cse786/ReferenceMaterial/CourseNotes/Modern
%2520GPU%2520Architecture.ppt
www.cse.ohio-state.edu/ parent/classes/581/Lectures/
12.IlluminationHandout.pdf
www.cs.bath.ac.uk/ pjw/NOTES/75-ACG/ch6-projective.pdf
www.cs.cmu.edu/afs/cs/academic/class/15462-f11/www/lec_slides/lec19.pdf
www.cs.kent.edu/ zhao/acg13/lectures/MC_Raytracing.pdf
www.cs.ubc.ca/ tmm/courses/cpsc414-03-fall/Vsep2003/slides/week2.mon.pdf
www.d.umn.edu/ data0003/Talks/gpuarch.pdf
www.fabiensanglard.net/shadowmapping/index.php
www.fedoa.unina.it/9012/1/Romano_Diego_23.pdf
www.lighthouse3d.com/opengl/glsl/index.php/index.php?textureMulti
www.matrix44.net/cms/notes/opengl-3d-graphics/coordinate-systems-in-opengl
www.mcqmc2012.unsw.edu.au/slides/MCQMC2012_Keller_Tutorial.pdf

Licenza
Il sottoscritto Massimo Perini, in qualit di autore dellOpera rappresentata nel presente documento, corrispondente al digest SHA-1 99564f3e03dfd8f9a3b06cb42149d246b7d9d1f2
(digest escluso), dichiara di concedere in licenza questOpera nei termini e alle condizioni
previste dalla Licenza Creative Commons Attribuzione - Non commerciale 4.0 Internazionale:
http://creativecommons.org/licenses/by-nc/4.0/deed.it
Il licenziante non presta alcuna garanzia con riguardo allOpera e si esime da ogni responsabilit che possa derivare dalluso dellOpera o dalla presente licenza.
LOpera stata rilasciata con la presente licenza in data 12/06/2014.

E possibile ottenere una copia dellOpera allindirizzo http://www.perinimassimo.com/rendering3D


o utilizzando il seguente QR Code:

Potrebbero piacerti anche