Você está na página 1de 84

PARTEA a II-a : Implementarea de aplicaii OpenGL

folosind biblioteca GLUT

OpenGL este o interfa de programare format din circa 150 de funcii care pot fi
folosite pentru modelarea si vizualizarea scenelor 3D. Dou aspecte importante au
determinat creterea continu a popularitii sale :
Funciile OpenGL sunt independente de platforma hardware-software

OpenGL ofer funcii de sintez de nivel nalt, care sunt realizate fie software fie

prin echipamente grafice specializate

In prezent exist implementri 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 aplicaiilor. Deoarece OpenGL nu conine funcii de
gestiune a ferestrelor de afiare i interaciune cu utilizatorul, implementrile OpenGL
sunt completate cu astfel de funcii. O asemenea implementare extins este i GLUT
(OpenGL Utilities Toolkit), la a crei utilizare ne referim n aceast parte a ndrumarului.

Dintre funciile de sintez de nivel nalt oferite de OpenGL menionm:


Maparea texturilor: aplicarea de imagini pe suprafee 3D
Eliminarea automat din imagini a prilor 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 innd cont de proprietile materialelor ;
Transformarea din spaiul 3D utilizator n spaiul 2D ecran prin specificarea
matricelor de transformare, posibilitatea de a modifica poziia i dimensiunea
obiectelor n spaiul 3D utilizator.
Exista de asemenea funcii care permit generarea simpl a unor obiecte solide, curbe i
suprafee de form liber precum i funcii de lucru cu imagini.

II.1. Convenii de numire a funciilor, constantelor


i tipurilor de date OpenGL

Numele funciilor OpenGL conin prefixul gl (de exemplu glClearColor) iar


constantele prefixul GL_ (de exemplu GL_COLOR_BUFFER_BIT).
Declaraiile funciilor OpenGL sunt de forma:
void glFunction{nr}{b s i f d}{v}(argumente);
nr - reprezint numrul de argumente ale funciei
b sau s sau i sau f sau d sau v - specific tipul argumentelor funciei, iar v dac
argumentele funciei 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 vrfurilor 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);
Funcia glColor3f() seteaz culoarea de desenare i are 3 parametri ce corespund
componentelor rou, verde i albastru, iar funcia glColor3fv() seteaz culoarea de
desenare avnd ca parametru un vector ce conine componentele culorii.

Tipuri de date OpenGL


Pentru un acelai tip de date n C, diferitele implementri 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 definete i tipul GLvoid. Acesta este cel mai adesea folosit n
apelurile de funcii OpenGL care accept pointeri la vectori de valori.

Tipul definit n
Sufix Tipul de date Corespondentul n C
OpenGL
b 8-bit integer signed char GLbyte
s 16-bit integer Short GLshort
i 32-bit integer int sau long GLint, GLsizei
f 32-bit floating-point Float GLfloat, GLclampf
d 64-bit floating-point Double GLdouble, GLclampd
ub 8-bitunsigned integer unsigned char GLubyte, GLboolean
us 16-bit unsigned integer unsigned short GLushort
unsigned int sau unsigned GLuint,GLenum,
ui 32-bit unsigned integer
long GLbitfield
Tabelul II.1. Tipuri de date OpenGL

II.2. Funcii GLUT de realizare a interfeei cu utilizatorul

II.2.1. Gestiunea ferestrelor

Iniializare fereastr

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

Funcia glutInit() iniializeaz variabilele interne ale pachetului de funcii GLUT i


proceseaz argumentele din linia de comand. Ea trebuie sa fie apelat naintea oricarei
alte comenzi GLUT. Parametrii funciei au aceeai semificaie ca i parametri funciei
main.

Iniializare mod de afiare

void glutInitDisplayMode(unsigned int mode);

unde mode specific modul de afiare:


folosirea modelului RGBA (culoarea se specific prin componentele sale rou,
verde, albastru i transparena sau opacitatea) sau a modelului de culoare bazat pe
indeci de culoare. n general se recomand folosirea modelului RGBA.
folosirea unei ferestre cu un singur buffer sau cu buffer dublu, pentru realizarea
animaiei.
folosirea bufferului de adncime pentru algoritmul z-buffer.

De exemplu, dac se dorete crearea unei ferestre cu buffer dublu ce folosete un model
de culoare RGBA i buffer pentru algoritmul z-buffer, se va apela:

glutInitDisplayMode(GLUT_DOUBLE |GLUT_RGB |GLUT_DEPTH;


Iniializare poziie fereastr

void glutInitWindowPosition(int x, int y) ;


Funcia glutInitWindowPosition specific colul stnga sus al ferestrei n coordonate
relative la colul stnga sus al ecranului.

Iniializare dimensiune fereastr

void glutInitWindowSize(int width, int height) ;


Funcia glutInitWindowSize specific dimensiunea n pixeli a ferestrei : limea (width)
i nlimea (height).

Creare fereastr

int glutCreateWindow(char *string) ;


Funcia glutCreateWindow creeaz o fereastra cu un context OpenGL. Ea intoarce un
identificator unic pentru fereastra nou creat. Fereastra nu va fi afiat nainte de apelarea
funciei glutMainLoop. Valoarea ntoars de funcie reprezint identificatorul ferestrei,
care este unic.

Creare ferestre copil

int glutCreateSubWindow(int win, int x, int y, int width, int


height);
Funcia creeaz o fereastr avnd ca printe fereastra identificat de win, unde :
- win - reprezint identificatorul ferestrei printe;
- (x, y) - reprezint colul stnga sus al ferestrei (x i y sunt exprimate n pixeli i
sunt relative la originea ferestrei printe);
- width - reprezint limea ferestrei (exprimat n pixeli);
- height - reprezint nlimea ferestrei (exprimat n pixeli);
Fereastra nou creat devine fereastra curent. Funcia ntoarce identificatorul ferestrei
create.

Distrugere fereastr

void glutDestroyWindow(int win) ;


Funcia 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) ;


Funcia selecteaz fereastra curent ca fiind cea identificat de parametrul win.

Aflarea ferestrei curente


int glutGetWindow(void) ;
Funcia ntoarce identificatorul ferestrei curente. Funcia ntoarce 0 dac nu exist nici o
fereastr curent sau fereastra curent a fost distrus.

Selectarea cursorului asociat ferestrei curente

void glutSetCursor(int cursor) ;


Funcia modific cursorul asociat ferestrei curente transformndu-l n cursorul specificat
de parametrul cursor, care poate avea una din urmtoarele 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 (folosete cursorul asociat ferestrei printe).

II.2. 2. Gestiunea meniurilor

Crearea meniurilor
Meniurile 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 aduga alte opiuni i nu i se pot
terge din opiuni.
int glutCreateMenu(void (*func)(int value)) ;
Funcia creeaz un nou meniu pop-up i ntoarce identificatorul su
(ntreg unic). Identificatorii meniurilor ncep de la valoarea 1. Valorile
lor sunt separate de identificatorii ferestrelor.
- parametrul func specific o funcie callback a aplicaiei, care va
fi apelat de biblioteca GLUT la selectarea unei opiuni din
meniu. Parametrul transmis funciei callback (value) specific
opiunea de meniu selectat.

Adugarea unei opiuni ntr-un meniu


void glutAddMenuEntry(char* name, int value) ;
Funcia adaug o nou opiune meniului curent. Opiunea este adugat la sfritul listei
de articole a meniului.
- name - specific textul prin care va fi reprezentat opiunea introdus
- value - reprezint valoarea transmis funciei callback asociat meniului la
selectarea opiunii respective

Adugarea unui sbmeniu ntr-un meniu


void glutAddSubMenu(char* name, int menu) ;

Funcia adaug un submeniu la sfritul meniului curent.


- name - reprezint numele submeniului introdus (textul prin care va fi afiat n
meniu)
- menu - reprezint identificatorul submeniului.

tergerea unei opiuni sau a unui submeniu

void glutRemoveMenuItem(int entry) ;


Funcia terge opiunea sau submeniul identificat de parametrul entry. Opiunile din
meniu de sub opiunea tears sunt renumerotate.

Distrugerea unui meniu


void glutDestroyWindow(int menu) ;
Funcia 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) ;
Funcia seteaz meniul curent ca fiind cel identificat de parametrul menu.

Aflarea meniului curent


int glutGetMenu(void) ;
Funcia ntoarce identificatorul meniului curent. Funcia ntoarce 0 dac nu exist meniu
curent sau meniul curent a fost distrus.

Ataare / detaare meniu unui buton al mouse-ului


void glutAttachMenu(int button) ;
void glutDetachMenu(int button) ;
Funcia glutAttachMenu ataeaz meniul curent butonului mouse-ului specificat de
parametrul button. Funcia glutDetachMenu detaeaz butonul asociat meniului curent.
Prin ataarea unui buton al mouse-ului meniului curent, meniul va fi derulat la apsarea
butonului respectiv n poziia curent a cursorului.

II.2.3. Controlul evenimentelor de intrare

In categoria evenimentelor de intrare sunt incluse evenimentele provocate de


apsarea unei taste sau a unuia dintre butoanele mouse-ului, de deplasarea mouse-ului i
de redimensionarea ferestrei de afiare de ctre utilizator. Pentru fiecare dintre aceste
tipuri de evenimente programatorul trebuie s specifice o funcie callback care va fi
apelat la producerea unui eveniment de tipul respectiv. Funciile GLUT menionate n
continuare servesc acestui scop.

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

Parametrul funciei glutReshapeFunc indic funcia callback care va fi apelat la


redimensionarea ferestrei. Parametrii width i height transmii funciei callback
reprezint noile valori ale limii i nlimii ferestrei.

Apsarea / eliberarea unei taste


void glutKeyboardFunc(void (*func)(unsigned char key, int x, int
y)) ;
Parametrul func reprezint funcia callback care va fi apelat la apsarea / eliberarea unei
taste care genereaz un caracter ASCII. Parametrul key al funciei callback reprezint
valoarea ASCII. Parametrii x i y indic poziia mouse-ului la apsarea tastei (poziie
specificat n coordonate fereastr).

Apsarea / eliberarea unui buton al mouse-ului


void glutMouseFunc(void (*func)(int button, int state, int x, int
y)) ;
Parametrul func specific funcia callback care va fi apelat la apsarea / eliberarea unui
buton al mouseului.Parametrul button al funciei callback poate avea una din urmtoarele
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 apsat sau eliberat. Parametrii x i y reprezint
poziia mouse-ului la apariia evenimentului. Valorile x i y sunt relative la colul stnga
sus al ferestrei aplicaiei.

Deplasarea mouse-ului
void glutMotionFunc(void (*func)(int x, int y)) ;
Se specific funcia callback care va fi apelat la deplasarea mouse-ului n timp ce un
buton este apsat. Parametrii x i y reprezint poziia mouse-ului n momentul apsrii
tastei. Valorile x i y sunt relative la colul stnga sul al ferestrei aplicaie.

