Knowledge Aided Engineering Manufacturing and Related Technologies INFORMATICA GRAFICA 5 Maggio Interattività michele.antolini@mail.polimi.it
Input Libreria glut interfaccia con il window system gestione eventi gestione input keyboard/mouse primitive 3D realizza trasparenza rispetto al window system sottostante
Input Input da tastiera glutkeyboardfunc( void (*func)(unsigned int key, int x, int y) Quando viene premuto un tasto ne restituisce il codice ASCII (key) e le coordinate (x,y) del mouse al momento della pressione void key_pressed(int key, int x, int y) { if(key == Q key == q ) exit(0); } Non viene riconosciuto l evento di rilascio del tasto
Input Input da tastiera GLUT definisce tasti speciali in glut.h Tasto F1: GLUT_KEY_F1 Tasto freccia in alto: GLUT_KEY_UP Etc. per F2, DOWN, LEFT... Modificatori: GLUT_ACTIVE_SHIFT GLUT_ACTIVE_CTRL GLUT_ACTIVE_ALT Restituiti dalla glutgetmodifiers() if ( glutgetmodifiers() == GLUT_ACTIVE_SHIFT )...
Input Eventi di input glutmousefunc(void (*func)(int button, int state, int x, int y)) Pressione di un tasto del mouse button può valere GLUT_LEFT_BUTTON GLUT_RIGHT_BUTTON GLUT_MIDDLE_BUTTON state può valere GLUT_UP GLUT_DOWN
Input Eventi di input glutmotionfunc( void (*func)(int x, int y) ) Questa callback viene attivata quando il mouse si muove con uno o più tasti premuti glutpassivemotionfunc( void (*func)(int x, int y) ) Questa callback viene attivata quando il mouse si muove senza tasti premuti
Input Operazioni in background glutidlefunc( void (*func)() ) Questa callback viene attivata quando non avvengono eventi durante l esecuzione del main loop gluttimerfunc (unsigned int msecs, void (*func) (int value), value); esegue la funzione specificata nel secondo parametro dopo almeno msecs millisecondi, passando il valore value viene eseguita solo una volta per ottenere un loop, richiamare la gluttimerfunc alla fine della funzione chiamata!
Input Operazioni in background Ad esempio: void Timer(int extra) { // code... glutpostredisplay(); gluttimerfunc(30,timer,0); } void Timer(int extra) { glutpostredisplay(); gluttimerfunc(30,timer,0); } int main(void) { glutinitdisplaymode(glut_double GLUT_RGB); glutcreatewindow( Window title"); glutdisplayfunc(display); gluttimerfunc(30,timer,0); glmatrixmode(gl_projection); glloadidentity(); glfrustum(-1,1,-1,1,1,3); gltranslated(0,0,-2); glmatrixmode(gl_modelview); glutmainloop(); return 0; }
Input Ridisegno della scena All interno delle callback, se vengono cambiati parametri che influenzano il disegno della scena, è necessario avvertire il motore grafico della necessità di ridisegnarla Per fare ciò, è necessario chiamare la funzione glutpostredisplay();
Double Buffering Ottimizzazione del rendering di una scena Si utilizzano due buffer: front buffer: visualizzato, non modificabile back buffer: modificabile, non visualizzato Alla fine della display() i buffer vengono scambiati Abilitazione double buffer: glutinitdisplaymode( GL_DOUBLE...[altri flag ); Scambio dei buffer alla fine della display(): void Display() { glclear(). /* disegno scena */. glutswapbuffers() }
Sistemi di coordinate I sistemi di coordinate di OpenGL e della finestra sono differenti OpenGL ha (0,0) in alto a sinistra (per la convenzione del refresh dello schermo da sinistra a destra, dall alto in basso) La finestra ha (0,0) in basso a sinistra I parametri y delle callback vanno riassegnati se si vogliono riutilizzare per disegnare tramite OpenGL y_gl = window_width y_win
Picking Disegnando una scena, è possibile dare dei nomi (indici) agli oggetti disegnati Passando alla modalità GL_SELECT è possibile controllare se il mouse è sopra uno degli oggetti (ed ovviamente conoscere quale) All inizio della display, azzerare lo stack dei nomi con glinitnames() Prima di disegnare un oggetto, chiamare glpushname( int name ) Disegnare l oggetto Chiamare glpopname(); Si possono anche innestare Push e Pop per creare gerarchie!
Picking void display() {... glinitnames(); glpushname(0); //si può usare una costante... drawbody(); glpopname(); glpushname(1); drawhead(); draweyes(); glpopname(); drawground(); }...
Picking Una volta dato un nome agli oggetti disegnati, il trucco è il seguente: Date le coordinate del mouse e il viewport attuale, ridisegnamo la scena in modalità GL_SELECT utilizzando un nuovo viewport intorno al cursore (nel nostro esempio, un quadrato 5x5 pixel) Tornando alla modalità GL_RENDER (quella predefinita) OpenGL restituisce il numero di oggetti (con un nome) disegnati Gli oggetti disegnati, sono quelli la cui proiezione appare alle coordinate attuali del mouse
Picking #define BUFSIZE 512 GLuint selectbuf[bufsize];... void startpicking(int cursorx, int cursory) { GLint viewport[4]; glselectbuffer(bufsize,selectbuf); //imposta il buffer per la selezione glgetintegerv(gl_viewport, viewport); //riceve il viewport corrente [x,y,w,h] glrendermode(gl_select); //modalità selezione } glmatrixmode(gl_projection); //modifica della proiezione attuale glpushmatrix(); glloadidentity(); glupickmatrix(cursorx,viewport[3]-cursory, 5, 5, viewport); gluperspective(45,viewport[2]/viewport[3],0.1,1000); glmatrixmode(gl_modelview); display(); //ridisegna la scena (in selection mode) glmatrixmode(gl_projection); glpopmatrix(); //reimposto la matrice in modalità GL_PROJECTION!!!! hits = glrendermode(gl_render); //ora è possibile processare il select buffer...... glmatrixmode(gl_modelview); //reimpostiamo la modalità di disegno
Picking Selection buffer Il numero di hits restituito dalla glrendermode() dice quanti oggetti sono stati effettivamente disegnati L array selectbuf viene riempito in questo modo: N oggetti nella name stack può essere >1 se si usano gerarchie Z minimo Z max Nome (indice) ripetuto se il primo campo > 1
Picking Esempio di selection buffer: hits = 3 0 //è stato disegnato un oggetto, name stack vuoto 10 //z min 2000 //z max 2 //è stato disegnato un oggetto,name stack conteneva 2 valori 2 //z min <- è il valore più basso, l utente vede questo 300 //z max 1 // primo valore nel name stack 2 // secondo valore nel name stack 1 //questa volta la name stack conteneva un solo valore 50 //z min 600 //z max 3 // valore nel name stack
Picking printf("%d hits:\n", hits); for (i = 0; i < hits; i++) printf( "Number: %d\n" "Min Z: %d\n" "Max Z: %d\n" "Name on stack: %d\n", (GLubyte)selecBuf[i * 4], (GLubyte)selectBuf[i * 4 + 1], (GLubyte)selectBuf[i * 4 + 2], (GLubyte)selectBuf[i * 4 + 3] ); printf("\n");