Grafică pe calculator în C şi OpenGL Sistemul de izualizare OpenGL 1. Definirea proiecńiei perspectiă şi a olumului de izualizare În OpenGL un punct este reprezentat printr-un ector coloană. Pentru matricele 4 4 utilizate în reprezentarea unei transformări geometrice în coordonate omogene, este utilizată conenńia coloană majoră. Conform acestei conenńii, fiind dat un număr de 16 alori reale, în ordinea a0, a1, K, a15, matricea corespunzătoare este: a0 a4 a8 a12 = a1 a5 a9 a13 A. (1) a2 a6 a10 a14 a3 a7 a11 a15 Sistemul de referinńă uniersal, WCS, definit în OpenGL este un sistem drept. De asemenea, sistemul de referinńă de obserare, VCS, este un sistem drept şi este definit, ca localizare şi orientare, în raport cu sistemul de referinńă uniersal. Originea sistemului de referinńă de obserare, coincide cu centrul de proiecńie (sistemul de izualizare OpenGL constituie un caz particular al sistemului PHIGS). În sistemul de referinńă de obserare se poate defini o transformare de proiecńie paralelă ortografică sau de proiecńie perspectiă. OpenGL oferă funcńii ce permit definirea proiecńiei perspectiă pe un plan perpendicular pe axa z a sistemului de referinńă de obserare, cu direcńia de obserare spre z (fig.1). y DirecŃia de obserare B z x O D z = znear B C A C z D z = zfar Fig. 1 Definirea proiecńiei perspectiă şi a olumului de izualizare în OpenGL 1
Lucrarea 5 Volumul de izualizare în cazul proiecńiei perspectiă, în OpenGL, este un trunchi de piramidă, ABCD A B C D. Trunchiul de piramidă de izualizare (frustum), este determinat de intersecńia a două plane de izualizare, planul apropiat şi planul depărtat, cu patru plane laterale. Planul de izualizare apropiat este şi planul în care sunt proiectate toate obiectele izibile ale scenei. SuprafaŃa ABCD din planul de izualizare apropiat (planul de proiecńie) constituie fereastra de izualizare (iew plane window). Prin urmare, trunchiul de piramidă de izualizare este orientat spre z şi este fi definit prin următoarele alori: (left, bottom) şi (right, top): coordonatele colńurilor ferestrei din planul din fańă (ale ferestrei de izualizare); znear: distanńa (ca aloare pozitiă) de la pozińia obseratorului la planul din fańă; zfar: distanńa (ca aloare pozitiă) de la pozińia obseratorului la planul din spate. FuncŃia OpenGL care defineşte o proiecńie perspectiă ca cea din figura 1 este: oid glfrustum(gldouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble znear, GLdouble zfar); ColŃurile ferestrei 2D din planul de proiecńie, (left, bottom, -znear) şi (right, top, -zfar) sunt mapate pe colńurile stânga-jos şi dreapta-sus ale ferestrei 2D din sistemul coordonatelor de decupare, adică ( 1, 1, 1) şi ( 1,1, 1). atricea de proiecńie este următoarea: P 2 znear right left 0 = 0 0 0 2 znear top bottom 0 0 right+ left right left top+ bottom top bottom zfar+ znear zfar znear 1 0 0. (2) 2 zfar znear zfar znear 0 O altă funcńie care poate fi folosită pentru definirea proiecńiei perspectiă este: oid gluperspectie(gldouble foy, GLdouble aspect, GLdouble znear, GLdouble zfar); FuncŃia gluperspectie() creează un olum de izualizare la fel ca şi funcńia glfrustum(), dar specificarea se face în alt mod. În cazul acestei funcńii olumul de izualizare se specifică prin unghiul de izualizare în planul O x y (deschiderea camerei de luat ederi), raportul dintre lăńimea şi înălńimea ferestrei definite în planul apropiat şi distanńele la planul apropiat, respecti depărtat (ca alori pozitie). Deci parametrii funcńiei sunt: foy: unghiul de izualizare în planul O x y, care trebuie să fie în interalul [.0,180.0] 0 ; aspect: raportul lăńime/înălńime al laturilor ferestrei din planul apropiat; acest raport trebuie să corespundă raportului lăńime/înălńime asociat porńii de afişare. De exemplu, dacă aspect = 2, atunci unghiul de izualizare pe direcńia axei x este de două ori mai mare decât cel pe direcńia axei y. Dacă poarta de afişare are lăńimea de două ori mai mare decât înălńimea, atunci imaginea a fi afişată nedistorsionat. 2
Grafică pe calculator în C şi OpenGL znear, zfar: distanńele între obserator şi planele de decupare de-a lungul axei negatie (se iau ca alori pozitie). z 2. Compunerea transformărilor geometrice Pentru a efectua transformări geometrice compuse nu este eficient să se calculeze produsul dintre matricea de reprezentare a fiecărui punct şi matricele de transformări succesie. Este de preferat să se calculeze o matrice de transformare compusă, care se poate aplica unuia sau mai multor obiecte. Pentru calculul matricelor de transformare compuse (prin produs de matrice) se foloseşte o matrice de transformare curentă C şi operańii de acumulare în matricea curentă prin înmulńire la dreapta. Rezultatul înmulńirii înlocuieşte conńinutul matricei curente. De exemplu, pentru secenńa de transformări în ordinea 1, 2, K, n, aplicate obiectelor scenei, mai întâi se inińializează matricea curentă C cu matricea identitate, după care se calculează matricea compusă prin postmultiplicare (înmulńire la dreapta) în ordine inersă celei în care se aplică matricele componente. C= I C = C n = n C = C n 1 = n n 1. C= C = K (3) C P 1 n n 1 2 1 = = n n 1 K 2 1 = P= n n 1 K 1 P În această transformare, se aplică mai întâi matricea 1 punctului P. Punctului astfel rezultat i se aplică transformarea 2 ş.a.m.d. Acest mod de calcul al matricelor compuse este folosit în OpenGL. atricea curentă se poate inińializa cu matricea identitate prin funcńia glloadindentity() sau cu o matrice oarecare, dată de un pointer la un ector de 16 alori consecutie, prin funcńia glloadatrix#(). glloadatrixd( const GLdouble *m); glloadatrixf( const GLfloat *m); Valorile din ectorul GLdouble *m (respecti GLfloat *m) sunt atribuite în ordinea coloană majoră matricei curente. ConŃinutul matricei curente poate fi modificat prin multiplicare (la dreapta) cu o altă matrice, dată printr-un ector de 16 alori de tip double sau float utilizând funcńia glultatrix#(). glultatrixd( const GLdouble *m); 3
Lucrarea 5 glultatrixf( const GLfloat *m); atricea inińială C este astfel înlocuită cu produsul C, unde este matricea corespunzătoare ectorului dat de pointerul m. Crearea unei matrice pentru o transformare elementară (translańie, scalare etc.) şi înmulńirea ei cu matricea curentă se poate face prin apelul unei singure funcńii OpenGL. Transformările compuse se efectuează prin acumularea produsului matricelor componente în matricea curentă. De exemplu, transformările de modelare din lucrarea precedentă au fost implementate în OpenGL după cum urmează: Transformarea 2 = T (0, 8,0) S(2,2,2) : gltranslated(0,-8,0); glscaled(2,2,2); Transformarea 3 = T (8,0,0) Rz ( π / 4) S(2,1,2 ) : gltranslated(8,0,0); glrotated(45,0,0,1); glscaled(2,1,2); Transformarea 4 = T ( 8,0,0) Rz ( π / 4) S(2,1,2 ) gltranslated(-8,0,0); glrotated(-45,0,0,1); glscaled(2,1,2); 3. Stiele matricelor de transformare utilizate în OpenGL Transformarea unui obiect din sistemul de referinńă local în sistemul de referinńă normalizat este compusă din succesiunea transformărilor de modelare (instanńiere), de obserare şi de normalizare n : i = (4) n i Transformarea de instanńiere i este, în general, specifică fiecărui obiect, deci se calculează pentru fiecare obiect în parte. Pentru cele mai multe din aplicańiile grafice, în care scena este obserată dintr-un singur punct de obserare, matricea de obserare este unică pentru toate obiectele dintrun cadru dat, dar se modifică în cadrul următor (imaginea următoare), dacă obseratorul şi-a schimbat pozińia de obserare (situańie întâlnită în grafica interactiă). atricea de normalizare n este definită de parametrii de proiecńie care corespund sistemului grafic. Această matrice este o caracteristică constructiă a sistemului grafic şi rămâne constantă pe toată perioada desfăşurării programului, pentru toate obiectele şi pentru toate imaginile generate. În concluzie, sunt necesare următoarele matrice de transformare în cursul generării imaginilor succesie, la momentele (cadrele) i, i+ 1, i+ 2, K. Cadrul i : = n i i1, pentru obiectul 1 4
Grafică pe calculator în C şi OpenGL = n i i2, pentru obiectul 2.. = n i ik, pentru obiectul k.. Cadrul i + 1: = n i+ 1 i1, pentru obiectul 1 = n i+ 1 i2, pentru obiectul 2.. = n i+1 ik, pentru obiectul k.. Pentru a eficientiza organizarea acestor operańii de transformări succesie, în OpenGL se folosesc mai multe stie de matrice de transformare, în care sunt reńinute şi reutilizate matricele intermediare de transformare. Transformările de modelare şi de obserare sunt efectuate într-o stiă de matrice, numită stia matricelor de modelare-izualizare (modeliew matrix stack). Transformarea de normalizare este prelucrată într-o stiă de matrice separată, numită stia matricelor de proiecńie (projection matrix stack). ai există încă o stiă de matrice pentru operańiile de texturare, numită stia matricelor de texturare (texture matrix stack). Separarea matricelor de modelare-izualizare şi de proiecńie permite execuńia în paralel a operańiilor din pipeline-ul grafic al acceleratoarelor hardware care au preăzute resurse pentru astfel de prelucrări. Fiecare stiă de matrice se comportă asemănător cu o stiă obişnuită asupra căreia se operează prin funcńii de introducere (push) şi extragere (pop). Aceste funcńii diferă foarte puńin de funcńiile push şi pop folosite în general în programare. În orice moment, una din cele trei stie de matrice este declarată ca stiă curentă şi toate operańiile cu matricele de transformare sunt adresate stiei curente. Setarea unei stiei curente se face prin apelul funcńiei: oid glatrixode(glenum mode); unde argumentul mode poate fi una din constantele simbolice GL_ODELVIEW, GL_PROJECTION sau GL_TEXTURE pentru setarea ca stiă curentă a stiei de modelareizualizare, a stiei de proiecńie sau a stiei de texturare. atricea din ârful stiei curente este matricea curentă C, cu care se efectuează operańiile cu matrice (glloadidentitz(), gltranslate#(), glloadatrix#(), glultatrix#(), etc.). OperaŃiile efectuate cu o stiă se realizează prin intermediul funcńiilor: - glpushatrix() care se apelează atunci când o matrice aflată în capul stiei trebuie salată pentru a fi utilizată ulterior; - glpopatrix() care se apelează atunci când operańiile de compunere a matricelor trebuie să continue cu o matrice aflată sub capul stiei. În figura 2 este ilustrat modul de acńionare a funcńiilor glpushatrix() şi glpopatrix(). 5
Lucrarea 5 glpushatrix() gltranslate#() glpopatrix() C= α β γ C= α β α γ C= αt α β γ C= α β γ Fig. 2 OperaŃii cu stia matricelor de transformare Stiele matricelor de transformare sunt deosebit de utile pentru redarea scenelor şi a obiectelor modelate ierarhic, în care scena sau fiecare obiect este compus din mai multe subobiecte, pe mai multe niele de ierarhie. Fiecare obiect component este definit printr-o matrice de localizare relati la obiectul căruia îi aparńine (obiect părinte), şi instanńierea acestuia se obńine prin compunerea matricei de localizare proprii cu matricea de localizare a obiectului părinte. În continuare prezentăm modalitatea de adăugare a noi obiecte a căror mişcare trebuie descrisă în raport de un obiect precedent. Presupunem că scena conńine obiectele o 1, o2, K, on, aflate în mişcare unele fańă de altele. Dorim să adăugăm obiectul o n+ 1, care se a mişca în raport cu obiectul o (fig. 3). Considerăm că matricea de transformare care permite n localizarea şi orientarea obiectului o n în raport cu sistemul uniersal este şi orientarea obiectului o n+ 1 este dată de matricea n+ 1. n, iar localizarea y n+1 y n o n n, n+1 o n+1 x n+1 y n+1 O o 1 n z n x z Fig. 3 odelarea obiectelor definite ierarhic 6
Grafică pe calculator în C şi OpenGL Putem scrie: n+ 1 = n n, n+ 1, (5) unde n, n+ 1 este matricea care realizează pozińionarea obiectului o n+ 1 în raport cu o n. łinând cont de cele de mai sus, rezultă că se poate adopta următoarea strategie: la adăugarea obiectului o n se a memora (glpushatrix()) matricea de transformare n (fără a fi inclusă şi scalarea); se reface n (glpopatrix()) şi se pozińionează obiectul o n+ 1 relati la obiectul o n (eentual se a memora matricea n+ 1, fără includerea scalării, pentru adăugarea unui nou obiect). 3. AplicaŃii În aplicańiile următoare se urmăreşte utilizarea stielor matricelor de transformări geometrice. Exemplul 1 Să se construiască un brań articulat de robot, constituit din patru segmente: brań, antebrań şi două degete (fig. 4). Fig. 4 BraŃ de robot BraŃul trebuie să se rotească în jurul umărului (capătul din stânga al primului segment) şi cotului. işcările de rotańie au loc atât timp cât sunt apăsate anumite taste. 7
Lucrarea 5 IndicaŃii. Pentru construirea celor patru segmente (brań, antebrań şi cele două degete) se poate folosi scalarea unui cub, dar mai întâi trebuie aplicată o transformare care să orienteze corespunzător fiecare segment. Deoarece sistemul de coordonate local al modelului (cubului) este inińial în centrul cubului, trebuie translat sistemul de coordonate local pe o muchie a cubului (sau pe una din feńele cubului), altfel, rotańiile cubului se or face fańă de centrul lui şi nu fańă de punctul de piotare. După apelul lui gltranslate#() (pentru stabilirea punctului de piotare) şi glrotate#() (pentru a piota cubul), se a efectua translańia sistemului de coordonate în echiul punct. Apoi cubul este scalat şi trasat, în felul acesta construind primul segment (brańul). Codul pentru primul segment este: gltranslatef (-1.0, 0.0, 0.0); glrotatef ((GLfloat) shoulder, 0.0, 0.0, 1.0); gltranslatef (1.0, 0.0, 0.0); glpushatrix(); glscalef (2.0, 0.4, 1.0); glutwirecube (1.0); glpopatrix(); Pentru construirea celui de-al doilea segment, trebuie mutat sistemul de coordonate local în următorul punct de piotare (rotańie). Deoarece sistemul de coordonate local al obiectului precedent a fost rotit anterior, axa x este deja de-a lungul brańului. De aceea translarea de-a lungul axei x deplasează sistemul de coordonate în următorul punct de rotańie (încheietura brańului). Odată stabilit punctul de rotańie se poate utiliza acelaşi cod pentru trasarea celui de-al doilea segment ca şi pentru primul segment. Acest procedeu poate continua pentru un număr oarecare de elemente (brań, antebrań, mână, degete). gltranslatef (1.0, 0.0, 0.0); glrotatef ((GLfloat) elbow, 0.0, 0.0, 1.0); gltranslatef (1.5, 0.0, 0.0); glpushatrix(); glscalef (3.0, 0.4, 1.0); glutwirecube (1.0); glpopatrix(); Folosind indicańiile de mai sus să se completeze programul de mai jos astfel încât să se realizeze funcńiile cerute. static int shoulder = 0, elbow = 30, finger=15; //unghiuri de rotatie GLfloat x1 = 3, x2 = 5, x3 = 1; //dimensiuni segmente GLfloat xp1 = -5; //pozitia pe x a primului punct de piotare oid init(oid) { } oid display(oid) { glclear (GL_COLOR_BUFFER_BIT); glcolor3f(1, 0, 0); glpushatrix(); 8
Grafică pe calculator în C şi OpenGL //primul obiect (brat) //al doilea obiect (antebrat) //deget superior } //deget inferior glpopatrix(); glutswapbuffers(); glflush(); oid reshape (int w, int h) { glviewport (0, 0, (GLsizei) w, (GLsizei) h); //transformarea de proiectie glatrixode (GL_PROJECTION); glloadidentity (); gluperspectie(65.0, (GLfloat) w/(glfloat) h, 1.0, 20.0); } //transformarea de obserare oid keyboard (unsigned char key, int x, int y) { glutpostredisplay(); } Probleme propuse 1. odificańi problema din exemplul 1 adăugând şi alte segmente la brań. De exemplu, adăugańi câtea degete la mână ca în fig. 5. Piotarea se a face în jurul muchiei marginale a unui segment. 9
Lucrarea 5 Fig. 5 BraŃ de robot cu degete 2. Să se modifice problema anterioară adăugând articulańii sferice în jurul cărora să se efectueze mişcarea de rotańie. ObseraŃie. În ederea adăugării de părńi suplimentare la brańul de robot (degete, eentual articulańii sferice pentru mişcarea de rotańie în jurul lor) se poate consulta programul "glutmech.cpp" sau "glutmech.exe". 10