II.2.4. Afisarea textelor

Pentru afiarea unui caracter se apeleaza functia glutStrokeCharacter :


void glutStrokeCharacter(void *font, int character);
- font specific fontul vectorial folosit, care poate avea una din urmtoarele valori:
GLUT_STROKE_ROMAN
GLUT_STROKE_MONO_ROMAN
- character specific caracterul ce va fi afiat

Exemplu
Funcia output prezentata mai jos realizeaza afiarea unui text cu format, incepand dintr-
o pozitie specificata a ferestrei curente.

void output(GLfloat x, GLfloat y, char *format,...)


{
va_list args;
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. Execuia aplicaiei.

Funcia de afiare callback


void glutDisplayFunc(void (*func)(void)) ;
Parametrul funciei glutDisplayFunc specific funcia callback a aplicaiei care va fi
apelat de GLUT pentru afiarea coninutului iniial al ferestrei aplicaiei precum i ori de
cte ori trebuie refcut coninutul ferestrei ca urmare a cererii explicite a aplicaiei, prin
apelul funciei glutPostRedisplay().

Bucla de execuie a aplicaiei


void glutMainLoop(void) ;
Aceasta este ultima funcie care trebuie apelat in funcia main a aplicaiei. Ea conine
bucla de execuie (infinit) a aplicaiei n care aplicaia ateapt evenimente. Orice
eveniment este tratat prin rutina callback specificat anterior n funcia main, prin apelul
funciei GLUT specifice tipului de eveniment.

Execuia unui proces n background


void glutIdleFunc(void (*func)(void)) ;
Parametrul transmis funciei glutIdleFunc este o funcie callback care va fi executat in
perioadele n care nu exist evenimente n curs de tratare sau n ateptarea tratrii -
funcia idle. Dac argumentul funciei glutIdleFunc este NULL atunci funcia idle
existent este dezactivat.
Terminarea afirii
O aplicaie GLUT poate rula pe mai multe maini. De exemplu, s presupunem
c programul principal este rulat pe o main client i rezultatul procesrii (imaginea
afiat) apare pe un terminal sau pe o staie de lucru (server), care este conectat n reea.
De obicei clientul adun o colecie de comenzi ntr-un singur pachet nainte de a-l trimite
n reea. Codul de reea de la client nu permite detectarea momentului n care programul
grafic a terminat desenarea unui cadru sau a unei scene 3D. Astfel, clientul poate atepta
la infint comenzi de desenare ca s completeze un pachet. Pentru a fora clientul s
trimit pachetul chiar dac nu este plin se folosete funcia 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 funcioneze corect att
n reea ct i pe o singur maina, se va include apelul functieie glFlush la sfritul
fiecrei scene. Funcia glFlush nu ateapt terminarea desenrii, ci doar foreaz
nceperea execuiei desenrii. Dac folosirea funciei glFlush nu este suficient pentru o
aplicaie, atunci se va folosi i funcia glFinish. Aceasta funcioneaz ca i glFlush dar
ateapt rspuns de notificare de la echipamentul grafic de indicare a terminri desenarii.
glFinish se va folosi pentru sincronizarea task-urilor.

void glFinish(void);

Observaie: folosirea excesiv a lui glFinish poate reduce performanele aplicaiei mai
ales dac se lucreaz n reea. Dac este suficient folosirea funciei glFlush
se va folosi aceasta n locul funciei glFinish.

II.4. Crearea unei aplicaii OpenGL folosind GLUT

Pentru a crea executabilul corespunztor unei aplicaii OpenGL se va deschide


fiierul 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 fiierul
surs anterior deschis. Pentru editarea legturilor trebuie adugate bibliotecile
opengl32.lib, glu32.lib i glut32.lib. Setrile corespunztoare pentru aceast operaie
sunt urmtoarele:
Se selecteaz opiunea Settings din meniul Project.
In cutia de dialog afiat se selecteaz Link
In zona de editare Object/library modules se adaug cele trei biblioteci
de mai sus.
Rularea unui program OpenGL necesit de asemenea urmtoarele biblioteci cu legare
dinamic : opengl32.dll, glu32.dll, glut32.dll.

In fiierele surs se va include fiierul header glut.h.

Exemplu 1
Programul din fiierul exemplu11.c afieaz un dreptunghi centrat n fereastr.

/* fiierul exemplul1.c */

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

void display(void)
{
/* terge toi pixelii */
glClear (GL_COLOR_BUFFER_BIT);

/* afieaz un dreptunghi cu interiorul alb avand colurile 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);

/* iniializeaz transformarea de vizualizare */


glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
/*
* declar dimensiunea iniial a ferestrei, poziia i
modul de afiare (buffer singular i RGBA).
* Deschide o fereastr cu titlul "hello".
* Apeleaz rutinele de iniializare.
* nregistreaz funcia 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 fiierul exemplu2.c trateaz evenimentele de la mouse. Se afieaz un
dreptunghi centrat n fereastra de afiare. La apsarea butonului stnga al mouse-ul
dreptunghiul va fi rotit pn la apsarea butonului drept al mouse-ului.

/* fiierul 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);
}
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)
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. Afiarea obiectelor 3D predefinite

GLUT conine funcii pentru afiarea urmtoarelor obiecte 3D:

con icosaedru teapot


cub octaedru tetraedru
dodecaedru sfera tor

Aceste obiecte pot fi afiate prin familii de curbe sau ca obiecte solide.

Exemplu: funcii de desenare cub, sfer si tor prin dou familii de curbe i ca solide.
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 funcii 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);
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 modificri asupra unui obiect complex poate apare
efectul de plpire a imaginii. Pentru evitarea acestui efect se asociaz ferestrei
aplicaiei un buffer dublu. Astfel, ntr-un buffer se pstreaz imaginea nemodificat
(imaginea ce este afiat pe ecran), iar n cel de-al doilea se construiete imaginea
modificat. n momentul n care s-a terminat construirea imaginii modificate se
interschimb buffer-ele (lucrul cu dou buffere este asemnator lucrului cu mai multe
pagini video n DOS). Pentru interschimbarea bufferelor se folosete funcia:
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. Ct 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 execuia secvenei din exemplu, obiectele A i B vor fi desenate cu rou 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 funcia glColor3f :

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


Parametrii funciei specific componentele rou, 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); /* rou */
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 modaliti 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.

Exemplu
Se afieaz toi 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 urmtoare terge
ntreaga fereastr folosind culoarea curent de tergere. Parametrul funciei glClear
indic bufferul care va fi ters. De obicei se seteaz o singur dat culoarea de tergere la
nceputul aplicaiei i apoi se apeleaz funcia de tergere de cte 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);


Funcia seteaz bufferul indicat prin parametrul mask la valoarea specificat. Valorile
posibile ale parametrului mask sunt prezentate n tabelul II.2:
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 adncime
Tabelul II.2.

II.7. Definirea primitivelor geometrice

Orice primitiv geometric este definit printr-o secven de puncte 3D numite


vrfuri. Fiecare vrf este reprezentat intern prin cele 3 coordonate (x, y, z). Pentru
vrfurile specificate de programator n 2D, sistemul asigneaz coordonatei z valoarea 0.
n OpenGL, linia nseamn segment de dreapt.
Poligoanele sunt suprafee mrginite de un contur poligonal nchis format din
segmente de dreapt. Segmentele de dreapt sunt specificate prin vrfurile capetelor
segmentelor. OpenGL impune cteva restricii 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 vrfurile sunt ntotdeauna puncte 3D, punctele ce formeaz


frontiera unui poligon nu este necesar sa fie coplanare. Dac vrfurile unui poligon nu
sunt coplanare, atunci dup rotaii, modificarea poziiei observatorului i proiecia 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.
Figura II.2

II.7.1. Definirea vrfurilor

n OpenGL toate primitivele geometrice sunt definite prin mulimi ordonate de


vrfuri. Pentru a specifica un vrf se folosete funcia:

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

Funcia poate avea:


2 parametri vrful va fi specificat n 2D prin coordonatele sale (x, y)
3 parametri vrful va fi specificat n 3D prin coordonatele sale (x, y, z)
4 parametri vrful va fi specificat n 3D prin coordonatele sale omogene (x, y,
z, w)
i n acest caz TYPE reprezint tipul coordonatelor vrfului (s - short, i int , f - float, d -
double). Apelul funciei glVertex trebuie s fie fcut ntre perechea de comenzi glBegin
i glEnd.

Exemplu
Modaliti de definire a vrfurilor:

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 mulime de puncte, o linie sau un poligon pornind de la vrfuri,


fiecare set de vrfuri trebuie s fie apelat ntre comenzile glBegin i glEnd. Argumentul
funciei glBegin determin tipul primitivei ce va fi afiat :
void glBegin(GLenum mode);
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.

GL_LINES specific afiarea mai multor segmente de dreapt, cte unul pentru fiecare
pereche de vrfuri. Vrfurile sunt conectate n ordinea v0 v1, v2 v3, v4 v5 etc. Dac
este dat un numr impar de vrfuri, ultimul vrf este ignorat.
GL_LINE_STRIP specific o polilinie de la vrful v0 la varful vn, conectnd vrfurile
n ordinea dat;
GL_LINE_LOOP specific un poligon, vrfurile fiind unite n ordinea dat; ultimul
vrf este conectat cu primul.
GL_POLYGON specific un poligon de la vrful v0 la vrful vn-1 (n trebuie s fie cel
puin 3). Poligonul trebuie s fie un poligon convex simplu. Pentru poligoanele concave
rezultatul afirii este nedefinit. De asemenea, vrfurile trebuie s fie situate n acelai
plan;
GL_QUADS specific o serie de patrulatere separate. Primul patrulater este desenat
folosind vrfurile v0, v1, v2 i v3, urmtorul v4, v5, v6 i v7 etc. Dac n nu este multiplu
de 4 vrfurile 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 vrfurile v0, v1, v2 i v3, Urmtorul refolosete ultimele dou vrfuri
v2, v3 i folosete urmtoarele dou n ordinea v5 i v6. Fiecare patrulater folosete
ultimele dou vrfuri de la patrulaterul anterior. n fiecare caz n trebuie s fie cel puin 4
i multiplu de 2;
GL_TRIANGLE_STRIP specific o serie de triunghiuri conectate. Primul triunghi
folosete vrfurile v0, v1 i v2. Urmtorul v2, v1 i v3, urmtorul 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 vrf comun,
vrful v0. Primul triunghi este desenat folosind vrfurile v0, v1 i v2, urmtorul folosete
v0, v2 i v3, urmtorul v0, v3 i v4 etc.

Funcia glEnd marcheaz sfritul listei de vrfuri.

void glEnd(void);

Exemplu:
Primitiva redat n figura II.4 este specificat prin urmtoarea secven :
glBegin(GL_POLYGON);
glVertex2f(0.0, 0.0);
glVertex2f(0.0, 3.0);
glVertex2f(3.0, 3.0);
glVertex2f(4.0, 1.5);
glVertex2f(3.0, 0.0);
glEnd();

Dac se folosete GL_POINTS n loc de GL_POLYGON, primitiva va fi format din 5


puncte.

Figura II.4

Restricii de folosire pentru glBegin i glEnd

Coordonatele vrfurilor se specific folosind funcia glVertex*. Pentru un vrf pot


fi furnizate informaii suplimentare, cum ar fi: culoarea, vectorul normal, etc. In tabelul
II.3 sunt specificate funciile care pot fi apelate ntre glBegin i glEnd :

Funcia Comentarii
glVertex* Stabilete coordonatele vrfului
Stabilete culoarea curent a
glColor*
vrfului
Seteaz indexul curent de
glIndex*
culoare
glNormal* Stabileste vectorul normal
glEvalCoord* Genereaz coordonatele
glCallList,
Execut lista (listele) de afiare
glCallLists
Seteaz coordonatele de
glTexCoord*
texturare
controloleaz desenarea
glEdgeFlag*
muchiilor
Stabilete proprietile de
glMaterial*
material
Tabelul II.3. Funcii care pot fi apelate ntre glBegin i glEnd
Dac ntre apelurile funciilor glBegin i glEnd apar apelurile altor funcii GLUT
se va genera cod de eroare. Pot apare ns instruciuni ale limbajului de programare n
care este implementat aplicaia.

Exemplu
Desenarea 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 vrf se calculeaz un unghi i se apeleaz functiile sin i cos. n plus apare
i overhead-ul introdus de bucl. Dac cercul va fi afiat de mai multe ori, pentru a
mbunti timpul de execuie, se vor calcula o singur dat coordonatele vrfurilor i se
vor salva ntr-un vector sau se va crea o list de afiare (display list).
ntre comenzile glBegin i glEnd vrfurile sunt generate doar la ntlnirea
apelului glVertex*. n momentul apelului funciei glVertex*, sistemul asociaz vrfului
respectiv culoarea curent, coordonatele de texturare, vectorul normal etc.

Exemplu
Primul vrf este desenat cu rou, 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); /* rou */
glVertex(...);
glColor3f(1.0, 1.0, 0.0); /* galben */
glColor3f(0.0, 0.0, 1.0); /* albastru */
glVertex(...);
glVertex(...);
glEnd();

