partea ii - cursuri automatica si calculatoareandrei.clubcisco.ro/3egc/lab/aplicatii opengl...

99
PARTEA a II-a : Implementarea de aplicaţii OpenGL folosind biblioteca GLUT OpenGL este o interfaţă de programare formată din circa 150 de funcţii care pot fi folosite pentru modelarea si vizualizarea scenelor 3D. Două aspecte importante au determinat creşterea continuă a popularităţii sale : Funcţiile OpenGL sunt independente de platforma hardware-software OpenGL oferă funcţii de sinteză de nivel înalt, care sunt realizate fie software fie prin echipamente grafice specializate In prezent există implementări OpenGL pentru sistemele de operare Microsoft Windows, Unix şi IBM PS/2. Acestea se prezintă sub forma unor biblioteci integrate (sau care pot fi integrate) în mediile de dezvoltare a aplicaţiilor. Deoarece OpenGL nu conţine funcţii de gestiune a ferestrelor de afişare şi interacţiune cu utilizatorul, implementările OpenGL sunt completate cu astfel de funcţii. O asemenea implementare extinsă este şi GLUT (OpenGL Utilities Toolkit), la a cărei utilizare ne referim în această parte a îndrumarului. Dintre funcţiile de sinteză de nivel înalt oferite de OpenGL menţionăm: Maparea texturilor: aplicarea de imagini pe suprafeţe 3D Eliminarea automată din imagini a părţilor nevizibile ale obiectelor prin algoritmul Z-buffer ; Efecte de iluminare a scenelor 3D folosind diferite modele de iluminare şi una sau mai multe surse de lumină; Simularea reflexiei si a transmisiei luminii ţinând cont de proprietăţile materialelor ; Transformarea din spaţiul 3D utilizator în spaţiul 2D ecran prin specificarea matricelor de transformare,

Upload: others

Post on 07-Mar-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

PARTEA a II-a : Implementarea de aplicaţii OpenGL folosind biblioteca GLUT

OpenGL este o interfaţă de programare formată din circa 150 de funcţii care pot fi folosite pentru modelarea si vizualizarea scenelor 3D. Două aspecte importante au determinat creşterea continuă a popularităţii sale :

Funcţiile OpenGL sunt independente de platforma hardware-software OpenGL oferă funcţii de sinteză de nivel înalt, care sunt realizate fie software fie

prin echipamente grafice specializate

In prezent există implementări OpenGL pentru sistemele de operare Microsoft Windows, Unix şi IBM PS/2. Acestea se prezintă sub forma unor biblioteci integrate (sau care pot fi integrate) în mediile de dezvoltare a aplicaţiilor. Deoarece OpenGL nu conţine funcţii de gestiune a ferestrelor de afişare şi interacţiune cu utilizatorul, implementările OpenGL sunt completate cu astfel de funcţii. O asemenea implementare extinsă este şi GLUT (OpenGL Utilities Toolkit), la a cărei utilizare ne referim în această parte a îndrumarului.

Dintre funcţiile de sinteză de nivel înalt oferite de OpenGL menţionăm: Maparea texturilor: aplicarea de imagini pe suprafeţe 3D Eliminarea automată din imagini a părţilor nevizibile ale obiectelor prin algoritmul Z-

buffer ; Efecte de iluminare a scenelor 3D folosind diferite modele de iluminare şi una sau

mai multe surse de lumină; Simularea reflexiei si a transmisiei luminii ţinând cont de proprietăţile materialelor ; Transformarea din spaţiul 3D utilizator în spaţiul 2D ecran prin specificarea

matricelor de transformare, posibilitatea de a modifica poziţia şi dimensiunea obiectelor în spaţiul 3D utilizator.

Exista de asemenea funcţii care permit generarea simplă a unor obiecte solide, curbe şi suprafeţe de formă liberă precum şi funcţii de lucru cu imagini.

II.1. Convenţii de numire a funcţiilor, constantelor şi tipurilor de date OpenGL

Numele funcţiilor OpenGL conţin prefixul gl (de exemplu glClearColor) iar constantele prefixul GL_ (de exemplu GL_COLOR_BUFFER_BIT). Declaraţiile funcţiilor OpenGL sunt de forma:

Page 2: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

void glFunction{nr}{b s i f d}{v}(argumente);

nr - reprezintă numărul de argumente ale funcţieib sau s sau i sau f sau d sau v - specifică tipul argumentelor funcţiei, iar v dacă

argumentele funcţiei sunt date sub formă de vector (b – byte, s – short, i – int, f – float, d – double, v – vector)

Exemple :

glVertex2i(1, 3);glVertex2f(1.0, 3.0);

Primul apel furnizează coordonatele vârfurilor ca întregi pe 32 biti iar al 2-lea ca numere reale (în formatul cu virgulă mobilă).

glColor3f(1.0, 0.0, 0.0);GLfloat color_array[] = {1.0, 0.0, 0.0};glColor3fv(color_array);

Funcţia glColor3f() setează culoarea de desenare şi are 3 parametri ce corespund componentelor roşu, verde şi albastru, iar funcţia glColor3fv() setează culoarea de desenare având ca parametru un vector ce conţine componentele culorii.

Tipuri de date OpenGL

Pentru un acelaşi tip de date în C, diferitele implementări OpenGL pot alege tipuri diferite. Pentru portabilitate, indiferent de implementarea OpenGL se recomandă utilizarea tipurilor de date definite în OpenGL. Acestea sunt prezentate in tabelul II.1.

OpenGL defineşte şi tipul GLvoid. Acesta este cel mai adesea folosit în apelurile de funcţii OpenGL care acceptă pointeri la vectori de valori.

Sufix Tipul de date Corespondentul în CTipul definit în OpenGL

b 8-bit integer signed char GLbytes 16-bit integer Short GLshorti 32-bit integer int sau long GLint, GLsizeif 32-bit floating-point Float GLfloat, GLclampfd 64-bit floating-point Double GLdouble, GLclampdub 8-bitunsigned integer unsigned char GLubyte, GLbooleanus 16-bit unsigned integer unsigned short GLushort

Page 3: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

ui 32-bit unsigned integerunsigned int sau unsigned long

GLuint,GLenum, GLbitfield

Tabelul II.1. Tipuri de date OpenGL

II.2. Funcţii GLUT de realizare a interfeţei cu utilizatorul

II.2.1. Gestiunea ferestrelor

Iniţializare fereastră

void glutInit(int *argc, char **argv);

Funcţia glutInit() iniţializează variabilele interne ale pachetului de funcţii GLUT şi procesează argumentele din linia de comandă. Ea trebuie sa fie apelată înaintea oricarei alte comenzi GLUT. Parametrii funcţiei au aceeaşi semificaţie ca şi parametri funcţiei main.

Iniţializare mod de afişare

void glutInitDisplayMode(unsigned int mode);

unde mode specifică modul de afişare: folosirea modelului RGBA (culoarea se specifică prin componentele sale roşu,

verde, albastru şi transparenţa sau opacitatea) sau a modelului de culoare bazat pe indecşi de culoare. În general se recomandă folosirea modelului RGBA.

folosirea unei ferestre cu un singur buffer sau cu buffer dublu, pentru realizarea animaţiei.

folosirea bufferului de adâncime pentru algoritmul z-buffer.

De exemplu, dacă se doreşte crearea unei ferestre cu buffer dublu ce foloseşte un model de culoare RGBA şi buffer pentru algoritmul z-buffer, se va apela:

glutInitDisplayMode(GLUT_DOUBLE |GLUT_RGB |GLUT_DEPTH;

Page 4: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Iniţializare poziţie fereastră

void glutInitWindowPosition(int x, int y) ;

Funcţia glutInitWindowPosition specifică colţul stânga sus al ferestrei în coordonate relative la colţul stânga sus al ecranului.

Iniţializare dimensiune fereastră

void glutInitWindowSize(int width, int height) ;

Funcţia glutInitWindowSize specifică dimensiunea în pixeli a ferestrei : lăţimea (width) şi înălţimea (height).

Creare fereastră

int glutCreateWindow(char *string) ;

Funcţia glutCreateWindow creează o fereastra cu un context OpenGL. Ea intoarce un identificator unic pentru fereastra nou creată. Fereastra nu va fi afişată înainte de apelarea funcţiei glutMainLoop. Valoarea întoarsă de funcţie reprezintă identificatorul ferestrei, care este unic.

Creare ferestre copil

int glutCreateSubWindow(int win, int x, int y, int width, int height);

Funcţia creează o fereastră având ca părinte fereastra identificată de win, unde :- win - reprezintă identificatorul ferestrei părinte;- (x, y) - reprezintă colţul stânga sus al ferestrei (x şi y sunt exprimate în pixeli şi

sunt relative la originea ferestrei părinte);- width - reprezintă lăţimea ferestrei (exprimată în pixeli);- height - reprezintă înălţimea ferestrei (exprimată în pixeli);

Fereastra nou creată devine fereastra curentă. Funcţia întoarce identificatorul ferestrei create.

Distrugere fereastră

void glutDestroyWindow(int win) ;

Page 5: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Funcţia distruge fereastra specificată de win. De asemenea, este distrus şi contextul OpenGL asociat ferestrei. Orice subfereastră a ferestrei distruse va fi de asemenea distrusă. Dacă win identifică fereastra curentă, atunci ea va deveni invalidă.

Selectarea ferestrei curente

void glutSetWindow(int win) ;

Funcţia selectează fereastra curentă ca fiind cea identificată de parametrul win.

Aflarea ferestrei curente

int glutGetWindow(void) ;

Funcţia întoarce identificatorul ferestrei curente. Funcţia întoarce 0 dacă nu există nici o fereastră curentă sau fereastra curentă a fost distrusă.

Selectarea cursorului asociat ferestrei curente

void glutSetCursor(int cursor) ;

Funcţia modifică cursorul asociat ferestrei curente transformându-l în cursorul specificat de parametrul cursor, care poate avea una din următoarele valori: GLUT_CURSOR_RIGHT_ARROW, GLUT_CURSOR_LEFT_ARROW, GLUT_CURSOR_WAIT, GLUT_CURSOR_HELP, GLUT_CURSOR_TEXT, GLUT_CURSOR_CROSSHAIR, GLUT_CURSOR_UP_DOWN, GLUT_CURSOR_LEFT_RIGHT, GLUT_CURSOR_TOP_SIDE, GLUT_CURSOR_BOTTOM_SIDE, GLUT_CURSOR_LEFT_SIDE, GLUT_CURSOR_RIGHT_SIDE, GLUT_CURSOR_TOP_LEFT_CORNER, GLUT_CURSOR_TOP_RIGHT_CORNER, GLUT_CURSOR_BOTTOM_RIGHT_CORNER, GLUT_CURSOR_BOTTOM_LEFT_CORNER, GLUT_CURSOR_NONE, GLUT_CURSOR_INHERIT (foloseşte cursorul asociat ferestrei părinte).

II.2. 2. Gestiunea meniurilor

Crearea meniurilorMeniurile create cu ajutorul GLUT-ului sunt meniuri simple, pop-up în cascadă. În timp ce un meniu este folosit el nu poate fi şters, nu i se pot adăuga alte opţiuni şi nu i se pot şterge din opţiuni.

Page 6: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

int glutCreateMenu(void (*func)(int value)) ;

Funcţia creează un nou meniu pop-up şi întoarce identificatorul său (întreg unic). Identificatorii meniurilor încep de la valoarea 1. Valorile lor sunt separate de identificatorii ferestrelor.

- parametrul func specifică o funcţie callback a aplicaţiei, care va fi apelată de biblioteca GLUT la selectarea unei opţiuni din meniu. Parametrul transmis funcţiei callback (value) specifică opţiunea de meniu selectată.

Adăugarea unei opţiuni într-un meniuvoid glutAddMenuEntry(char* name, int value) ;

Funcţia adaugă o nouă opţiune meniului curent. Opţiunea este adăugată la sfârşitul listei de articole a meniului.

- name - specifică textul prin care va fi reprezentată opţiunea introdusă- value - reprezintă valoarea transmisă funcţiei callback asociată meniului la

selectarea opţiunii respective

Adăugarea unui sbmeniu într-un meniu

void glutAddSubMenu(char* name, int menu) ;

Funcţia adaugă un submeniu la sfârşitul meniului curent.- name - reprezintă numele submeniului introdus (textul prin care va fi afişat în

meniu)- menu - reprezintă identificatorul submeniului.

Ştergerea unei opţiuni sau a unui submeniu

void glutRemoveMenuItem(int entry) ;

Funcţia şterge opţiunea sau submeniul identificat de parametrul entry. Opţiunile din meniu de sub opţiunea ştearsă sunt renumerotate.

Distrugerea unui meniu

void glutDestroyWindow(int menu) ;

Funcţia distruge meniul specificat prin parametru. Distrugerea unui meniu nu are nici un efect asupra submeniurilor. Dacă meniul distrus este cel curent, atunci meniul curent va deveni invalid.

Setarea meniului curent

void glutSetMenu(int menu) ;

Page 7: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Funcţia setează meniul curent ca fiind cel identificat de parametrul menu.

Aflarea meniului curent

int glutGetMenu(void) ;

Funcţia întoarce identificatorul meniului curent. Funcţia întoarce 0 dacă nu există meniu curent sau meniul curent a fost distrus.

Ataşare / detaşare meniu unui buton al mouse-ului

void glutAttachMenu(int button) ;void glutDetachMenu(int button) ;

Funcţia glutAttachMenu ataşează meniul curent butonului mouse-ului specificat de parametrul button. Funcţia glutDetachMenu detaşează butonul asociat meniului curent. Prin ataşarea unui buton al mouse-ului meniului curent, meniul va fi derulat la apăsarea butonului respectiv în poziţia curentă a cursorului.

II.2.3. Controlul evenimentelor de intrare

In categoria evenimentelor de intrare sunt incluse evenimentele provocate de apăsarea unei taste sau a unuia dintre butoanele mouse-ului, de deplasarea mouse-ului şi de redimensionarea ferestrei de afişare de către utilizator. Pentru fiecare dintre aceste tipuri de evenimente programatorul trebuie să specifice o funcţie callback care va fi apelată la producerea unui eveniment de tipul respectiv. Funcţiile GLUT menţionate în continuare servesc acestui scop.

Redimensionarea ferestrei

void glutReshapeFunc(void (*func)(int width, int height)) ;

Parametrul funcţiei glutReshapeFunc indică funcţia callback care va fi apelată la redimensionarea ferestrei. Parametrii width şi height transmişi funcţiei callback reprezintă noile valori ale lăţimii şi înălţimii ferestrei.

Apăsarea / eliberarea unei taste

void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y)) ;

Parametrul func reprezintă funcţia callback care va fi apelată la apăsarea / eliberarea unei taste care generează un caracter ASCII. Parametrul key al funcţiei callback reprezintă

Page 8: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

valoarea ASCII. Parametrii x şi y indică poziţia mouse-ului la apăsarea tastei (poziţie specificată în coordonate fereastră).

Apăsarea / eliberarea unui buton al mouse-ului

void glutMouseFunc(void (*func)(int button, int state, int x, int y)) ;

Parametrul func specifică funcţia callback care va fi apelată la apăsarea / eliberarea unui buton al mouseului.Parametrul button al funcţiei callback poate avea una din următoarele valori: GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON sau GLUT_RIGHT_BUTTON. Parametrul state poate fi GLUT_UP sau GLUT_DOWN după cum butonul mouse-ului a fost apăsat sau eliberat. Parametrii x şi y reprezintă poziţia mouse-ului la apariţia evenimentului. Valorile x şi y sunt relative la colţul stânga sus al ferestrei aplicaţiei.

Deplasarea mouse-ului

void glutMotionFunc(void (*func)(int x, int y)) ;

Se specifică funcţia callback care va fi apelată la deplasarea mouse-ului în timp ce un buton este apăsat. Parametrii x şi y reprezintă poziţia mouse-ului în momentul apăsării tastei. Valorile x şi y sunt relative la colţul stânga sul al ferestrei aplicaţie.

II.2.4. Afisarea textelor

Pentru afişarea unui caracter se apeleaza functia glutStrokeCharacter :

void glutStrokeCharacter(void *font, int character);- font specifică fontul vectorial folosit, care poate avea una din următoarele valori:

GLUT_STROKE_ROMAN GLUT_STROKE_MONO_ROMAN

- character specifică caracterul ce va fi afişat

