Sunteți pe pagina 1din 13

LABORATOR 5

Modele de iluminare si reflexie în OpenGL

În acest laborator se vor studia modelele de iluminare si reflexie în OpenGL

În lumea reală, atunci când lumina provenită de la diferite surse de lumină cade asupra
obiectelor opace, o parte este absorbită de obiecte, iar o parte este reflectată. Ochiul percepe
lumina reflectată de obiect, pentru a interpreta forma, culoarea si alte detalii ale obiectului.
Pentru calculul iluminării în grafica pe calculator trebuie să fie definite sursele de lumină
si interacţiunea dintre lumină si suprafeţe.
Un model de iluminare defineste natura luminii emise de o sursă de lumină, adică
distribuţia intensităţii luminii. Un model de reflexie descrie interacţiunea dintre lumină si o
suprafaţă, în funcţie de proprietăţile suprafeţei si natura sursei de lumină. Implementarea
unuimodel de reflexie în procesul de calculare a intensităţii culorii fiecărui pixel este cunoscută
sub numele de tehnică de umbrire.
Biblioteca OpenGL implementează modelul de reflexie Phong si modelele de umbrire
poligonală si umbrire Gouraud.
În mod implicit, sistemul de iluminare este inactivat si pentru desenarea primitivelor
geometrice se foloseste culoarea curentă. Pentru validarea iluminării obiectelor, se activează
sistemul de iluminare OpenGL prin apelul funcţiei glEnable(GL_LIGHTING).
Pentru calculul iluminării obiectelor trebuie să fie definite: sursele de lumină,
materialul suprafeţelor, modelul de umbrire a suprafeţelor.

1. Specificarea culorii
OpenGL permite utilizarea a două moduri de reprezentare a culorilor de afisare:
- modul RGBA: pentru fiecare pixel se memorează valorile R (Red), G (Green), B (Blue)
si A (Alpha);
- modul indexat: pentru fiecare pixel se memorează un număr, reprezentând un index
într-o tabelă de culori.
Modul RGBA este cel mai utilizat. În modul RGBA, pentru selectarea culorii curente
se folosesc funcţiile glColor#().

void glColor3{b s i f d ub us ui} (TYPE r, TYPE g, TYPE b);


void glColor4{b s i f d ub us ui} (TYPE r, TYPE g, TYPE b, TYPE a);
void glColor3{b s i f d ub us ui}v (const TYPE *v);
void glColor4{b s i f d ub us ui}v (const TYPE *v);

Funcţiile glColor3() specifică un triplet (R, G, B). Funcţiile glColor4() adaugă la tripletul
(R, G, B) o valoare de opacitate, numită valoare alfa (A). Valorile R, G, B si A variază în
domeniul [0,1] . Valoarea implicită a opacităţii este 1.0. Când sunt specificate valori din afara
domeniului [0,1] , acestea se mapează liniar în acest interval.

2. Definirea surselor de lumină


În OpenGL se pot defini mai multe surse de lumină punctiforme. Numărul de surse de
lumină admise variază în funcţie de implementare, dar cel puţin opt surse sunt disponibile în
orice bibliotecă OpenGL. Fiecare sursă de lumină poate fi validată prin apelul funcţiei
glEnable(GL_LIGHTi), unde i este indexul sursei de lumină.
O sursă de lumină se caracterizează prin intensitate si poziţia în scenă. Intensitatea unei
surse de lumină se specifică pentru fiecare componentă de iluminare (ambientală, de difuzie si
speculară) printr-un vector în spaţiul culorilor în modelul RGBA. Poziţia unei surse se specifică
printr-un vector în coordonate omogene corespunzătoare sistemului de referinţă universal.
Funcţia de definire a unui parametru al sursei de lumină este funcţia glLight#() care
are mai multe variante în funcţie de tipul argumentelor.

void glLightf(GLenum light, GLenum pname, const GLfloat params);


void glLighti(GLenum light, GLenum pname, const GLint params);
void glLightfv(GLenum light, GLenum pname, const GLfloat *params);
void glLightiv(GLenum light, GLenum pname, const GLint *params);