II.7.3. Dreptunghiuri n planul XOY

OpenGL furnizeaz o funcie 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);
Funcia afieaz dreptunghiul definit de colurile (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, colurile dreptunghiului sunt specificate prin doi vectori, fiecare coninnd o
pereche (x, y). TYPE reprezint tipul coordonatelor colurilor dreptunghiului (s - GLshort,
i GLint , f - GLfloat, d - GLdouble).

II.8. Specificarea atributelor de afiare 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 lime egal cu un pixel, iar poligoanele sunt
afiate avnd conturul cu linie continu i interior gol.

II.8.1. Dimensiunea punctelor

Pentru a specifica dimensiunea unui punct afiat se folosete funcia glPointSize.


void glPointSize(GLfloat size);
Funcia seteaz limea n pixeli a punctelor ce vor fi afiate. 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 avnd diferite limi, ca linii
continue sau ca linii punctate sau ntrerupte.

II.8.2.1.Limea liniilor

void glLineWidth(GLfloat width);


Funcia seteaz limea n pixeli a liniilor ce vor fi afiate; width trebuie s fie mai
mare ca 0.0, iar valoarea implicit este 1.0.

II.8.2.2. Tipul liniilor

Pentru afiarea liniilor punctate sau ntrerupte se va apela funcia glLineStipple,


care definete ablonul de generare a liniilor, apoi se va activa folosirea liniilor punctate
sau ntrerupte folosind funcia glEnable:

void glLineStipple(GLint factor, GLushort pattern);


Funcia 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 urmtorul bit din ablon s fie folosit. Are valori n
intervalul [1, 255]
- pattern - reprezint o succesiune de 16 bii care va fi repetat pentru a genera
o linie cu ablon. Dac bit = 1 se face afiarea, dac bit = 0 nu se afieaz;
ordinea de parcurgerea a biilor n ablon este de la bitul cel mai puin
semnificativ ctre bitul cel mai semnificativ. ablonul poate fi multiplicat prin
folosirea parametrului factor, care multiplic fiecare succesiune de bii cu
valori egale (1 sau 0) din ablon cu valoarea factor. Astfel, dac n sablon apar
3 bii consecutivi cu valoarea 1 i factor = 2, se vor genera 6 bii cu valoarea
1.
In figura II.5 sunt exemplificate diferite tipuri de linii obinute prin alegerea valorilor
pattern i factor.
Figura II.5

Generarea de linii cu ablon se va activa apelnd funcia glEnable cu parametrul


GL_LINE_STIPPLE i va fi dezactivat prin apelul funciei glDisable cu acelai
argument.
void glEnable(Glenum cap);

void glDisable(GLenum cap);


cap este o constant simbolic ce specific o capabilitate OpenGL. Ea poate avea una
din urmtoarele valori:
GL_CULL_FACE - activeaz / dezactiveaz eliminarea prilor nevizibile ale
obiectelor folosind metoda Back Face Culling.
GL_DEPTH_TEST activeaz / dezactiveaz calcularea valorilor buffer-ului de
adncime.
GL_LIGHTi - activeaz / dezactiveaz luarea n calcul a sursei de lumin i la
calculul de iluminare.
GL_LIGHTING activeaz / dezactiveaz calcularea culorii corespunztoare
fiecrui vrf.
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 afiarea 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 puin semnificativ ctre cel mai semnificativ). Dac factor = 2, ablonul va
fi multiplicat: 6 pixeli vizibili, 10 invizibili, 12 vizibili i 4 invizibili. Figura urmtoare
exemplific linii desenate folosind diverse abloane i diferii factori de multiplicare.
Dac nu se activeaz generarea liniilor cu ablon, afiarea va decurge ca i cum pattern ar
fi 0xFFFF i factor 1. Generarea liniilor cu ablon poate fi combinat cu setarea
diferitelor limi de linie pentru a produce linii punctate de diferite limi.
O modalitate de a privi generarea liniilor cu ablon este aceea c ablonul este
deplasat cu o poziie de fiecare dat cnd este afiat un pixel (sau factor pixeli sunt
afiati, dac factor este diferit de 1). Dac sunt desenate o serie de segmente de dreapt
conectate ntre apelurile funciilor glBegin i glEnd, atunci ablonul va continua s fie
deplasat cnd 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 execuia funciei glEnd ablonul
va fi resetat i dac n continuare, nainte de a dezactiva generarea de segmente de
dreapt cu ablon, mai sunt afiate segmente de dreapt, atunci la generare se va folosi
ablonul de la nceput. Dac segmentele de dreapt sunt afiate 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 limi 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);
/* afieaz 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);
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 ();
}

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 afiate prin contur continuu, dar pot fi afiate i cu
conturul punctat sau numai prin vrfurile ce-l compun. Un poligon poate avea interiorul
generat uniform sau folosind un anumit ablon. Poligoanele sunt afiate astfel nct
pentru poligoanele adiacente care mpart o latur sau un vrf, pixelii ce formeaz latura
respectiv sau vrful respectiv sunt afiai o singur dat ei sunt inclui numai ntr-un
singur poligon.

II.8.3.1. Modul de afiare


Un poligon este considerat ca avnd dou fee cea din fa i cea din spate. El
poate fi generat innd cont de ambele fee, numai de feele din fa (cele aflate spre
observator) sau numai de feele din spate. n mod implicit, feele din fa i din spate sunt
afiate n acelai mod. Pentru a modifica acest lucru sau pentru a afia poligoanele prin
contur sau numai prin vrfurile ce-l compun se va folosi funcia glPolygonMode :

void glPolygonMode(GLenum face, GLenum mode);


- face specific feele la care se refer parametrul mode; poate fi
GL_FRONT_AND_BACK (feele fa i spate), GL_FRONT (feele fa), sau
GL_BACK (feele spate);
- mode reprezint modul de afiare a feelor selectate; poate fi: GL_POINT
(poligoanele vor fi afiate prin vrfuri), GL_LINE (poligoanele vor fi afiate prin
contur), sau GL_FILL (poligoanele vor fi afiate cu interior plin)
n mod implicit, ambele tipuri de fee sunt afiate cu interiorul plin.

Exemplu
Se cere afiarea faelor 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 feelor

In mod implicit, feele ale cror vrfuri sunt parcurse n sens invers acelor de ceas
sunt considerate fee din fa (orientate spre observator). Aceast convenie poate fi
modificat de programator, apelnd funcia glFrontFace.

void glFrontFace(GLenum mode);


Parametrul mode specific orientarea feelor din fa ale poligoanelor. Valoarea
GL_CCW (valoarea implicit) corespunde unei orientri n sensul invers acelor de ceas a
conturului unei fee proiectate n coordonate de afiare. Valoarea GL_CW, indic o
orientare n sensul acelor de ceas a contururilor feelor din fa.

n cazul unei suprafee nchise construit din poligoane cu o anumit orientare,


toate feele spate nu vor fi vizibile niciodat ele vor fi ascunse de feele din fa ale
poligoanelor. n aceast situaie se poate mri viteza de afiare prin eliminarea
poligoanelor imediat ce s-a determinat dac ele reprezint fee spate. n mod similar dac
suntem n interiorul unui obiect atunci vor fi vizibile numai poligoanele care reprezint
feele spate. Pentru a specifica eliminarea feelor fa, respectiv feelor spate se va folosi
funcia glCullFace iar activarea eliminrii feelor respective se va face folosind funcia
glEnable avnd ca parametru GL_ CULL_FACE. Pentru dezactivare se va apela
glDisable cu acelai argument.

void glCullFace(GLenum mode);


Funcia 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 feele fa
- GL_BACK :se elimin feele spate
- GL_FRONT_AND_BACK :se elimin att feele fa ct i feele spate.

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 bii, care se va specifica folosind funcia glPolygonStipple.

void glPolygonStipple(const GLubyte *mask);

Funcia definete ablonul curent pentru generarea interiorului poligoanelor. Argumentul


mask este un pointer catre un bitmap de 3232 care este interpretat ca o masca de 0 i 1.
Pixelul din poligon corespunzator valorii 1 din masc va fi afiat.
Folosirea ablonului curent la generarea poligoanelor este activat, respectiv
dezactivat, apelnd funciile glEnable respectiv glDisable cu argumentul
GL_POLYGON_STIPPLE.

In programul din fiierul 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,
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);
}

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 biilor se poate modifica prin apelul funciei 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, aa cum se arat n figura II.7, i apoi sunt
desenate aceste triunghiuri.
Dac se descompune un poligon n triunghiuri i se face afiarea 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 vrf aparine sau nu unei muchii de contur prin
pstrarea pentru fiecare vrf a unui bit. La afiarea poligonului n modul GL_LINE nu
vor fi desenate laturile care nu aparin muchiilor de contur. n figura II.6 liniile punctate
reprezint laturi false.
Figura II.6. Divizarea unui poligon concav

n mod implicit orice vrf aparine unei muchii de contur. Acest convenie poate
fi controlat prin setarea flag-ului de apartenen la o muchie de contur cu ajutorul
funciei glEdgeFlag*. Funcia se apeleaz ntre comenzile glBegin i glEnd i acioneaz
asupra tuturor vrfurilor specificate dup apelul sau pn la urmtorul apel al funciei
glEdgeFlag. Ea se aplic doar vrfurilor care aparin 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 vrf definit n continuare va fi considerat ca aparinnd muchiilor de
contur pn la un nou apel al funciei 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 instruciuni este urmtorul (figura II.7):

Figura II.7.

II.8.3.5. Vectori normal

Un vector normal este un vector care are orientarea perpendicular pe o


suprafa. Pentru o suprafa plan este suficient o singur direcie perpendicular, ea
fiind aceeai pentru orice punct de pe suprafa, dar pentru o suprafa oarecare direcia
vectorului normal poate diferi pentru fiecare punct. n OpenGL se poate specifica un
vector normal pentru fiecare vrf. Vectorii normal pot fi asociai numai vrfurilor. Ei
sunt necesari n calculul iluminrii suprafeelor aproximate prin reele poligonale.
Funcia glNormal* se apeleaz pentru a specifica normala curent. Normala
curent va fi asociat tuturor vrfurilor definite n continuare prin apeluri ale funciei
glVertex*. Dac fiecare vrf are asociat o normal diferit se va proceda ca n exemplul
urmtor:

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);


Funcia glNormal3 seteaz componentele vectorului normal curent la valoarile
(nx,ny,nz), specificate prin parametri.
Versiunea glNormal3*v a acestei funcii primete 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 avnd orientri n
direcii opuse. Prin convenie, normala este acel vector care are direcia spre exteriorul
suprafeei. Dac se dorete folosirea vectorului normal orientat spre interiorul suprafeei
unui obiect se va modifica fiecare vector normal de la (x, y, z) la (-x, -y, -z).
Vectorii normal pot fi specificai avnd orice lungime, dar ei vor trebui
normalizai nainte de efectuarea calculelor de iluminare. n general, este bine ca vectorii
normal s fie furnizai normalizai. Dac se specific vectori normal nenormalizai
sistemul OpenGL i poate normaliza n mod automat. Pentru a cere aceast operaie se va
apela funcia glEnable avnd ca parametru GL_NORMALIZE. Implicit este dezactivat
normalizarea automat. n unele implementari ale OpenGL-ului normalizarea automat
necesit calcule suplimentare care pot reduce performanele aplicaiei.

II.9. Transformri ale obiectelor 3D n OpenGL

II.9.1. Etapele transformrii din spaiul 3D pe suprafaa de afiare

OpenGL utilizeaz un sistem de coordonate 3D dreapta.


Secvena de transformri aplicate asupra punctelor prin care este definit un obiect 3D
pentru a fi afiat pe ecran este urmtoarea (figura II.8):
transformarea de modelare i vizualizare ( ModelView)
transformarea de proiecie, nsoit de decupare la marginile volumului vizual canonic
mprirea perspectiv
transformarea n poarta de vizualizare din fereastra curent
Figura II.8. Secvena de transformari aplicate vrfurilor n OpenGL

Procesul de transformri necesar producerii imaginii dorite pentru a fi redat pe o


suprafa de afiare este asemnator cu cel al efecturii unei fotografii. Aceti pai ar fi
urmtorii:
Aranjarea scenei pentru a fi fotografiat n contextul dorit - transformarea de
modelare;
Aranjarea aparatului de fotografiat i ncadrarea scenei -transformarea de
vizualizare;
Alegerea lentilelor aparatului sau modificarea zoom-ului - transformarea de
proiecie;
Determinarea dimensiunii imaginii finale - transformarea n poarta de
vizualizare.

II.9.2. Transformarea de modelare i vizualizare

O aceeai imagine a unui obiect se poate obine n dou feluri :


poziionnd obiectul n faa unei camere de luat vederi fixe
poziionnd camera de luat vederi n faa obiectului fix

Prima operaie corespunde unei transformri de modelare a obiectului. Cea de a doua


operaie corespunde unei transformri de vizualizare. Deoarece ambele pot fi folosite
pentru a obine o aceeai imagine, sunt tratate mpreun, ca o singur transformare
Transformarea de modelare are drept scop poziionarea 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
avnd latura de o unitate, centrat n originea unui sistem de coordonate carteziene 3D.
Reprezentarea la mrimea dorit, poziionarea i orientarea sa n scena 3D, care este
definit ntr-un sistem de coordonate global, poate s presupun o transformare
compus din scalare i rotaie faa de originea sistemului de coordonate local, urmat de o
translaie. Prin aceast transformare se creaz o instan a cubului, de aceea
transformarea de modelare se mai numete i transformare de instaniere.
Transformarea de modelare este o transformare compus din transformri
geometrice simple care poate fi definit ca produs matricial, folosind funciile de
translaie, rotaie i scalare oferite de OpenGL.
Transformarea de vizualizare este determinat de poziia observatorului
(camera de luat vederi), direcia n care privete acesta si direcia sus a planului de
vizualizare. In mod implicit, observatorul este situat in originea sistemului de coordonate
n care este descris scena 3D, direcia n care privete este direcia negativa al axei OZ,
iar direcia sus a planului de vizualizare este direcia pozitiva a axei OY. Cu aceste valori
implicite, transformarea de vizualizare este transformarea identic.
Funcia gluLookAt permite modificarea parametrilor implicii ai transformrii de
vizualizare :
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,
GLdouble centerx,GLdouble centery,GLdouble centerz,
GLdouble upx,GLdouble upy,GLdouble upz);
- eyex, eyey, eyez reprezint poziia observatorului
- centerx, centery, centerz reprezint direca n care se privete
- upx, upy, upz reprezint direcia vectorului sus al planului de vizualizare

Poziia observatorului reprezint punctul de referin al vederii, R, iar direcia n care se


privete este direcia normalei la planul de vizualizare, n R. Vectorul sus determin
direcia pozitiv a axei verticale a sistemului de coordonate 2D ataat planului de
vizualizare. Sistemul de coordonate 2D ataat 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.
Funcia gluLookAt construiete matricea transformrii din sistemul de
coordonate obiect n sistemul de coordonate observator i o nmulete la dreapta cu
matricea curent.
In OpenGL transformarea de modelare i de vizualizare sunt exprimate printr-o
singur matrice de transformare, care se obine nmulind matricile celor dou
transformri. Ordinea de nmulire a celor dou matrici trebuie s corespund ordinei n
care ar trebui aplicate cele dou transformri : mai nti 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 [x w yw zw w]T. Daca A, B i C sunt 3
matrici de transformare care exprim transformrile de aplicat punctului n ordinea A, B,
C, atunci secvena de transformri 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 obine nmulind matricea transformrii de vizualizare cu
matricea transformrii de modelare. Fie V i M aceste matrici. Atunci,
VM = VM
Dac coordonatele unui vrf n sistemul de coordonate obiect sunt reprezentate prin
vectorul [xo yo zo wo]T, atunci coordonatele vrfului n sistemul de coordonate
observator (eye coordinates) se obin 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 proiecie

Matricea de proiecie este calculat n OpenGL n funcie de tipul de proiecie


specificat de programator i parametrii care definesc volumul de vizualizare. Matricea de
proiecie este matricea care transform volumul vizual definit de programator ntr-un
volum vizual canonic. Aceast transformare este aplicat vrfurilor care definesc
primitivele geometrice n coordonate observator, rezultnd 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 unitti,
centrat n originea sistemului coordonatelor de decupare. Dup aplicarea transformrii de
proiecie, orice punct 3D (din volumul vizual canonic) se proiecteaz n fereastra 2D
printr-o proiecie ortografic (x =x, y=y) condiie necesar pentru aplicarea algoritmului
z-buffer la producerea imaginii.
Dac coordonatele unui vrf n sistemul de coordonate observator sunt
reprezentate prin vectorul [xe ye ze we]T, iar P este matricea de proiecie, atunci
coordonatele de decupare ale vrfului (clip coordinates) se obin astfel:

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

Prezentm n continuare funciile OpenGL prin care pot fi definite proieciile i volumul
de vizualizare.

void glFrustum(GLdouble left, GLdouble right, GLdouble bottom,


GLdouble top, GLdouble near, GLdouble far);
Funcia definete o proiecie perspectiv cu centrul de proiecie n poziia
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 distanele lor fa de poziia observatorului (planul de
vizualizare). Planul din fa va fi folosit ca plan de proiecie. Lui i se ataeaz un sistem
de coordonate 2D avnd 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 proiecie.
- (left, bottom) i (right, top) reprezint colurile ferestrei din planul din fa
- znear, zfar reprezint distanele de la poziia observatorului la planul din fa,
respectiv spate. Ambele distane trebuie s fie pozitive.

Figura II.9. Volumul vizual perspectiv

Dac left=right sau bottom=top sau znear=zfar sau znear<=0 sau zfar<=0 se semnaleaz
eroare.
Colurile ferestrei 2D din planul de proiecie, (left, bottom,-near) i (right, top,-near) sunt
mapate pe colurile stnga-jos i dreapta-sus ale ferestrei 2D din sistemul coordonatelor
de decupare, adic (-1,-1,-1) i (1,1,-1). Matricea de proiecie este n acest caz :

2 * near
right - left 0 A 0

2 * near
P 0 B 0
top - bottom

0 0 C D

0 0 -1 0
unde
right left top bottom
A , B
right - left top - bottom

far near 2 * far * near


C- , D-
far - near far - near

Funcia glFrustum nmulete matricea curent cu matricea de proiecie rezultat


i memoraz rezultatul n matricea curent. Astfel, dac M este matricea curent i P este
matricea proieciei, atunci glFrustum nlocuiete matricea M cu M * P.

O alt funcie care poate fi folosit pentru proiecia perspectiv este gluPerspective :

void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble


near, GLdouble far);

Funcia gluPerspective creeaz un volum de vizualizare la fel ca i funcia glFrustum,


dar n acest caz el este specificat n alt mod. n cazul funciei gluPerspective acesta se
specific prin unghiul de vizualizare n planul XOZ (deschiderea camerei de luat vederi)
i raportul dintre limea i nlimea ferestrei definite n planul de aproape (pentru o
fereastr ptrat 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 lime / nlime al laturilor ferestrei din planul de
aproape; acest raport trebuie s corespund raportului lime/nime asociat porii
de afiare. De exemplu, dac aspect = 2.0 atunci unghiul de vizualizare este de
dou ori mai larg pe direcia x dect pe y. Dac poarta de afiare este de dou ori
mai lat dect nlimea atunci imaginea va fi afiat nedistorsionat.
- near i far reprezint distanele ntre observator i planele de decupare de-a lungul
axei z negative. ntotdeauna trebuie s fie pozitivi.

Proiecia ortografic este specificat cu ajutorul funciei glOrtho :

void glOrtho( GLdouble left, GLdouble right, GLdouble bottom,


GLdouble top, GLdouble near, GLdouble far);

unde
- (left, bottom) i (right, top) reprezint colurile ferestrei din planul din fa
- near, far reprezint distanele de la poziia observatorului la planul din fa,
respectiv planul din spate

Volumul de vizualizare este n acest caz un paralelipiped dreptunghic delimitat de planul


din faa i cel din spate, plane paralele cu planul de vizualizare (perpendiculare pe axa z),
precum i de planele sus, jos, dreapta , stnga. Direcia de proiecie este dat de axa Z a
sistemului de coordonate ataat 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 proiecie este n acest caz :

2
right - left 0 0 tx

2
0 0 ty
P top - bottom

-2
0 0 tz
far - near

0 0 0 1

unde
right left top bottom far near
tx - , ty - , tz -
right - left top - bottom far - near

Matricea curent este nmulit cu matricea de proiecie rezultat, rezultatul fiind depus n
matricea curent.

Tot pentru proiecia ortografic poate fi folosit i funcia gluOrtho2D care


definete matricea de proiecie 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 colurile ferestrei din planul din fa

II.9.4. Impartirea pespectiv

Prin aceast operaie se obin coordonate 3D n spaiul 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 .


Operaia este denumit mprire perspectiv deoarece numai n cazul unei proiecii
perspectiv wc este diferit de 1.

II.9.5. Transformarea n poarta de vizualizare

Aceast transformare se aplic coordonatelor dispozitiv normalizate pentru a se


obine coordonate raportate la sistemul de coordonate al fereastrei curente de afiare. Este
o transformare fereast-poart, n care fereastra este fereastra 2D din sistemul
coordonatelor normalizate, avnd colurile n (-1, -1, -1)-(1, 1, -1), iar poarta este un
dreptunghi din fereastra de afiare care poate fi definit prin apelul funciei glViewport.

void glViewport(GLint px, GLint Py, GLsizei width, GLsizei


height );

- (px, py) reprezint coordonatele n fereastr ale colului stnga jos al porii de
afiare (n pixeli). Valorile implicite sunt (0,0).
- width, height reprezint limea, respectiv nlimea porii de afiare. Valorile
implicite sunt date de limea i nlimea ferestrei curente de afiare.

Fie (xd, yd, zd) coordonatele dispozitiv normalizate ale unui vrf i (xw, yw, zw)
coordonatele vrfului n fereastra de afiare. Transformarea n poarta de
vizualizare este definit astfel :

xw = ox + (width/2)xd
yw = oy + (height/2)yd
zw = ((f-n)/2)zd + (n+f)/2

unde (ox, oy) reprezint coordonatele centrului porii de afiare.


n i f au valorile implicite 0.0 respectiv 1.0, dar pot fi modificate la valori cuprinse n
intervalul [0,1] folosind funcia DepthRange. Dac n i f au valorile implicite, atunci
prin transformarea n poarta de vizualizare volumul vizual canonic se transform n cubul
cu colurile de minim i maxim n punctele (px, py, 0)-(px+width, py+height,1).
Calculul coordonatei zw este necesar pentru comparaiile de adncime n algoritmul z-
buffer.

Observaie: n programul din fiierul exemplu5.c limea i nlimea porii de afiare


sunt specificate folosind limea i nlimea ferestrei curente a aplicaiei.

II.9.6. Funcii de operare cu matrici de transformare

Transformarea de modelare i vizualizare i transformarea de proiecie sunt


reprezentate prin matrici. Programatorul poate ncrca una dintre aceste matrici cu o
matrice proprie sau cu matricea unitate, sau o poate nmuli cu alte matrici.
naintea specificrii unei transformri trebuie selectat matricea curent, care va
fi modificat. Pentru aceasta se va apela funcia glMatrixMode.
void glMatrixMode( GLenum mode );
Parametrul mode reprezint matricea asupra creia se vor efectua modificrile ulterioare.
El poate avea una dintre urmtoarele valori:
- GL_MODELVIEW matricea curent va fi matriciea de modelare i vizualizare
- GL_PROJECTION matricea curent va fi matricea de proiecie.
- GL_TEXTURE matricea curent va fi matricea textur.

In programul din fiierul exemplu5.c, naintea transformrii de vizualizare, matricea


curent este setat la matricea identitate (de 4 linii i 4 coloane) cu ajutorul functiei
glLoadIdentity.
void glLoadIdentity(void);
Apelul funciei glLoadIdentity este necesar deoarece majoritatea funciilor de
transformare nmulesc matricea curent cu matricea specificat i rezultatul este depus n
matricea curent. Dac matricea curent nu este setat iniial la matricea identitate, atunci
se vor folosi matricile de transformare anterioare combinate cu cea furnizat n acel
moment
Dac se dorete ca o anumit matrice s devin matricea curent, atunci se va
folosi funcia glLoadMatrix*.
void glLoadMatrix{fd}(const TYPE *m);
Valorile coninute n vectorul m se memoreaz n matricea curent, n ordinea
coloanelor :

Observaie : Elementele unei matrici din limbajul C sunt memorate n ordinea


liniilor.
Funcia glMultMatrix* se poate folosi pentru a nmuli matricea curent cu
matricea dat ca parametru funciei glMultMatrix*.
void glMultMatrix{fd}(const TYPE *m);
Funcia nmulete matricea specificat de parametrul m cu matricea curent i
rezultatul nmulirii este stocat n matricea curent. Dac C este matricea curent, atunci
rezultatul nmulirii este C=Cm.

Pentru specificarea unei translaii se poate folosi funcia:

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


unde x, y i z reprezint componentele vectorului de translaie
Matricea curent este nmulit cu matricea de translaie i rezultatul nlocuiete
matricea curent. Dac M este matricea curent i T este matricea de translaie, atunci M
este nlocuit cu MT.
Daca matricea curenta este GL_MODELVIEW sau GL_PROJECTION, toate
obiectele afiate dup apelul functiei glTranslatef vor fi translatate.

Pentru rotaii se poate folosi funcia:

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


- angle reprezint unghiul de rotaie exprimat n grade.
- x, y, z reprezint coeficienii directori ai axei n jurul creia se realizeaz rotaia.
Funcia efectueaz o rotaie n sens trigonometric cu unghiul specificat, n jurul
vectorului ce unete originea cu punctul de coordonate (x, y, z).
Matricea curent este nmulit cu matricea de rotaie i rezultatul nlocuiete matricea
curent. Dac M este matricea curent i R este matricea de rotaie, atunci M este
nlocuit cu MR.
Dac matricea curent este GL_MODELVIEW sau GL_PROJECTION, toate
obiectele afiate dup apelul funciei glRotatef vor fi rotite.

Pentru scalare se poate folosi funcia:


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 nmulit cu matricea de scalare i rezultatul nlocuiete matricea
curent. Dac M este matricea curent i S este matricea de translaie, atunci M este
nlocuit cu M*S.
Dac matricea curent este GL_MODELVIEW sau GL_PROJECTION, atunci toate
obiectele afiate dup apelul funciei glScalef vor fi scalate.
Folosirea funciei glScale* diminueaz performanele calculului iluminrii, deoarece
vectorii normal trebuie renormalizai dup aceast transformare.

Exemplu
Considerm urmtoarea secven care specific o secven de trei transformri:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(N); /* aplic transformarea N */
glMultMatrixf(M); /* aplic transformarea M */
glMultMatrixf(L); /* aplic transformarea L */
glBegin(GL_POINTS);
glVertex3f(v); /* afieaz vrful v transformat*/
glEnd();