ExempluFuncţia output prezentata mai jos realizeaza afişarea unui text cu format, incepand dintr-o pozitie specificata a ferestrei curente.

void output(GLfloat x, GLfloat y, char *format,...){ va_list args;

Page 9: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

char buffer[200], *p;

va_start(args, format); vsprintf(buffer, format, args); va_end(args); glPushMatrix(); glTranslatef(x, y, 0); for (p = buffer; *p; p++) glutStrokeCharacter(GLUT_STROKE_ROMAN, *p); glPopMatrix();}

II.3. Execuţia aplicaţiei.

Funcţia de afişare callback

void glutDisplayFunc(void (*func)(void)) ;

Parametrul funcţiei glutDisplayFunc specifică funcţia callback a aplicaţiei care va fi apelată de GLUT pentru afişarea conţinutului iniţial al ferestrei aplicaţiei precum şi ori de câte ori trebuie refăcut conţinutul ferestrei ca urmare a cererii explicite a aplicaţiei, prin apelul funcţiei glutPostRedisplay().

Bucla de execuţie a aplicaţiei

void glutMainLoop(void) ;

Aceasta este ultima funcţie care trebuie apelată in funcţia main a aplicaţiei. Ea conţine bucla de execuţie (infinită) a aplicaţiei în care aplicaţia aşteaptă evenimente. Orice eveniment este tratat prin rutina callback specificată anterior în funcţia main, prin apelul funcţiei GLUT specifice tipului de eveniment. Execuţia unui proces în background

void glutIdleFunc(void (*func)(void)) ;

Parametrul transmis funcţiei glutIdleFunc este o funcţie callback care va fi executată in perioadele în care nu există evenimente în curs de tratare sau în aşteptarea tratării - funcţia idle. Dacă argumentul funcţiei glutIdleFunc este NULL atunci funcţia idle existentă este dezactivată.

Page 10: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Terminarea afişării

O aplicaţie GLUT poate rula pe mai multe maşini. De exemplu, să presupunem că programul principal este rulat pe o maşină client şi rezultatul procesării (imaginea afişată) apare pe un terminal sau pe o staţie de lucru (server), care este conectat în reţea. De obicei clientul adună o colecţie de comenzi într-un singur pachet înainte de a-l trimite în reţea. Codul de reţea de la client nu permite detectarea momentului în care programul grafic a terminat desenarea unui cadru sau a unei scene 3D. Astfel, clientul poate aştepta la infint comenzi de desenare ca să completeze un pachet. Pentru a forţa clientul să trimită pachetul chiar dacă nu este plin se foloseşte funcţia glFlush .

void glFlush(void);

În cazul în care nu există nici un client şi toate comenzile sunt executate pe server functia glFlush nu va avea nici un efect. Pentru ca un program să funcţioneze corect atât în reţea cât şi pe o singură maşina, se va include apelul functieie glFlush la sfârşitul fiecărei scene. Funcţia glFlush nu aşteaptă terminarea desenării, ci doar forţează începerea execuţiei desenării. Dacă folosirea funcţiei glFlush nu este suficientă pentru o aplicaţie, atunci se va folosi şi funcţia glFinish. Aceasta funcţionează ca şi glFlush dar aşteaptă răspuns de notificare de la echipamentul grafic de indicare a terminări desenarii. glFinish se va folosi pentru sincronizarea task-urilor.

void glFinish(void);

Observaţie: folosirea excesivă a lui glFinish poate reduce performanţele aplicaţiei mai ales dacă se lucrează în reţea. Dacă este suficientă folosirea funcţiei glFlush se va folosi aceasta în locul funcţiei glFinish.

II.4. Crearea unei aplicaţii OpenGL folosind GLUT

Pentru a crea executabilul corespunzător unei aplicaţii OpenGL se va deschide fişierul sursă *.C cu Microsoft Visual C++. În momentul în care se va compila programul, mediul Visual C++ va genera automat un proiect în care va fi inclus fişierul sursă anterior deschis. Pentru editarea legăturilor trebuie adăugate bibliotecile opengl32.lib, glu32.lib şi glut32.lib. Setările corespunzătoare pentru această operaţie sunt următoarele:

Se selectează opţiunea Settings din meniul Project. In cutia de dialog afişată se selectează Link In zona de editare Object/library modules se adaugă cele trei biblioteci

de mai sus.

Page 11: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Rularea unui program OpenGL necesită de asemenea următoarele biblioteci cu legare dinamică : opengl32.dll, glu32.dll, glut32.dll.

In fişierele sursă se va include fişierul header glut.h.

Exemplu 1Programul din fişierul exemplu11.c afişează un dreptunghi centrat în fereastră.

/* fişierul exemplul1.c */

#include "glut.h" /* glut.h se află în directorul curent */

void display(void){/* şterge toţi pixelii */ glClear (GL_COLOR_BUFFER_BIT);

/* afişează un dreptunghi cu interiorul alb avand colţurile în punctele(0.25, 0.25, 0.0) şi (0.75, 0.75, 0.0) */ glColor3f (1.0, 1.0, 1.0); glBegin(GL_POLYGON); glVertex3f (0.25, 0.25, 0.0); glVertex3f (0.75, 0.25, 0.0); glVertex3f (0.75, 0.75, 0.0); glVertex3f (0.25, 0.75, 0.0); glEnd();

glFlush ();}

void init (void) {/* selectează culoarea de fond */ glClearColor (0.0, 0.0, 0.0, 0.0);

/* iniţializează transformarea de vizualizare */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);}

Page 12: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

/* * declară dimensiunea iniţială a ferestrei, poziţia şi modul de afişare (buffer singular şi RGBA). * Deschide o fereastră cu titlul "hello". * Apelează rutinele de iniţializare. * Înregistrează funcţia callback de refacere a ferestrei. * Se intră în bucla principală şi se procesează evenimentele. */int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (250, 250); glutInitWindowPosition (100, 100); glutCreateWindow ("hello"); init (); glutDisplayFunc(display); glutMainLoop(); return 0; }

Exemplu 2

Programul din fişierul exemplu2.c tratează evenimentele de la mouse. Se afişează un dreptunghi centrat în fereastra de afişare. La apăsarea butonului stânga al mouse-ul dreptunghiul va fi rotit până la apăsarea butonului drept al mouse-ului.

/* fişierul exemplul2.c */

#include "glut.h" /* glut.h se află în directorul curent */#include <stdlib.h>

static GLfloat spin = 0.0;

void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0);}

Page 13: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

void display(void){ glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); glRotatef(spin, 0.0, 0.0, 1.0); glColor3f(1.0, 1.0, 1.0); glRectf(-25.0, -25.0, 25.0, 25.0); glPopMatrix(); glutSwapBuffers();}

void spinDisplay(void){ spin = spin + 2.0; if (spin > 360.0) spin = spin - 360.0; glutPostRedisplay();}

void reshape(int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-50.0, 50.0, -50.0, 50.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}

void mouse(int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(spinDisplay); break; case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN)

Page 14: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glutIdleFunc(NULL); break; default: break; }}

int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize (250, 250); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMainLoop(); return 0;}

II.5. Afişarea obiectelor 3D predefinite

GLUT conţine funcţii pentru afişarea următoarelor obiecte 3D:

con icosaedru teapotcub octaedru tetraedrudodecaedru sfera tor

Aceste obiecte pot fi afişate prin familii de curbe sau ca obiecte solide.

Exemplu: funcţii de desenare cub, sferă si tor prin două familii de curbe şi ca solide.

Page 15: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Desenare cub de latură size prin două familii de curbe

void glutWireCube(GLdouble size);

Desenare cub solid de latură size

void glutSolidCube(GLdouble size);

Desenare sferă prin două familii de curbe

void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);

Desenare sferă solidă

void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks);

Desenare tor prin două familii de curbe

void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings);

Desenare tor solid

void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings);

Alte funcţii sunt:

void glutWireIcosahedron(void); void glutSolidIcosahedron(void); void glutWireOctahedron(void); void glutSolidOctahedron(void); void glutWireTetrahedron(void); void glutSolidTetrahedron(void); void glutWireDodecahedron(GLdouble radius); void glutSolidDodecahedron(GLdouble radius); void glutWireCone( GLdouble radius, GLdouble height, GLint slices,GLint stacks); void glutSolidCone(GLdouble radius, GLdouble height, GLint slices,GLint stacks);

Page 16: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

void glutWireTeapot(GLdouble size); void glutSolidTeapot(GLdouble size);

Toate aceste obiecte sunt desenate centrate în originea sistemului de coordonate real.

În momentul în care se fac modificări asupra unui obiect complex poate apare efectul de “pâlpâire” a imaginii. Pentru evitarea acestui efect se asociază ferestrei aplicaţiei un buffer dublu. Astfel, într-un buffer se păstrează imaginea nemodificată (imaginea ce este afişată pe ecran), iar în cel de-al doilea se construieşte imaginea modificată. În momentul în care s-a terminat construirea imaginii modificate se interschimbă buffer-ele (lucrul cu două buffere este asemănator lucrului cu mai multe pagini video în DOS). Pentru interschimbarea bufferelor se foloseşte funcţia: glutSwapBuffers :

void glutSwapBuffers(void) ;

II.6. Specificarea culorilor

II.6.1. Culoarea de desenare

Într-un program OpenGL mai întai trebuie setată culoarea de desenare şi apoi se face desenarea efectivă a obiectelor. Cât timp culoarea de desenare nu se modifică, toate obiectele vor fi desenate cu acea culoare. Exemplu:

set_current_color(red); draw_object(A); draw_object(B); set_current_color(green); set_current_color(blue); draw_object(C);

La execuţia secvenţei din exemplu, obiectele A şi B vor fi desenate cu roşu iar obiectul C cu albastru. Comanda set_current_color(green) nu are nici un efect.

Pentru a seta o culoare de desenare se poate apela funcţia glColor3f :

void glColor3f(GLfloat red, GLfloat green, GLfloat blue) ;

Page 17: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Parametrii funcţiei specifică componentele roşu, verde şi albastru ale culorii ce va fi setată. Ei au valori în intervalul [0.0 , 1.1].Exemple:

glColor3f(0.0, 0.0, 0.0); /* negru */glColor3f(1.0, 0.0, 0.0); /* roşu */glColor3f(0.0, 1.0, 0.0); /* verde */glColor3f(1.0, 1.0, 0.0); /* galben */glColor3f(0.0, 0.0, 1.0); /* albastru */glColor3f(1.0, 0.0, 1.0); /* magenta */ glColor3f(0.0, 1.0, 1.0); /* cyan */glColor3f(1.0, 1.0, 1.0); /* alb */

Alte modalităţi de specificare a culorilor sunt prezentate în capitolul II.10.

II.6.2. Ştergerea ferestrei

Stergerea fondului ferestrei este necesar să fie efectuată înaintea începerii creerii unei noi imagini.

ExempluSe afişează toţi pixelii ferestrei în culoarea negru

glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT);

Prima comandă setează culoarea de ştergere negru şi comanda următoare şterge întreaga fereastră folosind culoarea curentă de ştergere. Parametrul funcţiei glClear indică bufferul care va fi şters. De obicei se setează o singură dată culoarea de ştergere la începutul aplicaţiei şi apoi se apelează funcţia de ştergere de câte ori este necesar.

void glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);

Valorile red, green, blue sunt în intervalul [0, 1]. Culoarea implicită de ştergere este (0, 0, 0, 0) - negru. Parametrul alpha specifică opacitatea; valoarea sa implicită este 0.0.

void glClear(GLbitfield mask);

Funcţia setează bufferul indicat prin parametrul mask la valoarea specificată. Valorile posibile ale parametrului mask sunt prezentate în tabelul II.2:

Page 18: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Mask Buffer-ul ce va fi şters GL_COLOR_BUFFER_BIT Buffer-ul curent pentru setarea culorii de desenare

GL_DEPTH_BUFFER_BIT Buffer-ul de adăncime

Tabelul II.2.

II.7. Definirea primitivelor geometrice

Orice primitivă geometrică este definită printr-o secvenţă de puncte 3D numite vârfuri. Fiecare vârf este reprezentat intern prin cele 3 coordonate (x, y, z). Pentru vârfurile specificate de programator în 2D, sistemul asignează coordonatei z valoarea 0.

În OpenGL, linia înseamnă segment de dreaptă. Poligoanele sunt suprafeţe mărginite de un contur poligonal închis format din

segmente de dreaptă. Segmentele de dreaptă sunt specificate prin vârfurile capetelor segmentelor. OpenGL impune câteva restricţii asupra poligoanelor (figura II.1): laturile poligoanelor nu se pot intersecta (poligoane simple) şi poligoanele trebuie să fie convexe. Nu pot fi descrise poligoane cu treceri interioare (ele nu sunt convexe).

Figura II.1. Poligoane valide si nevalide

Deoarece în OpenGL vârfurile sunt întotdeauna puncte 3D, punctele ce formează frontiera unui poligon nu este necesar sa fie coplanare. Dacă vârfurile unui poligon nu sunt coplanare, atunci după rotaţii, modificarea poziţiei observatorului şi proiecţia în ecran, punctele pot să nu mai formeze un poligon convex simplu.Problema din figura II.2 poate fi evitată prin folosirea triunghiurilor, deoarece orice trei puncte sunt coplanare.

Page 19: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Figura II.2

II.7.1. Definirea vârfurilor

În OpenGL toate primitivele geometrice sunt definite prin mulţimi ordonate de vârfuri. Pentru a specifica un vârf se foloseşte funcţia:

void glVertex{234}{sifd}[v](TYPE coords);

Funcţia poate avea: 2 parametri – vârful va fi specificat în 2D prin coordonatele sale (x, y) 3 parametri – vârful va fi specificat în 3D prin coordonatele sale (x, y, z) 4 parametri – vârful va fi specificat în 3D prin coordonatele sale omogene (x, y,

z, w)Şi în acest caz TYPE reprezintă tipul coordonatelor vârfului (s - short, i – int , f - float, d - double). Apelul funcţiei glVertex trebuie să fie făcut între perechea de comenzi glBegin şi glEnd.

Exemplu Modalităţi de definire a vârfurilor:

glVertex2s(2, 3); glVertex3d(0.0, 0.0, 3.1415926535898); glVertex4f(2.3, 1.0, -2.2, 2.0);

GLdouble dvect[3] = {5.0, 9.0, 1992.0};glVertex3dv(dvect);

II.7.2. Puncte, linii şi poligoane

Pentru a crea o mulţime de puncte, o linie sau un poligon pornind de la vârfuri, fiecare set de vârfuri trebuie să fie apelat între comenzile glBegin şi glEnd. Argumentul funcţiei glBegin determină tipul primitivei ce va fi afişată :

void glBegin(GLenum mode);

Page 20: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Parametrul mode poate avea una din valorile (figura II.3): GL_POINTS GL_LINES GL_POLYGON GL_TRIANGLES GL_QUADS GL_LINE_STRIP GL_LINE_LOOP GL_TRIANGLE_STRIP GL_TRIANGLE_FAN GL_QUAD_STRIP

Figura II.3. Tipurile de primitive geometrice definite în OpenGL.

Page 21: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

GL_LINES specifică afişarea mai multor segmente de dreaptă, câte unul pentru fiecare pereche de vârfuri. Vârfurile sunt conectate în ordinea v0 – v1, v2 – v3, v4 – v5 etc. Dacă este dat un număr impar de vârfuri, ultimul vârf este ignorat.GL_LINE_STRIP specifică o polilinie de la vârful v0 la varful vn, conectând vârfurile în ordinea dată;GL_LINE_LOOP specifică un poligon, vârfurile fiind unite în ordinea dată; ultimul vârf este conectat cu primul.GL_POLYGON specifică un poligon de la vârful v0 la vârful vn-1 (n trebuie să fie cel puţin 3). Poligonul trebuie să fie un poligon convex simplu. Pentru poligoanele concave rezultatul afişării este nedefinit. De asemenea, vârfurile trebuie să fie situate în acelaşi plan;GL_QUADS specifică o serie de patrulatere separate. Primul patrulater este desenat folosind vârfurile v0, v1, v2 şi v3, următorul v4, v5, v6 şi v7 etc. Dacă n nu este multiplu de 4 vârfurile suplimentare sunt ignorate;GL_TRIANGLES specifică o serie de triunghiuri separate;GL_QUAD_STRIP specifică o serie de patrulatere conectate. Primul patrulater este desenat folosind vârfurile v0, v1, v2 şi v3, Următorul refoloseşte ultimele două vârfuri v2, v3 şi foloseşte următoarele două în ordinea v5 şi v6. Fiecare patrulater foloseşte ultimele două vârfuri de la patrulaterul anterior. În fiecare caz n trebuie să fie cel puţin 4 şi multiplu de 2;GL_TRIANGLE_STRIP specifică o serie de triunghiuri conectate. Primul triunghi foloseşte vârfurile v0, v1 şi v2. Următorul v2, v1 şi v3, următorul v2, v3 şi v4. Se observă că ordinea asigură ca toate triunghiurile să fie orientate la fel;GL_TRIANGLE_FAN specifică o serie de triunghiuri conectate într-un vârf comun, vârful v0. Primul triunghi este desenat folosind vârfurile v0, v1 şi v2, următorul foloseşte v0, v2 şi v3, următorul v0, v3 şi v4 etc.

