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