La execuia secvenei de mai sus, matricea de modelare i vizualizare (MODELVIEW) va


conine succesiv : I, N, NM, i n final NML, unde I reprezint matricea identitate.
Transformarea aplicat vrfului v va fi NMLv, unde NML = NML.

II.9.7. Gestiunea stivelor de matrici


Un sistem OpenGL pstreaz cte o stiv de matrici pentru fiecare mod matrice
selectat cu ajutorul funciei MatrixMode. Astfel, exist :
Stiva matricilor Modelview (cel puin 32 matrici 4 x 4);
Stiva matricilor de proiecie (cel puin 2 matrici 4 x 4) ;
Stiva matricilor textur(cel puin 2 matrici 4 x 4).
Matricea curent este ntotdeauna matricea din vrful stivei corespunztoare
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 main i exist o singur rutin care deseneaz o roat. Aceast rutin
deseneaz roata ntr-o anumit poziie i orientare. Cnd se deseneaz maina, rutina de
afiare a roii se va apela de 4 ori, aplicndu-se diferite transformri pentru a poziiona
corect roile. De exemplu, pentru desenarea primei roi aceasta trebuie s fie translatat.
La desenarea celei de a doua roi trebuie aplicat o alt translaie (dar fa de poziia
iniial nu trebuie inut cont de prima translaie) i n acelai mod pentru desenarea
celorlalte roi.
Deoarece transformrile sunt pstrate ca matrici, o stiv de matrici furnizeaz un
mecanism util pentru efectuarea unei transformri ca apoi s se realizeze o alt
transformare fr a se mai ine cont de transformarea anterioar. Toate operaiile cu
matrici (glLoadMatrix, glMultMatrix, glLoadIdentity i funciile care creeaz matrici
de transformare specifice) lucreaz cu matricea curent sau cu matricea din vrful stivei.
Pentru lucrul cu stivele de matrici OpenGL pune la dispoziie funciile
glPushMatrix i glPopMatrix.

void glPushMatrix(void);

Funcia adaug un nou element la stiva curent i memoreaz matricea curent att n
elementul din vrful stivei ct i n intrarea urmtoare. Stiva curent este determinat de
ultimul apel al funciei glMatrixMode. Dac prin adugare se depaete capacitatea
stivei se genereaz eroare.

void glPopMatrix(void);

Funcia elimin intrarea din vrful stivei i nlocuiete matricea curent cu matricea care
era memorat n a 2-a intrare a stivei. Dac stiva avea o singur intrare, apelul funciei
glPopMatrix genereaz eroare.

Exemplu
Programul din fiierul exemplu5.c afieaz un cub care este mai nti scalat
(transformarea de modelare). Transformarea de vizualizare const dintr-o translaie a
poziiei observatorului pe axa z, n poziia (0,0,5). Observatorul privete spre origine iar
direcia axei sus este direcia 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)
{ 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 funcia display unde este
apelat i funcia de afiare a cubului, glutWireCube. Astfel funcia display poate fi
folosit n mod repetat pentru a afia coninutul ferestrei (de exemplu n cazul n care
fereastra este mutat pe ecran).
Transformarea de proiecie i transformarea n poarta de vizualizare sunt
specificate n funcia Reshape, care este apelat de sistem ori de cte ori este
redimensionat fereastra aplicaiei.
Efectul obinut prin mutarea observatorului n spatele cubului (folosind
transformarea de vizualizare) se poate obine 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
afiare a obiectelor. Funciile glColor3 specific un triplet (R, G, B). Funciile 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 afiare:
modul RGBA: pentru fiecare pixel se memoreaz valorile R, G, B i A.
modul indexat: pentru fiecare pixel se memoreaz un numr, reprezentnd un index
ntr-o tabela de culori.
Valorile R, G, B i A variaz n domeniul [0, 1].

n modul RGBA, pentru selectarea culorii curente de desenare se folosesc funciile


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 opacitii este 1.0.
Pentru versiunile funciei 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] cnd sunt folosite ca parametri direci, 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

Valoarea Valoarea minim Valoarea Valoarea maxim


Tip
minim se mapeaza la maxim se mapeaz la
b 1-byte integer -128 -1.0 127 1.0
s 2-byte integer -32,768 -1.0 32,767 1.0
i 4-byte integer -2,147,483,648 -1.0 2,147,483,647 1.0
u
unsigned 1-byte integer 0 0.0 255 1.0
b
u
unsigned 2-byte integer 0 0.0 65,535 1.0
s
u
unsigned 4-byte integer 0 0.0 4,294,967,295 1.0
i
Tabelul II.4. Conversia valorilor de culoare la numere reale

Componentele culorilor specificate prin funciile glColor* au semnificaii 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 strlucitor. Dac valorile sunt 0.5, culoarea este alb, iar la
jumtate din intensitate apare gri. Dac R=G=1 i B=0 lumina apare galben.
Pentru proprietile de material, valorile componentelor R, G i B corespund
proporiilor reflectate din acea culoare. Dac R=1, G=0.5 i B=0 pentru un material,
atunci acel material va reflecta toat lumina incident roie, jumtate 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
corespunztoare (MR, MG, MB) atunci ignorndu-se toate celelalte efecte ale
reflectivitii, lumina ce este perceput de ochiul observatorului este dat de formula
(LR*MR, LG*MG, LB*MB).
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 funciei
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 fiecrui vrf este tratat n mod individual. Pentru un
segment de dreapt culoarea se obine prin interpolarea culorilor vrfului. Pentru un
poligon, culorile punctelor interioare se obin prin interpolare pe baza culorilor vrfurilor.

Exemplu : n fiierul exemplul6.c se afieaz un triunghi folosind modelul de iluminare


Gouraud.

/* fiierul 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);
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;
}

n modelul Lambert culoarea unei primitive este dat de culoarea unui singur
vrf. Culoarea unui segment de dreapt este dat de culoarea celui de-al doile vrf.
Culoarea unui poligon este dat de culoarea unui vrf, conform tabelului II.5. Vrfurile
poligoanelor sunt numerotate ncepnd cu 1. Pentru a evita confuzii n ceea ce privete
culoarea de desenare n modelul Lambert se va specifica o singur culoare pentru o
primitiv.

Vrful folosit pentru selectarea culorii


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

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

II.10.3. Iluminarea unei scene 3D

Paii de adugare a iluminrii ntr-o scen sunt urmtorii :


1) Definirea vectorilor normal pentru fiecare vrf al tuturor obiectelor. Aceste
normale determin orientarea relativ a obiectelor fa de sursele de lumin ;
2) Crearea, selectarea i poziionarea uneia sau a mai multor surse de lumin ;
3) Crearea i selectarea unui model de iluminare care definete nivelul luminii
globale, ambiante i poziia observatorului ;
4) Definirea proprietilor de material pentru obiectele din scen.

Exemplu
Programul din fiierul exemplul7.c realizeaz afiarea unei sfere cu iluminare folosind o
surs de lumin. Normalele pentru sfer sunt definite de funcia glutSolidSphere.

/* fiierul exemplul7.c */
#include "glut.h"

void init(void)
{
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)


{
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, poziionarea i activarea uneia sau a mai multor surse de lumin

n programul din fiierul exemplul7.c se folosete o singur surs de lumin alb.


Poziia sa este specificat prin apelul funciei glLightfv. Acest exemplu folosete
culoarea implicit pentru sursa de lumina 0 (GL_LIGHT0), care este alb ; dac se
dorete o surs de lumin avnd o alt culoare se va folosi funcia 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 poziionate 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
funcia glEnable. De asemenea, trebuie apelat funcia glEnable avnd 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 proprieti cum sunt culoarea, poziia i direcia.
Funcia folosit pentru a specifica toate proprietile luminii este glLight*.

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


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

Funcia creaz o surs de lumin.


- light specific sursa de lumin creat; poate avea una din urmtoarele valori:
GL_LIGHT0, GL_LIGHT1, ... , sau GL_LIGHT7;
- 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 Observatie


GL_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) Poziia (x, y, z, w) a luminii
GL_SPOT_DIRECTION (0.0, 0.0, -1.0) Direcia (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 constant
GL_LINEAR_ATTENUATION 0.0 Factor de atenuare liniar
GL_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) att pentru GL_DIFFUSE ct i pentru
GL_SPECULAR.

Exemplu : definirea culorilor, poziiei 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 poziionat (care nu este plasat la infinit) poate aciona ca un


spot lumina va fi emis sub forma unui con. Pentru a specifica unghiul dintre axele
conului i o raz de pe suprafaa conului se folosete 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 direciile.
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 direcie 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);

Direcia este specificat n coordonate obiect omogene. Valoarea implicit a direciei 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 corespunztori ca i n cazul sursei de lumin GL_LIGHT0.

Exemplu : definirea unui spot de lumina alb :

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);

Observaie: Pentru a activa fiecare surs de lumin se folosete funcia glEnable cu


argumentul GL_LIGHTING. Pentru a dezactiva iluminarea se apeleaz functia
glDisable cu acelai parametru.

II.10.3.2. Specificarea parametrilor modelului de iluminare

Funcia glLightModel* definete parametrii modelului de iluminare:

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

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


urmtoarele 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 feele pentru care se face
calculul de iluminare. Nu are nici un efect n calculele de lumin pentru
puncte, linii i bitmap-uri. Dac param este 0 , calculele de iluminare se
fac numai pentru feele fa i vor fi folosite numai proprietile de
material ale feelor fa. Altfel vor fi considerate att feele fa ct i
feele spate. n acest caz vrfurile feelor spate vor fi luminate folosind
proprietile de material ale feelor spate (normalele vor fi inversate
nainte de a calcula iluminarea).
- param reprezint valoarea ce va fi folosit n corelaie cu pname.

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

- pname identific modelul de iluminare. El poate avea una din urmtoarele


dou valori:
GL_LIGHT_MODEL_AMBIENT, caz n care params va conine
componentele RGBA ale luminii ambiante.
GL_LIGHT_MODEL_LOCAL_VIEWER are aceeai semnificaie ca
i n cazul funciei glLightModel{fi}; n acest caz param devine params;
GL_LIGHT_MODEL_TWO_SIDE are aceeai semnificaie ca i n
cazul funciei glLightModel{fi}; n acest caz param devine params;
- param reprezint valoarea ce va fi folosit n corelaie cu pname.

n exemplul din fiierul exemplul7.c singurul element care este definit explicit
pentru modelul de iluminare este lumina ambiant global. De asemenea, modelul de
iluminare definete i poziia observatorului (la infinit sau la distan finit de scen)
precum i modul de efectuare a calculelor de iluminare a feelor fa respectiv spate ale
scenei. n programul din fiierul exemplul7.c se folosesc valorile implicite pentru acestea
observatorul este plasat la infinit i calculele de iluminare sunt efectuate pentru feele
fa. Folosirea unui observator local scenei crete 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
puin realiste.

n OpenGL modelul de iluminare are trei componente :


Intensitatea luminii ambiante globale
Poziionarea observatorului (local scenei sau la infinit)
Diferenierea calculrii iluminrii pentru feele obiectelor fa, respectiv spate.

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


Poziia observatorului afecteaz calculele pentru strlucirea produs de lumina
specular, mai precis intensitatea strlucirii ntr-un vrf depinde de normala n acel vrf,
direcia de la vrf la sursa de lumin i direcia de la vrf la observator.
Cu un observator plasat la infinit direcia dintre observator i orice vrf rmne
constant. Un observator local va furniza rezultate mai aproape de realitate, dar direcia
va trebui calculat pentru fiecare vrf, astfel c n acest caz performaele 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 fee


n programul din fiierul exemplul7.c numai feele fa sunt iluminate.

Exemplu: calcularea iluminrii pentru ambele fee :

glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_TRUE);
Dac se dorete s se calculeze apoi iluminarea numai pentru feele fa se va apela:

glLightModeli(LIGHT_MODEL_TWO_SIDE, GL_FALSE);

II.10.3.3. Definirea proprietilor de material pentru obiectele din scen

Proprietile de material ale unui obiect determin modul n care el reflect


lumina. Pentru proprietile unui material se pot specifica culorile ambiant, difuz,
specular, stralucirea sa i culoarea oricrei lumini emise. Acestea pot fi setate folosind
funcia glMaterialfv.

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


Funcia specific proprietile de material folosite n calculul iluminrii.
- face reprezint faa obiectului pe care se vor aplica proprietile de material; poate
avea una dintre valorile GL_FRONT, GL_BACK sau
GL_FRONT_AND_BACK.
- pname indic proprietile de material;
- param indic una dintre valorile proprietilor selectate n parametrul pname.

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

pname Valoare implicita Observaie


GL_AMBIENT (0.2, 0.2, 0.2, 1.0) Culoarea ambiant a materialului
GL_DIFFUSE (0.8, 0.8, 0.8, 1.0) Culoarea difuz a materialului
GL_AMBIENT_AND_DIFFUSE Culoarea ambiant i difuz a materialului
GL_SPECULAR (0.0, 0.0, 0.0, 1.0) Culoarea specular a materialului
GL_SHININESS 0.0 Exponentul specular
GL_EMISSION (0.0, 0.0, 0.0, 1.0) Culoarea emis a materialului
GL_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 setai cu funcia glMaterial*
afecteaz culoarea luminii ambiante i difuze reflectate de un obiect.

Exemplu: asignarea simultan a aceleeai 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 strlucirii speculare (folosind
GL_SPECULAR) i poate controla dimensiunea i luminozitatea strlucirii (folosind
GL_SHININESS). Parametrului GL_SHININESS i se poate asocia o valoare n
domeniul [0.0, 128.0];cu ct valoarea este mai mare cu att stlucirea 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 proprietilor de material


n fiierul din exemplul6.c toate vrfurile au asociate aceleai proprieti de
material. Uneori se dorete s se asocieze vrfurilor aceluiai obiect proprieti de
material diferite. De obiecei ntr-o scen sunt mai multe obiecte i fiecare au asociate
proprieti de material diferite.

Exemplu : desenarea a opt sfere fiecare avnd alte proprieti 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; strlucire 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);
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();

Funcia glMaterialfv este apelat n mod repetat pentru a seta proprietile de


material pentru fiecare sfer. Ea este reapelat doar pentru acele proprieti care se
modific de la o sfer la alta (adic de la un obiect la altul). Deoarece funcia
glMaterial* are un cost de execuie mare este bine s se minimizeze modificrile
proprietilor de material. O alt tehnic de a minimiza costurile asociate cu modificarile
proprietilor de material este folosirea funciei glColorMaterial :

void glColorMaterial(GLenum face, GLenum mode);

Proprietile de material specificate de parametrul mode ale feei specificate de


parametrul face ia ntotdeauna valoarea culorii curente. Astfel, o modificare asupra
culorii curente (folosind funcia glColor*) actualizeaz imediat proprietile de material
specificate.
- face poate avea una dintre urmtoarele valori: GL_FRONT, GL_BACK sau
GL_FRONT_AND_BACK (valoare implicit);
- mode poate avea una din urmtoarele valori: GL_AMBIENT, GL_DIFFUSE,
GL_AMBIENT_AND_DIFFUSE (valoare implicit), GL_SPECULAR sau
GL_EMISSION.

Observaie: glColorMaterial actualizeaz proprietatea/proprietile de material


specificate de parametrul mode ale faei/feelor specificate de parametrul face.

Dup apelul funciei glColorMaterial trebuie apelat funcia glEnable avnd ca


parametru GL_COLOR_MATERIAL. Apoi culoarea curent poate fi modificat
folosind funcia glColor* (sau alte proprieti de material folosind funcia glMaterial*).

Exemplu:

glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glColor3f(0.2, 0.5, 0.8);
/* afieaz obiecte */
glColor3f(0.9, 0.0, 0.2);
/* afieaz alte obiecte */
glDisable(GL_COLOR_MATERIAL);
Funcia glColorMaterial se va folosi de cte ori se dorete modificarea unui singur
parametru de material pentru majoritatea vrfurilor din scen. Dac se dorete
modificarea mai multor parametri de material se va folosi funcia glMaterial*.

II.11. Liste de afiare

II.11.1. Utilizarea listelor de afiare

O list de afiare reprezint un grup de comenzi OpenGL stocate pentru o


execuie ulterioar. La invocarea unei liste de afiare comenzile din ea sunt executate n
ordinea n care sunt ntlnite. Majoritatea comenzilor OpenGL pot fi stocate ntr-o list de
afiare sau pot apare n modul imediat (sunt executate imediat). Modul imediat de
programare poate fi combinat cu listele de afiare.
Listele de afiare pot mbunti programul deoarece instruciunile sunt stocate
pentru execuii ulterioare. Este indicat s se foloseasc liste de afiare n cazul n care se
redeseneaz de mai multe ori aceeai figur geometric sau dac trebuie aplicat de mai
multe ori un set de modificri de stare.
O list de afiare este un mod eficient i convenabil de a combina un set de
comenzi OpenGL.

Exemplu: desenarea unui cerc format din 100 de segmente. Codul corespunztor
desenrii cercului fr a folosi liste de afiare este urmtorul:

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 cnd cercul va fi afiat. O alt modalitate este de a salva aceste coordonate
ntr-un vector i a le folosi ori de cte 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++)
glVertex2fv(&circcoords[i][0]);
glEnd();
}
i aceast metod prezint dezavantajul incrementrii i testrii variabilei i. Ceea ce se
dorete este s se deseneze o singur dat cercul i s se cunoasc modul de redesenare
ulterior. Acest lucru este realizat prin folosirea listelor de afiare.

Exemplu: crearea unei liste de afiare

#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 afiare. Argumentul MY_CIRCLE_LIST al funciei
glNewList este un index ntreg care identific n mod unic lista de afiare. Ulterior lista
de afiare poate fi executat folosind comanda glCallList:

glCallList(MY_CIRCLE_LIST);

Listele de afiare sunt un mod convenabil i eficient de a vedea sub forma unui
nume o secven de comenzi OpenGL. O list de afiare conine numai apeluri OpenGL.
Alte apeluri - ca n exemplul de mai sus, cum ar fi funciile C cos i sin nu sunt stocate
n listele de afiare. Coordonatele i celelalte variabile (cum ar fi coninutul vectorului)
sunt evaluate i copiate n lista de afiare avnd valorile de la momentul compilrii listei.
Dup compilarea listei aceste valori nu pot fi modificate. Lista de afiare poate fi tears
i se poate crea una nou, dar o list de afiare existent nu poate fi editat.

Exemplu
Programul din fiierul exemplul8.c vizualizeaz unui tor din diferite unghiuri. Cel mai
eficient mod de a face acest lucru este de a pstra torul ntr-o list de afiare. Apoi, de
cte ori se dorete s se modifice poziia observatorului se va modifica matricea
ModelView i se va executa lista de afiare pentru desenarea torului.

/* fiierul exemplul8.c */

#include "glut.h"

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define M_PI 3.14

GLuint theTorus;

