LA LIBRERIA GRAFICA OPENGL - I Parte

Libreria grafica: Pacchetto software per lo sviluppo di applicazioni grafiche. API (Application Program Interface) composta da un insieme di funzioni e procedure delle quali esiste una precisa specifica. Funzionamento di una libreria grafica:

OPEN GL (Open Graphics Library)

Libreria grafica progettata per rendering in tempo reale e sviluppata (GL) per Silicon Graphics. Scritta in C.

Organizzazione della libreria per sistema X:

Una organizzazione simile vale per l'ambiente Microsoft Windows. Le funzioni GL / GLU / GLX / GLUT iniziano con "gl" / "glu" / "glx" / "glut".

Primitive geometriche

Primitive di base

Contenute nella libreria GL, consentono di disegnare oggetti a facce piane. Una primitiva e' specificata da: Ciascun vertice e' specificato dandone le coordinate in un sistema di riferimento locale alla primitiva (coordinate di modellazione).

Come si definisce una primitiva

glBegin(tipo primitiva);
  
glVertex(...) per ogni vertice che forma la primitiva
  
glEnd();
La funzione glVertex ha piu' varianti secondo il numero e il tipo di argomenti. Es:

Tipi di primitive

Nota su quadrilateri e poligoni

OpenGL garantisce trattamento corretto solo per poligoni (e quadrilateri come caso particolare) semplici e convessi. Alcune configurazioni di vertici per GL_QUADS, GL_QUAD_STRIP e GL_POLYGON possono dare luogo a poligoni intrecciati o non convessi e quindi a risultati errati.

Esempio

Questo definisce un triangolo giacente sul piano z=0:
  glBegin(GL_TRIANGLES);
  glVertex2f(-0.5,0.0);
  glVertex2f(0.5,0.0);
  glVertex2f(0.0,0.5);
  glEnd();

Primitive piu' avanzate

Contenute nella libreria GLU ed implementate a partire dalle primitive di base di GL.

Esempio

gluSphere(aux ,raggio, numero_fette, numero_strati)
dove aux e' un puntatore ad un oggetto ausiliario usato da OpenGL, la sfera viene approssimata mediante poligoni dividendola verticalmente in fette ed orizzontalmente in strati, controllo la precisione dell'approssimazione specificando quante fette e strati voglio usare.

Attributi pittorici

Lo stato corrente di OpenGL contiene i valori degli attributi. L'aspetto di una primitiva geometrica dipende dal valore corrente degli attributi al momento in cui viene eseguita.

Una volta che e' stato impostato un certo valore per un attributo, questo influisce sul modo in cui sono disegnate tutte le primitive che seguono fino a che il valore non viene nuovamente cambiato.

Portata degli attributi

Attributi a livello delle primitive

Attributi che influiscono su una primitiva nel suo complesso Vanno assegnati al di fuori della primitiva (= fuori da glBegin/glEnd).

Vanno assegnati prima della primitiva, in modo che al momento in cui si incontra la primitiva i valori siano quelli voluti.

Istruzioni per impostare gli attributi:

Attributi a livello dei vertici

Attributi che agiscono "vertice per vertice" anche all'interno della stessa primitiva Possono essere cambiati all'interno di una coppia glBegin/glEnd. Possono anche essere assegnati fuori (prima della primitiva) se l'attributo assume lo stesso valore per tutti i vertici della primitiva.

Se i vertici di una primitiva hanno valori diversi dell'attributo, il valore dell'attributo in un punto interno alla primitiva viene interpolato ed assume un valore ottenuto come media dei valori nei vertici, pesata rispetto alla distanza del punto dai vertici.

Esempio: un segmento con un vertice rosso e uno giallo assumera' al suo interno toni di arancio degradanti dal rosso verso il giallo).

Vedremo materiali e normali quando parleremo di illuminazione. Per adesso diciamo solo che, per far si' che un vertice brilli di luce propria di un certo colore, bisogna chiamare:

dove colore e' un vettore di 4 float che specificano il colore della luce emessa nel sistema RGBA.

Definizione di primitiva con attributi

Si devono scrivere nell'ordine: Esempio che disegna un triangolo pieno con colore rosso, verde, blu nei tre vertici e sfumato di conseguenza all'interno (il colore e' dovuto a luce propria emessa dal triangolo):
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  glBegin(GL_TRIANGLES);
  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, red);
  glVertex2f(-0.5,-0.5);
  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, green);
  glVertex2f(0.5,-0.5);
  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, blue);
  glVertex2f(0.0,0.5);
 glEnd();
dove red, green, blue sono tre vettori:
GLfloat red[4] = {1.0,0.0,0.0,1.0};
GLfloat green[4] = {0.0,1.0,0.0,1.0};
GLfloat blue[4] = {0.0,0.0,1.0,1.0};

Stack degli attributi