Funcţia glEnd marchează sfârşitul listei de vârfuri.

void glEnd(void);

Exemplu:Primitiva redată în figura II.4 este specificată prin următoarea secvenţă :

glBegin(GL_POLYGON); glVertex2f(0.0, 0.0); glVertex2f(0.0, 3.0); glVertex2f(3.0, 3.0);

Page 22: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glVertex2f(4.0, 1.5); glVertex2f(3.0, 0.0);glEnd();

Dacă se foloseşte GL_POINTS în loc de GL_POLYGON, primitiva va fi formată din 5 puncte.

Figura II.4

Restricţii de folosire pentru glBegin şi glEnd

Coordonatele vârfurilor se specifică folosind funcţia glVertex*. Pentru un vârf pot fi furnizate informaţii suplimentare, cum ar fi: culoarea, vectorul normală, etc. In tabelul II.3 sunt specificate funcţiile care pot fi apelate între glBegin şi glEnd :

Funcţia ComentariiglVertex* Stabileşte coordonatele vârfului

glColor*Stabileşte culoarea curentă a vârfului

glIndex*Setează indexul curent de culoare

glNormal* Stabileste vectorul normalăglEvalCoord* Generează coordonateleglCallList, glCallLists

Execută lista (listele) de afişare

glTexCoord*Setează coordonatele de texturare

glEdgeFlag*contrololează desenarea muchiilor

glMaterial*Stabileşte proprietăţile de material

Page 23: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Tabelul II.3. Funcţii care pot fi apelate între glBegin şi glEndDacă între apelurile funcţiilor glBegin şi glEnd apar apelurile altor funcţii GLUT

se va genera cod de eroare. Pot apare însă instrucţiuni ale limbajului de programare în care este implementată aplicaţia.

ExempluDesenarea unui cerc prin linii.

#define PI 3.1415926535897; GLint circle_points = 100;

glBegin(GL_LINE_LOOP); for (i = 0; i < circle_points; i++) { angle = 2*PI*i/circle_points; glVertex2f(cos(angle), sin(angle)); } glEnd();

Acest exemplu nu reprezintă cel mai eficient mod de a desena un cerc, mai ales dacă acest lucru se va face în mod repetat. Comenzile grafice folosite sunt rapide, dar pentru fiecare vârf se calculează un unghi şi se apelează functiile sin şi cos. În plus apare şi overhead-ul introdus de buclă. Dacă cercul va fi afişat de mai multe ori, pentru a îmbunătăţi timpul de execuţie, se vor calcula o singură dată coordonatele vârfurilor şi se vor salva într-un vector sau se va crea o listă de afişare (display list).

Între comenzile glBegin şi glEnd vârfurile sunt generate doar la întâlnirea apelului glVertex*. În momentul apelului funcţiei glVertex*, sistemul asociază vârfului respectiv culoarea curentă, coordonatele de texturare, vectorul normală etc.

ExempluPrimul vârf este desenat cu roşu, iar al doilea şi al treilea cu albastru:

glBegin(GL_POINTS); glColor3f(0.0, 1.0, 0.0); /* verde */ glColor3f(1.0, 0.0, 0.0); /* roşu */ glVertex(...); glColor3f(1.0, 1.0, 0.0); /* galben */ glColor3f(0.0, 0.0, 1.0); /* albastru */ glVertex(...); glVertex(...);

Page 24: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glEnd();

II.7.3. Dreptunghiuri în planul XOY

OpenGL furnizează o funcţie particulară, care permite desenarea unui dreptunghi cu interiorul plin, în planul XOY:

void glRect{sifd}(TYPE x1, TYPE y1, TYPE x2, TYPE y2); void glRect{sifd}v(TYPE* v1, TYPE* v2);

Funcţia afişează dreptunghiul definit de colţurile (x1, y1) şi (x2, y2). Dreptunghiul se află în planul z=0 şi are laturile paralele cu axele x, respectiv y. Dacă este folosită varianta cu vectori, colţurile dreptunghiului sunt specificate prin doi vectori, fiecare conţinând o pereche (x, y). TYPE reprezintă tipul coordonatelor colţurilor dreptunghiului (s - GLshort, i – GLint , f - GLfloat, d - GLdouble).

II.8. Specificarea atributelor de afişare ale primitivelor geometrice

În mod implicit un punct este desenat ca un singur pixel ecran, un segment de dreapta este desenat ca o linie continuă de lăţime egală cu un pixel, iar poligoanele sunt afişate având conturul cu linie continuă şi interior gol.

II.8.1. Dimensiunea punctelor

Pentru a specifica dimensiunea unui punct afişat se foloseşte funcţia glPointSize.

void glPointSize(GLfloat size);

Funcţia setează lăţimea în pixeli a punctelor ce vor fi afişate. Parametrul size reprezintă dimensiunea punctului exprimată în pixeli ecran. Ea trebuie să fie mai mare ca 0.0, iar valoarea sa implicită este 1.0.

II.8.2. Atributele liniilor

În OpenGL segmentele de dreaptă pot fi desenate având diferite lăţimi, ca linii continue sau ca linii punctate sau întrerupte.

II.8.2.1.Lăţimea liniilor

Page 25: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

void glLineWidth(GLfloat width);

Funcţia setează lăţimea în pixeli a liniilor ce vor fi afişate; width trebuie să fie mai mare ca 0.0, iar valoarea implicită este 1.0.

II.8.2.2. Tipul liniilor 

Pentru afişarea liniilor punctate sau întrerupte se va apela funcţia glLineStipple, care defineşte şablonul de generare a liniilor, apoi se va activa folosirea liniilor punctate sau întrerupte folosind funcţia glEnable:

void glLineStipple(GLint factor, GLushort pattern);

Funcţia setează şablonul curent de generare a liniilor. - factor - este un multiplicator pentru fiecare bit din şablonul de generare a

liniei cu şablon. De exemplu, dacă factor = 3 atunci fiecare bit din şablon va fi folosit de trei ori înainte ca următorul bit din şablon să fie folosit. Are valori în intervalul [1, 255]

- pattern - reprezintă o succesiune de 16 biţi care va fi repetată pentru a genera o linie cu şablon. Dacă bit = 1 se face afişarea, dacă bit = 0 nu se afişează; ordinea de parcurgerea a biţilor în şablon este de la bitul cel mai puţin semnificativ către bitul cel mai semnificativ. Şablonul poate fi multiplicat prin folosirea parametrului factor, care multiplică fiecare succesiune de biţi cu valori egale (1 sau 0) din şablon cu valoarea factor. Astfel, dacă în sablon apar 3 biţi consecutivi cu valoarea 1 şi factor = 2, se vor genera 6 biţi cu valoarea 1.

In figura II.5 sunt exemplificate diferite tipuri de linii obţinute prin alegerea valorilor pattern şi factor.

Figura II.5

Page 26: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Generarea de linii cu şablon se va activa apelând funcţia glEnable cu parametrul GL_LINE_STIPPLE şi va fi dezactivată prin apelul funcţiei glDisable cu acelaşi argument.

void glEnable(Glenum cap);

void glDisable(GLenum cap);

cap este o constantă simbolică ce specifică o ‘capabilitate’ OpenGL. Ea poate avea una din următoarele valori:

GL_CULL_FACE - activează / dezactivează eliminarea părţilor nevizibile ale obiectelor folosind metoda Back Face Culling.

GL_DEPTH_TEST –activează / dezactivează calcularea valorilor buffer-ului de adâncime.

GL_LIGHTi - activează / dezactivează luarea în calcul a sursei de lumină şi la calculul de iluminare.

GL_LIGHTING – activează / dezactivează calcularea culorii corespunzătoare fiecărui vârf.

GL_LINE_STIPPLE – activează / dezactivează generarea liniilor folosind şablon.

GL_NORMALIZE - acitivează /dezactivează normalizarea vectorilor normală. GL_POLYGON_STIPPLE - activează / dezactivează folosirea şablonului

curent la afişarea poligoanelor.

Exemplu:

glLineStipple(1, 0x3F07);glEnable(GL_LINE_STIPPLE);

În acest exemplu, pentru şablonul 0x3F07 (0011111100000111), o linie va fi desenată cu 3 pixeli vizibili, apoi 5 invizibili, 6 vizibili şi 2 invizibili (ordinea de parcurgere este de la bitul cel mai puţin semnificativ către cel mai semnificativ). Dacă factor = 2, şablonul va fi multiplicat: 6 pixeli vizibili, 10 invizibili, 12 vizibili şi 4 invizibili. Figura următoare exemplifică linii desenate folosind diverse şabloane şi diferiţi factori de multiplicare. Dacă nu se activează generarea liniilor cu şablon, afişarea va decurge ca şi cum pattern ar fi 0xFFFF şi factor 1. Generarea liniilor cu şablon poate fi combinată cu setarea diferitelor lăţimi de linie pentru a produce linii punctate de diferite lăţimi.

O modalitate de a privi generarea liniilor cu şablon este aceea că şablonul este deplasat cu o poziţie de fiecare dată când este afişat un pixel (sau factor pixeli sunt afişati, dacă factor este diferit de 1). Dacă sunt desenate o serie de segmente de dreaptă

Page 27: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

conectate între apelurile funcţiilor glBegin şi glEnd, atunci şablonul va continua să fie deplasat când se trece de la un segment la altul. În acest mod un şablon este folosit pentru mai multe segmente de dreaptă conectate între ele. La execuţia funcţiei glEnd şablonul va fi resetat şi dacă în continuare, înainte de a dezactiva generarea de segmente de dreaptă cu şablon, mai sunt afişate segmente de dreaptă, atunci la generare se va folosi şablonul de la început. Dacă segmentele de dreaptă sunt afişate folosind GL_LINES, atunci şablonul va fi resetat pentru fiecare segment de dreaptă.

Programul « exemplul3 » prezentat în continuare exemplifică folosirea diferitelorşabloane şi a diferitelor lăţimi pentru generarea liniilor.

/* exemplul3.c*/

#include "glut.h"

#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \ glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();

void myinit (void) { /* fondul are culoarea neagră */ glClearColor (0.0, 0.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(50.0, 150.0, -50.0, 350.0, -1.0, 1.0); }

void display(void){ int i;

glClear (GL_COLOR_BUFFER_BIT);/* afişează toate liniile cu alb */ glColor3f (1.0, 1.0, 1.0);

/* prima linie: 3 linii, fiecare cu un şablon */ glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0x0101); /* linie punctată */ drawOneLine (50.0, 125.0, 150.0, 125.0);

Page 28: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glLineStipple (1, 0x00FF); /* linie întreruptă */ drawOneLine (150.0, 125.0, 250.0, 125.0); glLineStipple (1, 0x1C47); /* întreruptă/punctată/întreruptă */ drawOneLine (250.0, 125.0, 350.0, 125.0);

/* linia a doua */ glLineWidth (5.0); glLineStipple (1, 0x0101); drawOneLine (50.0, 100.0, 150.0, 100.0); glLineStipple (1, 0x00FF); drawOneLine (150.0, 100.0, 250.0, 100.0); glLineStipple (1, 0x1C47); drawOneLine (250.0, 100.0, 350.0, 100.0); glLineWidth (1.0);

/* linia a treia: 6 linii cu şablon întrerupt/punctat/întrerupt, *//* ca parte a unei singure linii */ glLineStipple (1, 0x1C47); glBegin (GL_LINE_STRIP); for (i = 0; i < 7; i++) glVertex2f (50.0 + ((GLfloat) i * 50.0), 75.0); glEnd ();

/* linia a patra: 6 linii independente cu şablon *//* întrerupt/punctat/întrerupt */ for (i = 0; i < 6; i++) { drawOneLine (50.0 + ((GLfloat) i * 50.0), 50.0, 50.0 + ((GLfloat)(i+1) * 50.0), 50.0); }

/* linia a cincea: 1 linie cu şablon întrerupt/punctat/întrerupt *//* şi factor de multiplicare egal cu 5 */ glLineStipple (5, 0x1C47); drawOneLine (50.0, 25.0, 350.0, 25.0); glFlush ();}

Page 29: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (250, 250); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); myinit (); glutDisplayFunc(display); glutMainLoop(); return 0;}

II.8.3. Atributele poligoanelor

De obicei poligoanele sunt afişate prin contur continuu, dar pot fi afişate şi cu conturul punctat sau numai prin vârfurile ce-l compun. Un poligon poate avea interiorul generat uniform sau folosind un anumit şablon. Poligoanele sunt afişate astfel încât pentru poligoanele adiacente care împart o latură sau un vârf, pixelii ce formează latura respectivă sau vârful respectiv sunt afişaţi o singură dată – ei sunt incluşi numai într-un singur poligon.

II.8.3.1. Modul de afişareUn poligon este considerat ca având două feţe – cea din faţă şi cea din spate. El

poate fi generat ţinând cont de ambele feţe, numai de feţele din faţă (cele aflate spre observator) sau numai de feţele din spate. În mod implicit, feţele din faţă şi din spate sunt afişate în acelaşi mod. Pentru a modifica acest lucru sau pentru a afişa poligoanele prin contur sau numai prin vârfurile ce-l compun se va folosi funcţia glPolygonMode :

void glPolygonMode(GLenum face, GLenum mode);

- face specifică feţele la care se referă parametrul mode; poate fi GL_FRONT_AND_BACK (feţele faţă şi spate), GL_FRONT (feţele faţă), sau GL_BACK (feţele spate);

Page 30: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

- mode reprezintă modul de afişare a feţelor selectate; poate fi: GL_POINT (poligoanele vor fi afişate prin vârfuri), GL_LINE (poligoanele vor fi afişate prin contur), sau GL_FILL (poligoanele vor fi afişate cu interior plin)

În mod implicit, ambele tipuri de feţe sunt afişate cu interiorul plin.

ExempluSe cere afişarea faţelor din faţă cu interiorul plin, iar a celor din spate prin contur:

glPolygonMode(GL_FRONT, GL_FILL);glPolygonMode(GL_BACK, GL_LINE);

II.8.3.2. Orientarea feţelor

In mod implicit, feţele ale căror vârfuri sunt parcurse în sens invers acelor de ceas sunt considerate feţe din faţă (orientate spre observator). Această convenţie poate fi modificată de programator, apelând funcţia glFrontFace.

void glFrontFace(GLenum mode);

Parametrul mode specifică orientarea feţelor din faţă ale poligoanelor. Valoarea GL_CCW (valoarea implicită) corespunde unei orientări în sensul invers acelor de ceas a conturului unei feţe proiectate în coordonate de afişare. Valoarea GL_CW, indică o orientare în sensul acelor de ceas a contururilor feţelor din faţă.

În cazul unei suprafeţe închise construită din poligoane cu o anumită orientare, toate feţele spate nu vor fi vizibile niciodată – ele vor fi ascunse de feţele din faţă ale poligoanelor. În această situaţie se poate mări viteza de afişare prin eliminarea poligoanelor imediat ce s-a determinat dacă ele reprezintă feţe spate. În mod similar dacă suntem în interiorul unui obiect atunci vor fi vizibile numai poligoanele care reprezintă feţele spate. Pentru a specifica eliminarea feţelor faţă, respectiv feţelor spate se va folosi funcţia glCullFace iar activarea eliminării feţelor respective se va face folosind funcţia glEnable având ca parametru GL_ CULL_FACE. Pentru dezactivare se va apela glDisable cu acelaşi argument.

void glCullFace(GLenum mode);

Funcţia indică ce poligoane vor fi eliminate înainte de a fi convertite în coordonate ecran. Parametrul mode poate avea una din valorile :

- GL_FRONT : se elimină feţele faţă- GL_BACK  :se elimină feţele spate- GL_FRONT_AND_BACK :se elimină atât feţele faţă cât şi feţele spate.

