Escolar Documentos
Profissional Documentos
Cultura Documentos
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
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).
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
Iniializare fereastr
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:
Creare fereastr
Distrugere fereastr
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.
Redimensionarea ferestrei
void glutReshapeFunc(void (*func)(int width, int height)) ;
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.
Exemplu
Funcia output prezentata mai jos realizeaza afiarea unui text cu format, incepand dintr-
o pozitie specificata a ferestrei curente.
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();
}
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.
Exemplu 1
Programul din fiierul exemplu11.c afieaz un dreptunghi centrat n fereastr.
/* fiierul exemplul1.c */
void display(void)
{
/* terge toi pixelii */
glClear (GL_COLOR_BUFFER_BIT);
glFlush ();
}
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 */
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();
}
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
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) ;
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.
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.
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);
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.
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();
Figura II.4
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.8.2.1.Limea liniilor
Exemplu:
glLineStipple(1, 0x3F07);
glEnable(GL_LINE_STIPPLE);
/* exemplul3.c*/
#include "glut.h"
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);
/* 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);
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.
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.
/* 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 ();
}
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.
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.
glBegin (GL_POLYGON);
glNormal3fv(n0);
glVertex3fv(v0);
glNormal3fv(n1);
glVertex3fv(v1);
glNormal3fv(n2);
glVertex3fv(v2);
glNormal3fv(n3);
glVertex3fv(v3);
glEnd();
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.
Prezentm n continuare funciile OpenGL prin care pot fi definite proieciile i volumul
de vizualizare.
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
O alt funcie care poate fi folosit pentru proiecia perspectiv este gluPerspective :
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
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.
- (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
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();
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
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 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.
/* 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 ();
}
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.
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);
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 ();
}
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).
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.
glEnable(GL_LIGHT1);
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 exemplul de mai sus valorile folosite pentru lmodel_ambient sunt valorile implicite
pentru GL_LIGHT_MODEL_AMBIENT.
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
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);
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 :
Emisia
Prin asocierea unei culori RGBA parametrului GL_EMISSION se poate face ca
un obiect s par c furnizeaz lumin de culoarea selectat.
Exemplu:
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();
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*.
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();
}
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.
#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();
}
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();
}
}
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();
}
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.
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);
/* fiierul exemplul9.c */
#include glut.h
#include <stdlib.h>
GLuint listName;
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 ();
}
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.
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 :
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.
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.
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;
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.
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.
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 :
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.
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();
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.
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.
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.
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 :
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();
}
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);