Esiste il modo di cambiare temporaneamente il valore di un attributo e poi ripristinare lo stato precedente.
Esempio: cambiare il colore corrente in rosso, disegnare qualcosa in rosso e poi ripristinare il colore precedente qualunque esso sia.

Se voglio modificare il valore di un attributo momentaneamente per disegnare una certa primitiva, salvando il valore precedente per poi ripristinarlo, uso glPushAttrib e glPopAttrib.

Esempio che disegna un triangolo rosso, e anche tutto cio' che disegno in seguito sara' rosso (se non cambio colore nel frattempo):

  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, red);
  glBegin(GL_TRIANGLES);
  glVertex2f(-0.75,0.0);
  glVertex2f(-0.25,0.0);
  glVertex2f(-0.5,0.5);
  glEnd();
Esempio che disegna un triangolo in rosso e poi ripristina il colore precedente (cio' che disegno dopo sara' del colore che avevo prima di assegnare il rosso):
  /* salva su stack attributi relativi alla luce */
  glPushAttrib(GL_LIGHTING_BIT);
  /* imposta temporaneamente luce emessa di colore rosso */
  glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, red);
  glBegin(GL_TRIANGLES);
  glVertex2f(-0.75,0.0);
  glVertex2f(-0.25,0.0);
  glVertex2f(-0.5,0.5); 
  glEnd();
  /* ripristina condizioni precedenti */
  glPopAttrib();

Testo

OpenGL supporta due forme: STROKE e RASTER.

Trasformazioni geometriche

Nel prossimo capitolo vedremo: Per il momento consideriamo una situazione semplificata: In tal modo non e' necessario definire trasformazioni. Vedremo le trasformazioni in seguito.

Disegnamento della scena OpenGL

(Confrontare il corpo della funzione display nell'esempio es1.c).
  1. Abilitare le funzioni di OpenGL non di default:
  2. Pulire il foglio:
  3. Definizione delle trasformazioni (in questo esempio manca perche' usiamo le trasformazioni di default)
  4. Disegno:

OpenGL e GLUT

OpenGL assume di avere a disposizione una finestra di output su cui disegnare. Tale finestra deve essere richiesta dialogando col window system / window manager. OpenGL non prevede funzioni per questo: bisogna affiancare ad OpenGL un toolkit.
Glut e' un toolkit prototipale scritto per X window system che permette di ottenere finestre per disegnare in OpenGL e di gestirle.

Glut non e' un pacchetto per la realizzazione di interfacce grafiche, non fornisce sofisticati componenti di interfaccia (bottoni, campi di testo...).
Le funzionalita' di Glut sono piu' limitate:

Aprire una finestra di rendering

Sequenza di istruzioni da chiamare nell'ordine (tipicamente nel main):

1. glutInit(&argc, argv);

Stabilisce connessione con X server. Chiamata con gli stessi argomenti con cui il main program e' invocato da command line.

2. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

Stabilisce i requisiti della finestra che si vuole aprire. Qui i requisiti sono: una finestra abbia double buffer, RGBA color mode, e z-buffer per l'eliminazione delle parti nascoste.

3. glutInitWindowSize(dimX,dimY);

Stabilisce le dimensioni della finestra da aprire (in pixel).

4. win = glutCreateWindow(etichetta);

Crea la finestra e ritorna un identificatore intero per tale finestra. Etichetta e' una stringa che comparira' come titolo della finestra.

Gestire una finestra

Glut permette al programma di associare ad una finestra funzioni (dette callback) che vengono chiamate automaticamente quando avvengono certi eventi. Le principali callback previste: Le funzioni vengono registrate con glutXXXXXFunc(funzione); e deregistrate con glutXXXXXFunc(NULL); dove XXXXX e' il nome della funzione che si sta registrando.

Esempi:

glutDisplayFunc(f1);
glutIdleFunc(f2);
dove f1, f2 sono funzioni C del tipo void f(void).

Alcune delle funzioni callback accettano argomenti, che sono passati automaticamente dal sistema alla funzione chiamata.

Ciclo degli eventi

L'istruzione glutMainLoop() entra in un ciclo senza fine, interamente gestito da Glut, nel quale Va chiamato come ultima istruzione del main, dopo avere registrato le callback. Il loop non termina mai. Il programma puo' terminare eseguendo exit all'interno di una funzione callback.

Nota: se e' stata registrata una Idle callback, questa viene chiamata ad ogni ciclo.

Codice OpenGL in Glut

Il codice OpenGL trova posto nella display callback.

Non mettere codice OpenGL dentro altre callback. Se una callback deve ridisegnare la scena (es. idle callback per animazione), questo si ottiene chiamando la funzione glutPostRedisplay(); che provoca l'esecuzione della display callback.

Altro su GLUT

Altre informazioni su Glut (callback e menu' pop-up).