TRASFORMAZIONI GEOMETRICHE in 2D - trasformazioni di base - trasformazioni composte, si ottengono concatenando quelle di base TRASFORMAZIONI DI BASE - traslazione di vettore (dx,dy) - rotazione di angolo alpha attorno a origine - scalatura di fattori (sx,sy) lasciando ferma l'origine In coordinate cartesiane Traslazione esprimibile come somma di vettori P = (xP,yP) punto, Vt = (dx,dy) vettore traslazione P' = P+Vt = (xP+dx,y+dy) punto P traslato di Vt Rotazione e scalature esprimibili come prodotto matrice vettore P = (xP,yP) punto, alpha = angolo di rotazione, Mr[alpha] = ( cos(alpha) -sin(alpha) ) matrice ( sin(alpha) cos(alpha) ) P' = Mr[alpha] P = ( xP cos(alpha) -yP sin(alpha), xP sin(alpha) + yP cos(alpha) ) punto P ruotato di alpha attorno a origine in senso antiorario P = (xP,yP) punto, S = (sx,sy) fattori di scala Ms[S] = ( sx 0 ) ( 0 sy ) P' = Ms[S] P = (xP sx, yP sy) punto P scalato dei fattori in S Nota: con fattori di scala negativi ottengo riflessione rispetto all'asse (x o y) che avente il fattore negativo; se entrambi i fattori negativi, ottengo riflessione rispetto a origine TRASFORMAZIONI COMPOSTE Esempi: Rotazione attorno a un punto C = (xC,yC) diverso da origine - traslo di (-xC,-yC) per portare C nell'origine del nuovo riferimento - ruoto dell'angolo alpha voluto attorno a origine - traslo di (xC,yC) per portare C alla posizione originale P' = (Mr[alpha] (P-C)) + C Scalare un oggetto rispetto a un asse r diverso da x o y - ruoto per portare r a coincidere con l'asse x (per es.) del nuovo riferimento (se beta e' l'angolo tra asse x e r, ruoto di -beta) - scalo di fattore voluto rispetto a asse x, e fattore 1 per asse y - applico la rotazione inversa (ruoto di +beta) per portare r nella posizione originale P' = Mr[beta] ( Ms[sx,1] (Mr[-beta] P) ) Riflessione di rispetto a un punto C = (xC,yC) - traslo di vettore -C - scalo di fattori (-1,-1) - traslo di +C Trasformare un quadrato in un rombo con angolo nel vertice in basso=alpha - ruoto il quadrato di 45 gradi - scalo di fattori (cos(alpha/2)/cos(45), sin(alpha/2)/sin(45)) IN COORDINATE OMOGENEE cartesiane (x,y) ----> (x,y,1) omogenee omogenee (x,y,w) ----> (x/w,y/w) cartesiane (se w<>0) Matrici di rotazione e scalatura diventano 3x3 M = ( a b ) -----> ( a b 0 ) la riga e colonna aggiunte ( c d ) ( c d 0 ) sono uguali a quelle della matrice ( 0 0 1 ) identita' Anche traslazione si esprime come prodotto matrice vettore vettore di traslazione (dx,dy) ------> ( 1 0 dx ) gli elementi aggiunti ( 0 1 dy ) sono uguali a quelli ( 0 0 1 ) dell'identita' *** Verifcare che e' vero provando a fare prodotto matrice vettore *** PROPRIETA' DELLE TRASFORMAZIONI Derivabili da quelle del prodotto di matrici: - associativa - non commutativa - per come sono fatte le matrici associate alle trasformazioni di base, e' commutativa in alcuni casi particolari: - rotazione e scalatura con fattori uguali sui due assi - due trasformazioni dello stesso tipo Ricordare: L'ordine in cui le trasformazioni sono applicate al punto e' inverso all'ordine in cui sono scritte le matrici. *** ESERCIZI *** -1- data una scena, trasformarla opportunamente per farla rientrare esattamente nel quadrato di diagonale (0,0)-(1,1) -2- come -1-, ma ruotando la scena di 45 gradi prima di inquadrarla -3- Verificare l'equivalenza tra esprimere trasformazioni in cooordinate cartesiane e omogenee Mcart = ( a11 a12 ) Vcart = ( a13 a23 ) Pcart = ( x y ) ( a21 a22 ) vettore traslazione punto matrice scalatura o rotaz. Momog = ( a11 a12 a13 ) Pomog = ( x y 1 ) ( a21 a22 a23 ) ( 0 0 1 ) verificare che Momog Pomog = Mcart Pcart + Vcart -4- Dimostrare che prodotto di due matrici di trasformazione dello stesso tipo e' commutativo -5- Dimostrare che prodotto di matrice di rotazione per scalatura con fattori uguali sui due assi e' commutativo -6- Trovare controesempi per verificare che prodotto di matrice di rotazione per scalatura generica, di rotazione per traslazione, e di scalatura per traslazione, non e' commutativo -7- esprimere riflessione rispetto ad una retta assegnata mediante combinazione delle trasformazioni di base -8- esprimere mediante combinazione delle trasformazioni di base la trasformazione di un quadrato in un rombo IN OPENGL OpenGL e' un pacchetto per grafica 3D, non 2D. Tuttavia la grafica 2D si ottiene usando quella 3D con coordinate z = 0. Inoltre, tutti i vertici immessi (sia dando 2 che 3 coordinate, glVertex2f e glVertex3f) sono tradotti in rappresentazione interna a coordinate omogenee (4 coordinate x,y,z,w). OpenGL tiene 2 matrici di trasformazione nel suo stato corrente: - MODELVIEW per posizionare gli oggetti nella scena e la telecamera - PROJECTION per definire proiezione di vista (parallela o prospettica) sono matrici 4x4 (matrici in coordinate omogenee 3D), a queste matrici vanno soggette tutte le primitive che vengono rese: primitiva--> matr. MODELVIEW Mm--> matr. PROJECTION Mp--> visualizzazione (punti P) (Mm P) (Mp (Mm P) ) Vi sono primitive per modificare le matrici correnti. Sono le stesse su entrambe le matrici. Noi dobbiamo agire sulla MODELVIEW: glMatrixMode(GL_MODELVIEW); ---> intendiamo lavorare sulla MODELVIEW OpenGL fornisce primitive per assegnare la matrice corrente: glLoadIdentity(); ---> la pone uguale all'identita' glLoadMatrixf(float *M); M array di 16 float che contiene la matrice per colonne ---> la pone uguale alla matrice M; metodo pero' NON agevole, devo calcolare la matrice io Di solito si fa glLoadIdentity e poi si costruisce la matrice voluta componendo trasformazioni elementari sulla matrice corrente; la composizione avviene per POST-moltiplicazione, quindi le trasformazioni verranno eseguite in ordine inverso a come le compongo (altri sistemi, es. PHIGS, permettono di specificare se voglio pre- o post-moltiplicare). glTranslatef(dx,dy,dz); --> moltiplica con matrice di traslazione; mettere dz=0 per avere traslazione 2D glRotatef(ang,rx,ry,rz) --> moltiplica con matrice di rotazione attorno a retta per origine e coefficienti (rx,ry,rz); mettere rx=ry=0, rz=1 per rotazione attorno a asse z, che realizza rotazione 2D; angolo ang misurato in gradi glScalef(sx,sy,sz) -------> moltiplica con matrice di scalatura; mettere sz=1 per avere scalatura 2D esiste poi anche glMultMatrixf (moltiplica con matrice che costruisco a parte e passo in argomento). Per leggere la matrice corrente: glGetDoublev(GL_MODELVIEW_MATRIX, double *); glGetFloatv(GL_MODELVIEW_MATRIX, float *); --> ritornano la matrice corrente in un array di double o float passato come argomento (array di 16 elementi, memorizza la matrice per colonne) Esempio: Ruotare di 90 gradi attorno a punto C = (10,15) glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(10.0,15.0,0.0); glRotaref(90.0,0.0,0.0,1.0); glTranslatei(-10.0,-15.0,0.0); Ricordare: le trasformazioni vengono applicate in ordine inverso all'ordine nel quale specifico le matrici! PRIMITIVE E TRASFORMAZIONI Spesso si crea una scena definendo un solo oggetto e poi replicandolo piu' volte, ogni volta soggetto ad una trasformazione diversa. Es: una scena composta di parallelepipedi di varia forma e dimensione, tutti ottenibili scalando cubi (si dice: tutti ISTANZE del cubo). In questo modo si guadagna efficienza, specialmente se si usano due strumenti forniti da OpenGL: - display lists - stack di matrici DISPLAY LISTS Supponiamo di definire una primitiva: glBegin(...); ... glEnd(); Per default, OpenGL la manda in visualizzazione subito, e poi la "dimentica"; se voglio visualizzarla di nuovo, devo rieseguire il pezzo di codice contenente la sua definizione. Display list = modo per far si' che OpenGL "memorizzi" una primitiva in modo da poterla ridisegnare solo chiamandola per nome. Importante per efficienza: posso chiamare la stessa display list dopo aver cambiato lo stato (per es. la matrice MODELVIEW) ottenendo cosi' una versione trasformata dello stesso oggetto. Istruzioni: glNewList(ident,mode); --> alloca una nuova lista e la associa all'dentificatore (intero >0) passato; il modo puo' essere: - GL_COMPILE = la lista viene memorizzata ma non resa - GL_COMPILE_AND_EXECUTE = la lista viene memorizzata e resa se ident ha gia' associata una display list, essa viene rimpiazzata glEndList(); --> conclude la display list; tra glNewList e glEndList() trova posto il contenuto della display list, che e' una serie di comandi OpenGL (primitive tra glBegin(...) e glEnd(), cambiamenti di stato, chiamata ad altre display lists - ved. glCallList) glCallList(ident); --> rende la lista associata all'identificatore, usando lo stato corrente di OpenGL. la display list deve essere stata completamente definita (glEndList eseguito) prima di poter essere chiamata. glDeleteLists(id1,id2) --> cancella tutte le display list associate agli identificatori compresi tra id1 e id2 STACK DELLE MATRICI OpenGL ha uno stack di matrici di trasformazione che permette di modificare temporaneamente la matrice corrente per poi rispristinare quella precedente. glPushMatrix(); --> duplica la matrice corrente e pone la nuova copia in cima allo stack tutte le seguenti operazioni di modifica della matrice corrente agiscono sulla matrice in cima allo stack glPopMatrix(); --> toglie la matrice in cima allo stack, portando in cima la matrice che si trova immediatamente sotto (rispristina la matrice precedente) *** ESERCIZI *** -1- scrivere programma OpenGL che, data una scena 2D (per es. un insieme di punti letti da file), la visualizza inquadrandola nella finestra grafica; nota: devono essere trasformati in modo da stare nel quadrato (-1,-1)-(1,1), ved. esercizio -1- del gruppo precedente -2- scrivere un programma che definisce e visualizza una scena (per es. un tavolo) utilizzando istanze di una primitiva cubo, e trasformazioni di scalatura e traslazione -3- scrivere un programma che definisce e visualizza un ramo con foglie utilizzando un'unica primitiva (es. un rombo), e trasformazioni opportune ESEMPIO Programma che visualizza torre di Hanoi Display list che realizza quadrato unitario #define UNIT_SQUARE 1 /* identif. display list */ void defineUnitSquare(void) { glNewList(UNIT_SQUARE,GL_COMPILE); glBegin(GL_POLYGON); glVertex2f(0.0,0.0); glVertex2f(1.0,0.0); glVertex2f(1.0,1.0); glVertex2f(0.0,1.0); glEnd(); glEndList(); } Realizzazione di rettangolo chiamando la display list void drawRectangle(float x0, float y0, float w, float h) { /* modifica locale della matrice corrente */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(x0,y0,0.0); /* poi lo trasla alla pozizione voluta */ glScalef(w,h,1.0); /* prima lo scala alle dimensioni volute */ /* chiama la display list sotto effetto della trasformazione */ glCallList(UNIT_SQUARE); /* ripristina lo stato precedente */ glPopMatrix(); } Procedura che realizza la torre di Hanoi void drawHanoi(void) { float xp = -10.0, yp = 0.0, sx = 20.0, sy = 2.0; int i; for (i=0;i<5;i++) { drawRectangle(xp,yp,sx,sy); xp+=2; yp+=2; sx-=4; } }