Page 31: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

II.8.3.3. Tipul interiorului

În mod implicit poligoanele cu interiorul plin sunt generate folosind un şablon plin. De asemenea pentru generarea interiorului unui poligon se poate folosi un şablon de 32x32 biţi, care se va specifica folosind funcţia glPolygonStipple.

void glPolygonStipple(const GLubyte *mask);

Funcţia defineşte şablonul curent pentru generarea interiorului poligoanelor. Argumentul mask este un pointer catre un bitmap de 32×32 care este interpretat ca o masca de 0 şi 1. Pixelul din poligon corespunzator valorii 1 din mască va fi afişat.

Folosirea şablonului curent la generarea poligoanelor este activată, respectiv dezactivată, apelând funcţiile glEnable respectiv glDisable cu argumentul GL_POLYGON_STIPPLE.

In programul din fişierul exemplu4.c este exemplificată folosirea şabloanelor pentru generarea interioarelor poligoanelor.

/* exemplu4.c */

#include "glut.h"

void display(void){ GLubyte fly[] = {

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60, 0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20, 0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20, 0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22, 0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC, 0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30, 0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0, 0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0, 0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,

Page 32: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08, 0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08, 0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08};

GLubyte halftone[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55}; glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0); glRectf (25.0, 25.0, 125.0, 125.0); glEnable (GL_POLYGON_STIPPLE); glPolygonStipple (fly); glRectf (125.0, 25.0, 225.0, 125.0); glPolygonStipple (halftone); glRectf (225.0, 25.0, 325.0, 125.0); glDisable (GL_POLYGON_STIPPLE); glFlush ();}

void myinit (void) { glClearColor (0.0, 0.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 400.0, -100.0, 300.0, -1.0, 1.0); }

Page 33: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

int main(int argc, char** argv){ glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA); glutInitWindowSize (350, 150); glutInitWindowPosition (0, 0); glutCreateWindow (argv[0]); myinit (); glutDisplayFunc(display); glutMainLoop(); return 0;}

In mod implicit, pentru fiecare octet primul bit este considerat bitul cel mai semnificativ, Ordinea biţilor se poate modifica prin apelul funcţiei glPixelStore*().

II.8.3.4. Muchiile de contur

OpenGL permite desenarea de poligoane convexe, dar în practică apar deseori şi poligoane concave. Pentru a desena poligoane concave, de regulă acestea se descompun în poligoane convexe – de obicei triunghiuri, aşa cum se arată în figura II.7, şi apoi sunt desenate aceste triunghiuri.

Dacă se descompune un poligon în triunghiuri şi se face afişarea triunghiurilor nu se poate folosi functia glPolygonMode pentru a se desena numai laturile poligonului, deoarece laturile triunghiurilor se află în interiorul poligonului. Pentru a rezolva această problema se poate specifica dacă un vârf aparţine sau nu unei muchii de contur prin păstrarea pentru fiecare vârf a unui bit. La afişarea poligonului în modul GL_LINE nu vor fi desenate laturile care nu aparţin muchiilor de contur. În figura II.6 liniile punctate reprezintă laturi false.

Figura II.6. Divizarea unui poligon concav

Page 34: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

În mod implicit orice vârf aparţine unei muchii de contur. Acestă convenţie poate fi controlată prin setarea flag-ului de apartenenţă la o muchie de contur cu ajutorul funcţiei glEdgeFlag*. Funcţia se apelează între comenzile glBegin şi glEnd şi acţionează asupra tuturor vârfurilor specificate după apelul sau până la următorul apel al funcţiei glEdgeFlag. Ea se aplică doar vârfurilor care aparţin poligoanelor (GL_POLYGON), triunghiurilor (GL_TRIANGLES) şi patrulaterelor (GL_QUADS). Nu are efect asupra primitivelor de tipurile GL_QUAD_STRIP, GL_TRIANGLE_STRIP şi GL_TRIANGLE_FAN.

void glEdgeFlag(GLboolean flag); void glEdgeFlagv(const GLboolean *flag);

Dacă flag este GL_TRUE, atunci flag-ul de contur va fi setat la TRUE (valoarea implicită ), şi orice vârf definit în continuare va fi considerat ca aparţinând muchiilor de contur până la un nou apel al funcţiei glEdgeFlag* cu parametrul GL_FALSE.

Exemplu: Marcarea muchiilor de contur ale unui poligon

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);glBegin(GL_POLYGON); glEdgeFlag(GL_TRUE); glVertex3fv(V0); glEdgeFlag(GL_FALSE); glVertex3fv(V1); glEdgeFlag(GL_TRUE); glVertex3fv(V2);glEnd();

Efectul acestor instrucţiuni este următorul (figura II.7):

Figura II.7.

II.8.3.5. Vectori normală

Page 35: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Un vector normală este un vector care are orientarea perpendiculară pe o suprafaţă. Pentru o suprafaţă plană este suficientă o singură direcţie perpendiculară, ea fiind aceeaşi pentru orice punct de pe suprafaţă, dar pentru o suprafaţă oarecare direcţia vectorului normală poate diferi pentru fiecare punct. În OpenGL se poate specifica un vector normală pentru fiecare vârf. Vectorii normală pot fi asociaţi numai vârfurilor. Ei sunt necesari în calculul iluminării suprafeţelor aproximate prin reţele poligonale.

Funcţia glNormal* se apelează pentru a specifica normala curentă. Normala curentă va fi asociată tuturor vârfurilor definite în continuare prin apeluri ale funcţiei glVertex*. Dacă fiecare vârf are asociată o normală diferită se va proceda ca în exemplul următor:

glBegin (GL_POLYGON); glNormal3fv(n0); glVertex3fv(v0); glNormal3fv(n1); glVertex3fv(v1); glNormal3fv(n2); glVertex3fv(v2); glNormal3fv(n3); glVertex3fv(v3);glEnd();

void glNormal3{bsidf}(TYPE nx, TYPE ny, TYPE nz);

void glNormal3{bsidf}v(const TYPE *v);

Funcţia glNormal3 setează componentele vectorului « normală curentă » la valoarile (nx,ny,nz), specificate prin parametri. Versiunea glNormal3*v a acestei funcţii primeşte ca parametru un vector de 3 elemente pentru a specifica normala curentă. Versiunile b, s şi i scalează liniar valorile parametrilor în domeniul [-1.0,1.0].

Pe o suprafaţă, într-un punct dat, sunt doi vectori perpendiculari având orientări în direcţii opuse. Prin convenţie, normala este acel vector care are direcţia spre exteriorul suprafeţei. Dacă se doreşte folosirea vectorului normală orientat spre interiorul suprafeţei unui obiect se va modifica fiecare vector normală de la (x, y, z) la (-x, -y, -z).

Page 36: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Vectorii normală pot fi specificaţi având orice lungime, dar ei vor trebui normalizaţi înainte de efectuarea calculelor de iluminare. În general, este bine ca vectorii normală să fie furnizaţi normalizaţi. Dacă se specifică vectori normală nenormalizaţi sistemul OpenGL îi poate normaliza în mod automat. Pentru a cere această operaţie se va apela funcţia glEnable având ca parametru GL_NORMALIZE. Implicit este dezactivată normalizarea automată. În unele implementari ale OpenGL-ului normalizarea automată necesită calcule suplimentare care pot reduce performanţele aplicaţiei.

II.9. Transformări ale obiectelor 3D în OpenGL

II.9.1. Etapele transformării din spaţiul 3D pe suprafaţa de afişare

OpenGL utilizează un sistem de coordonate 3D dreapta.Secvenţa de transformări aplicate asupra punctelor prin care este definit un obiect 3D

pentru a fi afişat pe ecran este următoarea (figura II.8): transformarea de modelare şi vizualizare ( ModelView) transformarea de proiecţie, însoţită de decupare la marginile volumului vizual canonic împărţirea perspectivă transformarea în poarta de vizualizare din fereastra curentă

Figura II.8. Secvenţa de transformari aplicate vârfurilor în OpenGL

Procesul de transformări necesar producerii imaginii dorite pentru a fi redată pe o suprafaţă de afişare este asemănator cu cel al efectuării unei fotografii. Aceşti paşi ar fi următorii:

Aranjarea scenei pentru a fi fotografiată în contextul dorit - transformarea de modelare;

Page 37: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Aranjarea aparatului de fotografiat şi încadrarea scenei -transformarea de vizualizare;

Alegerea lentilelor aparatului sau modificarea zoom-ului - transformarea de proiecţie;

Determinarea dimensiunii imaginii finale - transformarea în poarta de vizualizare.

II.9.2. Transformarea de modelare şi vizualizare

O aceeaşi imagine a unui obiect se poate obţine în două feluri : poziţionând obiectul în faţa unei camere de luat vederi fixe poziţionând camera de luat vederi în faţa obiectului fix

Prima operaţie corespunde unei transformări de modelare a obiectului. Cea de a doua operaţie corespunde unei transformări de vizualizare. Deoarece ambele pot fi folosite pentru a obţine o aceeaşi imagine, sunt tratate împreună, ca o singură transformare

Transformarea de modelare are drept scop poziţionarea obiectelor în scena 3D. Această transformare este necesară deoarece, în mod uzual, fiecare obiect este definit ca obiect unitate într-un sistem de coordonate local. De exemplu, un cub poate fi definit ca având latura de o unitate, centrat în originea unui sistem de coordonate carteziene 3D. Reprezentarea la mărimea dorită, poziţionarea şi orientarea sa în scena 3D, care este definită într-un sistem de coordonate global, poate să presupună o transformare compusă din scalare şi rotaţie faţa de originea sistemului de coordonate local, urmată de o translaţie. Prin această transformare se crează o instanţă a cubului, de aceea transformarea de modelare se mai numeşte şi transformare de instanţiere.

Transformarea de modelare este o transformare compusă din transformări geometrice simple care poate fi definită ca produs matricial, folosind funcţiile de translaţie, rotaţie şi scalare oferite de OpenGL.

Transformarea de vizualizare este determinată de poziţia observatorului (camera de luat vederi), direcţia în care priveşte acesta si direcţia sus a planului de vizualizare. In mod implicit, observatorul este situat in originea sistemului de coordonate în care este descrisă scena 3D, direcţia în care priveşte este direcţia negativa al axei OZ, iar direcţia sus a planului de vizualizare este direcţia pozitiva a axei OY. Cu aceste valori implicite, transformarea de vizualizare este transformarea identică.

Funcţia gluLookAt permite modificarea parametrilor impliciţi ai transformării de vizualizare :

void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez, GLdouble centerx,GLdouble centery,GLdouble centerz, GLdouble upx,GLdouble upy,GLdouble upz);

Page 38: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

- eyex, eyey, eyez reprezintă poziţia observatorului - centerx, centery, centerz reprezintă direcţa în care se priveşte- upx, upy, upz reprezintă direcţia vectorului « sus » al planului de vizualizare

Poziţia observatorului reprezintă punctul de referinţă al vederii, R, iar direcţia în care se priveşte este direcţia normalei la planul de vizualizare, în R. Vectorul « sus » determină direcţia pozitivă a axei verticale a sistemului de coordonate 2D ataşat planului de vizualizare. Sistemul de coordonate 2D ataşat planului de vizualizare împreună cu normala la plan formează sistemul de coordonate 3D al planului de vizualizare, care în terminologia OpenGL este numit sistemul de coordonate observator.

Funcţia gluLookAt construieşte matricea transformării din sistemul de coordonate obiect în sistemul de coordonate observator şi o înmulţeşte la dreapta cu matricea curentă.

In OpenGL transformarea de modelare şi de vizualizare sunt exprimate printr-o singură matrice de transformare, care se obţine înmulţind matricile celor două transformări. Ordinea de înmulţire a celor două matrici trebuie să corespundă ordinei în care ar trebui aplicate cele două transformări : mai întâi transformarea de modelare apoi transformarea de vizualizare.

In OpenGL punctele 3D se reprezintă prin vectori coloană. Astfel, un punct (x,y,z) se reprezintă în coordonate omogene prin vectorul [xw yw zw w]T. Daca A, B şi C sunt 3 matrici de transformare care exprimă transformările de aplicat punctului în ordinea A, B, C, atunci secvenţa de transformări se exprimă matricial astfel :

[xw’ yw’ zw’ w’] T= C •B •A• [xw yw zw w]T

Transformarea de modelare şi vizualizare este o transformare compusă, reprezentată printr-o matrice VM, ce se obţine înmulţind matricea transformării de vizualizare cu matricea transformării de modelare. Fie V şi M aceste matrici. Atunci,

VM = V•MDacă coordonatele unui vârf în sistemul de coordonate obiect sunt reprezentate prin vectorul [xo yo zo wo]T, atunci coordonatele vârfului în sistemul de coordonate observator (“eye coordinates”) se obţin astfel:

[xe ye ze we]T = VM • [xo yo zo wo]T

Matricea VM este aplicată automat şi vectorilor normali.

II.9.3. Transformarea de proiecţie

Page 39: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Matricea de proiecţie este calculată în OpenGL în funcţie de tipul de proiecţie specificat de programator şi parametrii care definesc volumul de vizualizare. Matricea de proiecţie este matricea care transformă volumul vizual definit de programator într-un volum vizual canonic. Această transformare este aplicată vârfurilor care definesc primitivele geometrice în coordonate observator, rezultând coordonate normalizate. Primitivele reprezentate prin coordonate normalizate sunt apoi decupate la marginile volumului vizual canonic, de aceea coordonatele normalizate se mai numesc şi coordonate de decupare. Volumul vizual canonic este un cub cu latura de 2 unităti, centrat în originea sistemului coordonatelor de decupare. După aplicarea transformării de proiecţie, orice punct 3D (din volumul vizual canonic) se proiectează în fereastra 2D printr-o proiecţie ortografică (x’ =x, y’=y) condiţie necesară pentru aplicarea algoritmului z-buffer la producerea imaginii.

Dacă coordonatele unui vârf în sistemul de coordonate observator sunt reprezentate prin vectorul [xe ye ze we]T, iar P este matricea de proiecţie, atunci coordonatele de decupare ale vârfului (“clip coordinates”) se obţin astfel:

[xc yc zc wc]T = P • [xo yo zo wo]T

Prezentăm în continuare funcţiile OpenGL prin care pot fi definite proiecţiile şi volumul de vizualizare.

void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);

Funcţia defineşte o proiecţie perspectivă cu centrul de proiecţie în poziţia observatorului (punctul de referinţă al vederii). Volumul de vizualizare (figura II.9) este delimitat prin «  planul din faţă » şi «  planul din spate », plane paralele cu planul de vizualizare, definite prin distanţele lor faţă de poziţia observatorului (planul de vizualizare). Planul din faţă va fi folosit ca plan de proiecţie. Lui i se ataşează un sistem de coordonate 2D având axa verticală (sus) orientată ca şi axa verticală a planului de vizualizare. Deschiderea camerei de luat vederi este determinată printr-o fereastră rectangulară, cu laturile paralele cu axele, definită în planul de proiecţie.  

- (left, bottom) şi (right, top) reprezintă colţurile ferestrei din planul din faţă- znear, zfar reprezintă distanţele de la poziţia observatorului la planul din faţă,

respectiv spate. Ambele distanţe trebuie să fie pozitive.

Page 40: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Figura II.9. Volumul vizual perspectivă

Dacă left=right sau bottom=top sau znear=zfar sau znear<=0 sau zfar<=0 se semnalează eroare.Colţurile ferestrei 2D din planul de proiecţie, (left, bottom,-near) şi (right, top,-near) sunt mapate pe colţurile stânga-jos şi dreapta-sus ale ferestrei 2D din sistemul coordonatelor de decupare, adică (-1,-1,-1) şi (1,1,-1). Matricea de proiecţie este în acest caz :

unde

,

,

Funcţia glFrustum înmulţeşte matricea curentă cu matricea de proiecţie rezultată şi memorază rezultatul în matricea curentă. Astfel, dacă M este matricea curentă şi P este matricea proiecţiei, atunci glFrustum înlocuieşte matricea M cu M * P.

O altă funcţie care poate fi folosită pentru proiecţia perspectivă este gluPerspective :

Page 41: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far);

Funcţia gluPerspective creează un volum de vizualizare la fel ca şi funcţia glFrustum, dar în acest caz el este specificat în alt mod. În cazul funcţiei gluPerspective acesta se specifică prin unghiul de vizualizare în planul XOZ (deschiderea camerei de luat vederi) şi raportul dintre lăţimea şi înălţimea ferestrei definite în planul de aproape (pentru o fereastră pătrată acest raport este 1.0.)

