View
243
Download
3
Category
Preview:
Citation preview
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 2
OpenGL - Basics
OpenGL este un API (Application Programming Interface) standard pentru grafica
3D. Inainte de aparitia sa fiecare producator de hardware avea propria sa biblioteca grafica. Nu este greu de imaginat cat de costisitor era de produs o
aplicatie grafica pentru mai multe platforme.
Ce poate face?
• In primul rand scuteste efortul de a transpune scena 3D pe ecran. Acest lucru se face automat ( lantul de transformari si etapele benzii grafice )
• Implementeaza transformarile de: rotatie, translatie, scalare.
• Ofera o stiva de matrici in care putem pastra transformarile aplicate
anterior
• Poate desena diverse primitive cu diverse proprietati de material (obiectele
pot sa para metalice, de plastic etc.)
• Texturile (imagini aplicate pe obiecte) pot face o scena simpla sa arate mult mai realist
• Pot fi create obiecte transparente (mecanismul de blending)
• OpenGL ofera diverse modele de iluminare si mai multe surse de lumina.
Totusi modelul de iluminare folosit este unul basic pentru ca tine cont doar de pozitia obiectului fata de sursa de lumina nu si de celelalte obiecte din
scena. Insa facilitatile oferite de OpenGL micsoreaza efortul necesar
pentru a produce umbrele.
• Etc
Conventii de numire a functiilor
Desi la prima vedere numele functiilor par neintuitive, ele urmeaza o regula simpla. Majoritatea sunt de forma:
• gl{nume functie}{numar de parametri}{sufix care arata tipul
parametrilor}{v (daca parametrul este un vector} ( .......)
Fiind independent de platforma OpenGL prevede cateva tipuri de date. Pentru a
obtine o aplicatie portabila este recomandat sa le folositi pe acestea si nu altele
de aceasi marime caracteristice sistemului de operare folosit:
Nume Descriere sufix
GLbyte intreg pe 8 biti b
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 3
GLshort intreg pe 16 biti s
GLint, GLsizei intreg pe 32 de biti i
GLfloat, GLclampf reprezentare in virgula mobila pe 32 de
biti f
GLdouble, GLclampd reprezentare in virgula mobila pe 64 de
biti d
GLubyte, GLboolean intreg fara semn pe 8 biti Ub
GLushort intreg fara semn pe 16 biti Us
GLuint, GLenum, GLbitfield intreg fara semn pe 32 de biti Ui
Cateva exemple: glVertex3d -primeste 3 parametri de tip GLdouble
glColor3f -3 parametri de tip GLfloat Totusi exista si cateva exceptii in care
lipsesc numarul si tipul parametrilor (de exemplu glBegin) sau care incep cu un alt prefix (gluLookAt).
Sistem de coordonate
OpenGL foloseste un sistem de coordonate dreapta.
Avem ordinea axelor xyz. Un sistem de coordonate este dreapta, daca privind de-a lungul unei axe dinspre +infinit spre origine, o rotatie in sens trigonometric
va aduce o axa pozitiva, peste axa pozitiva urmatoare. De exemplu: (ox peste
oy) sau (oy peste oz) sau (oz peste ox).
Transformari ale obiectelor 3D in OpenGL
Orice secventa de transformari, inclusiv proiectia se poate reprezenta printr-o
matrice. OpenGL reprezinta intern punctele ca vectori coloana. Din acest motiv o
secventa de doua transformari T1 apoi T2 aplicate punctului p produc rezultatul:
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 4
p' = T2 T1 p
OpenGL foloseste constantele: GL_MODELVIEW, GL_PROJECTION pentru a identifica matricea de modelare-vizualizare, respectiv matricea de proiectie.
Functiile OpenGL care reprezinta transformari modifica matricea curenta. Trebuie
sa aveti grija ca inainte de a le aplica sa apelati
glMatrixMode(constanta_care_identifica_matricea) pentru a va asigura ca transformarile vor produce efectul dorit.
Transformarea de modelare pozitioneaza un obiect undeva in lume. Puteti
folosi rotatii, translatii, scalari. Transformarea de vizualizare pozitioneaza observatorul. Acelasi efect poate fi obtinut in ambele moduri, de aceea OpenGL le pastreaza ca o singura matrice: GL_MODELVIEW.
Pentru a stabili pozitia observatorului puteti folosi functia:
• gluLookAt (GLdouble ex, GLdouble ey, GLdouble ez,GLdouble cx,
GLdouble cy, GLdouble cz,GLdouble upx, GLdouble upy, GLdouble
upz) o (ex, ey, ez) reprezinta noua pozitie a observatorului
o (cx, cy, cz) va arata directia in care priveste acesta o (upx, upy, upz) reprezinta directia sus din planul de vizualizare
Implicit observatorul e situat in origine, priveste in directia negativa a axei oz, iar
directia sus a planului de vizualizare este directia pozitiva a axei oy (0,1,0).
In acest moment matricea de modelare-vizualizare este matricea identitate.
Cand apelati gluLookAt transformarea descrisa de aceasta este compusa cu cea
deja existenta. De aceea daca o apelati de doua ori, al doilea apel s-ar putea sa
produca alte rezultate decat cele pe care le asteptati.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 5
Inainte de gluLookAt puteti apela secventa :
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
pentru a incarca matricea identitate in matricea de modelare-vizualizare.
Obiectele le puteti aseza/transforma in scena folosind:
• glScalef(GLfloat x, GLfloat y, GLfloat z) • glTranslatef( GLfloat x, GLfloat y, GLfloat z) • glRotatef (GLfloat unghi, GLfloat x, GLfloat y, GLfloat z)
Singura a carei semnificatie nu e evidenta este glRotatef. Aceasta functie roteste in sens trigonometric in jurul axei x,y,z cu unghiul unghi.
O astfel de functie modifica matricea curenta, astfel incat transformarea se va
aplica tuturor obiectelor pe care le vom desena de acum incolo, lasandu-le
neschimbate pe cele deja desenate. Insa comportamentul lor este diferit de ceea ce ne-am astepta. Transformarile sunt aplicate obiectului in ordinea inversa
apelurilor.
Pana acum am vazut cum stabilim pozitia si orientarea observatorului in raport cu obiectele din lume. Insa pentru a face scena sa apara pe ecran trebuie sa
delimitam spatiul vizibil: volumul de vizualizare. OpenGL permite mai multe
moduri de a face acest lucru.
Proiectia ortografica se realizeaza cu ajutorul functiei:
• glOrtho(GLdouble left, GLdouble right, GLdouble bottom,
GLdouble top, GLdouble near, GLdouble far)
Volumul de vizualizare este un paralelipiped dreptunghic. Nu uitati insa ca
pozitia observatorul este implicit in origine si priveste in directia negativa a axei oz. Deci obiectele cu z intre -near si -far vor fi vizibile.
Proiectia perspectiva se poate realiza in doua moduri:
• glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
left, right, bottom, top se refera in acest caz la fereastra din planul apropiat.
Cum stim pozitia observatorului ( e cea implicita sau cea setata de noi cu gluLookAt) putem calcula volumul de vizualizare. Distantele near si far trebuie
sa fie pozitive.
Un alt mod de a specifica acest volum de vizualizare este cu ajutorul functiei:
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 6
• void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble
near, GLdouble far)
Ati recunoscut deja parametrii near si far. Parametrul aspect reprezinta raportul
dintre lungimea si inaltimea ferestrei in planul de aproape. Pentru a obtine o imagine nedistorsionata acest raport trebuie sa corespunda cu cel al ferestrei
de afisare. Parametrul fovy este unghiul de vizualizare in planul xOz si trebuie
sa fie in intervalul [0.0, 180.0]
Transformarea in poarta de vizualizare se defineste folosind functia:
• glViewport (GLint px, GLint py, GLint pz, GLsizei width, GLsizei
height)
px, py reprezinta coordonatele in fereastra ale coltului stanga jos al portii. Implicit sunt 0,0.
width, height sunt latimea si inaltimea portii. Valorile implicite sunt date de
latimea si inaltimea ferestrei in care se afiseaza.
Setarea culorii
Inainte de a face vreun desen trebuie sa setam o culoare de fond:
• glClearColor(GLclampf R, GLclampf G, GLclampf B, GLclampf A)
A reprezinta opacitatea.Apoi vom sterge imaginea:
• glClear(GL_COLOR_BUFFER_BIT)
Constanta data ca parametru arata ce buffer vrem sa stergem. OpenGL foloseste
mai multe buffere in diverse scopuri. Putem sterge mai multe cu acelasi apel astfel:
• glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
In acest caz am sters imaginea si bufferul folosit pentru a determina care figuri sunt vizibile (folosit de algoritmul z-buffer).
Acum putem seta o culoare care va fi folosita pentru urmatoarele desenari
(pana o schimbam din nou):
• glColor3f(GLfloat R, GLfloat G, GLfloat B);
Desenarea diverselor primitive
Exista mai multe tipuri de primitive pe care le putem desena folosind
OpenGL. Pentru inceput insa nu le voi prezenta pe toate.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 7
Putem desena ceva pe ecran folosind functia:
• glVertex3f(GLfloat x, GLfloat y, GLfloat z)
Pentru a avea vreun efect apelurile acestei functii trebuiesc incadrate intre
apelurile glBegin(GLenum tip_primitiva) si glEnd( ).
Tipul primitivei este identificat printr-una din constantele:
• GL_POINTS - deseneaza puncte • GL_LINES - deseneaza segmente. Doua puncte definesc un
segment, urmatoarele doua alt segment etc. • GL_POLYGON - deseneaza un poligon • GL_TRIANGLES - fiecare grup de 3 varfuri defineste un dreptunghi • GL_QUADS -patrulatere • GL_LINESTRIP - doar primul segment e definit prin doua puncte.
Urmatoarele au un capat comun cu cel anterior • GL_LINE_LOOP - Se deseneaza un segment si intre primul si ultimul punct • GL_TRIANGLE_STRIP - banda de triunghiuri. Toate in afara de primul (care
e definit prin 3 varfuri) au primele doua varfuri egale cu ultimele doua ale
triunghiului anterior • GL_TRIANGLE_FAN - toate triunghiurile au primul varf comun. Doua
triunghiuri succesive au o latura comuna • GL_QUAD_STRIP - asemanator cu triangle strip, dar sunt patrulatere
Este recomandat sa folositi GL_TRIANGLE_STRIP sau GL_TRIANGLE_FAN in loc de GL_TRIANGLES oricand este posibil si sa introduceti cat mai multe varfuri
intre un singur apel glBegin si glEnd pentru ca placile grafice sunt optimizate
pentru desenarea in acest mod si trebuie sa comunicam cat mai putine date placii.
Intre glBegin si glEnd puteti apela si glColor* pentru a stabili culoarea
varfurilor urmatoare.
Modul in care sunt afisate poligoanele se poate stabili (inainte de glBegin!) folosind:
• glPolygonMode (GLenum face, GLenum mode) o face poate fi :
� GL_FRONT_AND_BACK sau GL_FRONT sau GL_BACK. � Aceste constante identifica fetele fata sau spate (in mod
implicit fetele care sunt definite prin varfuri parcurse in sens
trigonometric sunt considerate fete fata o mode poate fi GL_POINT, GL_LINE sau GL_FILL
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 8
Stive de matrici
Stiti deja ca putem stabili o transformare care sa fie aplicata tuturor varfurilor de
acum incolo. Insa uneori avem nevoie sa definim o transformare nu fata de cea dinaintea ei, ci fata de una mai veche. De exemplu avem nevoie sa desenam o
masina. Desenam masina. Aplicam o translatie si desenam prima roata. Ne este
mai usor sa calculam pozitia celorlalte roti fata de masina, nu fata de prima roata.
OpenGL ne ofera o posibilitate de a face acest lucru prin existenta unei stive de
matrici. Cea din varful stivei este matricea curenta.
In momentul in care apelam glPushMatrix( ) matricea curenta este salvata in
stiva. Putem sa modificam si sa folosim matricea curenta.
Apoi cand vrem sa ne intoarcem la transformarea pastrata in stiva apelam
glPopMatrix( ).
Singurul lucru la care trebuie sa fim atenti este sa nu apelam glPopMatrix daca nu avem nici o matrice in stiva si sa nu depasim capacitatea stivei. Desi exista implementari care ofera stive foarte mari sau chiar nelimitate, standardul
prevede o stiva de 32 de matrici de modelare-vizualizare si o stiva de 2 matrici de proiectie. Stiva pe care lucreaza glPushMatrix si glPopMatrix este stabilita cu
ajutorul functiei glMatrixMode.
Gestiunea ferestrelor folosind biblioteca glut
Pe langa standardul OpenGL, glut ofera si functii care usureaza realizarea unei
interfete cu utilizatorul. Voi enumera cateva dintre ele (pentru mai multe informatii va puteti uita in indrumarul de laborator):
glutInit(int* argc, char** argv) initializeaza variabilele interne si
prelucreaza argumentele din linia de comanda. Trebuie apelata inaintea
oricarei alte functii glut.
glutInitDisplayMode( unsigned int mode) initializeaza modul de afisare.
mode specifica:
• modelul de culoare folosit. Se recomanda GLUT_RGB • folosirea unei ferestre cu buffer simplu sau dublu: GLUT_SINGLE sau
GLUT_DOUBLE
• folosirea bufferului de adancime pentru algoritmul z-buffer: GLUT_DEPTH Pentru a obtine valoarea lui mode putem aplica | intre valorile care ne intereseaza.
glutInitWindowPosition(int x, int y) >pozitioneaza fereastra fata de coltul stanga sus al ecranului.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 9
glutInitWindowSize(int width, int height) evident stabileste
dimensiunea ferestrei
int glutCreateWindow(char* nume) creaza o fereastra cu un context OpenGL
int glutDestroyWindow(int window) distruge fereastra window impreuna
cu toate subferestrele ei.
Functii pentru controlul evenimentelor de intrare
glutReshapeFunc( void (*f) (int width, int height) primeste ca parametru un pointer la o functie care trebuie apelata de fiecare data cand fereastra e
redimensionata.
glutKeyboardFunc( void (*f) (unsigned char key, int x, int y)) primeste ca parametru o functie care trebuie apelata de fiecare data cand se
apasa/elibereaza o tasta. key este valoarea ASCII. x si y reprezinta pozitia
mouse-ului la apasarea tastei.
glutMouseFunc( void (*f) (int buton, int stare, int x, int y) . *f va fi
apelata la apasarea sau eliberarea unui buton de mouse. buton poate fi:
GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON. Parametrul state poate fi: GLUT_UP sau GLUT_DOWN. Parametrii x si y
reprezinta pozitia mouse-ului la aparitia evenimentului
glutMotionFunc( void (*f) (int x, int y) . *f va fi apelata la deplasarea mouse-ului in timp ce un buton este apasat. Parametrii x si y reprezinta pozitia
mouse-ului in momentul apasarii.
Executia aplicatiei
glutDisplayFunc( void (*f)(void)) stabileste functia de afisare. Functia de afisare va fi apelata automat de fiecare data cand este necesara redesenarea
continutului ferestrei. Putem cere explicit acest lucru apeland:
glutPostRedisplay( ). In cazul in care folosim un buffer dublu, la sfarsitul lui *f
trebuie sa cerem schimbarea bufferelor prin glutSwapBuffers( ) .
glutIdleFunc(void (*f) (void)) . Parametrul este o functie care va fi
executata in perioadele in care nu exista evenimente in curs de tratare. NULL inseamna ca functia idle e dezactivata. Poate fi folosita pentru crearea unei
animatii.
glutMainLoop(void) este ultima functie care se apeleaza in main. Contine o bucla in care aplicatia asteapta evenimente.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 10
Iluminare si proprietati de material in OpenGL
Redarea luminilor in OpenGl este o sarcina care implica setari in mai multe
directii:
• setari generale ale mediului OpenGL si ale interpretarii luminii pe diferite
fete
• surse de lumini
• propietatile surselor de lumini • materiale
• normale la suprafata
Daca una din aceste setari este gresita, atunci nu va merge nimic corect.
Ca deobicei, pentru a avea succes trebuie sa programam de la inceput
foarte atent si foarte curat. De asemenea, este foarte putin probabil sa se
reuseasca sa un efect interesant daca nu este inteles bine mecanismul
luminilor.
Interpretarea modelului luminii naturale in OpenGL
Pentru inceput sa ne imaginam o scena complexa din lumea reala. Ea este
formata din obiecte cu diferite forme si texturi, dar si din multe lumini,
reflexii de lumini sau umbre. Din punct de vedere fizic, lumina este o
energie fotonica care se misca prin spatiu aproape instantaneu. Cand un
obiect primeste o raza de lumina, el pastreaza o parte din energie pentru
el, iar restul o imprastie in mediu. Partea care o primeste pentru el se
transforma in caldura, iar partea care o emana va determina practic culoarea obiectului.
Cum sunt structuralizate toate acestea intr-un model de lumini? In
OpenGL, se considera ca intr-o scena oarecare pot apare mai multe tipuri de lumini de felul urmator:
1. lumina ambientala
2. lumina difuza
3. lumina speculara
4. lumina emisa
Lumina ambientala
Aceasta este lumina care este prezenta in atmosfera “pur si simplu”. Nu
putem spune despre ea nici ca vine dintr-o anumita sursa, , nici ca este
stralucitoare , nici ca se reflecta de oglinda. Este provenita de la alte surse
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 11
de lumini in urma reflexilor repetate, nu se mai poate stabili exact unde a
fost sursa si cum a ajuns lumina in locul respectiv.
Un exemplu bun de lumina ambientala este cea vazuta intr-un hol care
primeste lumina numai de la sursele din camerele vecine. Lumina venita
poate fi amestecata din razele de lumina venite din numeroase reflexii.
Doar lumina ambientala nu ne ajuta sa vedem formele obiectelor colorate la fel. Motivul? Energia luminoasa este identica pt fiecare fata(nu depinde
de orientare) si prin urmare culoarea vazuta este exact aceiasi.
Lumina Difuza
Aceasta este lumina provenita de la o sursa anume. Ea este formata din
mai multe raze care se imprastie in toate directile. Acum lumina obiectului
este si calculata in functie de directia razei care lumineaza respectivul
obiect. Sursa de lumina poate fi la infinit (imaginati-va lumina solara intr-o zi senina) sau poate fi apropiata de obiect (imaginati-va un bec).
Diferenta dintre cele doua tipuri de surse se observa si in directia razelor.
La soare razele vin paralele, la bec razele chiar se vad cum emana dintr-un punct fix. Lumina difuza se apropie cel mai mult de majoritatea
luminilor din lumea reala, reprezinta clasa luminilor cu sursa si directie. De
retinut ca pozitia observatorului nu influenteaza culoarea obiectului in
acest caz, cu alte cuvinte culoarea este transmisa la fel in toate directiile.
Lumina speculara
Aceasta este componenta care da stralucire obiectelor. Se aseamana cu
lumina difuza, insa singura diferenta este ca speculara este focalizata. Pentru a intelege conceptul e bine sa ne imaginam o raza laser, sau un
reflector de foarte buna calitate. Razele care pleaca din reflector trebuie sa
fie paralele. Obiectele resping aceasta lumina tot intr-un mod specular si
prin urmare aceasta lumina nu poate fi vazuta din orice pozitie. Ochiul
trebuie sa se afle chiar pe directia ei.
Lumina emisa
Aceasta este lumina pe care un obiect o emite prin el insusi. In OpenGL
aceasta nu mai devine si sursa pentru alte obiecte din jurul lui. De regula
nu este nevoie sa fie folosita decat daca se doreste obtinerea de obiecte
incandescente (lampi, focuri, etc.. )
Culorile luminii si materialelor in OpenGL
De remarcat ca lumina are si culoare. Exista in lumea reala si lumini verzi
si lumini albastre, dar si lumini obisnuite albe. De cele mai multe ori,
obiectul amesteca culorile primite de la lumina cu culorile sale naturale,
putand rezulta chiar o culoare diferita de culoarea initiala a obiectului.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 12
In OpenGL culoarea poate fi specificata prin cele 3 componente RGB.
Acestea sunt niste valori reale intre 0 si 1. De exemplu o lumina cu
(R,G,B)=(1,1,1) reprezinta o lumina alba, cea mai puternica. O lumina
(0,0,1) reprezinta o lumina albastruie. In openGL atat lumina cat si corpul
au setate aceste valori pentru fiecare tip de lumina (ambientala, difuza si
speculara). Lumina reflectata de un anumit obiect se obtine inmultind
valoarea culorii cu valoarea luminii – bineinteles ambele trebuie sa se
refere la acelasi tip de lumina.
Din punct de vedere fizic se pot intampla lucruri mult mai interesanta cu
raza de lumina in momentul in care aceasta atinge corpul. De ce nu mai e
alba zapada cand se topeste? Pentru ca de regula zapada reflecta in
totalitate lumina primita, dar daca se topeste incepe sa si absoarba.
Pasii necesari pentru a seta un mediu propice luminii in OpenGL
Pentru a incepe sa folosim luminile avem nevoie de urmatoarele setari
1. Initializarea mediului
glEnable(GL_LIGHTING) : fara aceasta functie, OpenGL nu efectueaza calcule pentur iluminare
2. Activarea luminilor
glEnable(GL_LIGHT0) : acesta functie activeaza sursa de lumina
cu numarul 1
glEnable(GL_LIGHT1) : acesta functie activeaza sursa de lumina
cu numarul 2
....
glEnable(GL_LIGHT7) : acesta functie activeaza sursa de lumina
nr. 8
Toate propietatile luminii pe care le vom da in continuare se vor seta
in una din aceste 8 lumini. Acesta este numarul maxim de lumini
intr-o scena OpenGL (in anumite implementari acest numar poate fi
mai mare).
Cu toate acestea, mai exista o sursa in scena introdusa automat
chiar daca nu sunt aprinse aceste lumini: Lumina Ambientala Globala
GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 13
Aceasta este lumina prin care se pot vedea obiectele chiar daca noi
nu adaugam explicit lumina, ea defineste o lumina ambinetala de
baza, cam palida.
3. Setarea modelului de iluminare
Se pot seta diversi parametrii ai iluminarii:
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) : aceasta functie seteaza pozitia ochiului in (0,0,0). Avem nevoie de
ea atunci cand calculam reflexile speculare. Deobicei observatorul se
considera a fi la infinit astfel incat unghiul format de raza incidenta pe un punct si de linia observator-punct depinde doar de raza
incidenta.
glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_TRUE): aceasta
functie spune openGL-ului sa faca toate calculele si pentru fetele considerate ca sunt cu spatele la lumina. Deobicei aceste fete sunt
orientate spre interiorul corpurilor deci nu avem nevoie de lumina pe
ele. Insa daca vrem sa iluminam si partea interioara a unei jumatati
de sfera, trebui sa setam si acest parametru.
ShadeModel : Acesta nu face parte neaparat din modelul de
iluminare, insa e destul de important in acest context. Se seteaza cu
glShadeModel si poate fi de doua feluri: smooth sau flat. Modul flat
pune aceiasi culoare pe toata fata, in timp ce modul shade
interpoleaza valorile din colturi. Trebuie sa fim atenti la cazul in care
o lumina de tip spot cade pe centrul unui obiect fara sa ii atinga colturile. Daca se intampla asta, lumina va fi practic ignorata.
4. Setarea parametrilor obiectelor
Dupa ce am parcurs pasii de mai sus, putem sa incepem sa setam
parametrii efectivi ai luminilor. Ne alegem una din cele 8 surse de
lumina, sa zicem GL_LIGHT0, si vom opera asupra ei.
Un exemplu simplu - pentru a seta un parametru oarecare din cei
care urmeaza, se apeleaza un cod ca cel de mai jos:
GLfloat light_ambient[] = { 0.5, 0.5, 0.5, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
Acest cod seteaza propietatea GL_AMBIENT la valorile precizate
pentru sursa de lumina GL_LIGHT0. Cei 4 parametrii reprezinta
valorile RGBA ale luminii – intre 0 si 1. RGB este destul de clar ce
inseamna, alfa este folosit daca vrem sa facem, de exemplu, culoarea luminii mai importanta decat culoarea obiectului. Daca
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 14
obiectul are alfa mai mic decat 1.0, atunci culoarea naturala a
obiectului va fi mai putin importanta decat culoarea luminii atunci
cand se va calcula valoarea luminii reflectate.
Sa trecem acum la definirea completa a parametrilor luminii.
• GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR
Aceste valori sunt toate definite ca in exemplul de mai sus si
reprezinta culoarea luminii pentru cele 3 tipuri de lumini prezentate.
Pentru a crea un efect realistic e bine ca acestea sa aiba aceiasi valori – adica lumina difuza si ambientala sa fie de aceiasi culoare.
• GL_POSITION
Aceasta valoare e folosita pentru luminile care trebuie sa aiba o
sursa specificata: SPECULAR si DIFFUSE. Aceste tipuri de lumini au
nevoie de o pozitionare, trebuie sa stiu de unde pleaca lumina.
GLfloat light_position[] = { x,y,z,w};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
Precum vedeti, apelul este similar celui de la GL_AMBIENT. Daca w,
componenta a 4-a este 0 atunci se considera ca sursa este undeva
la infinit pe directia x,y,z (Directional Light). Altfel ea se afla exact la pozitia x,y,z (Positional Light).
• GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION,
GL_QUADRATIC_ATTENUATION
Acesti parametrii afecteaza factorii de atenuare a luminii. In lumea
reala teoretic lumina se poate atenua. OpenGL permite atenuarea
intensitatii luminii in functie de distanta, patratatul distantei sau
cubul distantei. Acesti parametrii se folosesc doar la luminile
positionale.
• GL_SPOT_DIRECTION, GL_SPOT_EXPONENT, GL_SPOT_CUTOFF
Acesti parametrii se folosesc la luminile positionale, atat pentru
componenta difuza cat si pentru componenta speculara. Dand acesti
3 parametrii, lumina emanata dintr-un punct (nu de la infinit) nu mai pleaca in toate directile ci numai dupa o anumita orientare. Se
doreste simularea luminilor de genul reflectoarelor de la concerte.
GL_SPOT_DIRECTION reprezinta directia (x,y,z) in care este orientat
spotul, GL_SPOT_EXPONENT reprezinta concentratia luminii in interiorul spotului (poate fi constanta sau mai puternica spre centru
si mai mica spre margini).
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 15
GL_SPOT_CUTOFF care reprezinta ungiul, sau deschiderea spotului.
Initial aceste e de 180 care inseamna (180*2=360) ca spotul este
de fapt tot o lumina emanata in toate directiile. Dar daca setam alt
unchi, suntem obligati sa dam o valoare intre 0 si 90 de grade, adica
sa determinam un spot realistic (fata de o anume directie – centru
spotului).
5. Un exemplu de setare lumini
nr light_position[] = { 0.0, 100.0, 0.0, 1.0 }; //seteaza pozitia
nr light_ambient [] = { 0.9, 0.4, 0.0, 1.0 }; //seteaza componenta ambientala
nr light_difusion[] = { 0.9, 0.4, 0.0, 1.0 }; //seteaza componenta de
difuzie
nr light_specular[] = { 0.9, 0.4, 0.0, 1.0 }; //seteaza componenta
speculara
nr direction [] = { 1.0, -1.0, 1.0}; //seteaza directia spotului
glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT1, GL_AMBIENT , light_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE , light_difusion);
glLightfv(GL_LIGHT1, GL_POSITION, light_position);
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, direction);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 3.0);
Acest exemplu seteaza o lumina rosiatica (0.9>0.4), pozitionata la inaltimea 100 (observati ca ultimul parametru al pozitiei nu este 0, deci
avem lumina pozitionala) si apoi ii definim si propietati de spot. Directia
este in jos, unghiul de deschidere totala va fi 45*2=90 si exponentul este
3 ca sa concentram lumina catre interiorul spotului. Matematic vorbind,
intensitatea luminii intr-o anumita parte a spotului, va fi cos(unghi(raza in
cadrul spotului, directia generala a spotului))) la puterea a 3-a.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 16
6. Setarea parametrilor materialului
Majoritatea caracteristicilor luminii trebuie sa se regaseasca in
propietatile de material pentru ca un obiect sa reflecte o culoare.
Aceasta va fi determinata pe baza propietatilor luminii dar si a
propietatilor materialului.
Pentru luminile neambientale trebuiesc intotdeauna setate normalele suprafetelor ce vor fi iluminate.
Caracteristicile materialelor sunt urmatoarele:
• GL_AMBIENT reprezinta partea ambientala a luminii ce va fi
reflectate de obiect. Acest parametru se va amesteca cu
GL_AMBIENT al sursei de lumina. De remarcat ca este de
forma (r,g,b,alfa) insa alfa nu conteaza intrucat in momentul
cand se va face blending, se ia in considerare o singura
valoare alfa – aceea a lui GL_DIFFUSE
• GL_DIFFUSE reprezinta componenta difuza a culorii
materialului. E de forma (r,g,b,alfa)
• GL_AMBIENT_AND_DIFFUSE acest parametru este folosit
deoarece in lumea reala sunt extrem de rare(practic nu exista)
obiectele care sa aiba valori diferite al culorii relflexiei
ambientale si difuze
• GL_SPECULAR aceasta este valoarea culorii speculare,
oglindite de obiect. Acest parametru poate fi diferit, el
reprezinta valoarea reflectata. De exemplu, la un diamanat,
culoarea reflectata nu e acelasi lucru cu culoarea obiectului. O
piatra pretioasa poate reflecta si raze colorate cu alte culori.
• GL_SHININESS este o valoare care ne spune cat de mult
este focalizata raza speculara reflectata. Maximul este 128 si
corespunde unei lumini concentrate practic practic la
maximum intr-o singura raza.
• GL_EMISSION este o setare prin care putem da
incandescenta unui obiect. Dand acest parametru, obiectul va
aparea generand lumina prin el insusi fara sa o primeasca din
alta parte
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 17
8. Alte idei de care sa tinem cont
Matricea ModelView influenteaza pozitia luminii doar in momentul
cand a fost setat prima oara GL_POSITION. Prin urmare, daca
modificam pozitia observatorului sau pozitia unor obiecte si astfel
modificam ModelView, vom avea surpriza sa nu gasim lumina la
locul ei. Trebuie sa resetam valoarea GL_POSITION de fiecare data cand schimbam ModelView. Deasemenea, ModelView modifica si
valorile normalelor. De aceea e bine sa apelam si
glEnable(GL_NORMALIZE) pentru a fi siguri ca normalele sunt puse
corect (normalele se seteaza pentru fiecare varf folosind de exemplu
glNormal3f. Aceasta functie poate fi apelata intre glBegin si glEnd. Functioneaza asemanator cu glColor: varfurile definite dupa apel vor
avea asociata ultima normala setata cu glNormal).
Daca vrem sa iluminam doar anumite obiecte putem face asta
setand glEnable (GL_LIGHT0) doar inainte de a desena obiectul in
cauza.
OpenGL nu ne da nici un mecanism prin care sa facem reflexii de
lumini sau umbre. O raza reflectata nu mai devine sursa de lumina
pentru alte obiecte.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 18
OpenGL - Advanced
Liste de afisare
O lista de afisare reprezinta un grup de comenzi OpenGL stocate pentru o
executie ulterioara. La invocarea unei liste de afisaree ccomenzile din ea
sunt executate un ordinea in care sunt intalnite. Majoritatea comenzilor
OpenGL pot fi stocate intr-o lista de afisare. listele de afisare pot
imbunatati programul deoarece instructiunile sunt stocate pentru executii ulterioare. Este indicat sa se foloseasca liste de afisare in cazul in care se
redeseneaza de mai multe ori aceeasi figura geometrica sau daca trebuie
aplicat de mai multe ori un set de modificari de stare.
Listele de afisare au si dezavantaje. Listele foarte mici nu vor imbunatati
executia programului datorita overheadului executiei listei. Un alt
dezavantaj consta din faptul ca o lista de afisare nu poate fi modificata si
continutul sau nu poate fi citit.
Fiecare lista de afisare este identificata printr-un index intreg. La crearea
unei liste trebuie sa nu se aleaga un index deja folosit altfel se va sterge
lista de afisare corespunzatoare acelui indice. Pentru a evita acest lucru se
poate folosi :
W GLuint glGenLists(GLsize i range); Aceasta functie va genera unul sau mai
multi indici nefolositi. Functia aloca un domeniu de range numere nefolosite si
valoarea intoarsa reprezinta indicele de inceput al intervalului. Functia intoarce 0
daca nu este disponibil numarul de indici ceruti sau daca range este 0.
W void glNewList(GLuint list, GLenum mode);
• list : un intreg pozitiv diferit de 0 care identifica in mod unic lista de
afisare
• valorile posibile ale parametrului mode sunt :
o GL_COMPILE : nu se doreste executarea intructiunilor la plasarea in lista
o GL_COMPILE_AND_EXECUTE : se doreste executarea intructiunilor
la plasarea in lista
Functia specifica inceputul unei liste de afisare.Functiile care vor fi apelate (pana
la intalnirea functie glEndList() ) sunt stocate in lista de afisare.
W void glNewList(GLuint list, GLenum mode); Functia marcheaza sfarsitul unei
liste de afisare
W void glCallList(GLuint list); Functia executa lista de afisare specificata de
parametrul list. O lista de afisare poate fi executata de mai multe ori si de
asemenea se poate imbina cu apeluri in modul imediat.
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 19
Alpha Testing & Z-Buffer & Blending & Obiecte transparente
Testul alpha permite acceptarea sau respingerea desenarii unui fragment
in functie de valoarea alpha (opacitatea) asociata acelui fragment. Pentru
activarea acestui test se apeleaza :
W void glEnable(GL_ALPHA_TEST); Testul consta in compararea valorii de
opacitatea asociata fragmentului cu o valoare de referinta ref
W void glAlphaFunc(GLenum func, GLclampf ref); Functia de comparatie (func
poate fi una din constantele :
• GL_LESS • GL_LEQUAL
• GL_EQUAL • GL_NOTEQUAL
• GL_GEQUAL
• GL_GREATER • GL_NEVER
• GL_ALWAYS
Testul de adancime (z-buffer) este folosit pentru a determina daca o primitiva va
fi sau nu afisata in functie de "adancimea" sa. Pentru a fi folosit fereastra de
afisare trebuie sa aiba asociata un buffer de adancime. Astfel parametrul intreg
al functiei GLUT InitDisplayMode trebuie sa contina bitul GLUT_DEPTH pozitionat
pe valoarea 1 si pentru a activa testul trebuie folosit si apelul :
W glEnable(GL_DEPTH_TEST)
Functia de comparatie intre adancimea fragmentului si ce a valorii
corespunzatoare care a fost deja memorata in z-buffer poate fi specificata prin
apelul functiei :
W void glDepthFunc(GLenum func); Parametrul func are aceleasi valori posibile
ca in cazul functiei glAlphaFunc
Testul de combinare (blending) este specific modului RGBA de specificare a
culorilor scenei de vizualizat. In acest mode de afisare fiecarui fragment i se
asociaza o pondere de amestec a colorii sale.
Daca valoarea A este 0 sau lipseste atunci fiecare nou fragment va suprascrie
pixelul corespunzator din memoria video. Se poate deci considera ca valoarea A
reprezinta gradul de opacitate (sau de transparenta a unui fragment). Modul de
combinare a culorilor fragmentului nou care se deseneaza (si care va fi numit in
continuare sursa) si respectiv a pixelului corespunzator din memoria video
(numit in continuare destinatie) este specificat cu ajutorul functiei :
W void glBlendFunc(GLenum fsursa, GLenum fdest); Parametrii fsursa sifdest
sunt asociati celor 2 factori de amestec sursa si destinatie
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 20
Cei 2 factori de amestec au fiecare cate 4 componente care corespund
coeficientilor de amestec pentru fiecare culoare fundamentala si factorului de
opacitate. Fie (Sr,Sr,Sg,Sa) si (Dr,Dg,Db,Da) cei 2 factori de amestec. Notam cu
(Rs,Gs,Bs,As) respectiv (Rd,Gd,Bd,Ad) informatia de culoare asociata
fragmentului sursa respectiv destinatiei. In urma procesului de blending va
rezulta un pixel cu coeficientii RGBA :
(RsSr+RdDr,GsSg+GdDg,BsSb+BdDb,AsSa+AdDa)
Parametrii functiei (glBlendFunc pot fi :
• GL_ZERO -> corespunde unui factor de amestec (0,0,0,0)
• GL_ONE -> (1,1,1,1)
• GL_SRC_ALPHA -> (As,As,As,As) • GL_ONE_MINUS_SRC_ALPHA -> (1-As,1-As,1-As,1-As)
• GL_DST_ALPHA -> (Ad,Ad,Ad,Ad) • GL_ONE_MINUS_DST_ALPHA -> (1-Ad,1-Ad,1-Ad,1-Ad)
Spre exemplu pentru a afisa un desen rezultat prin compunerea in proportii egale
a doua imagini se pot genera pe rand cele doua imagini setand factorul destinatie
la GL_ONE si factorul sursa la valoarea GL_SRC_APLHA unde valoarea A asociata
fiecarui fragment este 0.5
Modul de lucru cu compunerea culorilo se ativeaza cu glEnable(GL_BLEND) si
dezactiveaza cu glDisable(GL_BLEND)
Vizualizarea obiectelor transparente se poate simula in modul urmator :
• se afiseaza scena acceptand numai fragmentele cu alpha egal cu 1 (perfect opace)
• se dezactiveaza scrierea in z-buffer
• se redeseneaza scena acceptand numai fragmente cu alpha mai mic decat 1 (transparente) si folosindu-se ca functie de amestecare
glBlendFunc(GL_SRC_APLHA,GL_DST_ALPHA)
Observatie : in mod normal pentru a fi redat corect fenomenul de transparenta
ar trebui ca si corpurile transparente sa fie afisate in ordinea adancimii lor
realizandu-de o sortare a acestora.
Picking(selectie)
OpenGL pune la dispozitie un mecanism de selectie a obiectelor in spatiul
3D. Pasii pentru a realiza aceasta operatie sunt urmatorii :
• 1. Preluarea coordonatelor de la mouse din interiorul ferestrei de afisare • 2. Intrarea in modul de selectie
• 3. Redefinirea volumului vizual in jurul cursorului mouselui
• 4. Randarea scenei • 5. Iesirea modului de selectie si identificarea primitivelor care au fost
desenate in volumul vizual redefinit
SISTEME DE PRELUCRARE GRAFICA Laborator 1
Pagina 21
• Pentru a identifica obiectele renderizate acestea trebuiesc sa fie numite.
API-ul OpenGL permite acest lucru numele asignate obiectelor regasindu-se intr-o stiva de nume Numele in realitate sunt reprezentate prin intregi.
Manipularea stivei de nume se realizeaza astfel :
o void glInitNames(void); creaza o stiva de nume goala o void glPushName(GLuint name); adauga in varful stivei pe name
o void glPopName(void); sterge un nume din varful stivei
o void glLoadName(GLuint name); inlocuieste varful stivei cu name
In mod normal atunci cand primitivele sunt randate pentru selectie ele sunt
desenate intre un glPushName(name) si glPopName() care identifica primitiva
sau grupul de primitive (de exemplu cele sase fete ale unui cub pot fi desenate
intre glPushName(CUB) ... glPopName() )
• In modul de selectie nici un obiect nu este de fapt randat in memoria video
(framebuffer). In schimb numele obiectelor (plus informatia de adancime) sunt colectate intr-un vector.
• In terminologia OpenGL un hit are loc de fiecare data cand o primitiva este
desenata in modul de selectie . Hit recordurile sunt stocate in bufferul de selectie
• Cand OpenGL iese din modul de selectie intoarce bufferul de selectie ce va
contine un set de hit records Avand in vedere ca pentru fiecare hit record
sunt disponibile si informatiile de adancime se poate determina usor care obiect a fost selectat chiar daca unul sau mai mult obiecte sunt suprapuse.
• Structura unui hit record este urmatoarea :
o primul camp reprezinta numarul de nume care le contine hit recordul (un obiect poate sa aiba mai multe nume)
o al doilea si al treilea camp reprezinta adancimea minima si cea
maxima asociata pt hit o o secventa de nume avand totalul corespunzator cu numarul
acestora din primul camp (poate sa si lipseasca daca primul camp
are valoarea 0)
• Inainte de intrarea in modul de selectie trebuie specificat bufferul de selectie astfel :
o void glSelectBuffer(GLsizei size, GLuint *buffer);
• Intrarea in modul de selectie se face astfel : o void glRenderMode(GL_SELECT);
• Intoarcerea in modul normal de randare se face astfel : o nhits glRenderMode(GL_RENDER);
Functia intoarce numarul de hit records ce au fost create si stocate in bufferul de
selectie in cadrul procesului de selectie
Recommended