Argumentul light reprezintă indexul sursei de lumină si poate lua un nume simbolic
de forma GL_LIGHT0, GL_LIGHT1, ..., GL_LIGHTi,unde 0 i GL_MAX_LIGHTS -1.
Numărul maxim de surse de lumină depinde de implementarea bibliotecii.
Argumentul pname specifică un parametru al sursei de lumină. Sunt acceptate mai
multe valori, dinte care unele se referă la intensitatea culorii, iar altele la poziţia sursei (tabelul1).

Tabelul 1.
Valorile GL_AMBIENT, GL_DIFFUSE si GL_SPECULAR ale argumentului pname
permit definirea componentelor intensităţii culorii sursei de lumină. În primele două funcţii
argumentul params reprezintă valoarea care se va atribui parametrului indicat de pname. În
celelalte două funcţii, argumentul params reprezintă un pointer la un vector de patru valori
(de tip întreg sau virgulă flotantă), care specifică intensităţile RGBA ale componentei de
iluminare ambientală, difuză si speculară. Valorile implicite ale intensităţilor sunt (0.0, 0.0,
0.0, 1.0) pentru componenta ambientală si pentru componenta difuză si speculară a oricărei
lumini cu excepţia luminii cu index 0, care are intensitatea difuză si speculară implicită (1.0,
1.0, 1.0, 1.0).

În acest model de definire a sursei de lumină, componenta ambientală (GL_AMBIENT)


sereferă la intensitatea RGBA pe care o sursă de lumină o adaugă iluminării globale a scenei.
Componenta de iluminare difuză (GL_DIFFUZE) este cel mai apropiat mod de reprezentare a
ceea ce se consideră culoarea sursei de lumină. Componenta de iluminare (GL_SPECULAR)
afectează culoarea zonei strălucitoare (hightlight) a obiectelor luminate de sursa respectivă.
Valoarea transparenţei surselor de lumină (alpha) este ignorată dacă nu se validează calculul
transparenţei (color blending).
Valoarea GL_POSITION a argumentului pname permite definirea poziţiei sursei de
lumină. În această situaţie, argumentul params este un pointer la un vector de patru numere
(întregi sau virgulă flotantă) care reprezintă poziţia în coordonate omogene în sistemul de
referinţă universal al sursei de lumină. Această poziţie este transformată prin aplicarea valorii
matricei de modelare-vizualizare din momentul apelului funcţiei glLight#(), astfel încât
sursa de lumină va avea coordonatele transformate în sistemul de referinţă de observare, unde se
calculează intensitatea în vârfurile primitivelor geometrice.
Dacă componenta w a poziţiei este 0, atunci lumina este tratată ca o lumină
direcţională plasată la infinit, în direcţia definită de componentele x , y , z si se utilizează
această direcţie pentru calculul componentelor de reflexie difuză si speculară.
Dacă w ≠0 , atunci sursa este o sursă poziţională si se foloseste localizarea acesteia
pentru calculul direcţiei de iluminare a suprafeţelor. Poziţia implicită a unei surse este (0, 0, 1,0),
deci sursa este plasată la infinit pe axa z si ea luminează obiectele în direcţia −z .
Secvenţa de instrucţiuni pentru definirea intensităţii si poziţiei sursei de lumină de indice 0 arată
astfel:

GLfloat light_ambient[] = {1.0, 0.0, 0.0, 0.0} ;


GLfloat light_diffuse[] = {1.0, 0.0, 0.0, 0.0} ;
GLfloat light_specular[] = {1.0, 1.0, 1.0, 0.0} ;
GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0} ;
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);

În iluminarea reală, intensitatea luminii primite de un obiect scade odată cu cresterea


distanţei acestuia faţă de sursa de lumină. Dat fiind că sursele de lumină direcţionale (care au w
0 ) se consideră plasate la infinit, nu are sens calculul atenuării cu distanţa, astfel încât atenuarea
este invalidată pentru astfel de surse. Pentru sursele poziţionale, se foloseste un factor de atenuare
cu valoarea:

unde: r = distanţa dintre sursa de lumină si vârful în care se calculează iluminarea