- fovy reprezintă unghiul de vizualizare în planul XOZ, care trebuie să fie în intervalul [0.0,180.0].

- aspect reprezintă raportul lăţime / înălţime al laturilor ferestrei din planul de aproape; acest raport trebuie să corespundă raportului lăţime/înăţime asociat porţii de afişare. De exemplu, dacă aspect = 2.0 atunci unghiul de vizualizare este de două ori mai larg pe direcţia x decât pe y. Dacă poarta de afişare este de două ori mai lată decât înălţimea atunci imaginea va fi afişată nedistorsionată.

- near şi far reprezintă distanţele între observator şi planele de decupare de-a lungul axei z negative. Întotdeauna trebuie să fie pozitivi.

Proiecţia ortografică este specificată cu ajutorul funcţiei glOrtho :

void glOrtho( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);

unde- (left, bottom) şi (right, top) reprezintă colţurile ferestrei din planul din faţă- near, far reprezintă distanţele de la poziţia observatorului la planul din faţă,

respectiv planul din spate

Volumul de vizualizare este în acest caz un paralelipiped dreptunghic delimitat de planul din faţa şi cel din spate, plane paralele cu planul de vizualizare (perpendiculare pe axa z), precum şi de planele sus, jos, dreapta , stânga. Direcţia de proiecţie este dată de axa Z a sistemului de coordonate ataşat planului de vizualizare.

Fereastra definită în planul din faţă, (left, bottom,-near) şi (right, top,-near), este mapată pe fereastra 2D din sistemul coordonatelor de decupare (-1,-1,-1) şi (1,1,-1). Matricea de proiecţie este în acest caz :

Page 42: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

unde

, ,

Matricea curentă este înmulţită cu matricea de proiecţie rezultată, rezultatul fiind depus în matricea curentă.

Tot pentru proiecţia ortografică poate fi folosită şi funcţia gluOrtho2D care defineşte matricea de proiecţie ortografică în care near=-1 şi far=1.

void gluOrtho2D( Gldouble left, Gldouble right, Gldouble bottom, Gldouble top);

unde- (left, bottom) şi (right, top) reprezintă colţurile ferestrei din planul din faţă

II.9.4. Impartirea pespectivă

Prin această operaţie se obţin coordonate 3D în spaţiul coordonatelor de decupare, pornind de la coordonatele 3D omogene :

xd = xc/wc , yd = yc/wc , zd= zc/wc

Coordonatele (xd, yd, zd) sunt numite « coordonate dispozitiv normalizate ».Operaţia este denumită « împărţire perspectivă » deoarece numai în cazul unei proiecţii perspectivă wc este diferit de 1.

II.9.5. Transformarea în poarta de vizualizare

Această transformare se aplică coordonatelor dispozitiv normalizate pentru a se obţine coordonate raportate la sistemul de coordonate al fereastrei curente de afişare. Este o transformare fereastă-poartă, în care fereastra este fereastra 2D din sistemul coordonatelor normalizate, având colţurile în (-1, -1, -1)-(1, 1, -1), iar poarta este un dreptunghi din fereastra de afişare care poate fi definit prin apelul funcţiei glViewport.

void glViewport(GLint px, GLint Py, GLsizei width, GLsizei height );

Page 43: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

- (px, py) reprezintă coordonatele în fereastră ale colţului stânga jos al porţii de afişare (în pixeli). Valorile implicite sunt (0,0).

- width, height reprezintă lăţimea, respectiv înălţimea porţii de afişare. Valorile implicite sunt date de lăţimea şi înălţimea ferestrei curente de afişare.

Fie (xd, yd, zd) coordonatele dispozitiv normalizate ale unui vârf şi (xw, yw, zw) coordonatele vârfului în fereastra de afişare. Transformarea în poarta de vizualizare este definită astfel :

xw = ox + (width/2)xdyw = oy + (height/2)ydzw = ((f-n)/2)zd + (n+f)/2

unde (ox, oy) reprezintă coordonatele centrului porţii de afişare.n şi f au valorile implicite 0.0 respectiv 1.0, dar pot fi modificate la valori cuprinse în intervalul [0,1] folosind funcţia DepthRange. Dacă n şi f au valorile implicite, atunci prin transformarea în poarta de vizualizare volumul vizual canonic se transformă în cubul cu colţurile de minim şi maxim în punctele (px, py, 0)-(px+width, py+height,1). Calculul coordonatei zw este necesară pentru comparaţiile de adâncime în algoritmul z-buffer.

Observaţie: în programul din fişierul exemplu5.c lăţimea şi înălţimea porţii de afişare sunt specificate folosind lăţimea şi înălţimea ferestrei curente a aplicaţiei.

II.9.6. Funcţii de operare cu matrici de transformare

Transformarea de modelare şi vizualizare şi transformarea de proiecţie sunt reprezentate prin matrici. Programatorul poate încărca una dintre aceste matrici cu o matrice proprie sau cu matricea unitate, sau o poate înmulţi cu alte matrici.

Înaintea specificării unei transformări trebuie selectată matricea curentă, care va fi modificată. Pentru aceasta se va apela funcţia glMatrixMode.

void glMatrixMode( GLenum mode );

Parametrul mode reprezintă matricea asupra căreia se vor efectua modificările ulterioare. El poate avea una dintre următoarele valori:

- GL_MODELVIEW – matricea curentă va fi matriciea de modelare şi vizualizare- GL_PROJECTION – matricea curentă va fi matricea de proiecţie.

- GL_TEXTURE – matricea curentă va fi matricea textură.

Page 44: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

In programul din fişierul exemplu5.c, înaintea transformării de vizualizare, matricea curentă este setată la matricea identitate (de 4 linii şi 4 coloane) cu ajutorul functiei glLoadIdentity.

void glLoadIdentity(void);

Apelul funcţiei glLoadIdentity este necesar deoarece majoritatea funcţiilor de transformare înmulţesc matricea curentă cu matricea specificată şi rezultatul este depus în matricea curentă. Dacă matricea curentă nu este setată iniţial la matricea identitate, atunci se vor folosi matricile de transformare anterioare combinate cu cea furnizată în acel moment

Dacă se doreşte ca o anumită matrice să devină matricea curentă, atunci se va folosi funcţia glLoadMatrix*.

void glLoadMatrix{fd}(const TYPE *m);

Valorile conţinute în vectorul m se memorează în matricea curentă, în ordinea coloanelor :

Observaţie : Elementele unei matrici din limbajul C sunt memorate în ordinea liniilor.

Funcţia glMultMatrix* se poate folosi pentru a înmulţi matricea curentă cu matricea dată ca parametru funcţiei glMultMatrix*.

void glMultMatrix{fd}(const TYPE *m);

Funcţia înmulţeşte matricea specificată de parametrul m cu matricea curentă şi rezultatul înmulţirii este stocat în matricea curentă. Dacă C este matricea curentă, atunci rezultatul înmulţirii este C=C•m.

Pentru specificarea unei translaţii se poate folosi funcţia:

void glTranslatef(GLfloat x, GLfloat y, GLfloat z);

unde x, y şi z reprezintă componentele vectorului de translaţieMatricea curentă este înmulţită cu matricea de translaţie şi rezultatul înlocuieşte

matricea curentă. Dacă M este matricea curentă şi T este matricea de translaţie, atunci M este înlocuită cu M•T.

Page 45: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Daca matricea curenta este GL_MODELVIEW sau GL_PROJECTION, toate obiectele afişate după apelul functiei glTranslatef vor fi translatate.

Pentru rotaţii se poate folosi funcţia:

void glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);

- angle reprezintă unghiul de rotaţie exprimat în grade.- x, y, z reprezintă coeficienţii directori ai axei în jurul căreia se realizează rotaţia.

Funcţia efectuează o rotaţie în sens trigonometric cu unghiul specificat, în jurul vectorului ce uneşte originea cu punctul de coordonate (x, y, z). Matricea curentă este înmulţită cu matricea de rotaţie şi rezultatul înlocuieşte matricea curentă. Dacă M este matricea curentă şi R este matricea de rotaţie, atunci M este înlocuită cu M•R. Dacă matricea curentă este GL_MODELVIEW sau GL_PROJECTION, toate obiectele afişate după apelul funcţiei glRotatef vor fi rotite.

Pentru scalare se poate folosi funcţia:

void glScalef(GLfloat x, GLfloat y, GLfloat z);

unde x, y, z reprezintă factorii de scalare de-a lungul axelor x, y şi z.Matricea curentă este înmulţită cu matricea de scalare şi rezultatul înlocuieşte matricea curentă. Dacă M este matricea curentă şi S este matricea de translaţie, atunci M este înlocuită cu M*S.Dacă matricea curentă este GL_MODELVIEW sau GL_PROJECTION, atunci toate obiectele afişate după apelul funcţiei glScalef vor fi scalate.Folosirea funcţiei glScale* diminuează performanţele calculului iluminării, deoarece vectorii normală trebuie renormalizaţi după această transformare.

ExempluConsiderăm următoarea secvenţă care specifică o secvenţă de trei transformări:

glMatrixMode(GL_MODELVIEW);glLoadIdentity();glMultMatrixf(N); /* aplică transformarea N */glMultMatrixf(M); /* aplică transformarea M */glMultMatrixf(L); /* aplică transformarea L */glBegin(GL_POINTS); glVertex3f(v); /* afişează vârful v transformat*/

Page 46: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glEnd();

La execuţia secvenţei de mai sus, matricea de modelare şi vizualizare (MODELVIEW) va conţine succesiv : I, N, N•M, şi în final N•M•L, unde I reprezintă matricea identitate. Transformarea aplicată vârfului v va fi NML•v, unde NML = N•M•L.

II.9.7. Gestiunea stivelor de matrici

Un sistem OpenGL păstrează câte o stivă de matrici pentru fiecare mod matrice selectat cu ajutorul funcţiei MatrixMode. Astfel, există : Stiva matricilor Modelview (cel puţin 32 matrici 4 x 4); Stiva matricilor de proiecţie (cel puţin 2 matrici 4 x 4) ; Stiva matricilor textură(cel puţin 2 matrici 4 x 4).

Matricea curentă este întotdeauna matricea din vârful stivei corespunzătoare modului matrice curent.O stivă de matrici este folositoare pentru construirea modelelor ierarhice în care sunt construite obiecte complexe pornind de la obiecte simple. De exemplu, să presupunem că se desenează o maşină şi există o singură rutină care desenează o roată. Această rutină desenează roata într-o anumită poziţie şi orientare. Când se desenează maşina, rutina de afişare a roţii se va apela de 4 ori, aplicându-se diferite transformări pentru a poziţiona corect roţile. De exemplu, pentru desenarea primei roţi aceasta trebuie să fie translatată. La desenarea celei de a doua roţi trebuie aplicată o altă translaţie (dar faţă de poziţia iniţială – nu trebuie ţinut cont de prima translaţie) şi în acelaşi mod pentru desenarea celorlalte roţi.

Deoarece transformările sunt păstrate ca matrici, o stivă de matrici furnizează un mecanism util pentru efectuarea unei transformări ca apoi să se realizeze o altă transformare fără a se mai ţine cont de transformarea anterioară. Toate operaţiile cu matrici (glLoadMatrix, glMultMatrix, glLoadIdentity şi funcţiile care creează matrici de transformare specifice) lucrează cu matricea curentă sau cu matricea din vârful stivei.

Pentru lucrul cu stivele de matrici OpenGL pune la dispoziţie funcţiile glPushMatrix şi glPopMatrix.

void glPushMatrix(void);

Funcţia adaugă un nou element la stiva curentă şi memorează matricea curentă atât în elementul din vârful stivei cât şi în intrarea următoare. Stiva curentă este determinată de

Page 47: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

ultimul apel al funcţiei glMatrixMode. Dacă prin adăugare se depaşeşte capacitatea stivei se generează eroare.

void glPopMatrix(void);

Funcţia elimină intrarea din vârful stivei şi înlocuieşte matricea curentă cu matricea care era memorată în a 2-a intrare a stivei. Dacă stiva avea o singură intrare, apelul funcţiei glPopMatrix generează eroare.

ExempluProgramul din fişierul exemplu5.c afişează un cub care este mai întâi scalat (transformarea de modelare). Transformarea de vizualizare constă dintr-o translaţie a poziţiei observatorului pe axa z, în poziţia (0,0,5). Observatorul priveşte spre origine iar direcţia axei sus este direcţia axei OY a sistemului de coordonate obiect.

/* exemplu5.c */#include "glut.h"

void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0);}void display(void){ glClear (GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0); glLoadIdentity (); gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0); glScalef (1.0, 2.0, 1.0); glutWireCube (1.0); glFlush ();}void reshape (int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0); glMatrixMode (GL_MODELVIEW);}int main(int argc, char** argv)

Page 48: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

{ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}

Transformarea de vizualizare şi modelare este creată în funcţia display unde este apelată şi funcţia de afişare a cubului, glutWireCube. Astfel funcţia display poate fi folosită în mod repetat pentru a afişa conţinutul ferestrei (de exemplu în cazul în care fereastra este mutată pe ecran).

Transformarea de proiecţie şi transformarea în poarta de vizualizare sunt specificate în funcţia Reshape, care este apelată de sistem ori de câte ori este redimensionată fereastra aplicaţiei.

Efectul obţinut prin mutarea observatorului în spatele cubului (folosind transformarea de vizualizare) se poate obţine şi prin deplasarea cubului, folosind o transformare de modelare.

II.10. Iluminarea

II.10.1. Specificarea culorilor pentru lumină şi materiale

In capitolul II.6 ne-am referit la modul uzual în care sunt specificate culorile de afişare a obiectelor. Funcţiile glColor3 specifică un triplet (R, G, B). Funcţiile glColor4 adaugă tripletului (R,G,B) o valoare de opacitate, numită valoarea alfa (A).

OpenGL permite utilizarea a două moduri de reprezentare a culorilor de afişare: modul RGBA: pentru fiecare pixel se memorează valorile R, G, B şi A. modul indexat: pentru fiecare pixel se memorează un număr, reprezentând un index

într-o tabela de culori. Valorile R, G, B şi A variază în domeniul [0, 1].

Page 49: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

În modul RGBA, pentru selectarea culorii curente de desenare 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);

Valoarea implicită a opacităţii este 1.0. Pentru versiunile funcţiei glColor* care acceptă valori de tip real, domeniul

acestora trebuie să fie în intervalul [0, 1]. Valorile din afara intervalului [0,1] sunt trunchiate la valori în intervalul [0,1] când sunt folosite ca parametri direcţi, dar nu sunt trunchiate dacă sunt folosite pentru a modifica parametrii de material şi iluminare.

Valorile parametrilor de culoare specificate prin numere întregi sunt convertite în valori reale, conform tabelulului II.4

Tip Valoarea minimă

Valoarea minimă se mapeaza la

Valoarea maximă

Valoarea maximă se mapează la

b 1-byte integer -128 -1.0 127 1.0s 2-byte integer -32,768 -1.0 32,767 1.0i 4-byte integer -2,147,483,648 -1.0 2,147,483,647 1.0ub unsigned 1-byte integer 0 0.0 255 1.0

us unsigned 2-byte integer 0 0.0 65,535 1.0

ui unsigned 4-byte integer 0 0.0 4,294,967,295 1.0

Tabelul II.4. Conversia valorilor de culoare la numere reale

Componentele culorilor specificate prin funcţiile glColor* au semnificaţii diferite după cum sunt folosite pentru lumisa emisă de o sursă sau lumina reflectată de o suprafaţă. Pentru o sursă de lumină, valorile componentelor R, G şi B corespund unui procent din intensitatea maximă pentru fiecare culoare. Dacă valorile R, G şi B sunt 1.0 atunci lumina este alb strălucitor. Dacă valorile sunt 0.5, culoarea este albă, iar la jumătate din intensitate apare gri. Dacă R=G=1 şi B=0 lumina apare galbenă.

Pentru proprietăţile de material, valorile componentelor R, G şi B corespund proporţiilor reflectate din acea culoare. Dacă R=1, G=0.5 şi B=0 pentru un material, atunci acel material va reflecta toată lumina incidentă roşie, jumătate din lumina incidentă verde şi nimic din lumina incidentă albastră. Cu alte cuvinte dacă o sursă de lumină are componentele (LR, LG, LB) şi un material are componentele corespunzătoare (MR, MG, MB) atunci ignorându-se toate celelalte efecte ale reflectivităţii, lumina ce este percepută de ochiul observatorului este dată de formula (LR*MR, LG*MG, LB*MB).

