MODELLI LUCE
visualizzazione realistica di una scena in 3D:
proiezione su schermo
(da 3D a 2D, con i vari tipi di proiezione
che abbiamo visto)
ogni pixel dello schermo ha
un colore e
un' illuminazione - un'intensita' di luce
calcolati dal colore e dall'illuminazione
del punto corrispondente al pixel
su una superficie nello spazio
possiamo separare
il modello di illuminazione
(o di ombreggiatura, illumination or shading model)
che calcola
l'intensita' della luce in un punto dello spazio
dalla procedura o metodo per la resa realistica della
superficie 3D sullo schermo 2D (modello per ottenere
il colore di ogni pixel sulo schermo a partire dal colore
del punto corrispondente su una superficie nello
spazio 3D
(illumination procedure / surface rendering method)
classificazione delle superfici 3D per la luce:
per la descrizione di una scena dobbiamo specificare:
la forma della superficie 3D (modello geometrico) e di questo abbiamo visto alcuni metodi elementari,
il tipo di superficie 3D per quanto riguarda la luce,
sia per i raggi riflessi
sia per i raggi rifratti trasmessi dentro il materiale
il tipo di superficie 3D per quanto riguarda la luce:
superficie puo' essere :
lucida (shiny)
opaca (dull, matt)
trasparente (transparent),
traslucente (translucent)
colore
superficie con tessiture, "textures",
il tipo di superficie 3D per quanto riguarda la luce:
superficie puo' essere :
lucida (shiny) e quindi riflettente (specular) la luce in
una direzione (uno specchio, una sfera d'acciaio)
opaca (dull, matt) o ruvida, che diffonde la luce in tutte
le direzioni (una parete di gesso, una lavagna)
trasparente (transparent), che lascia passare la luce
mantenendo i raggi paralleli (vetro, acqua,ambra)
traslucente (translucent) lascia passare la luce diffusa
in piu'direzioni (madreperla, carta pergamena)
colore proprio della superficie, uniforme oppure con
presenza di una colorazione non uniforme, ovvero
superficie con tessiture, "textures", per una resa della
scena piu' realistica
le
tessiture, "textures",
simulano la superficie di un certo tipo di oggetti,
come potrebbero essere superfici di pavimenti,
muri, tessuti, tappeti, pelliccie, pelle, tatuaggi,
sabbia ecc
le tessiture sono generalmente ricavate da
fotografie di oggetti reali, digitalizzate e poi
copiate ("icollate come se fossero di tela
elastica) sulle superfici richieste
(vedremo il capitolo texture mapping
dell'OpenGL)
tessiture incollate come se fossero di tela
elastica sulle superfici richieste - due es. dal
lavoro di Tamiazzo, corso EGD 2007:
nota a destra l'effetto di immagine riflessa, simulato dalla texture!
classificazione delle superfici 3D per la luce:
sorgente luce:
dimensione
posizione
up
numero
up
colore
up
classificazione delle superfici 3D per la luce:
sorgente luce:
sorgente puntiforme (o quasi)
sorgente ad ampia superficie, con attributi di
riflettanza, specularita', trasparenza, e altri
dimensione:
posizione: sorgente vicina: raggi non paralleli
sorgente (molto) lontana:
i suoi raggi sono praticamente paralleli
numero:
nessuna (solo luce ambiente diffusa),
una sorgente di luce, piu' sorgenti
colore :
colore della luce
l' illuminazione di un punto generico nello spazio
non dipende solo dalle luci presenti nella scena, ma
anche dagli altri oggetti in scena:
si pensi alla situazione di un fotografo che fa una
foto in ambiente interno con uso della luce data dal
flash: per evitare ombre troppo crude e troppo
incise usa
l' illuminazione indiretta,
ottenuta ad esempio con il flash rivolto al soffitto,
e quindi con le persone illuminate indirettamente da
una luce diffusa proveniente dal soffitto
l' illuminazione di un punto generico di una
superficie 3D dipende dagli altri oggetti in scena:
sia per quanto riguarda l' illuminazione indiretta,
che per quanto riguarda le ombre riportate su un
oggetto dalla presenza di altri oggetti nella scena
per tale motivo un calcolo esatto (*) dell'intensita' di
luce in un punto dello spazio deve tener conto di tutta
la scena, sorgenti luce ("attivi") e oggetti "passivi" il calcolo della luce deve (dovrebbe) essere globale
(non solo locale) ; vedremo vari esempi di entrambi.
(*) con approssimazione soddisfacente per un "buon" realismo
tutto il corso di grafica si basa sulla luce ...
e ...
la luce e' un campo elettromagnetico,
prodotto dalle sorgenti di luce,
e che irradia gli oggetti presenti in scena;
ogni oggetto in parte assorbe la luce, in modo diverso a
seconda della frequenza della luce e dal tipo di materiale;
ogni oggetto in parte riflette la luce, parte della luce
incidente viene nuovamente irradiata dalla superficie
dell'oggetto
):-} tutta, se si tratta di uno specchio perfetto,
(:-{ nessuna, se e' un buco nero,
la luce e' un campo elettromagnetico, prodotto dalle
sorgenti di luce, e che irradia gli oggetti presenti in scena;
ogni oggetto in parte assorbe la luce,
in parte riflette la luce:
una superficie che appare di un certo colore ad.es. blu
trattiene le altre componenti ( colori sottrativi !! )
in generale dovremmo trattare separatamente almeno le tre
componenti primarie additive (codifica del pixel a 3
componenti RGB); il discorso sui colori e' rimandato ad un
capitolo successivo;
di seguito sono presentati alcuni modelli semplificati sulla
diffusione, riflessione e rifrazione della luce.
Primi metodi sviluppati: i metodi empirici o locali,
basati su un modello semplificato dell' illuminazione
( Warnock 1969, Bouknight 1970,
Gouraud 1971, Newell 1972,
Phong 1975)
nell'
OpenGL sono predefiniti
i metodi Gouraud e Phong ;
vedremo in seguito alcuni metodi globali piu' precisi e
piu' realistici, (ray-tracing, radiosity, ecc)
- ma richiedono molti piu' calcoli !
calcolo della luce riflessa
modelli di luce: sono modelli pratici, semplificati
per il calcolo dell'intensita' di luce
che esce da un punto di una superficie 3D
cioe' riflessa da una superficie:
devo prima calcolare l'intensita' di luce
incidente cioe'
l'intensita' della luce che arriva ad un punto
in base alla posizione della luce e
della superficie
un primo fattore che incide sulla quantita' di luce
che arriva ad una superficie e' la distanza
1) ATTENUAZIONE PER DISTANZA LUCE - SUPERFICIE:
l'intensita' di luce si attenua
con il quadrato della distanza:
a pari angolo di un cono
(cono con vertice nella
sorgente di luce)
se aumenta 2 volte la distanza
allora la stessa quantita' di
luce arriva su una superficie 4
volte maggiore:
f attenuazione = 1.0 / ( d 2 )
(se la terra fosse 2 volte piu'
vicina al sole riceverebbe 4
volte piu' energia solare)
Isorgente
d
sup1
2d
sup4
Iincid
l'intensita' di luce si attenua con il quadrato della distanza:
se aumenta 2 volte la distanza allora sulla stessa superficie
arriva una quantita' di luce 4 volte minore :
f attenuazione = 1.0 / ( d 2 )
in pratica per una resa piu'
"realistica" si usa la formula:
Iincid = f AttenuazPerDistanza * Isorgente
con
fAttenuazDistanza=1.0/( a0+a1*d+a2*d 2 )
con sorgente molto lontana, raggi
quasi paralleli, allora praticamente
non c'e' attenuazione per distanza,
f AttenuazPerDistanza = 1.0 e
Iincid = Isorgente
Isorgente
d
sup1
2d
sup4
Iincid
2) secondo fattore di attenuazione
della luce:
attenuazione luce per angolo
caso a): luce diffusa, assenza di
attenuazione per angolo
con luce a diffusione larga, uniforme,
es con una lampadina non schermata,
l'intensita' di luce non cambia con
l'angolo in cui si trova l'oggetto rispetto
un asse di centro luce, e la luce su tutti
i punti a distanza costante dalla
sorgente di luce hanno l'intensita' di
luce costante, e nella formula:
Iincid = f attenuaz_per_angolo * Isorgente
il fattore f attenuaz_per_angolo vale 1.0;
a
la lunghezza dei
"raggi" (=intensita')
e' costante
secondo fattore di attenuazione della luce:
caso b) luce concentrata, presenza attenuazione per angolo
se la luce e' a diffusione non uniforme, concentrata in un cono di
luce, (faretto o spot-light) allora l'intensita' di luce cambia con
l'angolo in cui si trova l'oggetto rispetto l' asse di centro luce:
Iincid = f attenuaz_per_angolo * Isorgente
cos(x)
angolo x
a
qui la lunghezza dei
"raggi" (=intensita')
NON e' costante
x
il fattore di attenuazione
e' funzione dell'angolo,
cambia con cosenoK(x)
con k da 1 a 50 e oltre...
caso b) luce concentrata, presenza attenuazione per angolo
luce a diffusione non uniforme, concentrata in un cono di luce,
("spot" light), l'intensita' di luce cambia con l'angolo in cui si
trova l'oggetto rispetto l' asse di centro luce:
Iincid = f attenuaz_per_angolo * Isorgente
a
x
il fattore di attenuazione
per angolo e' :
f attenuazione = Kangolo * cosk (x)
= 0.0
se x<a
se x>a
(fuori del cono di luce)
cos(x)
angolo x
con a angolo di apertura del cono di luce
della luce direzionale; Kangolo e' una costante
cosk (x) - nota k !!
combinando le due attenuazioni (attenuazione per distanza
e per angolo) abbiamo:
Iincidente = f attenuaz_per_distanza * f attenuaz_per_angolo * Isorgente
dove il primo fattore si riduce a 1 se la luce e' a distanza
"infinita" (il sole) o "molto grande", e il secondo fattore
diventa zero se l'oggetto e' fuori del cono di luce (luce
direzionale o spot)
data quindi un'idea del calcolo della Iincidente luce che arriva
ad un punto generico di una superficie,
vediamo ora quanta luce assorbita dalla superficie
viene di nuovo irradiata, ovvero riflessa
sorgente
luce
luce
incidente
osservatore
luce
riflessa
normale
luce
diffusa
oggetto
luce
rifratta
nel modello semplificato "locale", empirico, (anni 68-74)
si tien conto di tre tipi di luce o illuminazione
irradiata da un punto di un oggetto:
luce ambiente + luce diffusa a largo cono + luce riflessa
(da aggiungere il calcolo della luce rifratta dentro l'oggetto)
luce ambiente :
un oggetto non illuminato direttamente non appare nero, ma
ha sempre un po' di illuminazione: diremo che
c'e' "sempre" una componente di luce ambiente, diffusa, non
localizzata (come da moltissime sorgenti poste in tutti i punti
della scena attorno l'oggetto),
Iambiente = Ka * Ia
dove
Ka e' un coefficiente di diffusione ambientale (da 0.0 supeficie
nera che non riflette, a 1.0, superficie bianca che riflette tutta la
luce ambiente che arriva) , e
Ia e' l'intensita' della luce presente distribuita nell'ambiente
(da 0 a 1)
ma... la luce cosi' calcolata non da' alcun rilievo, come si vede
nella figura seguente ...
L'immagine seguente e' fornita dal programma "LightMaterial",
(programmi "tutors" di Nate Robins, da rete),
con solo luce ambiente (sono tutti a zero i coefficienti r, g, b
delle componenti di intensita' della luce per la parte "rifratta
diffusa" e "rifratta speculare" );
si noti che nell' oggetto toroidale scompare completamente
l'effetto 3D, la superficie appare uniformemente piatta!
si confronti questa resa dell' oggetto toroidale qui in figura, con
la sola luce ambiente diffusa, con l'immagine seguente..
componente della luce riflessa dalla superficie (e diffusa a cono
largo) la luce sorgente e' localizzata all'infinito,
in figura c'e' lo stesso oggetto toroidale, ora reso con luce
ambiente (coeff. 0.2) e
con luce riflessa diffusa (coeff. 1.0)
la seconda componente fornisce una resa piu' realistica 3D
(figura data dal programma "LightMaterial", di Nate Robins)
luce ambiente + luce diffusa a largo cono
la luce riflessa diffusa viene calcolata con
la formula di Lambert,
I rifl.diff = Iincid * Kd * cos(a)
a angolo tra la normale e la direzione della sorgente di luce,
come in figura
l'energia che arriva per
unita' di superficie
diminuisce all' aumentare sorgente
osservatore
dell'angolo di incidenza
luce
luce
della luce con la normale
riflessa
normale
alla superficie;
luce
a
una luce che arriva
incidente
luce
radente alla superficie
diffusa
lascia un' apporto di
energia nullo, come nella
oggetto
figura seguente ...
calcolo della seconda componente del modello empirico:
la luce riflessa diffusa:
cos(a)=1
la luce riflessa diffusa viene
calcolata con la formula di
Lambert,
a
I rifl.diff = Iincid * Kd * cos(a)
a = angolo tra la normale e la
sorgente di luce, come nelle
figure a fianco: sopra a = 00 ,
cos(0)=1, la quantita' di luce
(energia per unita' di superficie)
e' massima,
nella figura in basso a= 900
cos(a)=0, l'intensita' di luce e'
minima, cioe' zero.
a
a
cos(a)=0
intensita' di luce diffusa per riflessione data da una formula tipo:
I RiflessaDiffusa = I Incidente Kd * cos(a)
dove cos(a) e' fornito dal prodotto scalare di L . N
con L versore di direzione della sorgente di luce, dato da
L = ( Psorgente - P ) / | Psorgente - P |
e con N normale alla
superficie dell'oggetto
nel punto P (N data
assieme all'oggetto!)
nota: non si tien conto
della posizione dell'
osservatore o angolo della
direzione dell' osservatore
- qui parliamo di luce
riflessa diffusa
osservatore
sorgente
luce incidente
N
L
a
P
oggetto
sommando le due componenti:
I RiflessaDiffusa = I Incidente Kd * cos(a)
Iambiente = Ka * Ia
si ottiene per la luce ambiente + la luce diffusa (riflessa):
I diffusa = Iambiente + I RiflessaDiffusa = Ka * Ia + I Incidente Kd * cos(a)
modello sufficiente per una superficie opaca (gesso, carta...)
(dull in inglese, matt in tedesco)
non basta per una superficie generica: a questo dobbiamo
aggiungere la componente riflessa speculare, presente in tutte
le superfici non opache.
componente riflessa speculare ("shininess")
la luce incidente si riflette sulla superficie ed esce un cono di
luce, con intensita' funzione dell'angolo x rispetto la direzione
del versore R, simmetrico rispetto la normale del versore L della
luce di incidenza;
a seconda del materiale il cono di luce riflessa e' + o - stretto:
angolo apertura quasi zero per uno specchio,
cono molto ampio per materiale quasi opaco;
IRiflessaSpeculare = W(a) * IIncidente * Ks * cosn(x)
se l'osservatore O sta
dalla stessa parte della
sorgente della luce,
oppure dietro la
superficie, allora l'
intensita' di IRifl.Spec e'
zero;
di W(a) parleremo dopo ...
osservatore
sorgente
luce incidente
L
a
x
P
oggetto
R
N
O
nota: nella formula
I RiflssSpeculare = W(a) * I Incidente * Ks* cosn(x)
n=1
[[ x angolo tra il versore R (asse riflesso) e
la direzione dell'osservatore O ]]
n=8
n=50
la componente
cosn(x)
n=256
varia in funzione di n (figura a fianco) :
per n "piccoli" (sotto n=10) la curva
e' abbastanza larga (materiale poco
speculare, poco lucido, quasi opaco)
per n grandi (64, 256) la curva e'
molto stretta (materiale molto
riflettente,lucido) come dai due
esempi seguenti...
L
R
N
a
x
O
osservatore
P
oggetto
vedremo piu' avanti (slide 56 4 sfere)
...
high shininess expon
n=100 per il coefficiente cosn(a)
...
nota: nella formula
I RiflssSpeculare = W(a) * I Incidente * Ks* cosn(x)
n=1
[[ con x angolo tra il versore R (asse
riflesso) e la direzione dell'osservatore O ]]
n=8
n=50
n=256
talvolta si approssima
cosn(x) =
prodotto scalare (O.R)n
con (N.H)n = prodotto scalare
della normale N nel punto P e
del versore H dato dalla
media tra L e O
(H=
(L+O)/|L+O| ) ... costa meno in
termini di calcolo (L data gia')
H
N
R
L
a
x
O
osservatore
P
I RiflssSpeculare = W(a) * I Incidente * Ks* cosn(x)
n=1
cosn(x)
per n piccoli (in fig. n=5): la curva
e' larga (materiale opaco, toro in alto);
cosn(x) per n grandi (n=128) la curva e'
stretta (materiale lucido, toro in basso)
n=8
n=50
n=256
dal programma "LightMaterial", Nate Robins
nota: nella formula
I RiflssSpeculare = W(a) * I Incidente * Ks* cosn(x)
[[ x angolo tra il versore R (asse riflesso) e
la direzione dell'osservatore O ]]
1
L
a
N
argento
oro
vetro
0
W(a)
30
60
90
il coefficiente W(a) e' una funzione dell'angolo di incidenza
della luce rispetto la superficie, e dipende dal materiale, ed e'
massimo per luce quasi radente (fata morgana .. capita
talvolta di vedere un riflesso su superfici del tutto opache (una
strada) se l'angolo di incidenza e'vicino ai 900 (quasi radente)
sommando le tre componenti:
Iambiente = Ka * Ia
I RiflessaDiffusa = I Incidente Kd * cos(a)
I RiflssSpeculare = W(a) * I Incidente * Ks* cosn(x)
I = Iambiente + I RiflessaDiffusa + I RiflssSpeculare
= Ka * Ia + I Incidente Kd * cos(a) + W(a) * I Incidente * Ks* cosn(x)
= Ka*Ia + I
n
K
*N.L
+
W(a)*I
*
K
*
(N.H)
Incidente d
Incidente
s
per una sorgente di luce:
I = Iambiente + I Diffusa + I Speculare
= Ka * Ia + I Incidente Kd * cos(a) + W(a) * I Incidente * Ks* cosn(x)
= Ka * Ia + I Incidente Kd * N . L + W(a) * I Incidente * Ks* (N.H)n
in generale, con ns sorgenti di luce,
avremo la luce in un punto P della superficie
di un oggetto data da:
I = Iambiente + somma k ( I Diffusa k + I Speculare k )
per tutte le luci k da 1 a ns;
infine, per n sorgenti di luce, e, se si tiene anche conto
dell'attenuazione dovuta alla distanza della sorgente di luce
e dell'angolo di diffusione (spot), abbiamo il modello di
Bui Tuong Phong (shading function 1975):
I = Iambiente +
+ somma k ( fattenua.dist *fattenua.ang * (I Diffusa k +I Speculare k ) )
dove
I Diffusa k = Kd * Ik * ( N.Lk )
e
I Speculare k = Ks * Ik * (N . H )n
oppure zero se la luce sta dietro l'oggetto (per ora non
consideriamo la luce che viene attraverso l'oggetto, per
trasparenza)
(n.b.: in ogni caso I e' un fattore per il colore della
superficie, con un valore da 0.0 a 1.0)
dal Neumann-Sproull:
il modello di Phong e' una base ragionevolmente semplice e
valida per la resa degli oggetti; si devono pero' introdurre delle
tecniche opportune per evitare di calcolare questa funzione per
ogni pixel dello schermo!
si osservi che la formula di Phong va applicata separatamente
per le tre componenti R, G, B;
vediamo ora i metodi di Gouraud e di Phong piu' in dettaglio,
relativamentge a OpenGL e
al problema di: devo calcolare la luce riflessa per quanti punti
di un poligono (un triangolo) ?
consideriamo la faccia f1
dell'oggetto in figura: un
triangolo con i vertici A1, B1, C1;
nella versione piu' semplice si
calcola l'intensita' di luce per
un punto di f1 e si assegna
tale valore a tutta la superficie
(FLAT shading in OpenGL);
l'effetto di questo tipo di resa
della superficie (per tutto
l'oggetto) e' modesto; inoltre
sono evidenziati tutti i triangoli
anche quelli che sono coplanari
(in figura, tetraedro a destra)
C1
f1
A1
B1
Gouraud: (1971) un metodo di
interpolazione lineare molto
semplice: per la faccia f1
calcolo le tre intensita'
SOLO nei vertici A, B e C,
(con la formula di Phong)
poi calcolo l'intensita' in Pa e Pb, con
interpolazione lineare
tra A e C e ho Pa e
tra B e C e ho Pb , e poi sempre
con interpolazione lineare tra Pa e
Pb per avere l'intensita' nel punto P
(con calcolo incrementale tipo dda di
Bresenham per velocizzare il
calcolo nel passaggio da una linea
Pa --- Pb all' altra)
C1
Pa
A1
f1
Px
Pb
B1
segue figura
ottenuta con
OpenGL
metodo di Henri Gouraud 1971:
calcolo le normali all'oggetto nei
vertici di ogni superficie (triangolo),
ad es. facendo la media delle
normali alle faccie adiacenti,
oppure (oggetto geometrico)
calcolo le normali dalla definizione
esatta dell'oggetto; calcolo quindi
l'intensita' di luce nei vertici (tre nel
caso di f1) e poi :
per ogni punto P interno alla
superficie fk calcolo l' intensita' di
luce dall'interpolazione lineare tra i tre valori IA1, IB1, IC1
e ho: IP=IA1 + h( IB1- IA1 )+k( IC1- IA1)
con h e k fattori da 0 a 1, e h+k<=1
(tetraedro a sinistra in figura)
C1
f1
A1
B1
Phong adotta un metodo che da' una resa migliore, piu'
realistica, applicando la stessa formula per il calcolo
dell'intensita' di luce, ma:
invece di interpolare l'intensita' di luce calcolata nei vertici
del poligono (del triangolo)
si calcolano ai vertici le normali all'oggetto, e poi
si interpolano per ogni punto P della superficie le normali,
e si rifa' il calcolo dell'intensita' di luce in ogni punto;
il metodo richiede sensibilmente piu' calcoli (e tempo) del
metodo di Guoraud (anche con approccio dda)
ma fornisce risultati migliori;
Phong : si calcolano ai vertici le normali all'oggetto, e poi
si interpolano per ogni punto P della superficie le normali,
(e non le intensita' di luce calcolate solo ai vertici),
e si rifa' il calcolo dell'intensita' di luce in ogni punto;
il metodo Phong richiede molti piu' calcoli e quindi tempo
del metodo di Guoraud (anche con approccio dda)
- ma fornisce risultati migliori;
nota:
da Hearn e Baker:
il metodo di Phong richiede circa 6 volte il tempo del metodo di
Gouraud; con semplificazioni (espressione della formula di
Phong in forma di sviluppo in serie di Taylor troncata al tre
elementi) si ha la "fast Phong" formula, che e' comunque
ancora circa 2 volte piu' lenta del metodo di Gouraud;
metodo di Guoraud o Phong
nota:
i calcoli vanno fatti pixel per pixel della scena 2D,
dis-proiettando i pixel da 2D in 3D
(cosa possibile in quanto per ogni pixel viene conservata la
coordinata z, ed e' nota la trasformazione applicata per
ottenerlo),
e poi facendo i calcoli in 3D
(oppure si possono fare prima della proiezione in 3D, ma con
molti piu' punti, non sapendo prima quali punti appariranno
come pixel sulla scena 2D)
metodi migliori di resa di una scena :
ray-tracing (1980, Whitted)
radiosity (1984, Goral, Torrance, Greenberg, Bataille),
ibridi (1989, Hall)
photon-mapping (2001, Jensen)
e altri ...
per l'OpenGL vedere il sito ufficiale OpenGL.org (i tutorial
presenti nel manuale) e il sito di
Nate Robins www.cs.utah.edu/~narobins/opengl.html
OpenGL:
istruzioni necessarie per l'uso della luce; si deve specificare :
* che uso le luci
* quante luci uso
* dove sono le luci
per ogni poligono di ogni superficie di ogni oggetto
devo specificare un orientamento consistente (dei lati) del
poligono - (orario/antior.)
e la normale (verso l'esterno) (questo per discriminare i lati davanti dai lati dietro, che non si
vedono),
vediamo:
OpenGL:
istruzioni necessarie per l'uso della luce; si deve specificare :
* che uso le luci * quante luci uso * dove sono le luci
per ogni poligono di ogni superficie di ogni oggetto devo
specificare un orientamento consistente del poligono
(orario/antior.) e la normale (verso l'esterno) ; vediamo:
myDisplay (){ ... specifica uso di una luce:
...
glEnable(GL_LIGHTING); /* abilita uso luce */
... glCUBO(); ...
} /* myDisplay */
...
void glCUBO(){ disegna 6 facce,
specificando anche le normali
} /* glCUBO */
myDisplay (){ /* vedremo in EGD3D_12 */
glShadeModel(GL_SMOOTH); /* oppure (GL_FLAT); */
glEnable(GL_DEPTH_TEST);
...
glEnable(GL_LIGHTING); /* abilita uso luce */
glEnable(GL_LIGHT0); /* una luce */
glLightfv (GL_LIGHT0, GL_POSITION, position);
glCUBO();
/* disegna 6 facce */
} /* myDisplay */
...
void glCUBO(){
mySide4( 5, 1,0,4 ); /* left */
mySide4( 6, 2,3,7 ); /* right */
mySide4( 2, 0,1,3 ); /* back */
... piu' le altre tre facce
} /* glCUBO */
per una resa dell'immagine dell'oggetto con effetto luce si
deve specificare per ogni parte della superficie che forma
l'oggetto la normale alla superficie (qui i,j,k,l sono indici per
un array di punti )
void mySide4(int i,int j,int k, int l ){
if(clockwised) { givenormal(i,j,k);
glBegin(GL_QUADS);
glVertex3fv( punti[ i ] );
glVertex3fv( punti[ j ] ); idem k e l
....
glEnd();
} else { givenormal(i,k,j);
glBegin(GL_QUADS);
glVertex3fv(punti[i]); ..l..k..j ..
glEnd(); }
} /* mySide4 */
immagini ottenute con clockwise vero-falso, ovvero con normale
alla superficie volta all' interno(a sin), e all'esterno(a des)
qui il cubo ha solo 3 facce; la luce sta davanti (indicata con il cubetto celeste);
nel modello Goraud la superficie NON genera ombre, nella figura a sinistra le
due superfici interne (ma con normale verso noi) sono illuminate, anche se
dovrebbero essere in ombra (le ombre riportate sono un capitolo a parte)
immagini ottenute con clockwise vero-falso, ovvero con normale
alla superficie volta all' interno(a sin), e all'esterno(a des)
qui la luce sta in alto
calcolo della normale che da' l'orientamento di un poligono:
dato il poligono come un array di punti P0,P1,P2,P3...Pn
[ se e' un triangolo allora ho solo tre punti ]
posso ottenere il versore
N o norm
normale al poligono con un po' di calcoli, che vediamo ...
nota:
N o norm sara' poi usato dall'OpenGL:
... glNormal3fv( norm );
calcolo della normale che da' l'orientamento di un poligono:
dato il poligono come un array di punti P0,P1,P2,P3...Pn (nel
caso di un triangolo solo tre punti),
calcolo due vettori V1 e V2 ottenuti dai
tre punti adiacenti P0,P1,P2 del poligono:
V1 = P0-P1, e V2 = P1-P2,
la normale al poligono e' data dal
prodotto vettoriale V = V1 * V2
il vettore V viene poi normalizzato per ottenere un versore (la
normale al poligono)
N = V / |V|
che sara' poi usato dall'OpenGL:
... glNormal3fv( norm );
calcolo della normale ad un poligono:
void normalize( float v[3] ){
float d = sqrt( v[0]*v[0]+v[1]*v[1]+v[2]*v[2] );
if(d==0.0) exit(47); v[0]/=d; v[1]/=d; v[2]/=d;
}
void ncrossprod(float v1[3],float v2[3],float out[3] ){
out[0]=v1[1]*v2[2]-v1[2]*v2[1];
out[1]=v1[2]*v2[0]-v1[0]*v2[2];
out[2]=v1[0]*v2[1]-v1[1]*v2[0];
normalize(out);
}
void givenormal( int i0, int i1, int i2 ){
float d1[3], d2[3], norm[3]; int j;
for(j=0; j<3; j++){ d1[j]=punti[i0][j]-punti[i1][j];
d2[j]=punti[i1][j]-punti[i2][j];
} /* for j */
ncrossprod( d1, d2, norm );
if(Dentro) for(j=0;j<3;j++) norm[j]=-norm[j];
glNormal3fv( norm ); /* <<<<<< OpenGL */
} // givenormal
istruzioni per la resa della luce diffusa: luce / materiale
GLfloat luce_bianca[ ]={1.0,1.0,1.0,1.0};
GLfloat posizione[ ]={ 1.0, 1.0, 1.0, 0.0 }
// (8 luci previste in OpenGL, da 0 a 7)
glLightfv( GL_LIGHT0, GL_POSITION, posizione);
glLightfv( GL_LIGHT0, GL_DIFFUSE, luce_bianca);
glLightfv( GL_LIGHT0, GL_SPECULAR, luce_bianca);
..
inoltre posso specificare il "tipo di materiale", con:
GLfloat spec[ ] = {1.0,1.0,1.0,1.0};
GLfloat brilla[ ] = { 50.0 }; // esponente: 1 diffuso,100 brillante
glMaterialfv( GL_FRONT, GL_SPECULAR, spec );
glMaterialfv( GL_FRONT, GL_SHININESS, brilla );
primo param: GL_FRONT,GL_BACK, GL_FRONT_AND_BACK,
2.o param: GL_SPECULAR, GL_DIFFUSE, GL_AMBIENT, GL_EMISSION
3.o param: un vettore che specifica un "colore" RGBA, ovvero
i fattori da usare nella formula della luce riflessa ...
//posso specificare vari modelli luce, es illumina
//solo le facce verso l'osservatore (front), oppure
//entrambe - (default e' false)
glLightModeli(
GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
normalmente per le luci si assume il punto di vista per la luce
riflessa all'infinito, come qui sotto, per risparmiare tempo; piu'
realistico GL_TRUE, ma anche chiede piu' tempo...
glLightModeli(
GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
altri parametri: intensita' di luce globale:
GLfloat luce_ambiente[] = {0.2,0.2,0.2, 1.0);
glLightModelfv(
GL_LIGHT_MODEL_AMBIENT, luce_ambiente );
in ogni caso vedere
il manuale e
gli esempi su rete (dal manuale) ,
light.c, movelight.c, material.c,
e vari tutorials ....
colormat.c
segue una parte del demo
riguardante la specifica di "materiale" diverso per l'oggetto,
in realta' "materiali" diversi sono resi con modelli diversi
di luce diffusa/riflessa,
modelli diversi danno l'apparenza di un oggetto fatto da
materiali diversi (ottone, gomma, ...)
vediamo l'esempio del manuale -
"material.c"
dal manuale ("libro rosso") dell'OpenGL:
sono 3x4 sfere, con tre righe con tre tipi luce ambiente diversi,
quattro colonne con tipo riflessione diverso ("materiale" diverso)
dal "red book" demos, programma material.c,
che visualizza dodici sfere con parametri di resa diversi:
/* Draw twelve spheres in 3 rows with 4 columns.
first row spheres have materials with no ambient reflection.
1.st column has materials with blue, diffuse reflection only.
2.nd col.has blue diffuse reflection and specular reflection
with a low shininess (value 5 exponent) .
3.rd col.has blue diffuse reflection and specular reflection with a high shininess
exponent (more concentrated highlight).
4.th col.has materials which include an emissive component
vediamo in dettaglio la visualizzazione delle dodici sfere
// programma material.c dal manuale
GLfloat ambient[ ] = { 0.0, 0.0, 0.0, 1.0 }; // nessuna
GLfloat diffuse[ ] = { 1.0, 1.0, 1.0, 1.0 }; // luce bianca
GLfloat position[ ]= { 0.0, 3.0, 2.0, 0.0 }; // posiz in alto
GLfloat lmodel_ambient[ ]= { 0.4, 0.4, 0.4, 1.0 }; //luce amb
GLfloat local_view[ ] = { 0.0 };
// inizializzazioni:
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glOrtho ( -6.0,6.0, -3.0,3.0, -10.0,10.0); // spazio visibile
glMatrixMode(GL_MODELVIEW); glEnable(GL_DEPTH_TEST); ...
// una sola luce, GL_LIGHT0 (posso avere fino 10 luci...)
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); //nessuna
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); // luce bianca
glLightfv(GL_LIGHT0, GL_POSITION, position); // vedi sopra
// la luce e'puntiforme, in posizione data,
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
... // la luce non sta all'infinito
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
PRIMA RIGA:
1.st sphere - materials with no ambient reflection:
GLfloat no_mat[ ]
= { 0.0, 0.0, 0.0, 1.0 }; // RGBA
GLfloat mat_diffuse[ ] = { 0.1, 0.5, 0.8, 1.0 }; // RGBA
GLfloat no_shininess[ ] = { 0.0 }; // esponente del cosn(a)
// sphere first row, first column, diffuse reflection only
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT,
GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR,
no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glutSolidSphere(1.0, 16,
16); // sfera a 16 facce piane..
NB: GL_FRONT, non interessa visualizz.dell'altra faccia polig
PRIMA RIGA: materials with diffuse + reflection:
2.nd column with blue, diffuse plus specular reflection,
low shininess expon ( n=5 per il coefficiente cosn(a)
GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; // massimo
GLfloat low_shininess[] = { 5.0 }; // <<< cos5(a)
// second col: diffuse+specular reflection; low shininess;
glMaterialfv (GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv (GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv (GL_FRONT, GL_SHININESS, low_shininess);
glMaterialfv (GL_FRONT, GL_EMISSION, no_mat);
glutSolidSphere(1.0, 16, 16);
PRIMA RIGA: materials with diffuse light + high reflection:
3.rd column with blue, diffuse plus specular reflection,
high shininess expon ( n=100 per il coefficiente cosn(a)
GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; // massimo
GLfloat high_shininess[] = { 100.0 }; // <<< cos100(a)
// third col: diffuse+specular reflection; high shininess;
glMaterialfv (GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv (GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv (GL_FRONT, GL_SHININESS, high_shininess);
glMaterialfv (GL_FRONT, GL_EMISSION, no_mat);
glutSolidSphere(1.0, 16, 16);
PRIMA RIGA, quarta colonna:
has materials which include an emissive component
GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 }; // blue
GLfloat no_shininess[] = { 0.0 };
GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0}; // red
// 4.th: diffuse reflect+ emission; no ambient or specular
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
glutSolidSphere(1.0, 16, 16);
second row has materials with significant ambient reflection.
1.st column materials with blue, diffuse reflection only.
2.nd blue diffuse + specular reflection,low shininess expon.
3.rd diffuse + specular reflection, high shininess exponent
4.th has materials which also include an emissive component
per confronto, segue la 1.a riga di sfere senza rifless.ambiente
progr.material.c, 2.a riga,con luce ambiente diffusa; sfere: 1) solo luce riflessa diffusa;
2) riflessa diffusa+speculare 3)idem,luce speculare piu'lucida, 4)no speculare, si'
emmessa
GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
// qui solo i
GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 }; // parametri
GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 }; // della 2.a
GLfloat mat_specular[]= { 1.0, 1.0, 1.0, 1.0 }; // sfera
GLfloat low_shininess[] = { 5.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
glutSolidSphere(1.0, 16, 16);
// terza riga, materiale con riflessione ambiente colorata :
GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 }; //2.ariga
GLfloat mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 };//3.a:
colore luce ambiente piu' giallo -
12 sfere con varie luci ambiente(righe) e con + componenti (col)
solidi predefiniti OpenGL
nota:
la libreria OpenGL prevede un dato numero di solidi o oggetti
geometrici predefiniti, e sono: glut Objects:
- prima versione, a fil di ferro:
glutWireSphere (double radius, int slices, int stacks);
glutWireCone (double base, double height, int slices, int stacks);
glutWireCube (double size);
glutWireTorus (double innerRadius, double outerRadius, int sides, int rings);
glutWireDodecahedron (void);
glutWireTeapot (double size);
glutWireOctahedron (void);
glutWireTetrahedron (void);
glutWireIcosahedron (void);
di tutti esiste anche la versione a facce piene, "Solid" invece di
"Wire", come elencato nella pagina seguente:
solidi predefiniti OpenGL
nota:
la libreria OpenGL prevede un dato numero di solidi o oggetti
geometrici predefiniti, e sono:
glutSolidSphere (GLdouble radius, GLint slices, GLint stacks);
glutSolidCone (GLdouble base, GLdouble height, GLint slices,
GLint stacks);
glutSolidCube (GLdouble size);
glutSolidTorus (GLdouble innerRadius, GLdouble outerRadius,
GLint sides, GLint rings);
glutSolidDodecahedron (void); glutSolidTeapot (GLdouble
size);
glutSolidOctahedron (void);
glutSolidTetrahedron (void);
glutSolidIcosahedron (void); */
l'oggetto "teiera" o "teapot" risale agli anni settanta,
e' stato definito da M.Newell dell' univ. dell' Utah, nel 1975, (*)
e faceva parte di una primo insieme di oggetti 3D definiti da un
insieme di punti, assieme al maggiolino Volkswagen;
La teiera di Newell era definita da 306 punti, con 32 frammenti
di superfici bicubiche di Bezier
gli oggetti predefiniti in openGL possiedono anche le normali ai
frammenti di superfice, per cui si possono utilizzare anche per
prove di luci, come ad es nella pagina seguente...
_________________________
(*) Unix aveva 5 anni, il C aveva 4 anni, non c'era ancora il PC,
Jobs e Woszniak stavano montando il primo Apple2, il PDP
11/40 si stava diffondendo (assieme all'Unix e al C) ...
alcuni esempi di oggetti predefiniti OpenGL:
oggetto teiera e oggetto tetraedro
prodotti con il programma EGD3D_11LUCE1
di seguito altre figure prodotte con il programma detto;
Solidi OpenGL:
sfera, cono, toro,
(programma
EGD3D_12LUCESolidi )
solidi OpenGL a
4,6,8,12,20 facce:
tetraedro,
cubo,
ottaedro,
dodecaedro
icosaedro,
lo standard di base dell'OpenGL
definisce solo il modello di Gouraud,
alcuni modelli successivi piu' realistici sono stati
aggiunti dopo,
in particolare con i shading languages destinati
ad essere eseguiti dalla GPU cioe' dal
processore grafico;
rinviamo il discorso ad un tempo successivo.
fine capitolo modelli luce di Gouraud e Phong
Scarica

EGD23_LUCE