kc = GL_CONSTANT_ATTENUATION;
kl = GL_LINEAR_ATTENUATION;
kq = GL_QUADRATIC_ ATTENUATION;

Implicit acesti parametri au valorile kc=1, kl =0 , kq =0 , dar ei pot fi setaţi prin apelul uneia
din funcţiile glLightf() sau glLighti() astfel:
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);
glLightf(GL_LIGHT0, GL_LINEAR_ ATTENUATION, 1.0);
glLightf(GL_LIGHT0, GL_QUADRATIC_ ATTENUATION, 0.5);
Dacă se folosesc mai multe surse de lumină, pentru fiecare din ele se definesc
componentele intensităţii, poziţia si caracteristicile de atenuare.

3. Definirea proprietăţilor materialelor


În modele simple de reflexie (ca de exemplu cazul modelului Phong) se consideră că
lumina reflectată de o suprafaţă este constituită din trei componente:
 reflexia difuză;
 reflexia speculară;
 reflexia ambientală.
Reflexia difuză joacă cel mai important rol în culoarea pe care o prezintă o suprafaţă.
Ea reprezintă culoarea pe care o are suprafaţa luminată direct si depinde de componenta de
difuzie a luminii incidente, provenită de la una sau mai multe surse de lumină, de coeficientul de
reflexie de difuzie (reflectanţa de difuzie) a materialului si de unghiul dintre direcţia luminii si
normala la suprafaţă. Poziţia de observare nu influenţează componenta de difuzie a luminii
reflectate. În cazul unei surse punctiforme intensitatea luminii difuzate este:

Reflexia ambientală afectează culoarea de ansamblu pe care o prezintă o suprafaţă si


ea devine sesizabilă atunci când suprafaţa nu este luminată direct. Ca si reflexia difuză, această
componentă nu depinde de poziţia de observare. În modelul de reflexie Phong intensitatea dată de
componenta ambientală este:

ka fiind coeficientul de reflexie pentru lumina ambientală.

Reflexia speculară produce iluminarea mai puternică (hightlight) a unei zone a


obiectului, în funcţie de poziţia de observare (fig.1). În cazul unei singure surse
punctiforme,intensitatea luminii reflectate specular este:
Fig. 1. Reflexia speculară Phong
Prin combinarea relaţiilor (2)-(4) se obţine relaţia de calcul a culorii unei suprafeţe:

Din cele prezentate anterior rezultă că pentru calculul intensităţii culorii unei suprafeţe,
trebuie definiţi coeficienţii de reflexie ambientală, difuză si speculară. Aceste proprietăţi sunt
considerate proprietăţi de material ale suprafeţei si se specifică prin apelul uneia sau mai multora
din cele patru variante ale funcţiei glMaterial#():

void glMateriali(GLenum face, GLenum pname, GLint param);


void glMaterialf(GLenum face, GLenum pname, GLfloat param);
void glMaterialiv(GLenum face, GLenum pname, GLint *param);
void glMaterialfv(GLenum face, GLenum pname, GLfloat *param);

În aceste funcţii, argumentul face este numele feţei si depinde de orientarea acesteia;
poate lua ca valori constantele simbolice GL_FRONT, GL_BACK, GL_FRONT_AND_BACK.
Argumentul pname specifică proprietatea materialului, care se defineste prin apelul funcţiei
glMaterial#(). Acest argument poate lua una din următoarele valorile date în tabelul 2.

Tabelul 2

Funcţiile glMateriali() si glMaterialf() se folosesc numai pentru setarea strălucirii


