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