LA LIBRERIA GRAFICA OPENGL - II Parte
Traformazioni geometriche
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)
+------------------------+
Come si specificano le trasformazioni
OpenGL tiene 2 matrici di trasformazione nel suo stato corrente:
- MODELVIEW per le trasf. di modellazione e di vista
(posizionare gli oggetti nella scena e la telecamera)
- PROJECTION per la trasf. di proiezione (scegliere tipo di proiezione
parallela o prospettica e volume di vista)
Sono matrici 4x4 (matrici in coordinate omogenee 3D),
a queste matrici vanno soggette tutte le primitive che vengono rese:
Vi sono primitive per modificare le matrici correnti. Sono le stesse su
entrambe le matrici. Bisogna dichiarare esplicitamente su che matrice si
vuole agire.
-
glMatrixMode(matrice);
specifica su che matrice si lavorera' d'ora in poi,
dove matrice = GL_MODELVIEW oppure GL_PROJECTION
Per modificare la matrice corrente, OpenGL fornisce funzioni che permettono
di definire una trasformazione complessa come composizione di trasformazioni
elementari. Le trasformazioni elementari sono:
-
glLoadIdentity();
assegna la matrice corrente come la matrice identica
-
glTranslatef(dx,dy,dz); moltiplica la matrice corrente
con matrice di traslazione, (dx,dy,dz) e' il vettore traslazione
-
glRotatef(ang,rx,ry,rz); moltiplica con matrice di rotazione
attorno a retta passante per origine e parallela al
vettore (rx,ry,rz), ang e' angolo di rotazione misurato in gradi
-
glScalef(sx,sy,sz); moltiplica con matrice di scalatura
con fattori di scala sx,sy,sz sui tre assi, il punto fermo nella
scalatura e' l'origine
Posso ottenere qualsiasi trasformazione componendo queste.
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.
Esempio:
glLoadIdentity(); matrice identita' I
glTRanslate(...); matrice = I T = T dove T = matrice di traslazione
glRotate(...); matrice = T R dove R = matrice di rotazione
Risultato: nell'ordine prima ruoto poi traslo i punti
Esempio di trasfomazione composta
Rotazione 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 alpha voluto attorno a origine
- traslo di (xC,yC,zC) per portare C alla posizione originale
Nel codice:
3. glTranslatef(xC,yC,zC);
2. glRotatef(ang,rx,ry,rz);
1. glTranslatef(-xC,-yC,-zC);
Stack delle matrici
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 */
... modifiche alla matrice ...
... disegnamento 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 ...
Trasformazioni di modellazione e di vista
In OpenGL sono controllate agendo sulla stessa matrice, la MODELVIEW.
- PRIMA devono essere eseguite quelle di modellazione
- POI quelle di vista.
Cio' significa che nel codice sono invocate PRIMA le funzioni OpenGL
per la trasformazione di vista e DOPO quelle per le
trasformazioni di modellazione (ordine inverso!).
Trasformazioni di modellazione
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.
Nell'ordine: dimensiono (glScale), oriento (glRotate), posiziono (glTranslate)
ciascuno degli oggetti per comporre la scena.
Trasformazione di vista
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 mi permette di definire
la trasformazione di vista in modo piu' intuitivo.
-
gluLookAt(eyex,eyey,eyez,centerx,centery,centerz,upx,upy,upz);
porta scena davanti alla telecamera, dove
- (eyex,eyey,eyez) = punto dove voglio collocare l'occhio,
- (centerx,centery,centerz) = centro della scena, verso il
quale l'occhio viene rivolto,
- (upx,upy,upz) = direzione che definisce "l'alto" della telecamera.
E' implementata internamente facendo uso di rotazioni e traslazioni.
Trasformazione di proiezione
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 (proiezione parallela)
- 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 di definire 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.
gluPerspective(fovy,aspect,znear,zfar);
definisce trasformazione prospettica, dove
- fov = field of view = angolo di apertura della piramide in gradi,
- aspect = deformazione largezza/altezza della base del tronco di piramide
(in generale la si fa coincidere con quella della viewport),
- znear, zfar = distanza delle due basi del tronco di piramide dallo
occhio (valori positivi)
Trasformazione di viewport
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
- glViewport(x1,y1,x2,y2);
dove x1,y1 e x2,y2 sono le coordinate dell'angolo in basso a sx e
in alto a dx della viewport, in pixel.
Conservazione dell'aspect ratio
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:
-
o adeguando la viewport al volume di vista, eventualmente selezionando
solo una sottoparte della finestra attuale per il rendering (es. usare solo
una sottoparte quadrata se il volume di vista e' a base quadrata),
in questo caso agisco con glViewport.
-
oppure adeguando il volume di vista alla viewport (inquadrando piu' o meno
della scena a seconda della forma della finestra di rendering),
in questo caso modifico la trasformazione di proiezione.
Esempio
La finestra iniziale ha dimensione 400x400 pixel, le trasformazioni
iniziali sono:
- gluPerspective(fov,1.0,near,far);
- glViewport(0,0,400,400);
Aspect ratio = 1.0 perche' finestra quadrata.
Se la finestra viene deformata a 400x200
- o adeguo la viewport: glViewport(0,0,200,200);
(uso solo una sottoparte quadrata della viewport)
- o adeguo la trasformazione di proiezione:
gluPerspective(fov,2.0,near,far);
glViewport(0,0,400,200);
(inquadratura piu' larga, con aspect ratio = 2.0, perche' nella
viewport la dimensione x e' il doppio di quella y)
Display list
In OpenGL una primitiva grafica e' definita da una lista di vertici
racchiusi tra glBegin e glEnd, piu' eventualmente
altre istruzioni che specificano attributi (normali, colore...).
In condizioni normali, una primitiva viene mandata dal client al server,
che la visualizza immediatamente, e poi la "dimentica" (ovvero non la
memorizza). Se il client vuole ridisegnare la stessa primitiva una
seconda volta, deve reinviarla, con spesa di tempo.
Display list = serie di primitive di OpenGL a cui e' stato
assegnato un nome (identificatore numerico).
-
Quando il client invia al server una display list, il server la memorizza
(al contrario di quanto avviene per primitive non facenti parte di
display list).
-
Successivamente, il client puo' chiedere al server di ridisegnare le
primitive contenute nella display list semplicemente inviando il nome
della display list (un solo numero intero), risparmiando cosi' tempo.
Una display list viene visualizzata usando i parametri dello stato corrente
di OpenGL. Cosi' la stessa primitiva, inserita in una display list, puo'
essere chiamata con stato corrente modificato, dando luogo a un effetto
diverso.
Per esempio, tra una chiamata e l'altra della display list posso cambiare
colori, modalita' di visualizzazione wireframe/solid, spessore di linea,
trasformazioni geometriche.
Posso disegnare un'intera scena (es. composta da parallelepipedi di
dimensioni e colori diversi) usando un'unica display list che viene
scalata/traslata/colorata in modo diverso.
Istruzioni per display list
- first_list = glGenLists(num_list);
Crea num_list "nomi" di display list (indici interi) consecutivi,
e ritorna in first_list il primo di essi.
dopo, posso "riempire" le display list ai nomi
first_list, first_list+1, ... first_list+num_list-1.
-
glNewList(list_name,modo);
...primitive che compongono la lista...
glEndList();
Delimitano una definizione di display list. list_name e' il nome della
lista che sto definendo.
modo e' GL_COMPILE
(la display list e' solo memorizzata, non visualizzata) oppure
GL_COMPILE_AND_EXECUTE
(e' memorizzata e visualizzata direttamente)
- glCallList(list_name);
Chiama la display list indicata (ovvero ne visualizza il contenuto).
L'effetto della chiamata risente dello stato corrente OpenGL.
Nota:
Una display list viene visualizzata sotto l'influsso dello stato corrente
al momento in cui chiamo glCallList.
Questo non vieta di modificare lo stato corrente dentro la display list
stessa.
Tenere pero' presente che, in questo caso,
dopo ogni chiamata alla display list trovero' lo stato modificato.
Molto meglio cambiare lo stato localmente alla display list, usando
glPush... e glPop...
Esempio
/* definisce display list contenente un quadrato */
mylist = glGenLists(1);
glNewList(mylist,GL_COMPILE);
glBegin(GL_QUADS);
glVertex2f(0.0,0.0);
glVertex2f(1.0,0.0);
glVertex2f(1.0,1.0);
glVertex2f(0.0,1.0);
glEnd();
glEndList();
...
/* disegna piu' quadrati chiamando la display list varie volte */
glMatrixMode(GL_MODELVIEW);
for (i=0; i<5.0; i++)
{
glPushMatrix();
glTranslatef(0.2*i,0.0,0.0);
glScalef(0.1,0.1,1.0);
glCallList(mylist);
glPopMatrix();
}
Quest'esempio e' contenuto nel file quadra.c.
Illuminazione
A luci disabilitate,
ogni vertice ha il suo colore (assegnato con glColor),
e ogni punto facente parte di una primitiva 1D (GL_LINES,...) o 2D
(GL_TRIANGLES, GL_POLYGON,...) ha colore ottenuto interpolando
quello dei vertici della primitiva.
Ne segue che una primitiva ha un unico colore uniforme se i suoi vertici hanno
tutti lo stesso colore. Quindi in 3D se tutte le facce di un solido hanno
stesso colore, il solido appare come un'unica macchia di colore senza
effetto di tridimensionalita'.
A luce abilitata, ogni punto e' colorato con:
- un colore che dipende dalla luce che lo colpisce (proprieta'
della sorgente luminosa che emette la luce) e dalla capacita' di risposta
alla luce della primitiva di cui fa parte (proprieta' del materiale
di cui e' fatta la primitiva)
- un'intensita' che dipende dalle due cose di cui sopra,
ed eventualmente
dall'inclinazione con cui la luce lo colpisce (angolo tra direzione
della luce e direzione della normale alla primitiva in quel punto)
Fattori che entrano in gioco:
-
Dalla parte delle primitive:
Proprieta' di materiale (glMaterial) e normali
(glNormal) specificate mentre definisco la primitiva
-
Dalla parte delle luci:
Proprieta' delle sorgenti luminose (glLight) e
modello di illuminazione (glLightModel)
Tipi di luce
-
Luce ambiente:
proviene da tutte le direzioni, viene riflessa da una primitiva in tutte
le direzioni allo stesso modo. Provenendo da tutte le direzioni, colpisce
con la stessa intensita' ogni punto indipendentemente dalla sua normale.
Non utile a creare effetto 3D.
-
Luce diffusa:
proviene da una direzione in particolare, viene riflessa in tutte le
direzioni. Colpisce ogni punto con intensita' che dipende dall'angolo
formato dalla direzione della luce con la normale in quel punto.
E' quella che crea effetto 3D.
-
Luce speculare:
proviene da una direzione in particolare, viene riflessa in una direzione
in particolare. Crea effetti di "luccichio" tipo metalli o vetro.
Ogni sorgente luminosa contiene queste tre componenti di luce, e
ciascuna componente puo' avere colore e intensita' diversa.
Inoltre e' prevista una luce ambiente "di sfondo", indipendente
dalle sorgenti luminose (attiva anche a sorgenti luminose spente).
Ogni materiale ha una sensibilita' particolare a ciascuna delle tre
componenti della luce.
Inoltre esistono materiali in grado di emettere luce propria (luce emessa).
Normali
Nel caso di luce diffusa, l'intensita' dell'illuminazione dipende dall'angolo
formato dalla direzione della luce con la normale alla superficie.
OpenGL NON calcola da solo le normali, bisogna dargliele specificandole
nella primitiva stessa.
Assegnazione della normale corrente
glNormal3f(tre float) oppure
glNormal3fv(vettore di tre float)
Varie forme analogamente a quanto visto per glVertex...
Va chiamata tra glBegin e glEnd e influisce tutti i vertici che
seguono fino a che la normale corrente non viene modificata di nuovo.
Tipicamente:
- prima di elencare i vertici di una faccia assegno la normale
corrispondente a quella faccia
- elenco i vertici della faccia
- assegno la normale della prossima faccia, ecc.
In realta' la normale e' uno di quegli attributi OpenGL che valgono
"vertice per vertice" (come anche il colore).
Posso assegnare una normale diversa a ogni vertice della stessa faccia.
La normale per ciascun punto interno della faccia e' allora interpolata,
cosicche' la normale cambia gradualmente all'interno della faccia.
-
stessa normale per tutti i vertici di un poligono fa si' che il poligono
appaia come una faccia piana
-
normali diverse fanno si' che il poligono assuma un'apparenza curva
(noi pero' NON ci occupiamo di questo caso).
Per default la normale corrente e' (0,0,0) e gli oggetti appaiono "piatti"
(colorati di colore uniforme anche in presenza di luce diffusa, nonostante
l'inclinazione diversa delle facce).
Proprieta' di materiale
Stabiliscono, per le primitive immediatamente seguenti:
-
quanta luce ricevuta viene riflessa dalla primitiva
per ciascuno dei tre tipi di luce (ambiente, diffusa, speculare)
-
quanta luce e' emessa dalla primitiva stessa
(se diversa da zero la primitiva "brilla di luce propria")
-
intensita' della luce speculare riflessa
Sono assegnate con
glMaterial(faccia, nome_parametro, valore_parametro);
La funzione ha 4 varianti:
glMaterialf, glMateriali, glMaterialfv, glMaterialiv,
dove
- f/i a seconda che valore_parametro sia un float / un intero
- v a seconda che valore_parametro sia un array di float / interi
- faccia = GL_FRONT, GL_BACK o GL_FRONT_AND_BACK per assegnare proprieta'
alle front faces, le back faces, o a entrambe
- nome_parametro e valore sono illustrati dalla seguente tabella:
nome_parametro valore (scalare o vettore)
-------------------------------------------------------------------------
GL_AMBIENT vettore di componenti RGBA, default (0.2,0.2,0.2,1)
frazione di luce ambiente ricevuta che la primitiva
riflette, per ogni colore
-------------------------------------------------------------------------
GL_DIFFUSE vettore di componenti RGBA, default (0.8,0.8,0.8,1)
frazione di luce diffusa ricevuta che la primitiva
riflette, per ogni colore
-------------------------------------------------------------------------
GL_SPECULAR vettore di componenti RGBA, default (0,0,0,1)
frazione di luce speculare ricevuta che la primitiva
riflette, per ogni colore
-------------------------------------------------------------------------
GL_AMBIENT_AND_DIFFUSE per assegnare in un colpo GL_AMBIENT e GL_DIFFUSE
con lo stesso vettore RGBA
-------------------------------------------------------------------------
GL_EMISSION vettore di componenti RGBA, default (0,0,0,1)
componenti della luce emessa dalla primitiva stessa
-------------------------------------------------------------------------
GL_SHININESS intero tra 0 e 128
intensita' della luce speculare riflessa
-------------------------------------------------------------------------
Nota: componenti RGB = 0,0,0 implicano luce "nera",
ovvero nessuna luce (o nessuna componente di quel tipo nella luce).
Proprieta' delle sorgenti luminose
Posso definire una o piu' sorgenti luminose e, dopo averle definite,
abilitarle/disabilitarle (per default disabilitate).
Tipi di sorgenti
- All'infinito (raggi luminosi paralleli): posizionate in punto
(x,y,z,w) con w=0
- In un punto (raggi che escono dal punto in tutte le direzioni):
posizionate in punto (x,y,z,w) con w=1
- Spot light (in un punto, con solo un cono di luce uscente):
in un punto (x,y,z,w) con w=1, e con "angolo di apertura" limitato.
Noi NON ci occupiamo di spot light, chi fosse interessato puo'
consultare il manuale.
Ogni sorgente e' caratterizzata da
- posizione della sorgente
- quanta luce emette per ciascuno dei tre tipi di luce (ambiente,
diffusa, speculare)
- altri parametri di cui non ci occupiamo
NOTA:
La posizione della luce e' soggetta alle trasformazioni come tutte le
primitive geometriche, in particolare e' soggetta alla matrice MODELVIEW
corrente.
E' possibile ottenere luci che si spostano facendo precedere la
definizione della loro posizione da una qualche trasformazione.
Invece, trasformazioni poste dopo la definizione della luce
(ma prima della definizione degli oggetti della scena) non cambiano la
posizione della luce ma muovono solo la scena a luce ferma.
Definizione di sorgenti luminose
glLight(luce, nome_parametro, valore_parametro);
-
La funzione ha 4 varianti glLightf glLighti, glLightfv, glLightiv,
dove f/i,v con stesso funzionamento che in glMaterial.
-
luce = GL_LIGHT0, GL_LIGHT1,... (OpenGL fornisce almento 7 luci)
-
nome_parametro e valore sono illustrati dalla seguente tabella:
nome_parametro valore (scalare o vettore)
-------------------------------------------------------------------------
GL_AMBIENT vettore di componenti RGBA, default (0,0,0,1)
valori di luce ambiente emessa dalla sorgente
-------------------------------------------------------------------------
GL_DIFFUSE vettore di componenti RGBA, default (1,1,1,1) per
GL_LIGHT0 e (0,0,0,1) per le altre
valori di luce diffusa emessa dalla sorgente
-------------------------------------------------------------------------
GL_SPECULAR vettore di componenti RGBA, default (1,1,1,1) per
GL_LIGHT0 e (0,0,0,1) per le altre
valori di luce speculare emessa dalla sorgente
-------------------------------------------------------------------------
GL_POSITION vettore di coordinate (x,y,z,w)
posizione della luce, w=1 per posizione in un punto
(x,y,z) al finito, w=0 per posizione all'infinito
nella direzione del vettore (x,y,z)
-------------------------------------------------------------------------
... altri parametri per le luci spot (di cui non ci occupiamo) ...
-------------------------------------------------------------------------
... altri parametri per specificare come la luce e' attenuata con
l'aumentare della distanza dalla sorgente (non ce ne occupiamo) ...
-------------------------------------------------------------------------
Modello di illuminazione
Il modello di illuminazione controlla
- la luce ambiente "di sfondo"
- precisione/efficienza dell'algoritmo usato per calcolare
l'illuminazione: alcune funzionalita' sofisticate, necessarie per
illuminazione realistica di qualita', sono costose
computazionalmente e percio' sono disabilitate di default,
posso abilitarle nei casi in cui le ritengo necessarie
glLightModel(nome_parametro, valore_ parametro)
Anche questa funzione ha 4 versioni: glLightModelf,
glLightModeli, glLightModelfv, glLightModeliv.
nome_parametro valore
-------------------------------------------------------------------------
GL_LIGHT_MODEL_AMBIENT vettore di componenti RGBA della luce ambiente
"di sfondo" (default 0.2,0.2,0.2,1)
-------------------------------------------------------------------------
GL_LIGHT_MODEL_TWO_SIDE 0 oppure 1 (default = 0)
0 --> illumina solo front faces (in oggetti "chiusi" le back faces
non si vedono...)
-------------------------------------------------------------------------
GL_LIGHT_MODEL_LOCAL_VIEWER 0 oppure 1 (default = 0)
0 --> non tiene conto della posizione del punto di vista nel
calcolo delle riflessioni speculari (meno accurato ma piu' veloce)
-------------------------------------------------------------------------
Nota bene
In presenza di luci, il colore apparente di un oggetto e' determinato dal
colore della luce che riflette, e apparentemente glColor non ha effetto.
Si puo' usare l'istruzione glColorMaterial
per far si' che i parametri di materiale seguano il valore attuale
del colore assegnato con glColor
Abilitazioni per le luci
- glEnable(GL_LIGHTING); per abilitare il calcolo delle luci
- glEnable(GL_LIGHTi); per abilitare l'i-esima luce
- glEnable(GL_COLOR_MATERIAL);
per abilitare che il colore del materiale
segua in ogni momento il colore corrente (se serve)
Inoltre in presenza di illuminazione con luce diffusa puo' essere utile:
- glEnable(GL_NORMALIZE);
abilita normalizzazione automatica delle normali
- consente di passare a glNormal vettori di norma non necessariamente = 1.
- utile se le primitive subiscono trasformazioni di scalatura dopo essere
state definite. Infatti anche le normali, come le ccordinate dei
vertici, sono "geometria", e subiscono le trasformazioni geometriche;
quindi, possono risultare non piu' "normali" dopo la trasformazione
Cosa fare per ottenere una scena illuminata
-
Abilitare l'illuminazione e tutte le luci che si intendono usare,
usando glEnable(GL_LIGHTING) e
glEnable(GL_LIGHTi) per i=0...
-
Definire eventualmente i parametri modello di illuminazione, usando
glLightModel (se non vanno bene quelli di default)
-
Definire i parametri di ciascuna luce che si intende usare,
usando glLight(GL_LIGHTi,....)
-
Definire il materiale di ciascuna primitiva che si vuole tracciare,
usando glMaterial(....)
Nota: il materiale e' parte dello stato corrente di OpenGL e ha effetto
su tutte le primitive che seguono a partire dal punto dove viene
assegnato.
Inoltre e' di quegli attributi che POSSONO essere assegnati tra
glBegin e glEnd (e' proprieta' del singolo vertice).