Smoothing
Daniele Marini
1
Calcoli sui vettori
• Vettore normale
• equazione del piano: ax+by+cz+d=0; si può
anche scrivere come luogo:
n.(p p0 ) 0
e p è un qualunque punto nel piano; il vettore
n è dato da:
a
n b
c
a
b
e in coordinate omogenee : n
c
0
2
In generale possiamo partire da tre punti non allineati:
p0, p1, p2 con i quali determiniamo il piano (superfici
approssimate con poliedri triangolarizzati).
Le differenze p2 - p0 e p1 - p0 sono coplanari e il loro
prodotto dà la normale:
n = (p2 - p0) x (p1 - p0)
L’ordine è rilevante
3
Per il calcolo di normali di superfici curve dipende da
come la superficie è rappresentata, ma in generale si
stima un gradiente.
Es. sfera - equazione
f(x,y,z): x2 + y2 + z2 -1=0
In forma vettoriale:
f(p): p.p -1 = 0
Il vettore gradiente è dato da:
f
x 2x
f
n 2y 2p
y
f 2z
z
4
Se la sfera è rappresentata in forma parametrica il metodo
di calcolo cambia:
x x(u,v) cos(u)sin(v)
y y(u,v) cos(u)sin(v)
z z(u,v) sin(u)
con u,v
2
2
La normale si può ricavare dal piano tangente in p:
5
x
u
p y
,
u u
z
u
n
x
v
p y
v v
z
v
Individuano due vettori
tangenti il cui prodotto vettore
individua la normale - poiché ci
interessa solo la direzione si
può dividere per cos(u)
ottenendo un vettore unitario
p p
u v
cos(u)sin(v)
n cos(u)cos(u)cos(v) cos(u)p
sin(u)
6
Quando calcolare le normali?
• L’architettura a pipe line dei sistemi di rendering
prevede che la normale di una faccia sia nota a
priori (viene elaborato un vertice per volta e non
tutta l’informazione è disponibile)
• in generale è compito del programma applicativo
calcolare la normale. OpenGL permette di
associare a ogni vertice una normale (che
dobbiamo calcolare noi nell’applicativo):
glNormal3f(nx,ny,nz);
glNormal3fv(pointer_to_normal);
7
Shading di poligoni
(flat shading)
• N, V ed L variano su ogni poligono
• se si assume osservatore “distante” e
sorgente di luce distante (in OGL si setta a falso il flag
near_viewer) V e L sono costanti
• anche N è quindi costante sull’intero
poligono
• Il calcolo di shading viene fatto per l’intero
poligono una sola volta
8
OGL e flat shading
glShadeModel(GL_FLAT);
La normale che OGL utilizza è quella associata al
primo vertice del poligono
Per i triangle strip OGL usa la normale del terzo
vertice per il primo triangolo, la normale del
quarto per il secondo e così via
Per altre primitive valgono regole simili (vedi
manuali)
9
Triangle strip
10
Flat vs Smooth
Smooth shading
Flat shading
11
Effetti di flat shading
Bande di mach
12
Smooth shading (interpolato)
• Interpolazione di Gouraud
glShadeModel(GL_SMOOTH)
• Interpolazione di Phong
13
Gouraud
Le normali ai vertici di un poliedro vengono interpolate:
n1 n2 n3 n4
n
n1 n2 n3 n4
Gouraud usa interpolazione bilineare per calcolare il colore
dei pixel lungo i singoli poligoni, quindi:
-prima calcola colore ai vertici
-poi interpola colore
14
Interpolazione bilineare
interpoliamo lungo una
linea di scansione
descriviamo i lati
in forma parametrica,
aè il parametro
C4 (a ) (1 a )C0 aC1
C5 (a ) (1 a )C2 aC3
C45 (a ) (1 a )C4 aC5
15
Dipende
dall’orientamento
16
Phong Smoothing
• Basato sull’interpolazione
delle normali
• il colore si calcola alla fine sul
singolo pixel
na (1 a )nC a nB
n(a , ) (1 )n C n D
17
Gouraud vs. Phong shading
• hardware
• veloce
• continuo fino al I
ordine
• effetti lucentezza
limitati (migliorano se
si aumenta la
triangolazione)
• software
• lento
• continuo fino al II
ordine
• si può applicare
modello di Phong per
lucentezza
18
Sorgenti di luce in OGL
glLightfv(source, parameter, pointer_to_array)
glLightf(source, parameter, value)
I parametri sono:
Posizione (direzione) della sorgente
Livelli di
Ambiente
Diffusa
Speculare
Associati alla sorgente
19
GLFloat light0_pos[]={1.0, 2.0, 3.0, 1.0}
Se si pone quarta componente a 0 la sorgente è all’infinito e
definita come “direzione”
GLFloat light0_dir[]={1.0, 2.0, 3.0, 0.0}
Sorgente bianca con componenti di tutti e tre i tipi:
GLFloat diffuse0[]={1.0, 0.0, 0.0, 1.0}
GLFloat ambient0[]={1.0, 0.0, 0.0, 1.0}
GLFloat specular0[]={1.0, 0.0, 0.0, 1.0}
20
glEnable{GL_LIGHTING};
glEnable{GL_LIGHT0};
glLightfv(GL_LIGHT0,
glLightfv(GL_LIGHT0,
glLightfv(GL_LIGHT0,
glLightfv(GL_LIGHT0,
GL_POSITION, light0_pos);
GL_AMBIENT, ambient0);
GL_DIFFUSE, diffuse0);
GL_SPECULAR, specular0);
Se vogliamo comunque un contributo ambiente indipendente:
GLFloat global_ambient[]={0.1, 0.1, 0.1, 1.0};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,
global_ambient);
21
Se vogliamo inserire un termine di attenuazione
1
f (d)
2
a bd cd
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, a);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, b);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, c);
Si può convertire la sorgente da puntiforme a spot, specificando:
direzione
GL_SPOT_DIRECTION
esponente
GL_SPOT_EXPONENT
angolo di soglia
GL_SPOT_CUTOFF
Si usa sempre la
glLightf o glLightfv
22
• OGL assume sempre l’osservatore a
distanza infinita, in modo da considerare
costante la direzione del viewer da ogni
punto della scena
• Per forzare l’osservatore a condizioni di
distanza non infinita si usa la:
glLightModel(GL_LIGHT_MODEL_LOCAL_VIEWER,
GL_TRUE)
23
• OGL non si preoccupa di fare shading delle
facce nascoste; se si desidera vedere facce
nascoste si può forzare con:
glLightModel(GL_LIGHT_MODEL_TWO_SIDED,GL_TRUE)
24
OGL e i materiali
glMaterialf(face, value)
glMaterialfv(face, type, pointer_to_array)
GLFloat diffuse1[]={1.0, 0.8, 0.0, 1.0}
GLFloat ambient1[]={0.2, 0.2, 0.2, 1.0}
GLFloat specular1[]={1.0, 1.0, 1.0, 1.0}
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,
ambient1);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
diffuse1);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
specular1);
25
Con GL_FRONT e GL_BACK si specificano proprietà differente per le facce
frontali e nascoste
L’esponente nella componente speculare si specifica con:
GL_SHININESS
OGL permette di definire oggetti con componente emissiva:
GLFloat emission[]={0.0, 0.3, 0.3, 1.0};
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,
emission)
26