TRASFORMAZIONI GEOMETRICHE in 3D - trasformazioni di base - trasformazioni composte, si ottengono concatenando quelle di base TRASFORMAZIONI DI BASE - traslazione di vettore (dx,dy,dz) - rotazione di angolo alpha attorno a una retta di direzione assegnata, passante per l'origine - scalatura di fattori (sx,sy,sz) lasciando ferma l'origine TRASFORMAZIONI COMPOSTE Si ottengono applicando trasformazioni di base in successione. Esempi: Rotazione/scalatura attorno a un punto C = (xC,yC,zC) diverso da origine - traslo di (-xC,-yC,-zC) per portare C nell'origine del nuovo riferimento - ruoto dell'angolo voluto / scalo dei fattori voluti rispetto a origine - traslo di (xC,yC,zC) per portare C alla posizione originale TRASFORMAZIONI COME MATRICI Esprimendo i punti in coordinate omogenee, ogni trasformazione puo' essere rappresentata da una matrice M 4x4 in coordinate omogenee. Dato un punto P = (x,y,z,w), il punto trasformato e' P' = M P. Se un punto subisce due trasformazioni, prima una rappresentata dalla matrice M1 e poi un'altra rappresentata dalla matrice M2, il punto trasformato e' P' = M2 M1 P = M2 ( M1 P ) = (M2 M1) P per proprieta' associativa OpenGL tiene una matrice di trasformazione corrente su cui accumulo le matrici (corrispondenti a trasformazioni di base) che compongono la trasformazione complessa che voglio effettuare. Tale matrice risultante sara' applicata ai punti che costituiscono le primitive OpenGL che andro' a rendere. Ricordare: In OpenGL la nuova matrice che specifico viene composta con la matrice presente nel seguente modo: Mold vecchia matrice Mnew nuova matrice M' = Mold Mnew e' la matrice risultante ne segue che le trasformazioni sono applicate in ordine inverso all'ordine in cui compongo le matrici. ESEMPIO Trasformazione per far stare la scena in una finestra 3D uguale al cubo con x,y,z tra -1 ed 1. Siano minX,maxX, minY,maxY, minZ, maxZ le coordinate estreme della scena. 0) parto dalla matrice identica 1) traslo per portare il centro della scena nell'origine 2) scalo (rispetto all'origine) per portare la scena alle dimensioni volute Osservazione: Sto mappando in un volume cubico una scena che puo' avere un bounding box non cubico. Posso scegliere o di non mantenere le proporzioni della scena, e scalarla deformandola in modo tale che occupi tutto il cubo interamente, oppure rispettare le proporzioni ed lasciare eventualmente spazio vuoto nel cubo. glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (keep_ratio) /* decido di mantenere le proporzioni */ { max_dim = (maxX-minX); if ((maxY-minY) > max_dim) max_dim = (maxY-minY); if ((maxZ-minZ) > max_dim) max_dim = (maxZ-minZ); glScalef(2.0/max_dim,2.0/max_dim,2.0/max_dim); } else { glScalef(2.0/(maxX-minX), 2.0/(maxY-minY), 2.0/(maxZ-minZ)); } glTranslatef(-0.5*(maxX+minX), -0.5*(maxY+minY), -0.5*(maxZ+minZ)); } ALTRO PROBLEMA Mantenere le proporzioni in una scena quando la finestra su cui OpenGL fa il rendering viene ridimensionata (per es. da quadrata passa a rettangolare). Supponiamo di avere una scena 2D e di averla scalata e centrata nella area che per default OpenGL inquadra (coordinate tra -1 e +1). Per default OpenGL mappa questo quadrato nella finestra fisica in modo da occuparla interamente. Se la finestra e' quadrata --> la scena mantiene le proporzioni tra x e y. Se non e' quadrata --> la scena viene deformata. Posso ovviare dicendo a OpenGL di usare solo una sottoparte quadrata di una finestra rettangolare. L'istruzione da usare e' glViewport(x1,y1,x2,y2) dove x1,y1,x2,y2 specificano (in pixel) la sottoarea di finestra da utilizzare per il rendering tipicamente da mettere nella reshape callback (funzione chiamata automaticamente da Glut quando la finestra varia dimensione). Esempio: void ReshapeCallBack(int w, int h) { int d = ( (w>h) ? h : w ); glViewport(0, 0, d, d); } e nel main: glReshapeFunc(ReshapeCallBack); 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 tre assi - due scalature - due traslazioni - due rotazioni attorno a stesso asse (NON se ruoto attorno ad assi diversi) *** ESERCIZI *** -- Verificare la commutativita' della composizione di trasformazioni nei casi detti sopra, e trovare controesempi che mettano in evidenza la non commutativita' negli altri casi STRUTTURA DI UN PROGRAMMA OPENGL - BUILD_SCENE Una funzione che costruisce la scena posizionando i vari oggetti all'interno di essa. Tale funzione usera' matrici di trasfomazione per dare a ciascun oggetto le dimensioni e la posizione giusta. Queste trasformazioni sono locali a ciascun oggetto e non devono influenzare gli altri oggetti: sono racchiuse tra glPushMatrix e glPopMatrix. - TRASF_SCENE Una funzione che trasla e scala la scena per farla stare nel volume di vista (non abbiamo ancora visto le trasformazioni di vista, che permettono di modificare il volume di vista di default) - ADD_USER_TRANSF Una funzione (o piu' funzioni) che aggiunge eventuali trasformazioni utente (per es. se si e' data all'utente la possibilita' di ruotare interattivemente le scena) E' importante per pulizia che ci sia un solo posto nel programma dove sono eseguite le trasformazioni globali sulla scena: ADD_USER_TRANSF (tipicamente dentro la callback associata a qualche dispositivo di input) non esegue modifiche sulla matrice, ma si limita a cambiare i valori di qualche opportuna variabile globale (es. l'angolo di rotazione corrente), e poi chiamare glutPostRedisplay() (glutPostRedisplay provoca l'esecuzione la display callback). TRASF_SCENE (tipicamente dentro la display callback) esegue le modifiche sulla matrice in base ai valori dei parametri globali assegnati da ADD_USER_TRANSF, poi disegna la scena. BUILD_SCENE contiene le primitive OpenGL per disegnare la scena. Se sto usando display list, BUILD_SCENE e' chiamata una sola volta nel main per costruira la (o le) display list, e nella display callback la scena e' ridisegnata chiamando questa (queste) display list. Se non sto usando display list, BUILD_SCENE rende direttamente le primitive, ed e' chiamata nella display callback stessa (quindi, eseguita tutte le volte che ridisegno la scena).