Possiamo pensare una scena OpenGL come strutturata in modo gerarchico, cioe' composta da un insieme di oggetti, ciascuno dei quali puo' essere un aggregato di sotto-oggetti ecc.
Gli oggetti elementari (indivisibili) sono le singole primitive.
Un oggetto aggregato e' costituito da piu' oggetti (elementari o aggregati).
Questo porta a una gerarchia di aggregazione, che puo' essere rappresentata come un albero dove
Ciascuna primitiva (oggetto elementare) e' definito dandone i
vertici in un suo sistema di coordinate locale.
I sistemi di coordinate locali di primitive diverse sono indipendenti.
Esempio: un quadrato e un triangolo entrambi definiti con baricentro
in (0,0).
Un oggetto aggregato e' formato portando tutti i sotto-oggetti di
cui e' formato in un sistema di coordinate comune.
Esempio: lascio il quadrato con baricentro in (0,0) ma sposto il
triangolo sopra al quadrato (tipo tetto della casetta).
Continuo cosi' fino ad aver formato l'intera scena (pensata come oggetto aggregato complessivo).
I sistemi di coordinate in cui sono definiti i singoli oggetti (a qualsiasi livello della gerarchia di aggregazione) si chiamano coordinate di modellazione e ogni oggetto ha le sue.
Il sistema di coordinate in cui e' definita l'intera scena (coordinate di modellazione dell'oggetto al vertice della gerarchia) si chiama coordinate del mondo ed e' unico.
Per portare ciascun oggetto dalle sue coordinate di modellazione alle coordinate di modellazione dell'oggetto suo padre, operiamo trasformazioni di modellazione.
Le trasformazioni di modellazione sono una sequenza di trasformazioni di tre tipi: traslazioni, rotazioni, scalature.
Ho portato tutti gli oggetti nel sistema di coordinate del mondo. Prima di scattare la foto devo:
In OpenGL metto la scena davanti alla macchina fotografica, non viceversa.
La macchina fotografica ha un suo sistema di coordinate fisso, dette coordinate di vista, con
Le trasformazioni di vista portano la scena da coordinate del mondo a coordinate di vista. Compiono traslazioni e rotazioni.
Scelgono che lente montare sulla macchina, il che determina
In OpenGL sono definite dando il volume di vista
Le trasformazioni di proiezione portano, deformandolo, il volume di vista a coincidere con il cubo di diagonale (-1,-1,-1) - (1,1,1).
Il sistema di coordinate interno al cubo e' detto coordinate normalizzate di proiezione o NPC
In proiezione ortografica la posizione del punto di vista funge
solo da origine del sistema di riferimento,
non influisce sulla forma del volume di vista.
In proiezione prospettica la
posizione del punto di vista concorre a determinare la forma
del volume di vista in quanto e' definisce l'origine
del tronco di piramide.
Definisce il numero di righe e colonne del frame buffer, corrispondente alle dimensioni in pixel della finestra su schermo.
Ora OpenGL scatta la foto:
OpenGL compie questa sequenza (pipeline) di trasformazioni geometriche su ogni primitiva:
+------------------------+ |[3D] Object coordinates | sistema di riferimento locale in cui e' |(o modeling coordinates)| definito un singolo oggetto della scena +------------------------+ TRASFORMAZIONI DI| collocano il singolo oggetto all'interno della scena MODELLAZIONE | (in generale una trasf. diversa per ogni oggetto) V +------------------------+ sistema di riferimento globale di tutta |[3D] World coordinates | la scena +------------------------+ TRASFORMAZIONE DI| posiziona la scena davanti alla telecamera VISTA | V +------------------------+ sistema di riferimento solidale con la |[3D] View coordinates | telecamera: occhio in (0,0,0), che guarda verso | (o eye coordinates) | la direzione negativa dell'asse z +------------------------+ TRASFORMAZIONE DI| definisce tipo di trasformazione (parallela o PROIEZIONE | prospettica) e volume di vista V +------------------------+ sistema di riferimento normalizzato nel cubo |[3D] Normalized | con x,y,z tra -1 e +1, contiene (deformato | projection coordinates | dalla trasf. di proiezione) il volume di vista +------------------------+ TRASFORMAZIONE DI| fatta automaticamente da OpenGL, il programma controlla VIEWPORT | l'estensione della viewport con glViewport V +------------------------+ |[2D] Device coordinates | sistema di riferimento della finestra sullo |(o viewport coordinates)| schermo (coordinate 2D espresse in pixel) +------------------------+
Sono matrici 4x4 (matrici in coordinate omogenee 3D), a queste matrici vanno soggette tutte le primitive che vengono rese:
+-----+ +---------+ +-----+ +----------+ +-------+ |punto| |matrice | |punto| |matrice | |punto | | P |-->|MODELVIEW|-->| Mm P|-->|PROJECTION|-->|Mp Mn P|-->... +-----+ | Mm | +-----+ | Mp | +-------+ +---------+ +----------+
Vi sono primitive per modificare le matrici correnti. Sono le stesse su entrambe le matrici. Bisogna dichiarare esplicitamente su che matrice si vuole agire.
Per modificare la matrice corrente, OpenGL fornisce funzioni che permettono di definire una trasformazione complessa come composizione di trasformazioni elementari. Le trasformazioni elementari sono:
Importante: la composizione delle matrici avviene moltiplicando la nuova matrice a destra di quella corrente, quindi PRIMA viene eseguita la trasformazione corrispondente alla NUOVA matrice e DOPO la trasformazione corrispondente alla VECCHIA matrice.
In pratica le trasformazioni sono eseguite IN ORDINE INVERSO a come le specifico nel codice.
In OpenGL scalature e rotazioni avvengono sempre
tenendo come punto fermo l'origine del sistema di modellazione
corrente.
Per tenere fermo un altro punto C = (xC,yC,zC) diverso da origine:
Nel codice:
Le matrici MODELVIEW e PROJECTION fanno parte dello stato corrente. Cambiare la matrice corrente influisce su tutte le primitive da quel momento in poi. Se voglio modificarla momentaneamente per disegnare un certo gruppo di primitive (es. quelle che formano un oggetto), e poi ripristinarla, devo usare glPushMatrix e glPopMatrix. Tipicamente questo succede per le trasformazioni di modellazione con la MODELVIEW.
Esempio:
glMatrixMode(GL_MODELVIEW); glPushMatrix(); /* salva la matrice corrente su stack */ ... modifico la matrice ... ... disegno primitive sotto influsso della matrice modificata ... glPopMatrix(); /* rispristina la matrice precedente */ ... le primitive disegnate qui sono soggette alla matrice senza le modifiche fatte tra push e pop ...
In OpenGL sono controllate agendo sulla stessa matrice, la MODELVIEW.
Agiscono su ogni singolo oggetto separatamente per collocarli all'interno della scena.
Definite agendo sulla matrice MODELVIEW, tipicamente tra glPushMatrix e glPopMatrix affinche' la trasformazione agisca solo sull'oggetto in questione.
Supponiamo che ciascun oggetto abbia coordinate locali con
origine nel suo baricentro.
Di solito prima dimensiono (glScale), poi oriento (glRotate),
infine posiziono (glTranslate)
ciascuno degli oggetti per comporre la scena.
Agisce sull'intera scena per posizionarla davanti alla telecamera.
Definita agendo sulla matrice MODELVIEW, senza Push e Pop.
Oriento (glRotate), posiziono (glTranslate) la scena davanti alla telecamera (o la telecamera davanti alla scena).
Oppure: uso la funzione di utilita' gluLookAt, che permette di definire la trasformazione di vista in modo piu' intuitivo.
Definisce il tipo di proiezione e il volume di vista. Agisco sulla matrice PROJECTION con una fra:
glOrtho(left,right,bottom,top,near,far);
Specifica matrice ortografica.
Il volume di vista e' il parallelepipedo di diagonale
(left,bottom,-near) - (right,top,-far).
Per avere un volume di vista giacente davanti all'occhio,
near e far devono essere positivi.
glFrustum(left,right,bottom,top,near,far);
Specifica matrice prospettica.
Il volume di vista e' un tronco di piramide con l'apice in (0,0,0)
(l'occhio), base minore il rettangolo di diagonale
(left,bottom) - (right,top) giacente sul piano z=-near,
e base maggiore sul piano z=-far (ottenuta effettuando una proiezione
da (0,0,0) della base minore sul piano z=-far).
I valori di near e far devono essere positivi.
Al crescere del rapporto far/near si perde precisione nella
proiezione, quindi e' meglio evitare volumi di vista
troppo profondi, e casomai scalare prima la scena.
In alternativa a glFrustum, posso usare la funzione di utilita' gluPerspective, che accetta parametri piu' intuitivi:
La scena giace sul piano xy (z=0). Definiamo solo il rettangolo di base del volume di vista per la trasformazione ortografica:
Il contenuto del volume di vista viene mappato (deformandolo) nel cubo normalizzato delle coordinate di proiezione.
Questo cubo viene poi appiattito schiacciandolo nella direzione z e mappato nelle coordinate 2D della viewport grafica (finestra sullo schermo).
Di default OpenGL usa l'intera area della finestra. Posso invece specificare esplicitamente una viewport (es. piu' piccola) con
Se l'aspect ratio (rapporto tra dimensioni x e y) della viewport e quella del volume di vista non sono uguali, l'immagine della scena viene deformata allungandola in verticale o in orizzontale.
Per preservare nell'immagine le proporzioni della scena, devo mantenere le due aspect ratio uguali tra loro: