Corso Di Programmazione Grafica per il Tempo Reale Shading e smoothing Daniele Marini Scopo • Raffigurare forme con superfici curve rappresentate come poliedri • Il modello di illuminazione determina il valore di colore in punti significataivi (vertici per metodo di Gourad, punti intermedi per metodo di Phong) • Si tratta di un problema di approssimazione o interpolazione • Occorre stimare la curvatura in ogni punto, e il gradiente della curva approssimante 2 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 3 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 4 Il calcolo del gradiente di superfici curve dipende da come la superficie è rappresentata (forma parametrica o forma implicita). Es. sfera - equazione implicita 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 5 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: 6 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 determina 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) 7 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); 8 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 9 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) 10 Triangle strip 11 Flat vs Smooth Smooth shading Flat shading 12 Interpolazione • essenziale nei problemi di animazione: – date due posizioni “chiave” relative al fotogramma al tempo t 0 e al tempo t 1 determinare le posizioni intermedie relative a ogni singolo fotogramma – occorre garantire regolarità nel movimento – le posizioni possono riguardare oggetti, fotocamera o altro 13 Interpolazione Lineare • Definisce un percorso rettilineo tra due punti in uno spazio n-dimensionale • Una dimensione di interpolazione 14 Interpolazione Lineare t=1 • Data due punti P1 e P2 definisco una funzione nel parametro t[0,1] P(t) = P0 + t (P1 – P0) = (1-t)P0 + t P1 P2 P(t) t=0 P1 15 Interpolazione Lineare • Nel piano, dati due punti (x1,y1) e (x2, y2) si vuole calcolare (xP, yP) conoscendo il valore di xP y1 x1 y2 yP = ? dy xP y2-y1 x2 16 Interpolazione Lineare y p y1 dy vale la relazione : (y 2 y1 )(x p x1 ) dy x p x1 x 2 x1 da cui : (y 2 y1 )(x p x1 ) y p y1 x 2 x1 Si possono usare tecniche incrementali per accelerare il calcolo 17 Interpolazione Bi-lineare • Considero due dimensioni di interpolazione • Utilizzato per esempio all’interno di griglie regolari (es. texture) • Peso i punti con P P delle aree 1 2 A4 A1 P1 A2 P2 A3 P3 A4 P4 P A1 A2 A3 A4 A3 P A2 P3 A1 P4 18 Interpolazione quadratica e cubica • L’interpolazione lineare calcola i valori intermedi utilizzando l’equazione della retta (grado 1) passante per i due punti • Possiamo considerare anche equazioni di grado più alto (secondo o terzo) per ottenere interpolazioni più precise, ma abbiamo bisogno di più punti 19 Curve parametriche • Quando interpolo tra due punti l’interpolazione lineare è sufficiente • Quando ho più punti posso usare interpolazione lineare tra ogni coppia di punti successivi ma ottengo un percorso che presenta discontinuità di curvatura nei punti 20 Curve parametriche • Per risolvere il problema posso utilizzare una curva di grado stabilito che interpoli o approssimi i punti. • La curva avrà equazione C(t) f (P1 ,P2 ,...,PN ;t) t 0,1 • Esistono differenti schemi di costruzione della curva (Bezier, B-Spline, NURBS,etc) 21 Smooth shading (interpolato) • Interpolazione di Gouraud glShadeModel(GL_SMOOTH) • Interpolazione di Phong 22 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 23 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 24 Dipende dall’orientamento 25 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 26 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 27 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 28 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} 29 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); 30 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 31 • 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) 32 • 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) 33 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); 34 Con GL_FRONT e GL_BACK si specificano proprietà differenti 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) 35