(GL_SHININESS) la valoarea dată prin argumentul param.
Funcţiile glMaterialiv() si glMaterialfv() se folosesc pentru specificarea
celorlalte proprietăţi. Dacă argumentul pname este GL_COLOR_INDEX atunci param este un
pointer la un vector de trei valori de tip întreg, care conŃine indicii culorilor ambientală, de
difuzie si speculară ale materialului. În celelalte situaţii, param este un pointer la un vector de
patru valori de tip întreg sau cu virgulă flotantă, care sunt componentele rosu, verde, albastru si
alpha (transparenţă) ale componentei de reflexie specificate prin parametrul pname (ambientală,
difuză, speculară, emisie).
Reflexia difuză si ambientală se specifică de cele mai multe ori cu aceeasi culoare (asa
cum sunt suprafeţele reale) folosind parametrul GL_AMBIENT_AND_DIFFUSE în apelul
funcţiei glMaterial#().
Specificarea culorii produse de reflexia speculară se face prin parametrul
GL_SPECULAR, iar dimensiunea si strălucirea zonei prin parametrul GL_SHININESS.
Se poate observa că modelul OpenGL de reflexie permite adăugarea unei componente
emisive a luminii reflectate de o suprafaŃă. Componenta de emisie a unei suprafeţe se specifică
prin parametrul GL_EMISSION. Acest efect este folosit pentru simularea lămpilor sau a altor
surse de lumină din scenă.
Funcţia glMaterial#() defineste proprietăţile materialului curent, care se aplică
tuturor vârfurilor introduse după acesta prin funcţiile glVertex#()sau prin diferite funcţii de
modelare din biblioteca GLUT (de exemplu glutSolidSphere()). Proprietăţile materialului
curent se menţin până la următorul apel al funcţiei glMaterial#(). Calculele de iluminare se
pot executa diferit pentru feţele orientate direct (GL_FRONT) si cele orientate invers
(GL_BACK).
Un exemplu de definire a unui material este dat prin următoarele instrucţiuni:

GLfloat mat_ambient[] = {1.0, 0.0, 0.0, 1.0} ;


GLfloat mat_diffuse[] = {1.0, 0.0, 0.0, 1.0} ;
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0} ;
GLfloat mat_shininess = 50.0;
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess);

5. Aplicaţii

Exemplul 1
Să se afiseze un triunghi folosind modelul de colorare (umbrire) Gouraud. Vârfurile
triunghiului au culorile rosu, verde si, respectiv, albastru (fig. 2).
Fig. 2 Afisarea unui triunghi folosind modelul Gouraud

Soluţie. Programul care realizează imaginea din fig. 2 este următorul:


Exemplul 2
Să se evidenţieze diferenţa dintre umbrirea poligonală si umbrirea Gouraud în cazul unei
sfere reprezentate prin reţea de poligoane si iluminată cu o sursă de lumină. Sursa de
lumină se plasează la infinit, pe direcţia dată de vectorul
.La apăsarea butonului stâng al mouse-ului sfera se afisează folosind umbrirea
poligonală, iar la apăsarea butonului drept sfera se afisează folosind umbrirea Gouraud (fig.
3). Se utilizează proiecţia perspectivă si apoi proiecţia ortografică.

Soluţie. Programul care generează imaginile din figura 3 este următorul:

a) b)
Fig. 3 a) umbrire poligonală; b) umbrire Gouraud
O parte din funcţii sunt date mai jos.
Exemplul 3
Să se afiseze sfera din exemplul 2, folosind modelul Gouraud. La apăsarea unuia din cele
trei butoane ale mouse-ului se vor schimba coeficienţii de difuzie ai materialului: butonul din
stânga schimbă componenta rosie, cel din mijloc componenta verde si cel din dreapta
componenta albastră. Pentru modificare parametrilor de material se poate folosi funcţia:
void glColorMaterial(GLenum face, GLenum mode);
Această funcţie actualizează proprietăţile de material specificate de parametrul mode pentru
feţele specificate de parametrul face. Astfel, o modificare asupra culorii curente, folosind
funcţia glColor#() actualizează imediat proprietăţile de material specificate.
Soluţie. Principalele funcţii din program sunt prezentate mai jos.
Exemplul 4
Să se realizeze o aplicaţie în care o sursă de lumină este rotită în jurul unui tor. Când este
apăsat un buton al mouse-ului, sursa de lumină îsi schimbă poziţia cu 30 grade. Sursa de
lumină se va reprezenta printr-un mic cub wireframe.
Soluţie. Programul care realizează cerinţele problemei este prezentat mai jos.
MISCARE_SURSA.CPP

S-ar putea să vă placă și