Page 50: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Analog dacă sunt două surse de lumină, cu componentele (R1, G1, B1) şi (R2, G2, B2), atunci lumina rezultată va fi dată de (R1+R2, G1+G2, B1+B2). Dacă oricare dintre componentele rezultate sunt mai mari ca 1, atunci componenta respectivă va fi trunchiată la 1.

II.10.2. Specificarea modelului de iluminare

Modelele de iluminare care pot fi folosite în OpenGL sunt modelul Lambert şi modelul Gouraud. Modelul de iluminare dorit se specifică cu ajutorul funcţiei glShadeModel.

void glShadeModel (GLenum mode);

- mode specifică modelul de iluminare ce va fi selectat; el poate avea valorile: GL_SMOOTH: este valoarea implicită, prin care se selectează modelul Gouraud GL_FLAT : selectează modelul Lambert.

În modelul Gouraud culoarea fiecărui vârf este tratată în mod individual. Pentru un segment de dreaptă culoarea se obţine prin interpolarea culorilor vârfului. Pentru un poligon, culorile punctelor interioare se obţin prin interpolare pe baza culorilor vârfurilor.

Exemplu : în fişierul exemplul6.c se afişează un triunghi folosind modelul de iluminare Gouraud.

/* fişierul exemplul6.c */#include "glut.h"

void init(void) { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_SMOOTH);}

void triangle(void){ glBegin (GL_TRIANGLES); glColor3f (1.0, 0.0, 0.0); glVertex2f (5.0, 5.0);

Page 51: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glColor3f (0.0, 1.0, 0.0); glVertex2f (25.0, 5.0); glColor3f (0.0, 0.0, 1.0); glVertex2f (5.0, 25.0); glEnd();}

void display(void){ glClear (GL_COLOR_BUFFER_BIT); triangle (); glFlush ();}

void reshape (int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity (); if (w <= h) gluOrtho2D (0.0, 30.0, 0.0, 30.0*(GLfloat) h/(GLfloat) w); else gluOrtho2D (0.0, 30.0*(GLfloat) w/(GLfloat) h, 0.0, 30.0); glMatrixMode(GL_MODELVIEW);}

int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}

Page 52: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

În modelul Lambert culoarea unei primitive este dată de culoarea unui singur vârf. Culoarea unui segment de dreaptă este dată de culoarea celui de-al doile vârf. Culoarea unui poligon este dată de culoarea unui vârf, conform tabelului II.5. Vârfurile poligoanelor sunt numerotate începând cu 1. Pentru a evita confuzii în ceea ce priveşte culoarea de desenare în modelul Lambert se va specifica o singură culoare pentru o primitivă.

Tipul poligonului Vârful folosit pentru selectarea culorii poligonului

Poligon singular 1triangle strip i+2triangle fan i+2independent triangle 3iquad strip 2i+2independent quad 4i

Tabelul II.5. Selectarea culorii pentru un poligon în modelul Lambert

II.10.3. Iluminarea unei scene 3D

Paşii de adăugare a iluminării într-o scenă sunt următorii :1) Definirea vectorilor normală pentru fiecare vârf al tuturor obiectelor. Aceste

normale determină orientarea relativă a obiectelor faţă de sursele de lumină ;2) Crearea, selectarea şi poziţionarea uneia sau a mai multor surse de lumină ;3) Crearea şi selectarea unui model de iluminare care defineşte nivelul luminii

globale, ambiante şi poziţia observatorului ;4) Definirea proprietăţilor de material pentru obiectele din scenă.

ExempluProgramul din fişierul exemplul7.c realizează afişarea unei sfere cu iluminare folosind o sursă de lumină. Normalele pentru sferă sunt definite de funcţia glutSolidSphere.

/* fişierul exemplul7.c */#include "glut.h"

void init(void) {

Page 53: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_SMOOTH);

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST);}

void display(void){ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSolidSphere (1.0, 20, 16); glFlush ();}

void reshape (int w, int h){ glViewport (0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode (GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w, 1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-1.5*(GLfloat)w/(GLfloat)h, 1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}

int main(int argc, char** argv){

Page 54: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize (500, 500); glutInitWindowPosition (100, 100); glutCreateWindow (argv[0]); init (); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0;}

II.10.3.1. Crearea, poziţionarea şi activarea uneia sau a mai multor surse de lumină

În programul din fişierul exemplul7.c se foloseşte o singură sursă de lumină albă. Poziţia sa este specificată prin apelul funcţiei glLightfv. Acest exemplu foloseşte culoarea implicită pentru sursa de lumina 0 (GL_LIGHT0), care este albă ; dacă se doreşte o sursă de lumină având o altă culoare se va folosi funcţia glLight*. Într-o scenă pot fi incluse cel mult 8 surse de lumină diferite. Culoarea implicită a acestor surse de lumină este negru. Ele pot fi poziţionate la o distanţă finită sau infinită faţă de scenă. Sursele de lumină pot produce un fascicul de lumină mai îngust sau mai larg. După ce au fost definite caracteriticile surselor de lumină, acestea trebuie să fie activate folosind funcţia glEnable. De asemenea, trebuie apelată funcţia glEnable având ca parametru GL_LIGHTING pentru a activa efectuarea calculelor de iluminare (în mod implicit acestea sunt dezactivate).

Crearea surselor de lumină

Sursele de lumină au o serie de proprietăţi cum sunt culoarea, poziţia şi direcţia. Funcţia folosită pentru a specifica toate proprietăţile luminii este glLight*.

void glLight{if}(GLenum light, GLenum pname, TYPE param);void glLight{if}v(GLenum light, GLenum pname, TYPE *param);

Funcţia crează o sursă de lumină.- light specifică sursa de lumină creată; poate avea una din următoarele valori:

GL_LIGHT0, GL_LIGHT1, ... , sau GL_LIGHT7;

Page 55: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

- pname specifică caracteristicile luminii, conform tabelului II.6;- param indică valorile caracteristicilor setate prin pname.

Valorile implicite ale parametrului param pentru valorile parametrului pname

pname Valoarea implicita ObservatieGL_AMBIENT (0.0, 0.0, 0.0, 1.0) Intensitatea ambiantă a luminii (RGBA)GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) Intensitatea luminii difuze (RGBA)GL_SPECULAR (1.0, 1.0, 1.0, 1.0) Intensitatea luminii speculare (RGBA)GL_POSITION (0.0, 0.0, 1.0, 0.0) Poziţia (x, y, z, w) a luminiiGL_SPOT_DIRECTION (0.0, 0.0, -1.0) Direcţia (x, y, z) spotului de luminăGL_SPOT_EXPONENT 0.0 Exponentul spotului deluminăGL_SPOT_CUTOFF 180.0 Unghiul spotului de luminăGL_CONSTANT_ATTENUATION 1.0 Factor de atenuare constantGL_LINEAR_ATTENUATION 0.0 Factor de atenuare liniarGL_QUADRATIC_ATTENUATION 0.0 Factor de atenuare cuadric

Tabelul II.6.

Valorile implicite din tabelul de mai sus pentru GL_DIFFUSE şi GL_SPECULAR se aplică doar pentru sursa de lumină GL_LIGHT0. Pentru celelate surse de lumină, valoarea implicită este (0.0, 0.0, 0.0, 1.0) atât pentru GL_DIFFUSE cât şi pentru GL_SPECULAR.

Exemplu : definirea culorilor, poziţiei şi a factorilor de atenuare pentru o sursă de lumină

GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.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);glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);

O sursă de lumină poziţionată (care nu este plasată la infinit) poate acţiona ca un spot – lumina va fi emisă sub forma unui con. Pentru a specifica unghiul dintre axele

Page 56: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

conului şi o rază de pe suprafaţa conului se foloseşte parametrul GL_SPOT_CUTOFF. Unghiul conului este de fapt dublul acestei valori după cum se arată în figura II.10:

Figura II.10.

Valoarea implicită a parametrului GL_SPOT_CUTOFF este 180.0 (caracteristica de lumină spot este dezactivată), adică lumina este emisă în toate direcţiile. Valoarea parametrului GL_SPOT_CUTOFF trebuie să fie situată în intervalul [0.0,90.0] (altfel are valoarea 180.0).

Exemplu : setarea parametrului GL_SPOT_CUTOFF la 45o

glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);

De asemenea, trebuie specificată o direcţie a spotului care determină axele conului de lumină :

GLfloat spot_direction[] = { -1.0, -1.0, 0.0 };glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);

Direcţia este specificată în coordonate obiect omogene. Valoarea implicită a direcţiei este (0.0, 0.0, -1.0).

Surse de lumină multiple

Într-o scenă pot fi definite cel mult 8 surse de lumină. Constatele folosite pentru referirea celor 8 surse de lumină sunt : GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, GL_LIGHT3, …, GL_LIGHT7. Dacă se specifică o altă sursă de lumină trebuie să i se seteze parametrii corespunzători ca şi în cazul sursei de lumină GL_LIGHT0.

Exemplu : definirea unui spot de lumina albă :

Page 57: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat light1_position[] = { -2.0, 2.0, 1.0, 1.0 };GLfloat spot_direction[] = { -1.0, -1.0, 0.0 };

glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);glLightfv(GL_LIGHT1, GL_POSITION, light1_position);glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5);glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5);glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2);

glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0);

glEnable(GL_LIGHT1);

Observaţie: Pentru a activa fiecare sursă de lumină se foloseşte funcţia glEnable cu argumentul GL_LIGHTING. Pentru a dezactiva iluminarea se apelează functia glDisable cu acelaşi parametru.

II.10.3.2. Specificarea parametrilor modelului de iluminare

Funcţia glLightModel* defineşte parametrii modelului de iluminare:

void glLightModel{fi}(GLenum pname, TYPE param);

- pname reprezintă parametrul modelului de iluminare. El poate avea una din

următoarele două valori: GL_LIGHT_MODEL_LOCAL_VIEWER, caz în care param specifică

modul de calcul al unghiului de reflexie. GL_LIGHT_MODEL_TWO_SIDE - specifică feţele pentru care se face

calculul de iluminare. Nu are nici un efect în calculele de lumină pentru

Page 58: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

puncte, linii şi bitmap-uri. Dacă param este 0 , calculele de iluminare se fac numai pentru feţele faţă şi vor fi folosite numai proprietăţile de material ale feţelor faţă. Altfel vor fi considerate atât feţele faţă cât şi feţele spate. În acest caz vârfurile feţelor spate vor fi luminate folosind proprietăţile de material ale feţelor spate (normalele vor fi inversate înainte de a calcula iluminarea).

- param reprezintă valoarea ce va fi folosită în corelaţie cu pname.

void glLightModel{fi}v( GLenum pname, const TYPE *params );

- pname identifică modelul de iluminare. El poate avea una din următoarele două valori: GL_LIGHT_MODEL_AMBIENT, caz în care params va conţine

componentele RGBA ale luminii ambiante. GL_LIGHT_MODEL_LOCAL_VIEWER are aceeaşi semnificaţie ca

şi în cazul funcţiei glLightModel{fi}; în acest caz param devine params; GL_LIGHT_MODEL_TWO_SIDE are aceeaşi semnificaţie ca şi în

cazul funcţiei glLightModel{fi}; în acest caz param devine params;- param reprezintă valoarea ce va fi folosită în corelaţie cu pname.

În exemplul din fişierul exemplul7.c singurul element care este definit explicit pentru modelul de iluminare este lumina ambiantă globală. De asemenea, modelul de iluminare defineşte şi poziţia observatorului (la infinit sau la distanţă finită de scenă) precum şi modul de efectuare a calculelor de iluminare a feţelor faţă respectiv spate ale scenei. În programul din fişierul exemplul7.c se folosesc valorile implicite pentru acestea – observatorul este plasat la infinit şi calculele de iluminare sunt efectuate pentru feţele faţă. Folosirea unui observator local scenei creşte complexitatea calculelor deoarece sistemul OpenGL trebuie să calculeze unghiul dintre observator şi fiecare obiect. Folosind un observator plasat la infinit unghiul este ignorat şi rezultatele sunt ceva mai puţin realiste.

În OpenGL modelul de iluminare are trei componente : Intensitatea luminii ambiante globale Poziţionarea observatorului (local scenei sau la infinit) Diferenţierea calculării iluminării pentru feţele obiectelor faţă, respectiv spate.

Page 59: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Lumina ambianta globală

Pentru a specifica intensitatea luminii ambiante globale ca RGBA se va folosi parametrul GL_LIGHT_MODEL_AMBIENT după cum urmează :

GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

În exemplul de mai sus valorile folosite pentru lmodel_ambient sunt valorile implicite pentru GL_LIGHT_MODEL_AMBIENT.

Observator local sau plasat la infinit

Poziţia observatorului afectează calculele pentru strălucirea produsă de lumina speculară, mai precis intensitatea strălucirii într-un vârf depinde de normala în acel vârf, direcţia de la vârf la sursa de lumină şi direcţia de la vârf la observator.

Cu un observator plasat la infinit direcţia dintre observator şi orice vârf rămâne constantă. Un observator local va furniza rezultate mai aproape de realitate, dar direcţia va trebui calculată pentru fiecare vârf, astfel că în acest caz performaţele scad. În mod implicit observatorul este plasat la infinit.

Exemplu: definirea unui observator local în punctul de coordonate (0, 0, 0) (în coordonate observator):

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

Pentru a trece din nou la un observator plasat la infinit:

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);

Calculul luminii pentru ambele feţe

În programul din fişierul exemplul7.c numai feţele faţă sunt iluminate.

Exemplu: calcularea iluminării pentru ambele feţe :

Page 60: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_TRUE);

Dacă se doreşte să se calculeze apoi iluminarea numai pentru feţele faţă se va apela:

glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_FALSE);

II.10.3.3. Definirea proprietăţilor de material pentru obiectele din scenă

Proprietăţile de material ale unui obiect determină modul în care el reflectă lumina. Pentru proprietăţile unui material se pot specifica culorile ambiantă, difuză, speculară, stralucirea sa şi culoarea oricărei lumini emise. Acestea pot fi setate folosind funcţia glMaterialfv.

void glMaterial{if}[v](GLenum face, GLenum pname, TYPE param);

Funcţia specifică proprietăţile de material folosite în calculul iluminării.- face reprezintă faţa obiectului pe care se vor aplica proprietăţile de material; poate

avea una dintre valorile GL_FRONT, GL_BACK sau GL_FRONT_AND_BACK.

- pname indică proprietăţile de material;- param indică una dintre valorile proprietăţilor selectate în parametrul pname.

Valorile posibile pentru pname sunt date în tabelul II.7.

pname Valoare implicita ObservaţieGL_AMBIENT (0.2, 0.2, 0.2, 1.0) Culoarea ambiantă a materialuluiGL_DIFFUSE (0.8, 0.8, 0.8, 1.0) Culoarea difuză a materialuluiGL_AMBIENT_AND_DIFFUSE Culoarea ambiantă şi difuză a materialuluiGL_SPECULAR (0.0, 0.0, 0.0, 1.0) Culoarea speculară a materialuluiGL_SHININESS 0.0 Exponentul specular GL_EMISSION (0.0, 0.0, 0.0, 1.0) Culoarea emisă a materialuluiGL_COLOR_INDEXES (0,1,1) Indicii de culoare ambiantă, difuză şi speculară

Tabelul II.7.

Reflexia difuză şi ambiantă

Parametrii GL_DIFFUSE şi GL_AMBIENT setaţi cu funcţia glMaterial* afectează culoarea luminii ambiante şi difuze reflectate de un obiect.

Page 61: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Exemplu: asignarea simultană a aceleeaşi valori luminii reflectate difuze şi ambiante :

GLfloat mat_amb_diff[] = { 0.1, 0.5, 0.8, 1.0 };glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_amb_diff);

Reflexia speculară

OpenGL permite setarea culorii RGBA a strălucirii speculare (folosind GL_SPECULAR) şi poate controla dimensiunea şi luminozitatea strălucirii (folosind GL_SHININESS). Parametrului GL_SHININESS i se poate asocia o valoare în domeniul [0.0, 128.0];cu cât valoarea este mai mare cu atât stălucirea este mai mică şi mai luminoasă.

Exemplu :

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat low_shininess[] = { 5.0 };glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);