/* afiare 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);
glVertex3f(x, y, z);
}
}
glEnd();
}
}

/* creeaz lista de afiare 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 apsarea tastei 'x' - se rotete n jurul axei x


la apsarea tastei 'y' - se rotete n jurul axei y
la apsarea tastei 'i' - se poziioneaza torul n poziia
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);
glutMainLoop();
return 0;
}

Utilizatorul poate roti torul n jurul axei OX sau OY prin apsarea tastelor x
respectiv y. De cte ori se ntampl acest lucru este apelat funcia callback keyboard
care nmulete matricea de rotaie de 30o n jurul axei x sau y cu matricea curent
ModelView, dup care este apelat funcia glutPostRedisplay, care face ca funcia
glutMainLoop s apeleze funcia display i s afieze torul dup prelucrarea altor
evenimente. La apsarea tastei i funcia keyboard reface matricea iniial ModelView i
reafieaz torul n poziia sa iniial. Funcia display terge fereastra i apeleaz funcia
glCallList pentru a executa comenzile din lista de afiare.
Dac nu s-ar fi folosit liste de afiare funcia display ar fi trebuit s conin
comenzi de desenare a torului de fiecare dat cnd ar fi fost apelat.

O list de afiare conine numai comenzi OpenGL. n exemplul din fiierul


exemplul8.c sunt stocate apelurile funciilor glBegin, glVertex i glEnd. Parametrii
apelurilor sunt evaluai i valorile lor sunt copiate n lista de afiare la crearea sa. Toate
calculele trigonometrice pentru crearea torului sunt fcute o singur dat ceea ce duce la
creterea performanelor afirii.

Exemplu: aplicarea unor transformri 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 acelai mod este bine s se
pstreze matricea de transformare ntr-o list de afiare.

Exemplu
In unele implementri, se vor putea mbuntai performanele prin transformarea
obiectelor n momentul definirii lor n loc de a le transforma de fiecare dat cnd sunt
afiate :

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

glCallList(1);

Listele de afiare au i dezavantaje. Listele foarte mici nu vor mbunti execuia


programului datorit overhead-ului execuiei listei. Un alt dezavantaj const din faptul c
o list de afiare nu poate fi modificat i coninutul su nu poate fi citit. Dac aplicaia
necesit pstrarea datelor separat fa de lista de afisare atunci va fi necesar memorie
suplimentar.

II.11.2. Crearea i executarea listelor de afiare

Funciile glNewList i glEndList sunt folosite pentru delimitarea unei liste de


afiare, care este executat prin apelul funciei glCallList avnd ca parametru
identificatorul su. n fiierul exemplul9.c lista de afiare este creat n funcia init. n
funcia display lista de afiare va fi apelat de 10 ori. Listele de afiare aloc memorie
pentru a stoca comenzile i valorile oricrei variabilele necesare. Funcia glTranslatef
din lista de afiare modific poziia urmtorului obiect ce va fi afiat. Apelul drawLine
este de asemenea afectat de funcia glTranslatef care o precede.

/* fiierul 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 rou */
glBegin (GL_TRIANGLES);
glVertex2f (0.0, 0.0);
glVertex2f (1.0, 0.0);
glVertex2f (0.0, 1.0);
glEnd ();
glTranslatef (1.5, 0.0, 0.0); /* modificare poziie */
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++) /* afiare 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();
}

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;
}

Observaie: Dac o list de afiare conine comenzi de transformare trebuie avut grij
care va fi efectul acestora n program mai trziu.

La un moment dat poate fi creat numai o singur lista de afiare. Cu alte cuvinte
trebuie terminat crearea unei liste de afiare (glNewList i glEndList) nainte de a crea
o alt list. Apelul funciei glEndList fr a fi apelat nainte funcia glNewList va genera
eroarea GL_INVALID_OPERATION.

II.11.2.1. Crearea unei liste de afiare

Fiecare list de afiare este identificat printr-un index ntreg. La crearea unei liste
de afiare trebuie s se aib grij s nu se aleag un index care este deja folosit, altfel se
va terge lista de afiare existent. Pentru evitarea acestui lucru se va folosi
funcia glGenLists ce va genera unul sau mai muli indici nefolosii :

GLuint glGenLists(GLsizei range);

Funcia aloc un domeniu de range numere continue nefolosite ca indici pentru liste de
afiare. Valoarea ntoars de funcie reprezint indicele de nceput a blocului de indici
nefolosii. Indicii returnai vor fi marcai ca folosii astfel ca apelurile ulterioare ale
funciei glGenLists nu vor ntoarce aceti indici pn nu vor fi teri. Funcia ntoarce 0
dac nu este disponibil numarul de indici cerui sau dac range este 0.

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

listIndex = glGenLists(1);
if (listIndex != 0) {
glNewList(listIndex,GL_COMPILE);
...
glEndList();
}
Observaie: Indexul 0 nu reprezint un index valid pentru lista de afiare.

void glNewList (GLuint list, GLenum mode);

Funcia specific nceperea unei liste de afiare. Funciile OpenGL care vor fi apelate
(pn la ntlnirea funciei glEndList care marcheaz sfritul listei de afiare) sunt
stocate n lista de afiare, excepie facnd cteva funcii OpenGL care nu pot fi stocate.
Aceste funcii restricionate sunt executate imediat n timpul crerii listei de afiare.
- list este un ntreg pozitiv diferit de 0 care identific n mod unic lista de afiare.
- valorile posibile ale parametrului mode sunt GL_COMPILE i
GL_COMPILE_AND_EXECUTE. Se folosete valoarea GL_COMPILE dac
nu se dorete executarea comenzilor OpenGL la plasarea lor n lista de afiare;
pentru execuia imediat n momentul plasrii n lista de afiare, pentru folosiri
ulterioare, se va secifica parametrul GL_COMPILE_AND_EXECUTE.

void glEndList (void);

Funcia marcheaz sfritul unei liste de afiare.

La crearea unei liste de afiare ea va fi stocat mpreun cu contextul OenGL


curent. Astfel, dac contextul va fi distrus, de asemenea lista de afiare va fi distrus. n
unele sisteme este posibil ca listele de afiare s partajeze contexte multiple. n acest caz
lista de afiare va fi distrus n momentul n care ultimul context din grup este distrus.
La crearea unei liste de afiare n ea vor fi stocate doar valorile expresiilor. Dac
valorile dintr-un vector sunt modificate, valorile din lista de afiare nu vor fi modificate.

Exemplu
Se creaz o list de afiare ce conine o comand care seteaz culoarea curent de afiare
negru
(0.0, 0.0, 0.0). Modificarea ulterioar a valorii vectorului color_vector n rou (1.0, 0.0,
0.0) nu
are nici un efect asupra listei de afiare deoarece aceasta conine 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 afiare 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 afiare (apelul
funciei glNewList n timpul crerii unei liste de afiare 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 reea, clientul poate rula pe o main i


server-ul pe alta. Dup crearea unei liste de afiare ea se va afla la server astfel c server-
ul nu se poate baza pe client pentru nici o informaie relativ la lista de afiare. Astfel,
orice comand care ntoarce o valoare nu poate fi stocat ntr-o list de afiare. n plus,
comenzile care modific starea clientului cum ar fi glPixelStore, glSelectBuffer i
comenzile de definire a vectorilor de vrfuri nu pot fi stocate ntr-o list de afiare.
Operaiile unor comenzi OpenGL depind de starea clientului. De exemplu,
funciile de specificare a vrfurilor vectorilor (cum ar fi glVertexPointer, glColorPointer
i glInterleavedArrays) seteaz pointeri de stare ai clientului i nu pot fi stocate ntr-o
list de afiare. Funciile glArrayElement, glDrawArrays i glDrawElements transmit
date ctre server pentru a construi primitive din elementele vectorilor. Astfel de operaii
pot fi stocate ntr-o list de afiare.
Vectorul de vrfuri stocat n lista de afiare este obinut prin dereferenierea datei
din pointeri nu prin stocarea pointerilor . Astfel, modificrile datelor din vectorul de
vrfuri nu va afecta definirea primitivei n lista de afiare.
Funcii cum ar fi glFlush i glFinish nu pot fi stocate ntr-o list de afiare
deoarece depind de starea clientului n momentul execuiei.
II.11.2.2. Execuia unei liste de afiare

Dup crearea unei liste de afiare aceasta poate fi executat prin apelul funciei
glCallList. O list de afiare poate fi executat de mai multe ori i de asemenea o list de
afiare poate fi executat mbinndu-se cu apeluri n modul imediat.

void glCallList (GLuint list);

Functia execut lista de afiare specificat de parametrul list. Comenzile din lista de
afiare sunt executate n ordinea n care au fost salvate ca i cum ar fi executate fr a se
folosi o lista de afiare. Dac lista nu a fost definit nu se va ntmpla nimic.
Funcia glCallList poate fi apelat din orice punct al programului atta timp ct
contextul OpenGL care acceseaz lista de afiare este activ (contextul care a fost activ la
crearea listei de afiare sau un context din acelai grup partajat). O list de afiare poate
fi creat ntr-o funcie i executat n alt funcie atta timp ct indexul su o identific n
mod unic. De asemenea, contextul unei liste de afire nu poate fi salvat ntr-un fiier i
nici nu se poate crea o list de afiare dintr-un fiier. n acest sens o list de afiare este
proiectat pentru a fi folosit temporar.

II.11.3. Liste de afiare ierarhice

O list de afiare ierarhic este o list de afiare care execut o alt list de afiare
prin apelul funciei glCallList, ntre perechile de funcii glNewList i glEndList. O list
de afiare ierarhic este folositoare pentru un obiect alctuit din componente, n mod
special dac aceste componente sunt folosite de mai multe ori.

Exemplu: o list de afiare care deseneaz o biciclet prin apelul altor liste de afiare
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 recursivitii infinite limita nivelului de imbricare al listelor de
afiare este 64, dar aceast limit depinde de implementare. Pentru a determina limita
specific implementrii OpenGL pe care se lucreaz se apeleaz funcia :

glGetIntegerv(GL_MAX_LIST_NESTING, GLint *data);

OpenGL permite crearea unei liste de afiare care s apeleze o alt list de afiare
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 afiare ierarhic

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

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

Pentru afiarea poligonului se apeleaz lista de afiare 4. Pentru a edita un vrf


este necesar s se creeze din nou lista de afiare corespunztoare vrfului respectiv.
Deoarece un index identific n mod unic lista de afiare, crearea unei alte liste cu acelai
index o va terge n mod automat pe cea existent. Trebuie reinut c aceast metod nu
folosete n mod optim memoria i nu mbuntete performanele, dar este folositoare n
unele cazuri.

II.11.4. Gestiunea listelor de afiare cu indici


Pentru a obine un indice nefolosit care s identifice o nou list de afiare se
poate folosi funcia glGenLists. Dac nu se dorete folosirea acestei funcii atunci se
poate folosi glIsList pentru a determina dac un anumit index este folosit.

GLboolean glIsList(GLuint list);

Funcia ntoarce GL_TRUE dac indexul specificat de parametrul list este deja folosit
pentru o list de afiare i GL_FALSE n caz contrar.

Pentru a terge n mod explicit o list de afiare sau un domeniu continuu de liste
se folosete funcia glDeleteLists. Folosirea funciei glDeleteLists elibereaz indicii
corespunztori listelor terse s fie disponibili din nou.

void glDeleteLists(GLuint list, GLsizei range);

Funcia terge range liste de afiare ncepnd de la indexul specificat de list. Este ignorat
ncercarea de a se terge o list de afiare care nu a fost creat.

II.11.5. Execuia listelor de afiare multiple

OpenGL furnizeaz un mecanism eficient de a executa succesiv liste de afiare.


Acest mecanism necesit introducerea indicilor listelor de afiare ntr-un vector si apoi
apelarea funciei glCallLists. O utilizare pentru acest mecanism este acela de a crea un
font i fiecare indice de list de afiare s corespund valorii ASCII a caracterului din
font. Pentru a avea mai multe fonturi este necesar stabilirea unui index iniial diferit
pentru fiecare font. Acest index iniial poate fi specificat prin apelarea funciei glListBase
nainte de a apela glCallLists.

void glListBase(GLuint base);

Funcia specific offset-ul care este adunat indicilor listelor de afiare n apelul funciei
glCallLists pentru a obine indicii listelor de afiare finali. Valoarea implicit a
parametrului base este 0. Parametrul base nu are nici un efect asupra apelului glCallList,
care execut o singur list de afiare, sau asupra funciei glNewList.

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


Functia execut n liste de afiare. Indicii listelor care vor fi executate vor fi calculai prin
adunarea offset-ului indicat de baza curent a listei de afiare (specificat cu ajutorul
funciei 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
octei vor fi citii din lists i apoi sunt deplasai i adunai octet cu octet pentru a calcula
offset-ul listei de afiare. Pentru aceasta este folosit urmtorul algoritm (byte[0]
reprezint nceputul secvenei de octei).

/* b = 2, 3 sau 4; octeii sunt numerotai n vector 0,1,2,3 */


offset = 0;
for (i = 0; i < b; i++) {
offset = offset << 8;
offset += byte[i];
}
index = offset + listbase;

Exemplu
Definirea listelor de afiare multiple: afiarea caracterelor dintr-un set de caractere
vectorial

void initStrokedFont(void)
/* seteaz indicii listelor de afiare pentru fiecare caracter
corespunztor 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); /* spaiu */
glTranslatef(8.0, 0.0, 0.0);
glEndList();
}

Funcia glGenLists aloc 128 de indici continui pentru listele de afiare. Primul
indice alocat devine baza listei de afiare. Pentru fiecare caracter va fi creat cte o list
de afiare; fiecare index al listei de afiare este suma dintre indicele de baz i valoarea
ASCII a literei. n acest exemplu sunt create numai cteva litere i caracterul . Dup
crearea listelor de afiare poate fi apelata funcia glCallLists pentru a le executa.

Exemplu
Apelul functiei printStrokedString avnd ca parametru un caracter :

void printStrokedString(GLbyte *s)


{
GLint len = strlen(s);
glCallLists(len, GL_BYTE, s);
}

II.11.6. Gestiunea variabilelor de stare folosind liste de afiare

O list de afiare poate conine apeluri care s modifice valorile variabilelor de


stare OpenGL. Aceste valori se modific la execuia listei de afiare (ca i n modul
imediat de execuie al comenzilor) i modificrile se pstreaz i dup execuia complet
a listei de afiare.

Exemplu
Modificrile culorii curente i a matricii curente fcute n timpul execuiei listei de
afiare rmn 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 urmtoarea secven de cod, segmentul de dreapt desenat dup lista de
afiare va avea culoarea roie (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 modificrile strii s fie pstrate, dar alteori dup execuia
unei liste de afiare se dorete s se revin la starea anterioar. ntr-o list de afiare nu
poate fi folosit funcia glGet*, aa c trebuie folosit un alt mod de a interoga i stoca
valorile variabilelor de stare. n acest scop poate fi folosit funcia glPushAttrib pentru a
salva un grup de variabile de stare i glPopAttrib pentru a reface variabilele.

Exemplu
Refacerea variabilelor de stare din interiorul unei liste de afiare

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();
Exemplu
Dac se folosete lista de afiare 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 afiare apelat de 10
ori*/
drawLine(); /* unde i cum apare aceast linie? */
glFlush();
}

II.11.7. ncapsularea schimbrilor de mod

Listele de afiare pot fi folosite pentru a organiza i stoca grupuri de comenzi,


pentru a modifica diferite moduri sau a seta diferii parametri. Cnd se dorete comutarea
de la un grup de setri la un altul folosirea listelor de afiare poate fi mai eficient dect
apelarea direct.
Listele de afiare pot fi mai eficiente dect modul imediat pentru comutarea ntre
diferite setri ale surselor de lumin, modelelor de iluminare i parametrilor de material.
De asemenea, listele de afiare se pot folosi i pentru generarea liniilor cu ablon, precum
i pentru ecuaiile planului de decupare. n general, execuia listelor de afiare este cel
puin tot att de rapid ca i apelul direct dar n cazul folosirii listelor de afiare este
introdus un overhead.

Exemplu
Folosirea listelor de afiare pentru a comuta ntre trei abloane diferite de linii. La nceput
se apeleaz funcia glGenLists pentru a aloca o list de afiare pentru fiecare ablon.
Apoi se folosete funcia 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);

Você também pode gostar