Emisia

Prin asocierea unei culori RGBA parametrului GL_EMISSION se poate face ca un obiect să pară că furnizează lumină de culoarea selectată.

Exemplu:

GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);

Modificarea proprietăţilor de material

În fişierul din exemplul6.c toate vârfurile au asociate aceleaşi proprietăţi de material. Uneori se doreşte să se asocieze vârfurilor aceluiaşi obiect proprietăţi de material diferite. De obiecei într-o scenă sunt mai multe obiecte şi fiecare au asociate proprietăţi de material diferite.

Page 62: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Exemplu : desenarea a opt sfere fiecare având alte proprietăţi de material :

GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };GLfloat mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 };GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat no_shininess[] = { 0.0 };GLfloat low_shininess[] = { 5.0 };GLfloat high_shininess[] = { 100.0 };GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

/* reflexie difuză */glPushMatrix(); glTranslatef (-3.75, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glutSolidSphere();glPopMatrix();

/* reflexie difuză şi speculară; strălucire redusă */glPushMatrix(); glTranslatef (-1.25, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glutSolidSphere();glPopMatrix();

/* reflexie difuză şi speculară; stralucire ridicată */glPushMatrix(); glTranslatef (1.25, 3.0, 0.0);

Page 63: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glutSolidSphere();glPopMatrix();

/* reflexie difuză, emisie */glPushMatrix(); glTranslatef (3.75, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat); glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); glutSolidSphere();glPopMatrix();

Funcţia glMaterialfv este apelată în mod repetat pentru a seta proprietăţile de material pentru fiecare sferă. Ea este reapelată doar pentru acele proprietăţi care se modifică de la o sferă la alta (adică de la un obiect la altul). Deoarece funcţia glMaterial* are un cost de execuţie mare este bine să se minimizeze modificările proprietăţilor de material. O altă tehnică de a minimiza costurile asociate cu modificarile proprietăţilor de material este folosirea funcţiei glColorMaterial :

void glColorMaterial(GLenum face, GLenum mode);

Proprietăţile de material specificate de parametrul mode ale feţei specificate de parametrul face ia întotdeauna valoarea culorii curente. Astfel, o modificare asupra culorii curente (folosind funcţia glColor*) actualizează imediat proprietăţile de material specificate.

- face poate avea una dintre următoarele valori: GL_FRONT, GL_BACK sau GL_FRONT_AND_BACK (valoare implicită);

- mode poate avea una din următoarele valori: GL_AMBIENT, GL_DIFFUSE, GL_AMBIENT_AND_DIFFUSE (valoare implicită), GL_SPECULAR sau GL_EMISSION.

Page 64: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Observaţie: glColorMaterial actualizează proprietatea/proprietăţile de material specificate de parametrul mode ale faţei/feţelor specificate de parametrul face.

După apelul funcţiei glColorMaterial trebuie apelată funcţia glEnable având ca parametru GL_COLOR_MATERIAL. Apoi culoarea curentă poate fi modificată folosind funcţia glColor* (sau alte proprietăţi de material folosind funcţia glMaterial*).

Exemplu:

glColorMaterial(GL_FRONT, GL_DIFFUSE);glEnable(GL_COLOR_MATERIAL);glColor3f(0.2, 0.5, 0.8);/* afişează obiecte */glColor3f(0.9, 0.0, 0.2);/* afişează alte obiecte */glDisable(GL_COLOR_MATERIAL);

Funcţia glColorMaterial se va folosi de câte ori se doreşte modificarea unui singur parametru de material pentru majoritatea vârfurilor din scenă. Dacă se doreşte modificarea mai multor parametri de material se va folosi funcţia glMaterial*.

II.11. Liste de afişare

II.11.1. Utilizarea listelor de afişare

O listă de afişare reprezintă un grup de comenzi OpenGL stocate pentru o execuţie ulterioară. La invocarea unei liste de afişare comenzile din ea sunt executate în ordinea în care sunt întâlnite. Majoritatea comenzilor OpenGL pot fi stocate într-o listă de afişare sau pot apare în modul imediat (sunt executate imediat). Modul imediat de programare poate fi combinat cu listele de afişare.

Listele de afişare pot îmbunătăţi programul deoarece instrucţiunile sunt stocate pentru execuţii ulterioare. Este indicat să se folosească liste de afişare în cazul în care se redesenează de mai multe ori aceeaşi figură geometrică sau dacă trebuie aplicat de mai multe ori un set de modificări de stare.

Page 65: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

O listă de afişare este un mod eficient şi convenabil de a combina un set de comenzi OpenGL.

Exemplu: desenarea unui cerc format din 100 de segmente. Codul corespunzător desenării cercului fără a folosi liste de afişare este următorul:

drawCircle(){ GLint i; GLfloat cosine, sine;

glBegin(GL_POLYGON);

for(i=0;i<100;i++){ cosine=cos(i*2*PI/100.0); sine=sin(i*2*PI/100.0); glVertex2f(cosine,sine); } glEnd();}

Această metodă este ineficientă deoarece calculele trigonometrice vor fi efectuate de fiecare dată când cercul va fi afişat. O altă modalitate este de a salva aceste coordonate într-un vector şi a le folosi ori de câte ori este nevoie :

drawCircle(){ GLint i; GLfloat cosine, sine; static GLfloat circoords[100][2]; static GLint inited=0;

if(inited==0){ inited=1; for(i=0;i<100;i++){ circcoords[i][0]=cos(i*2*PI/100.0); circcoords[i][1]=sin(i*2*PI/100.0); } } glBegin(GL_POLYGON); for(i=0;i<100;i++)

Page 66: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glVertex2fv(&circcoords[i][0]); glEnd();}

Şi această metodă prezintă dezavantajul incrementării şi testării variabilei i. Ceea ce se doreşte este să se deseneze o singură dată cercul şi să se cunoască modul de redesenare ulterior. Acest lucru este realizat prin folosirea listelor de afişare.

Exemplu: crearea unei liste de afişare

#define MY_CIRCLE_LIST 1

buildCircle(){ GLint i; GLfloat cosine, sine;

glNewList(MY_CIRCLE_LIST, GL_COMPILE); glBegin(GL_POLYGON); for(i=0;i<100;i++){ cosine=cos(i*2*PI/100.0); sine=sin(i*2*PI/100.0); glVertex2f(cosine,sine); } glEnd(); glEndList();}

Codul pentru desenarea cercului se află între apelurile glNewList şi glEndList. Aceste apeluri delimitează o listă de afişare. Argumentul MY_CIRCLE_LIST al funcţiei glNewList este un index întreg care identifică în mod unic lista de afişare. Ulterior lista de afişare poate fi executată folosind comanda glCallList:

glCallList(MY_CIRCLE_LIST);

Listele de afişare sunt un mod convenabil şi eficient de a vedea sub forma unui nume o secvenţă de comenzi OpenGL. O listă de afişare conţine numai apeluri OpenGL. Alte apeluri - ca în exemplul de mai sus, cum ar fi funcţiile C cos şi sin – nu sunt stocate în listele de afişare. Coordonatele şi celelalte variabile (cum ar fi conţinutul vectorului) sunt evaluate şi copiate în lista de afişare având valorile de la momentul compilării listei.

Page 67: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

După compilarea listei aceste valori nu pot fi modificate. Lista de afişare poate fi ştearsă şi se poate crea una nouă, dar o listă de afişare existentă nu poate fi editată.

Exemplu Programul din fişierul exemplul8.c vizualizează unui tor din diferite unghiuri. Cel mai eficient mod de a face acest lucru este de a păstra torul într-o listă de afişare. Apoi, de câte ori se doreşte să se modifice poziţia observatorului se va modifica matricea ModelView şi se va executa lista de afişare pentru desenarea torului.

/* fişierul exemplul8.c */

#include "glut.h"

#include <stdio.h>#include <math.h>#include <stdlib.h>

#define M_PI 3.14

GLuint theTorus;

/* afişare tor */void torus(int numc, int numt){ int i, j, k; double s, t, x, y, z, twopi;

twopi = 2 * (double)M_PI; for (i = 0; i < numc; i++) { glBegin(GL_QUAD_STRIP); for (j = 0; j <= numt; j++) { for (k = 1; k >= 0; k--) { s = (i + k) % numc + 0.5; t = j % numt;

x = (1+.1*cos(s*twopi/numc))*cos(t*twopi/numt); y = (1+.1*cos(s*twopi/numc))*sin(t*twopi/numt); z = .1 * sin(s * twopi / numc);

Page 68: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glVertex3f(x, y, z); } } glEnd(); }}

/* creează lista de afişare pentru tor */void init(void){ theTorus = glGenLists (1); glNewList(theTorus, GL_COMPILE); torus(8, 25); glEndList();

glShadeModel(GL_FLAT); glClearColor(0.0, 0.0, 0.0, 0.0);}

void display(void){ glClear(GL_COLOR_BUFFER_BIT); glColor3f (1.0, 1.0, 1.0); glCallList(theTorus); glFlush();}

void reshape(int w, int h){ glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(30, (GLfloat) w/(GLfloat) h, 1.0, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);}

/* la apăsarea tastei 'x' - se roteşte în jurul axei x

Page 69: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

la apăsarea tastei 'y' - se roteşte în jurul axei y la apăsarea tastei 'i' - se poziţioneaza torul în poziţia originală*/void keyboard(unsigned char key, int x, int y){ switch (key) { case 'x': case 'X': glRotatef(30.,1.0,0.0,0.0); glutPostRedisplay(); break; case 'y': case 'Y': glRotatef(30.,0.0,1.0,0.0); glutPostRedisplay(); break; case 'i': case 'I': glLoadIdentity(); gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0); glutPostRedisplay(); break; case 27: exit(0); break; }}

int main(int argc, char **argv){ glutInitWindowSize(200, 200); glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutCreateWindow(argv[0]); init(); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutDisplayFunc(display);

Page 70: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glutMainLoop(); return 0;}

Utilizatorul poate roti torul în jurul axei OX sau OY prin apăsarea tastelor x respectiv y. De câte ori se întamplă acest lucru este apelată funcţia callback keyboard care înmulţeşte matricea de rotaţie de 30o în jurul axei x sau y cu matricea curentă ModelView, după care este apelată funcţia glutPostRedisplay, care face ca funcţia glutMainLoop să apeleze funcţia display şi să afişeze torul după prelucrarea altor evenimente. La apăsarea tastei ‘i’ funcţia keyboard reface matricea iniţială ModelView şi reafişează torul în poziţia sa iniţială. Funcţia display şterge fereastra şi apelează funcţia glCallList pentru a executa comenzile din lista de afişare.

Dacă nu s-ar fi folosit liste de afişare funcţia display ar fi trebuit să conţină comenzi de desenare a torului de fiecare dată când ar fi fost apelată.

O listă de afişare conţine numai comenzi OpenGL. În exemplul din fişierul exemplul8.c sunt stocate apelurile funcţiilor glBegin, glVertex şi glEnd. Parametrii apelurilor sunt evaluaţi şi valorile lor sunt copiate în lista de afişare la crearea sa. Toate calculele trigonometrice pentru crearea torului sunt făcute o singură dată ceea ce duce la creşterea performanţelor afişării.

Exemplu: aplicarea unor transformări unor obiecte geometrice şi apoi desenarea rezultatului:

glNewList(1, GL_COMPILE); afiseaza_obiectele_geometrice(); glEndList();

glLoadMatrix(M);glCallList(1);

Dacă obiectele sunt transformate de fiecare dată în acelaşi mod este bine să se păstreze matricea de transformare într-o listă de afişare.

ExempluIn unele implementări, se vor putea îmbunătaţi performanţele prin transformarea obiectelor în momentul definirii lor în loc de a le transforma de fiecare dată când sunt afişate :

Page 71: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glNewList(1, GL_COMPILE);glLoadMatrix(M);afiseaza_obiectele_geometrice(); glEndList();

glCallList(1);

Listele de afişare au şi dezavantaje. Listele foarte mici nu vor îmbunătăţi execuţia programului datorită overhead-ului execuţiei listei. Un alt dezavantaj constă din faptul că o listă de afişare nu poate fi modificată şi conţinutul său nu poate fi citit. Dacă aplicaţia necesită păstrarea datelor separat faţă de lista de afisare atunci va fi necesară memorie suplimentară.

II.11.2. Crearea şi executarea listelor de afişare

Funcţiile glNewList şi glEndList sunt folosite pentru delimitarea unei liste de afişare, care este executată prin apelul funcţiei glCallList având ca parametru identificatorul său. În fişierul exemplul9.c lista de afişare este creată în funcţia init. În funcţia display lista de afişare va fi apelată de 10 ori. Listele de afişare alocă memorie pentru a stoca comenzile şi valorile oricărei variabilele necesare. Funcţia glTranslatef din lista de afişare modifică poziţia următorului obiect ce va fi afişat. Apelul drawLine este de asemenea afectat de funcţia glTranslatef care o precede.

/* fişierul exemplul9.c */

#include “glut.h”#include <stdlib.h>

GLuint listName;

void init (void){ listName = glGenLists (1); glNewList (listName, GL_COMPILE); glColor3f (1.0, 0.0, 0.0); /* culoarea curentă roşu */ glBegin (GL_TRIANGLES); glVertex2f (0.0, 0.0); glVertex2f (1.0, 0.0);

Page 72: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glVertex2f (0.0, 1.0); glEnd (); glTranslatef (1.5, 0.0, 0.0); /* modificare poziţie */ glEndList (); glShadeModel (GL_FLAT);}void drawLine (void){ glBegin (GL_LINES); glVertex2f (0.0, 0.5); glVertex2f (15.0, 0.5); glEnd ();}

void display(void){ GLuint i;

glClear (GL_COLOR_BUFFER_BIT); glColor3f (0.0, 1.0, 0.0); /* culoarea curentă verde */ for (i = 0; i < 10; i++) /* afişare 10 triunghiuri */ glCallList (listName); drawLine (); glFlush ();}

void reshape(int w, int h){ glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) gluOrtho2D (0.0, 2.0, -0.5 * (GLfloat) h/(GLfloat) w, 1.5 * (GLfloat) h/(GLfloat) w); else gluOrtho2D (0.0, 2.0*(GLfloat) w/(GLfloat) h, -0.5, 1.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}

Page 73: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

void keyboard(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); }}

int main(int argc, char** argv){ glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(650, 50); glutCreateWindow(argv[0]); init (); glutReshapeFunc (reshape); glutKeyboardFunc (keyboard); glutDisplayFunc (display); glutMainLoop(); return 0;}

Observaţie: Dacă o listă de afişare conţine comenzi de transformare trebuie avut grijă care va fi efectul acestora în program mai târziu.

La un moment dat poate fi creată numai o singură lista de afişare. Cu alte cuvinte trebuie terminată crearea unei liste de afişare (glNewList şi glEndList) înainte de a crea o altă listă. Apelul funcţiei glEndList fără a fi apelat înainte funcţia glNewList va genera eroarea GL_INVALID_OPERATION.

II.11.2.1. Crearea unei liste de afişare

Fiecare listă de afişare este identificată printr-un index întreg. La crearea unei liste de afişare trebuie să se aibă grijă să nu se aleagă un index care este deja folosit, altfel se va şterge lista de afişare existentă. Pentru evitarea acestui lucru se va folosi funcţia glGenLists ce va genera unul sau mai mulţi indici nefolosiţi :

Page 74: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

GLuint glGenLists(GLsizei range);

Funcţia alocă un domeniu de range numere continue nefolosite ca indici pentru liste de afişare. Valoarea întoarsă de funcţie reprezintă indicele de început a blocului de indici nefolosiţi. Indicii returnaţi vor fi marcaţi ca folosiţi astfel ca apelurile ulterioare ale funcţiei glGenLists nu vor întoarce aceşti indici până nu vor fi şterşi. Funcţia întoarce 0 dacă nu este disponibil numarul de indici ceruţi sau dacă range este 0.

Exemplu: alocarea unui singur index; dacă el este liber va fi folosit pentru a crea o nouă listă de afişare :

listIndex = glGenLists(1);if (listIndex != 0) { glNewList(listIndex,GL_COMPILE); ... glEndList();}

Observaţie: Indexul 0 nu reprezintă un index valid pentru lista de afişare.

void glNewList (GLuint list, GLenum mode);

Funcţia specifică începerea unei liste de afişare. Funcţiile OpenGL care vor fi apelate

(până la întâlnirea funcţiei glEndList care marchează sfârşitul listei de afişare) sunt

stocate în lista de afişare, excepţie facând câteva funcţii OpenGL care nu pot fi stocate.

Aceste funcţii restricţionate sunt executate imediat în timpul creării listei de afişare.

- list este un întreg pozitiv diferit de 0 care identifică în mod unic lista de afişare.

- valorile posibile ale parametrului mode sunt GL_COMPILE şi

GL_COMPILE_AND_EXECUTE. Se foloseşte valoarea GL_COMPILE dacă

nu se doreşte executarea comenzilor OpenGL la plasarea lor în lista de afişare;

pentru execuţia imediată în momentul plasării în lista de afişare, pentru folosiri

ulterioare, se va secifica parametrul GL_COMPILE_AND_EXECUTE.

void glEndList (void);

Funcţia marchează sfârşitul unei liste de afişare.

Page 75: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

La crearea unei liste de afişare ea va fi stocată împreună cu contextul OenGL

curent. Astfel, dacă contextul va fi distrus, de asemenea lista de afişare va fi distrusă. În

unele sisteme este posibil ca listele de afişare să partajeze contexte multiple. În acest caz

lista de afişare va fi distrusă în momentul în care ultimul context din grup este distrus.

La crearea unei liste de afişare în ea vor fi stocate doar valorile expresiilor. Dacă

valorile dintr-un vector sunt modificate, valorile din lista de afişare nu vor fi modificate.

Exemplu

Se crează o listă de afişare ce conţine o comandă care setează culoarea curentă de afişare

negru

(0.0, 0.0, 0.0). Modificarea ulterioară a valorii vectorului color_vector în roşu (1.0, 0.0,

0.0) nu

are nici un efect asupra listei de afişare deoarece aceasta conţine valorile de la crearea sa.

GLfloat color_vector[3] = {0.0, 0.0, 0.0};glNewList(1, GL_COMPILE); glColor3fv(color_vector);glEndList();color_vector[0] = 1.0;

Într-o listă de afişare nu pot fi stocate şi executate orice comenzi OpenGL. În tabelul II.8 sunt prezentate comenzile care nu pot fi stocate într-o listă de afişare (apelul funcţiei glNewList în timpul creării unei liste de afişare generează eroare).

glColorPointer() glFlush() GlNormalPointer()glDeleteLists() glGenLists() GlPixelStore()glDisableClientState() glGet*() GlReadPixels()glEdgeFlagPointer() glIndexPointer() GlRenderMode()glEnableClientState() glInterleavedArrays() GlSelectBuffer()glFeedbackBuffer() glIsEnabled() GlTexCoordPointer()glFinish() glIsList() GlVertexPointer()

Tabelul II.8.

La folosirea unui sistem OpenGL în reţea, clientul poate rula pe o maşină şi server-ul pe alta. După crearea unei liste de afişare ea se va afla la server astfel că server-

Page 76: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

ul nu se poate baza pe client pentru nici o informaţie relativă la lista de afişare. Astfel, orice comandă care întoarce o valoare nu poate fi stocată într-o listă de afişare. În plus, comenzile care modifică starea clientului cum ar fi glPixelStore, glSelectBuffer şi comenzile de definire a vectorilor de vârfuri nu pot fi stocate într-o listă de afişare.

Operaţiile unor comenzi OpenGL depind de starea clientului. De exemplu, funcţiile de specificare a vârfurilor vectorilor (cum ar fi glVertexPointer, glColorPointer şi glInterleavedArrays) setează pointeri de stare ai clientului şi nu pot fi stocate într-o listă de afişare. Funcţiile glArrayElement, glDrawArrays şi glDrawElements transmit date către server pentru a construi primitive din elementele vectorilor. Astfel de operaţii pot fi stocate într-o listă de afişare.

Vectorul de vârfuri stocat în lista de afişare este obţinut prin dereferenţierea datei din pointeri nu prin stocarea pointerilor . Astfel, modificările datelor din vectorul de vârfuri nu va afecta definirea primitivei în lista de afişare.

Funcţii cum ar fi glFlush şi glFinish nu pot fi stocate într-o listă de afişare deoarece depind de starea clientului în momentul execuţiei.

II.11.2.2. Execuţia unei liste de afişare

După crearea unei liste de afişare aceasta poate fi executată prin apelul funcţiei glCallList. O listă de afişare poate fi executată de mai multe ori şi de asemenea o listă de afişare poate fi executată îmbinându-se cu apeluri în modul imediat.

void glCallList (GLuint list);

Functia execută lista de afişare specificată de parametrul list. Comenzile din lista de afişare sunt executate în ordinea în care au fost salvate ca şi cum ar fi executate fără a se folosi o lista de afişare. Dacă lista nu a fost definită nu se va întâmpla nimic.

Funcţia glCallList poate fi apelată din orice punct al programului atâta timp cât contextul OpenGL care accesează lista de afişare este activ (contextul care a fost activ la crearea listei de afişare sau un context din acelaşi grup partajat). O listă de afişare poate fi creată într-o funcţie şi executată în altă funcţie atâta timp cât indexul său o identifică în mod unic. De asemenea, contextul unei liste de afişăre nu poate fi salvat într-un fişier şi nici nu se poate crea o listă de afişare dintr-un fişier. În acest sens o listă de afişare este proiectată pentru a fi folosită temporar.

II.11.3. Liste de afişare ierarhice

Page 77: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

O listă de afişare ierarhică este o listă de afişare care execută o altă listă de afişare prin apelul funcţiei glCallList, între perechile de funcţii glNewList şi glEndList. O listă de afişare ierarhică este folositoare pentru un obiect alcătuit din componente, în mod special dacă aceste componente sunt folosite de mai multe ori.

Exemplu: o listă de afişare care desenează o bicicletă prin apelul altor liste de afişare pentru desenarea componentelor :

glNewList(listIndex,GL_COMPILE); glCallList(handlebars); glCallList(frame); glTranslatef(1.0,0.0,0.0); glCallList(wheel); glTranslatef(3.0,0.0,0.0); glCallList(wheel);glEndList();

Pentru evitarea recursivităţii infinite limita nivelului de imbricare al listelor de afişare este 64, dar această limită depinde de implementare. Pentru a determina limita specifică implementării OpenGL pe care se lucrează se apelează funcţia :

glGetIntegerv(GL_MAX_LIST_NESTING, GLint *data);

OpenGL permite crearea unei liste de afişare care să apeleze o altă listă de afişare care nu a fost încă creată. Nu va avea nici un efect dacă prima listă o apelează pe cea de a doua care încă nu a fost definită.

Exemplu : listă de afişare ierarhică

glNewList(1,GL_COMPILE); glVertex3f(v1); glEndList();glNewList(2,GL_COMPILE); glVertex3f(v2); glEndList();glNewList(3,GL_COMPILE); glVertex3f(v3); glEndList();

Page 78: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glNewList(4,GL_COMPILE); glBegin(GL_POLYGON); glCallList(1); glCallList(2); glCallList(3); glEnd();glEndList();

Pentru afişarea poligonului se apelează lista de afişare 4. Pentru a edita un vârf este necesar să se creeze din nou lista de afişare corespunzătoare vârfului respectiv. Deoarece un index identifică în mod unic lista de afişare, crearea unei alte liste cu acelaşi index o va şterge în mod automat pe cea existentă. Trebuie reţinut că această metodă nu foloseşte în mod optim memoria şi nu îmbunătăţeşte performanţele, dar este folositoare în unele cazuri.

II.11.4. Gestiunea listelor de afişare cu indici

Pentru a obţine un indice nefolosit care să identifice o nouă listă de afişare se poate folosi funcţia glGenLists. Dacă nu se doreşte folosirea acestei funcţii atunci se poate folosi glIsList pentru a determina dacă un anumit index este folosit.

GLboolean glIsList(GLuint list);

Funcţia întoarce GL_TRUE dacă indexul specificat de parametrul list este deja folosit pentru o listă de afişare şi GL_FALSE în caz contrar.

Pentru a şterge în mod explicit o listă de afişare sau un domeniu continuu de liste se foloseşte funcţia glDeleteLists. Folosirea funcţiei glDeleteLists eliberează indicii corespunzători listelor şterse să fie disponibili din nou.

void glDeleteLists(GLuint list, GLsizei range);

Funcţia şterge range liste de afişare începând de la indexul specificat de list. Este ignorată încercarea de a se şterge o listă de afişare care nu a fost creată.

II.11.5. Execuţia listelor de afişare multiple

Page 79: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

OpenGL furnizează un mecanism eficient de a executa succesiv liste de afişare. Acest mecanism necesită introducerea indicilor listelor de afişare într-un vector si apoi apelarea funcţiei glCallLists. O utilizare pentru acest mecanism este acela de a crea un font şi fiecare indice de listă de afişare să corespundă valorii ASCII a caracterului din font. Pentru a avea mai multe fonturi este necesară stabilirea unui index iniţial diferit pentru fiecare font. Acest index iniţial poate fi specificat prin apelarea funcţiei glListBase înainte de a apela glCallLists.

void glListBase(GLuint base);

Funcţia specifică offset-ul care este adunat indicilor listelor de afişare în apelul funcţiei glCallLists pentru a obţine indicii listelor de afişare finali. Valoarea implicită a parametrului base este 0. Parametrul base nu are nici un efect asupra apelului glCallList, care execută o singură listă de afişare, sau asupra funcţiei glNewList.

void glCallLists(GLsizei n, GLenum type, const GLvoid *lists);

Functia execută n liste de afişare. Indicii listelor care vor fi executate vor fi calculaţi prin adunarea offset-ului indicat de baza curentă a listei de afişare (specificat cu ajutorul funcţiei glListBase la valorile întregi indicate de parametrul lists. Parametrul type specifică tipul valorilor din lists. El poate avea una din valorile GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT sau GL_FLOAT, adică ceea ce indică lists poate fi tratată ca un vector de bytes, unsigned bytes, shorts, unsigned shorts, integers, unsigned integers, sau floats. De asemenea parametrul type poate avea una din valorile GL_2_BYTES, GL_3_BYTES sau GL_4_BYTES caz în care succesiuni de 2, 3 sau 4 octeţi vor fi citiţi din lists şi apoi sunt deplasaţi şi adunaţi octet cu octet pentru a calcula offset-ul listei de afişare. Pentru aceasta este folosit următorul algoritm (byte[0] reprezintă începutul secvenţei de octeţi).

/* b = 2, 3 sau 4; octeţii sunt numerotaţi în vector 0,1,2,3 */ offset = 0; for (i = 0; i < b; i++) { offset = offset << 8; offset += byte[i]; } index = offset + listbase;

Page 80: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Exemplu Definirea listelor de afişare multiple: afişarea caracterelor dintr-un set de caractere vectorial

void initStrokedFont(void)/* setează indicii listelor de afişare pentru fiecare caracter corespunzător valorii lor ASCII */{ GLuint base;

base = glGenLists(128); glListBase(base);

glNewList(base+'A', GL_COMPILE); drawLetter(Adata); glEndList(); glNewList(base+'E', GL_COMPILE); drawLetter(Edata); glEndList(); glNewList(base+'P', GL_COMPILE); drawLetter(Pdata); glEndList(); glNewList(base+'R', GL_COMPILE); drawLetter(Rdata); glEndList(); glNewList(base+'S', GL_COMPILE); drawLetter(Sdata); glEndList(); glNewList(base+' ', GL_COMPILE); /* spaţiu */ glTranslatef(8.0, 0.0, 0.0); glEndList();}

Funcţia glGenLists alocă 128 de indici continui pentru listele de afişare. Primul indice alocat devine baza listei de afişare. Pentru fiecare caracter va fi creată câte o listă de afişare; fiecare index al listei de afişare este suma dintre indicele de bază şi valoarea ASCII a literei. În acest exemplu sunt create numai câteva litere şi caracterul ‘ ‘. După crearea listelor de afişare poate fi apelata funcţia glCallLists pentru a le executa.

ExempluApelul functiei printStrokedString având ca parametru un caracter :

void printStrokedString(GLbyte *s){ GLint len = strlen(s);

Page 81: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

glCallLists(len, GL_BYTE, s);}

II.11.6. Gestiunea variabilelor de stare folosind liste de afişare

O listă de afişare poate conţine apeluri care să modifice valorile variabilelor de stare OpenGL. Aceste valori se modifică la execuţia listei de afişare (ca şi în modul imediat de execuţie al comenzilor) şi modificările se păstrează şi după execuţia completă a listei de afişare.

ExempluModificările culorii curente şi a matricii curente făcute în timpul execuţiei listei de afişare rămân vizibile şi după executarea sa:

glNewList(listIndex,GL_COMPILE); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POLYGON); glVertex2f(0.0,0.0); glVertex2f(1.0,0.0); glVertex2f(0.0,1.0); glEnd(); glTranslatef(1.5,0.0,0.0);glEndList();

Dacă se va apela următoarea secvenţă de cod, segmentul de dreaptă desenat după lista de afişare va avea culoarea roşie (culoarea curentă) şi va fi translatat cu (1.5, 0.0, 0.0):

glCallList(listIndex);glBegin(GL_LINES); glVertex2f(2.0,-1.0); glVertex2f(1.0,0.0);glEnd();

Uneori este necesar ca modificările stării să fie păstrate, dar alteori după execuţia unei liste de afişare se doreşte să se revină la starea anterioară. Într-o listă de afişare nu poate fi folosită funcţia glGet*, aşa că trebuie folosit un alt mod de a interoga şi stoca valorile variabilelor de stare. În acest scop poate fi folosită funcţia glPushAttrib pentru a salva un grup de variabile de stare şi glPopAttrib pentru a reface variabilele.

Page 82: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Exemplu Refacerea variabilelor de stare din interiorul unei liste de afişare

glNewList(listIndex,GL_COMPILE); glPushMatrix(); glPushAttrib(GL_CURRENT_BIT); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POLYGON); glVertex2f(0.0,0.0); glVertex2f(1.0,0.0); glVertex2f(0.0,1.0); glEnd();

glTranslatef(1.5,0.0,0.0); glPopAttrib(); glPopMatrix();glEndList();

ExempluDacă se foloseşte lista de afişare de mai sus atunci se va desena un segment de dreaptă de culoare verde şi netranslatat:

void display(void){ GLint i; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 1.0, 0.0); /* setează culoarea curentă verde */ for (i = 0; i < 10; i++) glCallList(listIndex); /* lista de afişare apelată de 10 ori*/ drawLine(); /* unde şi cum apare această linie? */ glFlush();}

II.11.7. Încapsularea schimbărilor de mod

Listele de afişare pot fi folosite pentru a organiza şi stoca grupuri de comenzi, pentru a modifica diferite moduri sau a seta diferiţi parametri. Când se doreşte comutarea de la un grup de setări la un altul folosirea listelor de afişare poate fi mai eficientă decât apelarea directă.

Page 83: PARTEA II - Cursuri Automatica si Calculatoareandrei.clubcisco.ro/3egc/lab/Aplicatii OpenGL folosing... · Web viewProgramatorul poate încărca una dintre aceste matrici cu o matrice

Listele de afişare pot fi mai eficiente decât modul imediat pentru comutarea între diferite setări ale surselor de lumină, modelelor de iluminare şi parametrilor de material. De asemenea, listele de afişare se pot folosi şi pentru generarea liniilor cu şablon, precum şi pentru ecuaţiile planului de decupare. În general, execuţia listelor de afişare este cel puţin tot atât de rapidă ca şi apelul direct dar în cazul folosirii listelor de afişare este introdus un overhead.

ExempluFolosirea listelor de afişare pentru a comuta între trei şabloane diferite de linii. La început se apelează funcţia glGenLists pentru a aloca o listă de afişare pentru fiecare şablon. Apoi se foloseşte funcţia glCallList pentru a comuta între un şablon şi altul.

GLuint offset;offset = glGenLists(3);glNewList (offset, GL_COMPILE); glDisable (GL_LINE_STIPPLE);glEndList ();glNewList (offset+1, GL_COMPILE); glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0x0F0F);glEndList ();glNewList (offset+2, GL_COMPILE); glEnable (GL_LINE_STIPPLE); glLineStipple (1, 0x1111);glEndList ();#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \ glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();glCallList (offset);drawOneLine (50.0, 125.0, 350.0, 125.0);glCallList (offset+1);drawOneLine (50.0, 100.0, 350.0, 100.0);glCallList (offset+2);drawOneLine (50.0, 75.0, 350.0, 75.0);