You are on page 1of 197

UNIVERSITATEA DIN BACU FACULTATEA DE INGINERIE

Culea George

Gbureanu Ctlin

PRELUCRARE GRAFIC
Note de curs - laborator

Editura Alma Mater Bacu 2007

1 ELEMENTE INTRODUCTIVE
1.1 Sistemul grafic OpenGL
Grafica cu calculatorul (n special grafica 3D i n particular grafica interactiv 3D) i caut propriul drum ntr-un numr n cretere de aplicaii, de la programe de grafic simple pentru calculatoare personale pn la software de modelare i vizualizare sofisticat pentru staii grafice i supercalculatoare. Deoarece a crescut interesul pentru grafica cu calculatorul, a crescut de asemenea i dorina de a fi capabil s scrii aplicaii care pot rula pe o varietate de platforme cu un domeniu de capaciti grafice. Un standard grafic uureaz aceast sarcin prin eliminarea nevoii de a scrie un driver grafic distinct pentru fiecare platform pe care ruleaz aplicaia. Pentru a fi viabil, un standard grafic propus pentru aplicaii interactive 3D trebuie s satisfac cteva criterii. El trebuie s fie implementabil pe platforme cu capaciti grafice diferite fr compromiterea performanelor grafice. El trebuie s asigure o interfa natural care permite unui programator s descrie operaiile de redare ntr-un mod concis. n final, interfaa trebuie s fie suficient de flexibil pentru a gzdui extensii astfel nct dac noi operaii grafice devin semnificative sau disponibile n noile subsisteme grafice, aceste operaii s poat fi asigurate fr fragmentarea interfeei. OpenGL (Open Graphics Library) ndeplinete aceste criterii prin asigurarea unei interfee simple, directe pentru operaiile fundamentale de redare grafic 3D. El permite primitive grafice de baz cum ar fi punctele, segmentele de dreapt, poligoanele i imaginile, precum i operaii de redare de baz cum ar fi transformrile afine i proiective i calculele de iluminare. El permite de asemenea operaii de redare avansat cum ar fi maparea texturilor i redarea cu antialiasing. OpenGL este o interfa software pentru plcile grafice. OpenGL se bazeaz pe IrisGL dezvoltat de Silicon Graphics (SGI). Scopul iniial al dezvoltrii IrisGL a fost de a dezvolta o interfa programabil pentru staiile grafice SGI. Aceast interfa programabil s-a intenionat iniial a fi independent de hardware i a ndeplini cerinele speciale ale programrii grafice 3D. Ulterior IrisGL a devenit interesant i pentru alte staii. n 1992 a luat fiin OpenGL Architecture Review Board (ARB) printre ai crui membrii se afl principalii productori de staii grafice cum ar fi SGI, Sun, HewlettPackard, Microsoft, Evans&Sutherland, IBM, Intergraph. Site-ul ARB OpenGL poate fi gsit la www.opengl.org. OpenGL a devenit un standard industrial, disponibil din anul 1992, pe baza specificaiilor realizate de acest consoriu independent. Scopul ARB este de a controla dezvoltarea OpenGL, i de a introduce noi funcionaliti n versiunile urmtoare. OpenGL evolueaz n mod continuu permind ca inovaiile la nivelul hardware-ului s fie accesibile dezvoltatorilor de aplicaii prin mecanismul de extensii 3

OpenGL Adugrile la specificaii (prin extensii) sunt bine controlate de consoriul ARE i actualizrile propuse sunt anunate din timp pentru a permite dezvoltatorilor s adopte modificrile. Atunci cnd extensiile sunt larg acceptate, ele sunt luate n considerare pentru includerea n nucleul de baz OpenGL. Este asigurat compatibilitatea cu dezvoltrile anterioare ale bibliotecii astfel c aplicaiile mai vechi vor rula pe acceleratoarele hardware cu drivere OpenGL mai noi. Utilizatorii finali ai OpenGL, furnizorii independeni de software i ali realizatori de aplicaii bazate pe APLuI OpenGL pot utiliza biblioteca fr cerine de licen. OpenGL Performance Characterisation Committee, o alt organizaie independent, creeaz i menine benchmark-urile OpenGL i public rezultatele acestor benchmark-uri pe site-ul www.specbenc.org/gpc/opc.static/index.htinl. OpenGL este portabil, fiind disponibil pe o varietate de sisteme cum ar fi PC, Macintosh, Silicon Graphics, UNIX, Linux, Irix, Solaris, HP-UX OpenGL ruleaz pe fiecare din principalele sisteme de operare incluznd MacOS, OS/2, UNIX, Windows95, Windows NT, Linux, OPENStep, Python i BeOS. Lucreaz de asemenea cu fiecare sistem de ferestre principal, incluznd Presentation Manager, Win32 i X/Window System. OpenGL este practic disponibil pe aproape orice calculator care suport un monitor grafic, o implementare OpenGL poate fi n mod eficient gzduit la aproape orice nivel al hardware-ului grafic, de la memoria video de baz la cele mai sofisticate subsisteme grafice. OpenGL poate fi apelat din limbajele de programare C, C++, Java, FORTRAN i Ada i ofer independen complet fa de topologiile i protocoalele de reea. OpenGL este de asemenea scalabil deoarece poate rula pe o varietate de calculatoare, de la cele personale pn la staii de lucru i supercalculatoare Aceasta se realizeaz prin mecanismul OpenGL de cerere a capacitilor hardware. OpenGL este bine structurat avnd o arhitectur intuitiv i comenzi logice (n numr de cteva sute). Utiliznd comenzile OpenGL se pot scrie aplicaii avnd cteva linii de cod spre deosebire de programele realizate utiliznd alte biblioteci. Una din caracteristicile forte ale interfeei OpenGL este c interfaa sa este uor de utilizat de ctre nceptori fiind n acelai timp suficient de puternic pentru a satisface cerinele unor aplicaii profesioniste indiferent c acestea sunt simulatoare de zbor, animaii, aplicaii de proiectare asistat sau vizualizri tiinifice. Driverele OpenGL ncapsuleaz informaii despre substratul hardware, elibernd dezvoltatorul aplicaiei de necesitatea de a scrie aplicaiile pentru anumite caracteristici hardware.

1.2 Sisteme grafice pentru grafica 3D


Pentru grafica 3D sunt disponibile cteva sisteme. Un sistem relativ bine cunoscut este PHIGS (Programmer's Hierarchical Interactive Graphics System). Bazat pe GKS (Graphics Kernal Systems), PHIGS este standard ANSI. PHIGS asigur modalitatea de a manipula i a desena obiecte 3D prin ncapsularea descrierii obiectelor i a atributelor ntro list de display care este apoi referit cnd obiectul este afiat sau manipulat. Un avantaj al listei de display este c un obiect complex este descris doar o dat chiar dac este afiat de mai multe ori. Aceasta este important n special dac obiectul de afiat trebuie transmis de4

a lungul unui canal de band joas (cum ar fi reeaua). Un dezavantaj al listei de display este c poate cere un efort considerabil pentru respecificarea obiectului dac el este modificat continuu ca rezultat al interaciunii cu utilizatorul. O alt dificultate cu PHIGS este lipsa suportului caracteristic de redare avansat cum ar fi suportul pentru maparea texturilor. PEX extinde sistemul de ferestre X (standard pentru staiile UNIX) pentru a include posibilitatea de a manipula i desena obiecte 3D (PEXlib este API care asigur protocolul PEX). Original bazat pe PHIGS, PEX permite redarea n mod imediat, ceea ce nseamn c obiectele pot fi afiate dup ce sunt descrise, fr a fi necesar ca mai nti s se complecteze o list de display. PEX de obicei nu permite caracteristici avansate de redare, i este disponibil doar pentru utilizatorii X. n linii mari, metodele de descriere a obiectelor grafice, pentru a fi redate utiliznd PEX sunt similare celor OpenGL. Ca OpenGL i PEXlib, RenderMan este o API care asigur o modalitate de redare a obiectelor geometrice. Spre deosebire de aceste interfee, oricum, RenderMan asigur un limbaj de programare (denumit shading language) pentru descrierea felului cum aceste obiecte trebuie s apar Ia desenare. Aceast programabilitate permite generarea imaginilor care arat foarte real, dar este de nepracticat pentru implementarea celor mai multe acceleratoare grafice, fcnd din RenderMan o alegere slab pentru grafica interactiv 3D. n final, exist API-uri care asigur accesul la redarea 3D ca un rezultat al metodelor pentru descrierea obiectelor grafice de nivel ridicat. Liderii acestora sunt HOOPS i IRIS Inventor. Obiectele asigurate de aceste interfee sunt de obicei mai complexe dect primitivele geometrice simple descrise cu API-uri cum ar fi PEXlib sau OpenGL; ele pot comprima nu doar geometria dar de asemenea i informaii despre cum sunt ele desenate i cum reacioneaz la intrrile utilizatorului. HOOPS i Inventor elibereaz programatorul de descrierea plicticoas a operaiilor de desenare individuale, dar accesul simplu la obiecte complexe n general nsemnnd pierderea controlului fin asupra redrii (sau cel puin fcnd un asemenea control dificil). n orice caz, OpenGL poate asigura o baz bun pe care s se construiasc asemenea API-uri de nivel ridicat. Caracteristicile de standardizare, stabilitate, fiabilitate, portabilitate, uurin n utilizare i buna documentare fac din OpenGL un produs preferat naintea altor biblioteci pentru realizarea vizualizrilor tiinifice, a mediilor virtuale, aplicaiilor CAD/CAM/CAE, imagistic medical, jocuri, etc. Cei mai renumii dezvoltatori de software utilizeaz OpenGL ca suport pentru realizarea unor API de nivel mai nalt. Spre exemplu, Openlnventor asigur o interfa cu utilizatorul care permite uurina realizrii aplicaiilor OpenGL. Iris Performer extinde funcionalitatea OpenGL i permite caracteristici suplimentare create pentru cerinele unei rate de remprosptare a imaginii mai mari necesare n simulri vizuale i realitatea virtual. OpenGL Optimizer este un toolkit pentru interaciunea, modificarea n timp real i redarea unor modele complexe cum ar fi cele din aplicaiile CAD/CAM. Lista aplicaiilor realizate avnd la baz OpenGL este mare i ea cuprinde aplicaii de modelare i animaie 3D (Maya, truSpace, 3D Studio Max, etc.), aplicaii CAD/CAM (CATIA, 3D Studio Viz, Pro/ENGINEER, I-DEAS, etc), simulri vizuale i realitate virtual (Visualisation Data Explorer, WorldToolKit, Designer, Workbranch, etc.), playere VRML {Cosmo World, RenderSoft VRML Editor, etc.), jocuri (Quake2, X-Plane, Unreal, etc.). 5

Pentru a ine pasul cu inovrile la nivelul hardware-ului, fr ns a fora programatorii s lucreze n limbaj de asamblare, soluia oferit de firmele din domeniul grafic este un limbaj de nivel nalt pentru OpenGL - OpenGL Shading Language (sau GLslang), independent de hardware, uor de utilizat, suficient de puternic pentru a trece testul timpului i care va reduce drastic nevoia de extensii. Continund tradiia de compatibilitate "backwards", pe care au avut-o toate cele patru versiuni OpenGL, OpenGL 2.0 va fi un superset al lui OpenGL 1.4, astfel c aplicaiile mai vechi vor rula pe acceleratoarele hardware cu drivere OpenGL 2.0 fr modificri.

1.3 Caracteristici OpenGL


Dei specificaia OpenGL definete un anumit flux de procesare grafic, furnizorii de platforme au libertatea de a realiza o implementare OpenGL particular pentru a ndeplini obiective de performan i de cost al sistemului unice. Apelurile individuale OpenGL pot fie executate de hardware dedicat, pot rula ca rutine software pe sisteme standard CPU, sau pot fi imlementate ca o combinaie de rutine hardware i software. Dezvoltatorii de aplicaii au garania unor rezultate de afiare consistente indiferent de implementarea OpenGL. OpenGL permite dezvoltatorilor de software accesul la primitive geometrice i imagine, liste de display, transformri de modelare, iluminare i texturare, antialiasing, blending i multe alte faciliti. Din punctul de vedere al programatorului, OpenGL reprezint un set de comenzi care permit specificarea obiectelor geometrice n dou sau trei dimensiuni, mpreun cu comenzi care controleaz felul n care aceste obiecte sunt rasterizate n buffer-ul cadru (framebuffer). Pentru cele mai multe din aceste comenzi, OpenGL asigur o interfa cu efect imediat, n sensul c specificarea unui obiect determin desenarea sa. OpenGL conine o mare cantitate de informaii de stare. Aceast stare controleaz modul n care sunt desenate obiectele n framebuffer. OpenGL se afl totdeauna ntr-o stare definit, setat prin variabile de condiie; aceasta nseamn c OpenGL este o maina de stare. Un exemplu de variabil de condiie este culoarea curent cu care sunt redate (desenate) primitivele individuale. Aceasta este setat utiliznd comanda glcolor() i apoi culoarea setat se aplic tuturor obiectelor care se deseneaz, pn cnd este utilizat o nou comand de modificare a culorii. La un anumit moment, o parte din aceast stare chiar i coninutul unei texturi i al memoriei video - este disponibil n mod direct utilizatorului, care poate utiliza comenzi pentru a obine valori asociate cu diferite informaii de stare. O parte a informaiilor de stare sunt vizibile, ns, doar prin efectul pe care l au asupra a ceea ce se deseneaz. OpenGL permite de asemenea aplicaii de vizualizare cu imagini 2D tratate ca tipuri de primitive care pot fi manipulate la fel ca i obiectele geometrice 3D. OpenGL dispune de unmai 10 primitive geometrice, i orice obiect care se deseneaz n OpenGL este compus din aceste primitive. Setul de instruciuni din bibliotec conine cteva sute de comenzi, toate fiind prefixate de gl. OpenGL asigur controlul direct asupra operaiilor fundamentale de grafic 3D i 2D. Aceste operaii includ specificarea unor 6

parametrii cum ar fi matricele transformrilor, coeficienii ecuaiilor de iluminare, operatori pentru actualizarea pixelilor. El nu asigur o modalitate pentru descrierea sau modelarea obiectelor geometrice complexe (cum ar fi cilindrul, cubul, sfera, etc.). Altfel spus, OpenGL asigur mecanismele pentru a descrie cum sunt redate obiectele geometrice complexe i nu mecanismele de a descrie obiectele complexe nsele. Toate corpurile complexe trebuie s fie construite de dezvoltatorul aplicaiei 3D pe baza primitivelor simple - puncte, linii, poligoane. Pentru a simplifica puin lucrurile pentru dezvoltatorii de aplicaii, experii n grafica 3D au dezvoltat cteva biblioteci dintre care cele mai importante sunt GLU (OpenGL Utility Library), GLUT (OpenGL Utility Toolkit) sau echivalentul su Microsoft -GLAUX. GLU simplific lucrurile pentru crearea calculelor de proiecie i pentru construirea suprafeelor complexe, reprezentnd printre altele curbe i suprafee NURBS (Non-uniform-rational-B-splines). GLUT este un utilitar independent de sistem pentru manevrarea n mod simplu a ferestrelor OpenGL i pentru furnizarea dezvoltatorului de aplicaii de rutine pentru controlarea evenimentelor externe provenite de la utilizator prin mouse sau tastatur. Oricine dorete s devin expert n grafica 3D trebuie s se familiarizeze cu cteva noiuni fundamentale de algebr i geometrie analitic. Altfel utilizarea comenzilor OpenGL se face mecanic fr o profund nelegere a mecanismelor interne. Aceste noiuni sunt calculul vectorial (produs scalar, produs vectorial), calcul matricial (nmulirea matricelor, matrice identitate), transformri geometrice. Sunt de asemenea necesare cteva cunotine din domeniul opticii. Cei interesai pot s i remprospteze aceste cunotine i din cri care prezint fundamentele graficii cu calculatorul. Un program tipic care utilizeaz OpenGL ncepe cu deschiderea unei ferestre n framebuffer-ul n care programul va desena. Apoi, se apeleaz funcii pentru alocarea unui context GL i asocierea sa cu fereastra. Odat ce contextul OpenGL este alocat, programatorul este liber s dea comenzi OpenGL. Unele comenzi sunt utilizate pentru desenarea obiectelor geometrice simple (cum ar fi puncte, segmente de dreapt i poligoane), n timp ce altele au efect asupra redrii acestor primitive inclusiv a felului cum sunt iluminate, colorate i a modului n care spaiul modelului utilizatorului este mapat la ecranul bidimensional. Sunt i comenzi care controleaz efectiv framebuffer-ul, cum ar fi citirea i scrierea pixelilor. Din punctul de vedere al implementatorului, OpenGL este un set de comenzi care au efect asupra felului n care opereaz hardware-ul grafic. Dac hardware-ul const doar dintr-un framebuffer adresabil, atunci comenzile OpenGL trebuie s fie implementate n ntregime software, de CPU-ul calculatorului gazd. Tipice pentru acest moment sunt ns plcile grafice care conin acceleratoare grafice variind de la cele cu un subsistem de redare capabil s redea linii i poligoane 2D pn la procesoare n virgul mobil sofisticate capabile de transformri i calcule asupra datelor geometrice. Sarcina implementatorului este de a asigura interfaa software CPU astfel nct pentru fiecare comand OpenGL s se divid sarcinile ntre CPU i placa grafic. Pentru a se obine un optim al performanei n executarea comenzilor OpenGL, aceast diviziune trebuie s fie n concordan cu placa grafic disponibil.

2 BAZELE PROGRAMRII N OPENGL


2

2.1 Arhitectura OpenGL

OpenGL deseneaz primitive ntr-o memorie video, subiectul a numeroase moduri selectabile. O primitiv poate fi un punct, segment de dreapt, poligon sau bitmap. Fiecare mod poate fi modificat independent; setarea unuia nu afecteaz setarea altora (dei pot interaciona n mai multe moduri pentru a determina ceea ce se produce n final n memoria video). Modurile sunt setate, primitivele specificate i celelalte operaii OpenGL sunt descrise prin intermediul comenzilor, n forma apelurilor de funcii sau proceduri.
Date vrfuri Date pixeli Liste de display Operaii cu pixeli Memorare textur Bufferul de cadru

Evaluator polinomial

Operaii pe vrfuri Asamblarea primitivelor Rasterizare

Operaii pe fragment

Figura 2.1 Schema fluxului de procesare OpenGL Figura 2.1 arat schema fluxului de procesare OpenGL. Modelul de interpretare a comenzilor de ctre OpenGL este client-server. Aceasta nseamn c programul (client) d comenzile i aceste comenzi sunt procesate i interpretate de OpenGL (server). Server-ul poate sau nu s opereze pe acelai calculator cu client-ul. Multe dintre comenzi pot fi acumulate n liste de display pentru o procesare ulterioar. n cazul n care se lucreaz cu procesare imediat (deci fr liste de display) comenzile sunt transmise prin fluxul de procesare OpenGL. Comenzile nu sunt altceva dect apeluri de funcii i proceduri OpenGL. 8

Primul stadiu de procesare asigur o modalitate eficient pentru aproximarea curbelor i a suprafeelor curbe prin evaluarea funciilor polinomiale ale valorilor de la intrare. Acest stadiu este parcurs doar de acele comenzi utilizate pentru reprezentarea curbelor i a suprafeelor Bezier i spline. Urmtorul nivel opereaz asupra primitivelor geometrice descrise prin coordonatele vrfurilor: puncte, segmente de dreapt i poligoane. n acest stadiu vrfurile sunt transformate i iluminate, i primitivele sunt decupate fa de volumul de vizualizare pentru a fi pregtite pentru nivelul urmtor rasterizarea. Rasterizarea convertete o primitiv proiectat, scalat la viewport ntr-o serie de fragmente. Fiecare fragment comprim pentru o locaie a unui pixel din memoria video culoarea, coordonatele de textur i adncimea (z). Rasterizarea produce o serie de adrese i de valori pentru memoria video utiliznd descrierea 2D a unui punct, segment de dreapt, sau poligon. Fiecare fragment astfel produs alimenteaz nivelul urmtor care asigur operaii asupra fragmentelor individuale nainte ca ele s modifice memoria video. Aceste operaii includ actualizri condiionale n memoria video pe baza noilor valori sau a valorilor de adncime memorate anterior (pentru efectuarea testului de ascundere), amestecarea culorilor fragmentelor cu culorile memorate, precum i mascarea i celelalte operaii logice asupra valorilor din fragment. Cnd este rasterizat un segment de dreapt sau un poligon, aceste date asociate sunt interpolate de-a lungul primitivei pentru a obine o valoare pentru fiecare fragment. Rasterizarea fiecrui tip de primitiv este controlat de un grup corespunztor de parametrii (atribute de redare a primitivelor). Un atribut de lime afecteaz rasterizarea punctului i un altul afecteaz rasterizarea segmentelor de dreapt. Suplimentar, se poate specifica o secven stipple (stilul liniei -linie punctata, ntrerupt, etc.) pentru segmentele de dreapt, i un model de haur pentru poligoane. Antialiasing-ul poate fi activat sau dezactivat individual pentru fiecare tip de primitiv. Cnd este activat, o valoare acoperitoare este calculat pentru fiecare fragment ce descrie poriunea acelui fragment care este acoperit de primitiva proiectat. Aceast valoare acoperitoare este utilizat dup ce texturarea a fost terminat pentru modificarea valorii alfa a fragmentului (n modul RGBA) sau valorii color index (n modul index). Procesarea pixelilor i a imaginilor trece peste seciunea de procesare a vrfurilor din flux pentru a transmite un bloc de fragmente n mod direct prin blocul de rasterizare spre blocul operaiilor pe fragmente individuale, determinnd eventual ca un bloc de pixeli s fie scris direct n memoria video. Valorile pot fi de asemenea citite din memoria video sau copiate dintr-o poriune a memoriei video n alta. Aceste transferuri pot include unele tipuri de decodificri i codificri. Se poate constata c exist dou fluxuri de date. Fluxul din partea de sus a schemei este pentru primitivele bazate pe vertex-uri. Fluxul din partea de jos este pentru primitive bazate pe pixeli - primitive imagine. Se poate spune c texturarea combin cele dou tipuri de primitive. Aa cum s-a mai artat, la modul general, sunt dou operaii principale care se pot face utiliznd OpenGL: - Se deseneaz ceva; - Se modific starea (aspectul) a ceea ce se deseneaz. n ceea ce privete obiectele pe care le putem desena cu OpenGL, i acestea sunt de dou tipuri: - Primitive geometrice; 9

- Primitive imagine. Altfel spus, grafica pe care o putem realiza utiliznd OpenGL este att grafic vectorial ct i grafic punctual. Primitivele geometrice pe care le poate reda OpenGL sunt puncte, linii i poligoane. Primitivele imagine sunt bitmap-uri i imagini grafice (adic pixeli care se pot extrage dintr-o imagine JPEG dup ce s-a citit aceast imagine n program). Suplimentar, OpenGL prin maparea texturilor unete primitivele geometrice cu cele imagine. O alt operaie comun care se face asupra ambelor tipuri de primitive este setarea strii. Setarea strii este procesul de iniializare al datelor interne, utilizate de OpenGL pentru redarea primitivelor. Setarea poate fi o operaie simpl cum ar fi stabilirea dimensiunii i culorii unui punct desenat dar i o operaie mai complicat cum ar fi iniializarea nivelelor multiple pentru maparea texturilor. Trebuie subliniat c dei primitivele geometrice pe care le poate reda OpenGL nu sunt spaiale, n sensul c ele pot fi redate i n plan, totui OpenGL este o bibliotec de grafic 3D. Ceea ce este deosebit n felul n care se deseneaz un punct ntr-o bibliotec 2D, i felul n care se deseneaz un punct ntr-o bibliotec 3D sunt coordonatele acestui punct. Bibliotecii 2D i se furnizeaz coordonate 2D, pe cnd bibliotecii 3D i se furnizeaz coordonate 3D i prin mecanismele proieciei se face transformarea din sistemul de coordonate 3D n 2D urmnd ca apoi primitivele s fie redate pe dispozitivul de afiare. Efectul comenzilor OpenGL asupra memoriei video este fundamental controlat de sistemul de ferestre care aloc resurse de memorie video. Sistemul de ferestre este cel care determin care poriuni ale memoriei video pot fi accesate de OpenGL la un anumit moment de timp i tot el este cel care i comunic lui OpenGL cum sunt structurate acele poriuni. n mod similar, afiarea coninutului memoriei video pe un tub CRT nu este controlat de OpenGL (incluznd transformarea valorilor individuale din memoria video prin asemenea tehnici, cum ar fi corecia gamma). Configurarea memoriei video are loc n exteriorul OpenGL, n conjuncie cu sistemul de ferestre; iniializarea unui context OpenGL are loc cnd sistemul de ferestre aloc o fereastr pentru redare OpenGL. Suplimentar, OpenGL nu are faciliti de obinere a intrrilor de la utilizator, deoarece este de ateptat ca sistemul de ferestre sub care ruleaz OpenGL s asigure asemenea faciliti. Aceste considerente fac de fapt OpenGL independent de sistemul de ferestre.

2.2 Descriere general OpenGL, GLU i GLAUX

2.2.1 OpenGL Utility Library (GLU)


10

Un principiu de baz n proiectarea interfeei OpenGL a fost de a se asigura portabilitatea unui program fr a se specifica ct de nalt s fie nivelul la care pot fi descrise obiectele grafice. Ca rezultat, interfaa de baz OpenGL nu permite redarea unor obiecte geometrice, care sunt asociate n mod tradiional cu standardele grafice. Spre exemplu, implementarea OpenGL nu red poligoane concave. Un motiv ar fi c algoritmii pentru redarea (umplerea) poligoanelor concave sunt mai compleci dect cei pentru redarea poligoanelor convexe n particular, dac se red un poligon concav mai mult de o dat este mai eficient s fie mai nti descompus n poligoane convexe (sau triunghiuri) i apoi s se deseneze poligoanele convexe. Un algoritm de descompunere a poligoanelor concave este asigurat ca parte a bibliotecii GLU, care este asigurat pentru fiecare implementare OpenGL. GLU asigur de asemenea o interfa, care se bazeaz pe evaluatorii polinomiali OpenGL, pentru descrierea i afiarea curbelor i a suprafeelor NURBS (cu posibilitatea de segmentare spaial), precum i o modalitate de reprezentare a cvadricelor (sferelor, conurilor, i a cilindrilor). GLU este util att pentru redarea unor obiecte geometrice utile ct i pentru exemplificarea modelului de construire a unei biblioteci care se bazeaz pe OpenGL pentru redarea n memoria video. Pentru a nu exista o imagine confuz asupra a ceea ce reprezint OpenGL trebuie subliniat c OpenGL nu este un limbaj de programare ci aa cum s-a mai artat o API (interfa pentru programarea aplicaiilor). Atunci cnd ne referim la o aplicaie OpenGL, nelegem c aplicaia respectiv a fost scris ntr-un limbaj de programare (cum ar fi C) i c apeleaz funcii OpenGL. Nu este obligatoriu ca o aplicaie s utilizeze doar pachetul de funcii OpenGL pentru desenare. Simultan pot fi utilizate mai multe biblioteci grafice. Spre exemplu se pot utiliza funciile OpenGL pentru partea de reprezentare 3D iar pentru partea de grafic ce ine de interfaa aplicaiei s se utilizeze funciile grafice specifice mediului cu care se lucreaz (spre exemplu interfaa GDI a Windows-ului). Ca orice API, funciile OpenGL pot fi apelate dup conveniile de apel din C. Deci apelarea bibliotecii din limbajul C nu constituie o problem. Apelarea din C++ a funciilor API, se face n acelai mod ca din limbajul C, cu consideraii minore. Funciile OpenGL pot fi de asemenea apelate din limbaje de tipul Visual Basic - care pot apela funcii C. Dei OpenGL este o interfa API puternic ce conine peste 300 funcii ea nu are nici mcar o singur funcie pentru managementul ferestrelor i a ecranului. De asemenea nu are funcii pentru manevrarea evenimentelor de la mouse i tastatur. Motivul este clar - independena de platform. Crearea i deschiderea unei ferestre se realizeaz n mod diferit n diferitele sisteme de operare. Pentru a putea lucra, programele OpenGL necesit ns o interfa grafic bazat pe ferestre. Deoarece OpenGL este independent de platform, este nevoie de o modalitate de a integra OpenGL n fiecare sistem grafic bazat pe ferestre. Fiecare sistem grafic bazat pe ferestre care suport OpenGL are funcii suplimentare API pentru controlarea ferestrelor OpenGL, manevrarea culorilor i a altor caracteristici. Aceste API-uri suplimentare sunt dependente de platform.

2.2.2 Biblioteci disponibile


11

Pentru crearea ferestrelor dar i pentru alte operaii necesare n realizarea aplicaiilor grafice OpenGL, s-au creat biblioteci suplimentare cum ar fi GLAUX sau GLUT (OpenGL Utility Toolkit). Trebuie spus c funciile puse la dispoziie de aceste dou biblioteci sunt similare i c un utilizator care a nvat utilizarea uneia dintre aceste biblioteci va utiliza cu uurin i cealalt bibliotec. Pentru simplitatea programelor care exemplific OpenGL, noi vom utiliza biblioteca GLAUX, care simplific interaciunea cu sistemul de ferestre i cu mouse-ul sau tastatura. Unul dintre motivele pentru care am ales aceast bibliotec este faptul c programele sunt implementate n Visual C (versiunea 6.0) i c acest mediu conine biblioteca GLAUX precum i o serie de aplicaii pentru exemplificarea funciilor OpenGL care se bazeaz pe biblioteca GLAUX. GLAUX este o bibliotec care face scrierea programelor OpenGL, n partea legat de sistemul de ferestre mult mai uoar. OpenGL este independent de sistemul de ferestre i de sistemul de operare. n felul acesta, partea din aplicaia realizat cu OpenGL, care face redarea este de asemenea independent de platform. Oricum pentru ca OpenGL s poat face redarea are nevoie de o fereastr n care s deseneze. n general aceast fereastr este controlat de sistemul de operare bazat pe ferestre cu care se lucreaz. Pentru a putea integra OpenGL n diferitele sisteme grafice bazate pe ferestre sunt utilizate biblioteci suplimentare pentru modificarea unei ferestre native ntr-una capabil OpenGL. Fiecare sistem de gestionare a ferestrelor are propria sa bibliotec, unic i funciile care fac acest lucru. Iat cteva astfel de biblioteci: - GLX pentru sistemul X Windows, obinuit pe platformele Unix; - AGL pentru Apple Macintosh; - WGL pentru Miocrosoft Windows. Pentru a simplifica programarea i dependena de sistemul de ferestre noi vom utiliza biblioteca GLAUX. GLAUX este un toolkit pentru realizarea simpl a aplicaiilor OpenGL. Biblioteca GLAUX simplific procesul crerii ferestrelor, al lucrului cu evenimente n sistemul de ferestre i manevrarea animailor. n general aplicaiile care necesit mai mult (adic butoane, meniuri, bare de scroll, etc.) n realizarea interfeei cu utilizatorul, vor utiliza o bibliotec proiectat pentru a realiza aceste caracteristici cum ar fi Motif sau Win32 API. Aplicaiile prototip sau cele care nu necesit toate caracteristicile unei interfee grafice cu utilizatorul complete, pot ns lucra cu GLAUX datorit modelului su de programare simplificat i datorit independenei de sistemul de ferestre.

2.3 GLAUX
Iniial biblioteca GLAUX a fost creat ca un toolkit pentru a permite nvarea OpenGL fr a intra n detaliile unui anumit sistem de operare sau de interfa cu utilizatorul., Pentru aceasta GLAUX conine funcii pentru crearea ferestrelor i pentru citirea intrrilor de la mouse i de la tastatur. Intern aceste funcii utilizeaz funciile API ale mediului n care se lucreaz. Modul de apelare al funciilor GLAUX rmne ns acelai pentru toate platformele. Dei are doar cteva funcii pentru crearea ferestrelor, 12

biblioteca GLAUX scutete utilizatorul de sarcina de a utiliza funciile Windows API care realizeaz acest lucru. Dei nu face parte din specificaia OpenGL, biblioteca GLAUX este implementat pentru fiecare platform pentru care se implementeaz OpenGL. Windows-ul nu face excepie de la acest lucru, i biblioteca GLAUX este inclus free n Win32 SDK de la Microsoft. Dac mediul de programare n care se lucreaz nu conine biblioteca GLAUX ea poate fi obinut free de la MicrosoftWin32 SDK. n afara funciilor pentru ferestre i pentru manevrarea evenimentelor de la tastatur biblioteca GLAUX conine o serie de funcii pentru desenarea unor obiecte 3D: sfera, cubul, torul i chiar un ceainic, etc. Programele scrise cu GLAUX-ul pot fi mutate, prin recompilare pe diverse medii. Suplimentar acestor funcii principale biblioteca GLAUX implementeaz cteva funcii pentru a permite operaii specifice sistemului cum ar fi inversarea buffer-elor i ncrcarea imaginilor. Utilizarea lor poate face ns programele neportabile. Toate exemplele i aplicaiile din aceast carte sunt scrise n C. Pentru C, exist cteva elemente necesare pe care trebuie s le fac o aplicaie: - Fiierele header aa cum se tie, conin prototipurile tuturor funciilor apelate, parametrii acestora, definirea valorilor constante. Aplicaiile OpenGL trebuie s includ fiierele header OpenGL, GLU i GLAUX (gl.h, glu.h, glaux.h). - Proiectele aplicaiei trebuie s includ cele trei biblioteci care vor fi legate (la linkeditare) de aplicaie (opengl32.1ib, glu32.1ib i glaux.lib). - Bibliotecile sunt dependente de implementarea OpenGL pentru sistemul de operare pe care se lucreaz. Fiecare sistem de operare are propriile sale biblioteci. Pentru sistemul Unix, biblioteca OpenGL este de obicei denumit libGL.so i pentru Microsoft Windows este denumit opengl32. lib. Funciile celor trei biblioteci pot fi recunoscute dup prefixele lor: gl pentru OpenGL, glu pentru GLU i aux pentru GLAUX. Tipurile enumerare (enumerated types) sunt definiii OpenGL pentru tipurile de baz (adic float, double, int, etc.) utilizate de program pentru definirea variabilelor. Pentru a se simplifica independena de platform a programelor OpenGL, se definete un set complet de tipuri enumerated types. Este indicat s se utilizeze aceste tipuri pentru a se simplifica transferarea programelor pe alte sisteme de operare. n continuare se d structura de baz care va fi utilizat ntr-o aplicaie. - Se configureaz i se deschide fereastra - Se iniializeaz starea OpenGL - Se nregistreaz funciile callback - Redare - Redimensionare - Intrri: tastatur, mouse, etc. - Bucla de procesare a evenimentelor de intrare. n general, acetia sunt paii ntr-o aplicaie OpenGL, pai pe care i detaliem n continuare. 1) Se alege tipul de fereastr necesar pentru aplicaie i se iniializeaz fereastra. 2) Se iniializeaz starea OpenGL care nu este necesar a fi modificat n fiecare poriune din program. Asemenea operaii pot fi setarea culorii background-ului, poziia surselor de lumin, setri pentru texturare. 13

3) Se nregistreaz funciile callback utilizate de aplicaii. Funciile callback sunt rutine scrise de programator pe care GLAUX-ul le apeleaz la apariia anumitor evenimente, cum ar fi remprosptarea ferestrei, micarea mouse-ului de ctre utilizator. Cea mai important funcie callback este cea de redare a scenei. 4) Se introduce bucla principal de procesare a evenimentelor. Aici aplicaia recepioneaz evenimentele, i se programeaz cnd anume sunt apelate funciile callback. Exemplu Structura unui program simplu se exemplific n continuare; Programul afieaz un ptrat pe care l translateaz pe axa x la apsarea sgeilor stnga, dreapta. #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK MutaStanga(void); void CALLBACK MutaDreapta(void); static GLfloat x=0; void myinit (void) { glClearColor(1.0, 1.0,1.0, 1.0); } void CALLBACK MutaStanga(void) { x=x-10; } void CALLBACK MutaDreapta(void) { x=x+10; } void CALLBACK display (void) { glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity (); glTranslatef(x, 0.0, 0.0); glBegin(GL_QUADS); glBegin(GL_QUADS); glColor3f (1.0, 0.0, 0.0); glVertex2f(100.0,100.0); 14

glColor3f (0.0, 1.0, 0.0); glVertex2f(150.0,100.0); glColor3f (0.0, 0.0, 1.0); glVertex2f(150.0,150.0); glColor3f (1.0, 1.0, 0.0); glVertex2f(100.0,150.0); glEnd(); glFlush(); } /*void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho (-160.0, 160.0, -160.0, 160.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); }*/ void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-160.0, 160.0, -160.0*(GLfloat)h/(GLfloat)w, 160.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-160.0*(GLfloat)w/(GLfloat)h, 160.0*(GLfloat)w/(GLfloat)h, -160.0, 160.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 300, 200); auxInitWindow ("Un patrat care se translateaza pe axa x"); myinit (); auxKeyFunc (AUX_LEFT, MutaStanga); auxKeyFunc (AUX_RIGHT, MutaDreapta); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); 15

} Marea majoritate a programelor din aceast carte se bazeaz pe acest model. Pentru a obine fiierul executabil plecnd de la aceast surs, n mediul Visual C 6.0, parcurgei paii urmtori: - Se editeaz programul. - Se compileaz programul (Build/ Compile). La compilare se va ntreba dac se dorete crearea workspace-ului. Se va rspunde cu yes.

Figura 2.2 - Se introduce n proiect bibliotecile opengl32.1ib, glu32.1ib, glaux. lib (Project / Settings / Link / Project Options) - Se construiete fiierul executabil i se ruleaz aplicaia (Build/Execute...) Programul afieaz pe un background alb un ptrat care la apsarea sgeilor stnga/dreapta poate fi deplasat (figura 2.2). Se poate remarca n codul aplicaiei utilizarea att a funciilor GLAUX ncep cu aux) ct i a celor OpenGL (ncep cu gl). Win32 permite crearea unei ferestre grafice dintr-o aplicaie n mod consol. Aceste detalii sunt acoperite de biblioteca GLAUX, creat tocmai pentru a ascunde aceste detalii de platform. Spre exemplu aplicaia urmtoare nu face altceva dect s creeze o fereastr i s atepte apoi introducerea unei taste. /* Programul afieaz o fereastr i ateapt introducerea unei taste dup care se nchide fereastra */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> #include <conio.h> int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); 16

auxInitPosition (50, 50, 200, 200); auxInitWindow ("Deschiderea unei ferestre intr-o aplicatie consola"); cprintf("Apasati o tasta pentru inchiderea ferestrei\n"); getch(); return(0); } Fereastra va fi afiat i la introducerea unei taste n fereastra consol se va nchide aplicaia (figura 2.3)

Figura 2.3 S vedem cum este scris funcia principal a aplicaiei: main(). Funciile auxlnitDisplayMode(), auxinitPosition() j auxInitWindow() fac parte din pasul de configurare a ferestrei. Folosind funcia auxinitDisplayMode() se specific diverse informaii privitoare la buffer-ele utilizate de fereastra aplicaiei - dac se folosete modelul de culoare RGBA sau index, dac se folosesc unul sau dou buffer-e de culoare, dac fereastra are sau nu asociate buffer-e de adncime, buffer ablon sau/i buffer de acumulare. void auxInitDisplayMode(GLbitfield mask); Argumentul mask este un SAU la nivel de bit ntre AUX_RGBA (modelul de culoare RGBA), AUX_INDEX (modelul de culoare index). AUX_SINGLE (un buffer de culoare), AUX_DOUBLE (dou buffer-e de culoare). AUX_DEPTH (buffer de adncime), AUX_STENCIL (buffer ablon). AUX_ACCUM (buffer de acumulare). Valorile implicite sunt pentru modelul de culoare index, cu un singur buffer de culoare. n exemplul de mai sus, ferestrei i se va asocia un singur buffer de culoare i modelul de culoare va fi RGB. Poziia ferestrei pe ecran: colul stnga-sus al ferestrei va fi poziionat la pixelul (0,0) al ecranului. Dimensiunea ferestrei este de 300 pixeli pe lime i de 200 pixeli pe nlime. Prototipul funciei care specific aceti parametrii este; auxInitPosition (GLint x, Glint y, Glsizei width, Glsizei heigth); Se remarc faptul c poziia colului stnga-sus este specificat n coordonatele ecranului. Sistemul de coordonate al ecranului este figurat de cele dou axe de coordonate. Funcia auxInitWindows() creeaz fereastra i specific titlul afiat pe bara de titlu. Dac aplicaia s-ar rezuma doar la funcia main() care ar include doar funciile comentate pn n acest moment rezultatul ar fi afiarea pe ecran a unei ferestre de 17

culoare neagr care ar i disprea imediat fr a se mai ntmpla nimic altceva. n exemplu, se apeleaz n continuare funcia myinit () care conine setrile proprii fiecrei aplicaii, n general este vorba de acele setri care se fac o singur dat n program. n cazul programului nostru n funcia myinit() s-a setat culoarea de tergere a ecranului, tergere care se realizeaz odat cu apelarea funciei glClear(GL_COLOR_BUFFER_BlT) din funcia display. Urmtoarele 4 funcii nregistreaz rutinele callback, rutine care se definesc n cadrul programului. Este vorba de nregistrarea rutinelor MutaStanga(), MutaDreapta(), my/Reshape() i display(). Funcia auxMainLoop() pe lng faptul c nregistreaz funcia callback display() este i bucla de procesare a evenimentelor, care interpreteaz evenimentele i apeleaz rutinele callback scrise de programator.

2.3.1 Funciile callback GLAUX


GLAUX-ul utilizeaz mecanismul callback pentru a realiza procesarea evenimentelor. Utiliznd acest mecanism se simplific procesarea evenimentelor pentru dezvoltatorul aplicaiei. Comparnd cu programarea tradiional de manevrare a evenimentelor, n care autorul trebuia s recepioneze i s proceseze fiecare eveniment, i s apeleze aciunile necesare, mecanismul callback simplific procesul prin definirea aciunilor care sunt suportate, i manevrarea automat a intrrilor dinspre utilizator. Tot ce trebuie s fac programatorul este s scrie codul pentru ceea ce se ntmpl cnd are loc evenimentul. GLAUX permite mai multe tipuri de funcii callback, incluznd: - auxMainLoop() - apelat cnd trebuie s fie remprosptai pixelii din fereastr. - auxReshapeFunc () - apelat cnd fereastra i modific dimensiunea. - auxKeyFunc () - apelat cnd se apas o tast la tastatur. - auxMouseFunc () - apelat cnd utilizatorul apas sau relaxeaz butonul mouse-ului - auxidleFunc() - apelat cnd nu se ntmpl nimic altceva. Funcia este foarte util n animaii. Funcia callback pentru redare n rutina principal a exemplului anterior apare urmtorul apel: auxMainLoop(display); Tot ceea ce se deseneaz se scrie n funcia display () (n cazul nostru) nregistrat de funcia auxMainLoop(). Funcia callback display() este una dintre cele mai importante funcii callback. Funcia display() este apelat atunci cnd este necesar a se remprospta coninutul ferestrei. Acesta este motivul pentru care tot ceea ce se deseneaz trebuie programat aici. Pe scurt, funcia display(), din aplicaia noastr, red un ptrat. Deoarece pentru fiecare vrf al ptratului s-a specificat alt culoare i deoarece n mod implicit n OpenGL este setat modelul de umbrire Gouraud, care interpoleaz intensitile vrfurilor, ptratul va fi desenat cu o combinaie a culorilor specificate pentru fiecare vrf Se va studia fiecare funcie OpenGL detaliat, n capitolele urmtoare. Funcia glFlush() determin ca orice funcie OpenGL neexecutat pn n acest moment s fie executat n momentul apelului glFlush. n aceast situaie se afl, n 18

cazul nostru, toate apelurile din display(). Intern OpenGL utilizeaz un flux de redare care proceseaz comenzile n mod secvenial. Deseori comenzile OpenGL sunt reinute pn cnd server-ul OpenGL proceseaz mai multe comenzi deodat. Desenarea este accelerat deoarece hardware-ul grafic lent este deseori accesat mai puin pentru un set dat de instruciuni de desenare. Se va exemplifica funcia auxKeyFunc() care n funcia principal a programului a fost apelat sub forma: auxKeyFunc (AUX_LEFT, MutaStanga); Funcia auxKeyFunc() asociaz apsarea tastei - sgeat stnga - cu funcia MutaStanga(). Funcia MutaStanga() din aceast aplicaie este: void CALLBACK MutaStanga(void) { x=x-10;) Rezultatul este c la apsarea tastei <, variabila x va fi modificat, n consecin, se va redesena fereastra iar funcia de translaie glTranslatef() din display() va determina deplasarea ptratului spre stnga cu 10 uniti. Exemplul de mai sus arat o modalitate de tratare a evenimentelor de la utilizator. Cele dou proceduri nregistrate n acest caz trateaz intrrile de la tastatur: sgeat stnga , sgeat dreapta . GLAUX permite intrri de la utilizator prin mai multe dispozitive de intrare cum ar fi tastatura, mouse-ul, etc. Funcia pentru redimensionarea ferestrei Funcia callback myReshape() este apelat atunci cnd se redimensioneaz fereastra. Funcia este nregistrat de funcia: auxReshapeFunc (myReshape); S presupunem c nu am include n aplicaie aceste funcii. Rezultatul este artat n figura 2.6. n figura 2.7 s-a redimensionat fereastra. Se poate ns constata c poziiile n pixeli ale ptratului nu s-au modificat. Trebuie specificat c n fereastra OpenGL pixelul (0, 0) se afl n colul stnga jos al ferestrei i orientarea axelor este cea din figura 2.4, n cazul n care nu se definete funcia MyReshape().

100

(150,150)

100

Figura 2.4 Un ptrat care se translateaz pe axa x 19

Rolul funciei myReshape este pentru redimensionarea ferestrei. La aplicarea funciei coninutul ferestrei este redesenat, lund n considerare noile dimensiuni. Sunt cazuri n care la redimensionarea ferestrei se dorete ca desenul s nu-i modifice dimensiunile ci s fie decupat n cazul micorrii ferestrei i afiat la dimensiunea real n cazul lrgirii acesteia. n alte cazuri, cum este de altfel i cazul aplicaiei noastre ne dorim ca la micorarea ferestrei s fie proporional modificate i dimensiunile desenului. Funcia auxIdIeFunc Biblioteca GLAUX asigur o funcie care permite realizarea animailor. Aceast funcie, auxidleFunc(ldleFunction) nregistreaz funcia idleFunction() care este apelat n mod continuu n timp ce programul este n ateptare, mai puin n situaiile n care fereastra este mutat sau redimensionat. Iat un exemplu de scriere a funciei idleFunction(). void CALLBACK IdleFunction (void) { t+=dt; display(); } Funcia actualizeaz o variabil i apoi apeleaz funcia de desenare. Animaia necesit abilitatea de a desena o secven de imagini. Funcia auxidleFunc() este mecanismul pentru realizarea animailor. Programatorul nregistreaz prin aceast funcie o rutin care actualizeaz variabilele de micare (de obicei variabile globale care controleaz cum se mic obiectele) i apoi cere ca scena s fie actualizat. Funcia IdleFunction() cere ca funcia nregistrat prin auxMainLoop()-display(), s fie apelat ct de repede posibil. Aceasta este de preferat apelrii n mod direct a rutinei de redare, deoarece este posibil ca utilizatorul aplicaiei s fi interacionat cu aplicaia i s fie necesar ca s fie procesate evenimentele de intrare. Exemplu: Exemplul urmtor (figura 2.5) arat un exemplu de utilizare a funciei auxidleFunc().

Figura 2.5 #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> 20

#include <GL/glaux.h> void myinit(void); void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK IdleFunction(void); void myinit (void) { glClearColor(1.0, 1.0,1.0, 1.0); glColor3f(0.0,0.0,0.0); } void CALLBACK display (void) { glClear(GL_COLOR_BUFFER_BIT); auxWireCube(100); glFlush(); } void CALLBACK IdleFunction(void) { glRotatef(30,1,1,1); display(); Sleep(300); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-160.0, 160.0, -160.0*(GLfloat)h/(GLfloat)w, 160.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0); else glOrtho (-160.0*(GLfloat)w/(GLfloat)h, 160.0*(GLfloat)w/(GLfloat)h, -160.0, 160.0, -80.0, 80.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 300, 200); auxInitWindow ("Un cub care se roteste"); myinit (); 21

auxReshapeFunc (myReshape); auxIdleFunc(IdleFunction); auxMainLoop(display); return(0); } Funcii GLAUX pentru desenarea primitivelor 3D n exemplul anterior s-a constatat c s-a utilizat o funcie GLAUX pentru desenarea unui cub wireframe avnd latura de 100 de uniti - auxWireCube(100). Dimensiunea unei uniti n pixeli fiind cea specificat n funcia myReshape(). Biblioteca GLAUX dispune de funcii pentru desenarea i a altor corpuri 3D. n continuare vom enumera aceste funcii. - void auxSolidBox(Gldouble width, Gldouble height, Gldouble depth); permite desenarea unui paralelipiped, centrat n origine, pentru care se specific limea, nlimea i adncimea. Paralelipipedul are atribut de umplere. - void auxWireBox(Gldouble width, Gldouble height, Gldouble depth); similar cu auxSolidBox() dar wireframe (doar cu atribut de contur). - void auxSolidCube(Gldouble width); permite desenarea unui cub, centrat n origine, pentru care se specific latura. Cubul are atribut de umplere. - void auxWireCube(Gldouble width); similar cu auxSolidCube() dar wireframe (doar cu atribut de contur). - void auxSolidTetrahedron(Gldouble radius); permite desenarea unui tetraedru (poliedru cu 4 fee, feele sunt triunghiulare), centrat n origine, pentru care se specific raza. Corpul are atribut de umplere. - void auxWireTetrahedron(Gldouble radius); similar cu auxSolidTetrahedron() dar wireframe (doar cu atribut de contur). - void auxSolidOctahedron(Gldouble radius); permite desenarea unui octaedru (poliedru cu 8 fee, feele sunt triunghiulare), centrat n origine, pentru care se specific raza. Corpul are atribut de umplere. - void auxWireOctahedron (Gldouble radius); similar cu auxSolidOctahedron() dar wireframe (doar cu atribut de contur). - void auxSolidDodecahedron(Gldouble radius); permite desenarea unui dodecaedru (poliedru cu 12 fee, feele sunt pentagonale), centrat n origine, pentru care se specific raza. Corpul are atribut de umplere. - void auxWireDodecahedron(Gldouble radius); similar cu auxSolidDodecahedron() dar wireframe (doar cu atribut de contur). - void auxSolidDodecahedron (Gldouble radius); permite desenarea unui icosaedru (poliedru cu 20 fee, feele sunt triunghiulare), centrat n origine, pentru care se specific raza. Corpul are atribut de umplere. - void auxWireIcosahedron(Gldouble radius); similar cu auxSolidicosahedron() dar wireframe (doar cu atribut de contur). - void auxSolidCylinder{Gldoubble radius, Gldouble height); permite desenarea unui cilindru, centrat n origine, pentru care se specific raza bazei i nlimea. Cilindrul are atribut de umplere. - void auxWireCylinder(Gldouble radius, Gldouble height); similar cu auxSolidCylinder() dar wireframe (doar cu atribut de contur). 22

void auxSolidCone(Gldouble radius, Gldouble height); permite desenarea unui con, centrat n origine, pentru care se specific raza bazei i nlimea. Conul are atribut de umplere. void auxWireCone(Gldouble radius, Gldouble height); similar cu auxSolidConeOdar wireframe (doar cu atribut de contur). void auxSolidSphere(Gldouble radius); permite desenarea unei sfere, centrat n origine, pentru care se specific raza. Corpul are atribut de umplere. void auxWireSphere(GldoublG radius); similar cu auxSoildSphere() dar wireframe (doar cu atribut de contur). void auxSolidTorus{Gldouble InnerRadius, Gldouble outerRadius); permite desenarea unui tor (forma colacului), centrat n origine. Parametrul innerRadius este raza seciunii prin tor, iar outerRadius este raza gurii din centrul torului. Corpul are atribut de umplere. void auxWireTorus(Gldouble innerRadius, Gldouble outerRadius); similar cu auxSolidTorus() dar wireframe (doar cu atribut de contur). void auxSolidTeapot(Gldouble size); permite desenarea unui ceainic, centrat n origine, pentru care se specific dimensiunea (aproximativ diametrul). Corpul are atribut de umplere. void auxWireTeapot (Gldouble size); similar cu auxSolidTorus() dar wireframe (doar cu atribut de contur).

Exemplu:

Figura 2.6 (cub, paralelipiped, tetraedru, octaedru, dodecaedru, icosaedru, tor, con, sfer, cilindru, ceainic - reprezentate wireframe) Programul urmtor reprezint wireframe toate primitivele enumerate mai sus (figura 2.6). Pentru poziionarea corpurilor n cadrul ferestrei, naintea apelrii fiecrei 23

funcii de desenare s-a apelat o funcie de translatare. Iniial s-a aplicat o rotaie care are efect asupra tuturor corpurilor. Codul programului este dat n continuare: /* Programul afieaz primitivele 3D GLAUX */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void myinit (void) { glClearColor(1.0, 1.0,1.0, 1.0); glColor3f(0.0,0.0,0.0); } void CALLBACK display (void) { glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glRotatef(30,1,1,1); glTranslatef(-250,300,0); auxWireCube(100); glTranslatef(200,-50,0); auxWireBox(200, 100, 50); glTranslatef(200,-100,0); auxWireTetrahedron(100); glTranslatef(200,-50,0); auxWireOctahedron(100); glTranslatef(-700,0,0); auxWireDodecahedron(100); glTranslatef(220,-70,0); auxWireIcosahedron(100); glTranslatef(230,-80,0); auxWireTorus(30, 80); glTranslatef(220,-100,0); auxWireCone(75, 150); glTranslatef(-600,20,0); auxWireSphere(80); glTranslatef(250,-50,0); auxWireCylinder(75, 100); glTranslatef(230,-120,0); auxWireTeapot(80); 24

glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-300.0, 300.0, -300.0*(GLfloat)h/(GLfloat)w, 300.0*(GLfloat)h/(GLfloat)w, -300.0, 300.0); else glOrtho (-300.0*(GLfloat)w/(GLfloat)h, 300.0*(GLfloat)w/(GLfloat)h, -300.0, 300.0, -300.0, 300.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 900, 600); auxInitWindow ("Primitive GLAUX"); myinit (); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Funcia auxMouseFunc Funcia auxMouseFunc() asociaz o funcie callback cu o aciune asupra mouseului. Prototipul funciei este: void auxMouseFunc (int button, int mode, AUXMOUSEPROC func); - Funcia func va fi apelat atunci cnd este apsat sau relaxat butonul button al mouse-ului. - Parametrul button poate avea una din urmtoarele valori: AUX_LEFTBUTTON, AUX_MIDDLEBUTTON sau AUX_RIGHTBUTTON. - Parametrul mode specific aciunea asociat cu butonul mouseului. Aceasta poate fi AUX_MOUSEDOWN sau AUX_MOUSEUP. Funcia auxSwapBuffers Funcia auxSwapBuffers() comut ntre cele dou buffer-e color n timpul desenrii cu dublu buffer. Prototipul funciei este: void auxSwapBuffers(void) : 25

Funcia este utilizat n special pentru animaie. Apelul ei va determina afiarea pe ecran a scenei ascunse. Funcia necesit ca la iniializarea ferestrei cu funcia auxInitDisplayMode() s fie utilizat flag-ul AUX_DOUBLE, pentru a specifica folosirea a dou buffere de culoare. Funcia auxSetOneColor Funcia auxSetOneColor() seteaz o culoare n paleta de culori n cazul modelului index de culoare. Prototipul funciei este: void auxSetOneColor(int index, float red, float green, float blue); In cazul modelului de culoare index se creeaz o palet de culori. O culoare este selectat prin specificarea unui index n paleta de culori. Aceast funcie asociaz cu un anumit index o culoare specificat prin componentele RGB ale culorii.

3 PRIMITIVE GEOMETRICE
3
n acest capitol se va discuta despre primitivele geometrice de care dispune OpenGL pentru redarea scenelor, precum i modul n care se controleaz starea OpenGL pentru aspectul acestor primitive. Se va discuta apoi despre modul de reprezentare a curbelor i a suprafeelor curbe utiliznd evaluatori OpenGL dar i funciile GLU pentru curbe i suprafee spline. Un subcapitol va fi dedicat pentru redarea cvadricelor utiliznd funciile GLU. In afara tratrii acestor primitive vectoriale este inclus un subcapitol special pentru tratarea primitivelor punctuale de care dispune OpenGL (bitmap-uri, imagini).

3.1 Primitive geometrice OpenGL


y

P(x,y,z) x z

Figura 3.1 26

nainte de a ncepe s discutm despre felul n care sunt construite obiectele 3D pe baza primitivelor geometrice simple, trebuie s explicm n detaliu sistemul de coordonate utilizat de OpenGL. Acesta este un sistem cartezian. Axele x i y formeaz un plan, ceva de genul suprafeei vizibile a monitorului. Axa z adaug cea de a treia dimensiune - adncimea spaial (figura 3.1). Astfel pentru a avea o poziie spaial fix n acest sistem de coordonate, un punct este necesar s fie specificat prin trei coordonate (x, y, z). Primitivele geometrice (puncte, segmente de dreapt, i poligoane) sunt definite de un grup de unu sau mai multe vrfuri (vertex-uri). Un vrf definete un punct, punctul terminal al unei muchii, sau colul n care se ntlnesc dou muchii ale unui poligon. Unui vrf i sunt asociate date (constnd din coordonatele de poziie, culori, normale, i coordonate de textur) i fiecare vrf este procesat n mod independent i n acelai fel. Singura excepie de la aceast regul este n cazul n care un grup de vrfuri trebuie s fie decupate astfel ca primitiva respectiv s fie cuprins n regiunea specificat prin volumul de vizualizare definit de funcia myReshape(). n acest caz datele despre un vrf pot fi modificate i sunt create noi vrfuri. Tipul decuprii depinde de primitiva care este reprezentat de grupul de vrfuri.

... ..
GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP

GL_TRIANGLES

GL_TRIANGLE_FAN GL_TRIANGLE_STRI

GL_QUADS

GL_QUAD_STRIP

GL_POLYGON

Figura 3.2 Toate primitivele geometrice sunt specificate prin vrfuri (coordonatele vrfurilor). Intern OpenGL opereaz cu coordonate omogene. Coordonatele omogene sunt de forma (x, y, z, w). Funciile OpenGL permit specificarea vrfurilor n coordonate 2D, 3D i n coordonate omogene. n funcie de parametrul funciei glBegin() (care poate fi unul din cele 10 nume enumerate n figura 3.2) i de felul cum sunt organizate vrfurile, OpenGL poate reda oricare din primitivele artate n figura 3.2. Exemplu Pentru ca cele spuse s fie mai clare se va exemplifica printr-o funcie de redare a unui patrulater. void patrulater( GLfloat color[] ) { 27

glBegin( GL_QUADS ) ; glColor3fv( color ); glVertex2f( 0.0, 0.0 ); glVertex2f( 1.0, 0.0 ) ; glVertex2f( 1.5, 1.118 ); glVertex2f( 0.5, 1.118 ) ; glEnd(); } Funcia patrulater() determin OpenGL s deseneze un patrulater ntr-o singur culoare. Patrulaterul este planar deoarece, coordonat z este setat automat la 0 de funcia glvertex2f (). Dac s-ar fi dorit ca patrulaterul s nu se afle n planul x0y, ci ntr-un plan oarecare, atunci ar fi fost necesar s fie utilizat o funcie glvertex3#(). n felul acesta sar fi furnizat pentru fiecare vrf i cea de a treia coordonat. Trebuie remarcat de asemenea c numele primitivei geometrice se d ca parametru al funciei glBegin() i corpul n care sunt furnizate coordonatele primitivei este delimitat de funciile glBegin() i glEnd().

3.1.1 Formatul comenzilor OpenGL


Fiecare din comenzile care specific coordonatele vrfului, normalele, culorile sau coordonatele de textur sunt disponibile n cteva formate pentru a se potrivi diferitelor formate de date ale aplicaiilor i numrului de coordonate (figura 3.3). Datele pot fi de asemenea transmise acestor comenzi fie ca o list de argumente sau ca un pointer la un tablou ce conine date. Variantele se disting prin sufixele mnemonicelor comenzilor.
glvertex3fv(v)

Numrul componentelor 2-(x,y) 3- (x,y,z) 4 (x,y,z,w)

Tipul datei b-byte ub-unsigned byte s-short us-unsigned short i-int ui-unsigned int f-float d-double

Vector V se va omite pentru formele scalare Ex: glVertex2f(x,y)

Figura 3.3 Interfaa de programare a aplicaiilor OpenGL (OpenGL API) are astfel proiectate apelurile nct s fie acceptate aproape orice tipuri de date de baz, al cror nume este reflectat n numele funciei. Cunoscnd felul n care sunt formate numele apelurilor este uor de determinat care apel va fi utilizat pentru un format particular de 28

date i pentru o anume dimensiune. Spre exemplu, coordonatele vrfurilor pentru aproape toate modelele comerciale sunt reprezentate de un vector cu trei componente n virgul mobil. n felul acesta, cea mai potrivit comand este glvertex3fv(coord). n acest caz coord este un vector cu trei componente de tip float. Dac cele trei componente s-ar furniza ca parametri ai funciei glVertex# atunci forma apelului ar fi givertex3f (x, y, z); unde x, y, z sunt elemente de tip float. Fiecare vrf poate fi specificat cu dou, trei sau patru coordonate (patru coordonate indic coordonate omogene 3D). Dup cum s-a artat mai nainte, intern, OpenGL utilizeaz coordonate omogene 3D pentru specificarea vrfurilor. Pentru acele forme de apel glvertex#() care nu specific toate coordonatele (adic glvertex2f()), OpenGL va fixa implicit z=0.0 i w=1.0.

3.1.2 Specificarea primitivelor geometrice OpenGL


n OpenGL cele mai multe obiecte geometrice sunt desenate prin includerea unei mulimi de coordonate care specific vrfurile i opional normalele, coordonatele de textur i culorile ntre perechea de comenzi glBegin()/glEnd(): glBegin(tipul_primitivei) ; //se specific coordonatele vrfurilor, normalele, //culorile, coordonatele de texturare glEnd(); unde tipul_primitivei determin felul cum sunt combinate vrfurile din blocul respectiv. Spre exemplu, pentru specificarea unui patrulater cu vrfurile avnd coordonatele (0,1,0), (1,3,0), (3,4,0),(0,4,0) se poate scrie: glBegin(GL_QUADS) glVertex3i(0,1,0) ; glVertex3i(1,3,0) ; glVertex3i(3,4,0) ; glVertex3i(0,4, 0) ; glEnd(); Cele zece primitive geometrice care pot fi astfel desenate sunt descrise n figura 3.2. Acest grup particular de primitive permite ca fiecare obiect s poat fi descris printr-o list de vrfuri, i permite satisfacerea necesitilor fiecrei aplicaii grafice. Exemplu: Glfloat red, greed, blue; Glfloat coords[3]; glBegin(tipul_primitivei); for (i=0; i< nvertex; ++i){ glColor3f( red, green, blue ); glVertex3fv( coords); } glEnd() ; 29

n acest exemplu, nvertex este numrul vrfurilor care se specific. Acestea sunt grupate dup tipul primitivei, specificat ca parametru al funciei glBegin(). Spre exemplu dac tipul primitivei este GL_QUADS i nvertex este 12 se vor desena 3 patrulatere. Tipurile posibile pentru tipul primitivei sunt: GL_POINTS GL_LINE_STRIP GL_LINES GL_LINE_LOOP GL_TRIANGLES GL_TRIANGLE_STRIP GL_TRIANGLE_FAN GL_QUADS GL_QUAD_STRIP GL_POLYGON n esen sunt doar 5 tipuri de primitive (punct, linie, triunghi, patrulater i poligon) restul de 5 chiar dac nu introduc primitive suplimentare prezint avantajul ca n cazul n care dou vrfuri aparinnd la dou primitive distincte, se suprapun, s fie memorate o singur dat. n felul acesta se ctig att timp de procesare ct i spaiu de memorie.
coordonate de vrfuri Normala curent Transformare vrfuri normale Coordonate de vrfuri transformate

Culoare curent

Iluminare

culoare procesat

Coordonatele de texturi curente

Funcia de generare a coordonatelor de texturare

Matricea de texturare

Coordonatele de texturare

Figura 3.4 Asocierea valorilor curente cu vrfurile Pentru procesarea unui vrf mai pot fi, suplimentar, utilizate normala curent, coordonatele texturii curente i culoarea curent. OpenGL utilizeaz normalele pentru calculele de iluminare. Normala curent este un vector 3D care se poate seta prin specificarea celor trei coordonate. Culoarea poate fi format din valorile pentru rou, verde, albastru i alfa (atunci cnd se utilizeaz modelul de culoare RGBA) sau o singur valoare index (atunci cnd la iniializare se specific modul index). Una dou trei sau patru coordonate de textur determin felul cum imaginea unei texturi se mapeaz pe o primitiv. 30

Atunci cnd este specificat un vrf, culoarea curent, normala, coordonatele texturii sunt utilizate pentru a obine valori care sunt apoi asociate cu vrful (figura 3.4). nsui vrful este transformat de matricea de modelare-vizualizare, care este o matrice de 4x4. Aceast transformare are loc intern prin nmulirea matricei de modelare vizualizare cu coordonatele vrfului obinndu-se coordonatele acestuia n sistemul de vizualizare. Culoarea asociat vrfului se obine fie pe baza calculelor de iluminare, fie dac iluminarea este dezactivat, pe baza culorii curente. Coordonatele de texturare sunt transmise n mod similar unei funcii de generare a coordonatele de texturare (care poate fi identitate). Coordonatele de texturare rezultate sunt transformate de matricea de texturare (aceast matrice poate fi utilizat pentru scalarea sau rotirea unei texturi ce se aplic unei primitive). Reguli pentru construirea poligoanelor Nu ne referim aici la triunghiuri dei fac i ele parte din categoria poligoanelor. Motivele sunt simple: triunghiurile aparin ntotdeauna unui singur plan, triunghiurile sunt ntotdeauna convexe. Regula 1 Poligoanele trebuie s fie totdeauna planare. Aceasta nseamn c toate vrfurile unui poligon trebuie s aparin aceluiai plan. n figura 3.5 se poate vedea un poligon planar i altul neplanar (rsucit).

Figura 3.5

Figura 3.6 Regula 2 Poligoanele trebuie s fie convexe. Pentru a verifica dac un poligon este convex se face testul urmtor: dac oricare linie care traverseaz poligonul este intersectat n mai mult de dou puncte de laturile poligonului acesta nu este convex (figura 3.6). Regula 3 Muchiile poligoanelor nu se pot intersecta. Spre exemplu poligonul din figura 3.7 nu este un poligon corect n concepia OpenGL.

Figura 3.7 31

Orientarea poligoanelor n OpenGL ordinea specificrii vrfurilor este cea dat de ordinea apelurilor givertex# () n blocul glBegin() /glEnd().

Figura 3.8 Ordinea stabilit a vrfurilor este implicit n sens invers rotirii acelor de ceasornic. Ordinea vrfurilor se specific n OpenGL prin funcia glFrontFace() care are ca parametrii (figura 3.8): - GL_CCW pentru sensul trigonometric (invers acelor de ceasornic "counterclockwise") - care este valoarea implicit - GL_CW pentru sensul rotirii acelor de ceasornic ("clockwise") O primitiv geometric are orientare directa ("frontface") daca ordinea specificrii vrfurilor coincide cu ordinea stabilit a vrfurilor. Dac ordinea specificrii vrfurilor nu coincide cu ordinea stabilit a vrfurilor atunci primitiva are orientare inversa ("backface") Ordinea corect pentru specificarea vrfurilor primitivelor OpenGL In figura 3.9 este artat ordinea n care trebuie specificate vrfurile primitivelor OpenGL pentru ca orientarea acestora s fie n sens invers rotirii acelor de ceasornic adic ordinea direct n OpenGL.

Figura 3.9

32

Eliminarea poligoanelor n funcie de orientare n OpenGL se poate realiza eliminarea anumitor suprafee n funcie de orientarea acestora. - Validarea eliminrii primitivelor geometrice n funcie de orientare: - glEnable(GL_CULL_FACE); - Selectarea suprafeelor eliminate: - glCullFace(GLenum type); unde type poate fi: GL_BACK - sunt eliminate poligoanele avnd orientare invers, GL_FRONT - sunt eliminate poligoanele avnd orientare direct. Utilitatea orientrii poligoanelor La construirea unui corp solid toate poligoanele care-1 mrginesc trebuie s aib aceeai orientare. Dac spre exemplu toate poligoanele au orientare trigonometric, toate poligoanele vor fi poligoane fa i vor fi vizibile. Se poate stabili ca feele spate s fie eliminate n situaia n care corpul este vizualizat din exterior. Dac ns corpul este vizualizat dinspre interior atunci se va stabili s fie vizibile doar feele spate i s fie eliminate feele fa. S presupunem acum c un anumit corp solid a fost consistent construit, deci cu toate poligoanele avnd aceeai orientare. Orientarea specificat ns nu este aceeai cu cea stabilit pentru feele fa. Atunci se poate interveni i se schimb orientarea stabilit pentru feele fa.

3.1.3 Atribute ale primitivelor de ieire


n acest subcapitol ne vom referi la atribute primitivelor de ieire: dimensiunea punctului, grosimea sau stilul liniei, modelul de umplere pentru primitivele cu atribut de umplere, etc. Atributul de culoare Modelele de culoare OpenGL sunt RGBA sau Color Index. Fiecare implementare OpenGL trebuie s permit redarea att n modelul de culoare RGBA (denumit uneori ca modelul TrueColor) ct i n modelul index (sau colormap). Pentru redarea cu modelul RGBA, culorile vrfurilor sunt specificate utiliznd apelul glColor#(). Pentru modelul index, indexul culorii fiecrui vrf este specificat cu apelul gllndex# (). Sistemul de ferestre cere specificarea modelului de culoare al ferestrei. Dac se utilizeaz GLUT, atunci modelul de culoare al ferestrei se specific folosind apelul glutlnitDisplayMode(), cu flag-urile GLUT_RGBA (pentru modelul RGBA) sau GLUT_INDEX (pentru modelul index). Dac se utilizeaz biblioteca GLAUX, modelul de culoare se specific folosind funcia auxinitDisplayMode() cu flag-urile AUX_RGBA sau AUX_INDEX. Setrile de culoare pentru primitive pot fi specificate utiliznd fie modelul RGBA fie modelul index. Odat specificat o anumit culoare, va afecta toate primitivele care urmeaz pn la o modificare a culorii. Noua culoare va afecta apoi doar primitivele specificate dup modificarea culorii. 33

n modelul RGB se vor specifica componentele rou, verde i albastru ale culorii. Se poate folosi i varianta RGBA n care se specific i o a patra component valoarea alfa. Aceast a patra component este utilizat pentru amestecarea culorilor pentru obiectele care se suprapun. O aplicaie important a amestecrii culorilor este simularea efectului de transparen. Pentru aceste calcule valoarea alfa corespunde coeficientului de transparen. Pentru a folosi modelul RGB (sau RGBA), se seteaz simplu culoarea cu funcia glColor#() dnd celor patru parametrii ai culorii valori cuprinse ntre 0.0 i 1.0. Pentru specificarea componentelor culorii pot fi utilizate valori ntregi, n virgul mobil sau alte formate numerice. Ca i n cazul funciei giVertex se vor utiliza ca sufix coduri ca 3, 4, d, f i i pentru a indica numrul parametrilor i formatul acestora. De pild, funcia urmtoare specific componentele de culoare RGB n virgul mobil i seteaz culoarea curent ca albastru de intensitate maxim: glColor3f(0.0, 0.0, 1.0); Valoarea implicit a culorii este alb (1, 1, 1) i valoarea implicit pentru alfa este 1. n mod opional, se pot seta valorile de culoare utiliznd tablourile. n acest caz se va aduga funciei un al treilea sufix - v - i se va furniza un singur argument - pointer-ul la tabloul ce conine componentele culorii. Utiliznd un tablou colorArray care conine spre exemplu valorile anterioare, se va seta culoarea utiliznd apelul: glColor3fv(colorArray); Cellalt model pentru setarea culorii, disponibil n OpenGL este modelul index care face referine la tabele de culoare. Acest model este utilizat n cazul n care spaiul de memorare este limitat. n acest model se seteaz ca i culoare curent o culoare din tabelul de culori utiliznd funcia: gllndex#(index); unde index specific o poziie n tabloul cu culori. Funcia necesit de asemenea un sufix (d, f, i) care specific tipul datelor. Un tablou de culori poate fi setat cu funcia: glIndexPointer(type, offset, ptr); unde parametrul type d tipul datei, parametrul offset, d spaierea ntre valori consecutive de culoare i parametrul ptr este un pointer spre primul element al tabloului de culori. A patra component de culoare Componenta alfa pentru o culoare este o msur a opacitii fragmentului. Ca i cu celelalte componente de culoare, domeniul valorilor sale este ntre 0.0 (care reprezint complet transparent) i 1.0 (complet opac). Valorile alfa sunt importante pentru o mulime de utilizri despre care se va discuta pe larg n capitolul 8 (Efecte vizuale: transparena, ceaa, antialiasing).

Atributele punctului Pentru punct pot fi setate dou atribute: culoare i dimensiune. Culoarea este controlat de setarea curent a culorii, iar dimensiunea punctului se seteaz cu funcia: void glPointSize(Glfloat size); 34

Parametrul size poate fi specificat ca orice valoare pozitiv n virgul mobil. Dac valoarea specificat nu este un ntreg, ea va fi rotunjit la cea mai apropiat valoare ntreag (presupunnd c antialiasing-ul este dezactivat). Valoarea implicit pentru size este 1. Atributele liniei Atributele de baz pentru segmentul de linie dreapt sunt tipul liniei, grosimea liniei i culoarea liniei. Alte efecte posibile, cum ar fi tipul peni sau tipul pensul, pot fi implementate cu adaptri ale funciilor pentru tipul i grosimea liniei. Pentru afiarea unui segment de dreapt ntr-o singur culoare este folosit setarea curent a culorii. O alt posibilitate ar fi ca linia s fie afiat cu culoarea variind de-a lungul liniei. O modalitate de a face acest lucru este de a atribui culori diferite fiecrei extremiti a unei linii, n loc de a se seta o culoare curent pentru ntreaga linie. De pild, poriunea de cod urmtoare seteaz o extremitate a liniei verde iar cealalt galben. Rezultatul va fi afiarea unei linii continue n culori care interpoleaz culorile extremitilor. glShadeModel(GL_SMOOTH); glBegin (GL_LINES); glColor3f (0.0, 1.0, 0.0); glVertex2i (-5,-5); glColor3f (1.0, 1.0, 0.0); glVertex2i (5,5); glEnd (); n ceea ce privete cellalt atribut al linie - tipul - n mod implicit acesta este tipul continuu. n afara liniilor continue se pot utiliza linii ntrerupte, punctate sau n diverse combinaii linie-punct. Spaiile dintre liniue sau puncte, dimensiunea liniuelor pot fi de asemenea modificate. Stilul liniei este definit de programator - nu exist un set de stiluri din care programatorul s-i aleag un anume stil. ablonul se stabilete ntr-un cuvnt de 16 bii n care fiecare bit are semnificaia de un pixel. Modelul astfel stabilit se repet de-a lungul liniei. Dac se dorete ca semnificaia fiecrui bit s fie de 2, 3, ... pixeli se poate realiza o multiplicare cu un factor. Pentru a se putea afia linii de diferite stiluri trebuie realizat activarea acestui atribut cu funcia glEnable(): glEnable(GL_LINE_STIPPLE); Altfel toate liniile vor fi afiate ca linii continue. Revenirea la linie continu se face, evident, cu funcia glDisable(). Un anumit tip de linie este specificat cu funcia: void glLineStipple(GLint repeatFactor, GLushort pattern); care specific ablonul dup care sunt distribuii pixelii la desenarea liniei. Parametrul pattern d un model, n binar, pe 16 bii (l=pixel on, 0=pixel off) i parametrul ntreg repeatFactor specific de cte ori se repet fiecare bit din model. Modelul este aplicat pixelilor de-a lungul liniei ncepnd cu biii mai puin semnificativi. Spre exemplu, apelul: glLineStipple(1, 0x00ff); 35

specific o linie ntrerupt n care liniuele ocup 8 pixeli iar spaiul dintre liniue este tot de 8 pixeli. Deoarece biii mai puin semnificativi sunt pe on fiecare segment de dreapt care se deseneaz va ncepe cu liniu i modelul se va repeta pn se ajunge la cealalt extremitate a segmentului de dreapt. n cazul n care se deseneaz o linie frnt modelul nu va fi restartat dup fiecare segment de dreapt, ci va fi aplicat continuu. Iat spre exemplu cum se poate specifica o linie ntrerupt cu intervale egale pentru ntrerupere i linie. Exemplu: GLint factor=l; GLushort pattern=0x00ff; glEnable(GL_LINE_STIPPLE); glLineStipple(factor, pattern); glBegin(GL_LINES); glVertex2f(20, 30); glVertex2f(100, 30); glEnd( ); pixelii corespunztori biii cuvntului pattern 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 modelul liniei

Figura 3.10 Din figura 3.10 se poate constata care este corespondena dintre modelul liniei i cuvntul pattern utilizat. Ultimul atribut al liniei - grosimea - se seteaz cu funcia: void glLineWidth(Glfloat width); Valoarea implicit a parametrului width este 1. Valorile n virgul mobil sunt rotunjite la ntregul cel mai apropiat atunci cnd nu este activat antialiasing-ul.

Atributele poligoanelor Pentru poligoane, atributul de baz este stilul de umplere. Poligoanele pot fi umplute ntr-o singur culoare, cu un anumit model de umplere, sau fr atribut de umplere ("hollow") atunci cnd se reprezint doar conturul. Aa cum s-a artat un poligon are dou fee: fa i spate care pot fi diferit reprezentate. Aceasta permite reprezentarea seciunilor prin corpuri. Se pot selecta atribute diferite pentru poligoanele 36

"fa" i pentru cele "spate", se poate inversa definirea poligoanelor "fa" sau "spate" i se poate elimina afiarea poligoanelor "fa" sau "spate". n mod implicit ambele fee sunt desenate la fel. Pentru a schimba acest lucru se utilizeaz funcia glPolygonMode(), glPolygonMode(GLenum face, GLenum mode) care stabilete modul de desenare al poligoanelor (mode: GL_POINT, GL_LINE, GL_FILL) i tipul feelor care sunt afectate (face: direct -GL_FRONT, invers - GL_BACK, ambele - GL_FRONT_AND_BACK). n mod implicit ambele fee sunt desenate cu atribut de umplere. Se poate spre exemplu, stabili ca partea fa s fie desenat plin iar cea spate s fie desenat cu wireframe (fr atribut de umplere). glPolygonMode(GL_FRONT, GL_FILL); glPolygonMode(GL_BACK, GL_LINE); Culoarea primitivelor cu atribut de umplere Triunghiurile, patrulaterele i poligoanele sunt primitivele care au atribut de umplere. Acestea pot fi colorate cu o anumit culoare sau pot fi umplute cu un anumit model de umplere. n ceea ce privete culoarea, aceasta se poate stabili pentru fiecare vrf n parte sau se utilizeaz culoarea curent de desenare. Funcia utilizat este glColor3f(). n funcie de modelul de umbrire, poligoanele sunt umplute cu o culoare compact sau cu o interpolare a culorii vrfurilor. Modelul de umbrire se stabilete cu funcia glShadeModel(). void glShadeModel (Glenum mode); Dac se stabilete o umbrire poligonal constant (parametrul GL_FLAT) atunci culoarea de umplere a poligoanelor va fi culoarea curent sau culoarea stabilit pentru ultimul vrf al poligonului. Dac se stabilete modelul de umbrire Gouroud (GL_SMOOTH) atunci se vor interpola culorile vrfurilor (ca la ptratul reprezentat pentru exemplificare funciilor glaux). Utilizarea abloanelor de umplere Aa cum liniile pot fi desenate avnd anumite stiluri i poligoanele pot fi umplute cu anumite modele de umplere. Pentru aceasta programatorul stabilete ablonul, care se va repeta apoi pe suprafaa ntregului poligon. Pentru activarea umplerii cu ablon se folosete funcia glEnable(). glEnable(GL_POLYGON_STIPPLE); Modelul de umplere se specific folosind funcia glPolygonStipple avnd ca parametru un pointer spre un tablou care conine ablonul. glPolygonStipple(fillPattern); Parametrul fillPattern este un pointer la o masc de 32X32 bii. Tabloul fillPattern conine elemente de tip GLubyte. O valoare 1 n masc arat c pixelul corespunztor va fi pe on, i 0 indic un pixel pe of f. Intensitatea pixelilor este setat n funcie de setarea culorii curente. Spre exemplu GLubyte fillPattern[]={Oxff, 0x00, Oxff, 0x00, ...}; Biii trebuie s fie specificai ncepnd cu rndul de jos al modelului, i continund pn la rndul cel mai de sus (al-32-lea). Modelul este apoi aplicat de-a lungul ferestrei curente, umplnd poligonul specificat acolo unde modelul se suprapune 37

cu interiorul poligonului. Odat specificat modelul i activat umplerea cu ablon se poate trece la desenarea poligonului. O alt modalitate de umplere a poligoanelor este utiliznd texturile. De asemenea, poligoanele pot fi umplute cu culoarea curent setat. Ca i n cazul liniilor se pot specifica culori diferite pentru fiecare vrf al unui poligon i n acest caz culoare interiorului poligonului va fi interpolarea culorilor vrfurilor poligonului. Aa cum s-a mai artat poligoanele pot fi desenate n modul wireframe sau doar marcnd vrfurile poligonului, depinde de ce parametrii sunt folosii pentru funcia glPolygonMode(): GL_FILL - cu atribut de umplere GL_LINE - fr atribut de umplere(wireframe) GL_POINTS - marcate vrfurile n OpenGL, funciile de redare a poligoanelor pot fi aplicate doar poligoanelor convexe. Pentru un poligon concav, trebuie mai nti desprit ntr-o mulime de poligoane convexe, de obicei triunghiuri. Pentru a afia apoi doar poligoanele originale trebuie s putem specifica care linii fac parte din poligoanele originale. Pentru aceasta se folosete funcia glEdgeFlag, care arat dac un vrf este sau nu primul punct al unei laturi din poligonul original. Funcia glEdgeFlag() este utilizat n interiorul perechii glBegin/glEnd. glEdgeFlag(GL_FALSE); Aceast comand arat c vrful care urmeaz nu precede o latur a unui poligon original. De asemenea, comanda se aplic tuturor vrfurilor care urmeaz pn la un nou apel al funciei glEdgeFlag. Argumentul GL_TRUE arat c vrful urmtor iniiaz o latur a poligonului original. Antialiasing Pentru activarea procedurilor pentru antialiasing se folosete apelul: glEnable(); avnd ca parametru una din valorile GL_POINT_SMOOTH, GL_LINESMOOTH sau GL_POLYGON_SMOOTH. Funcii de interogare Se pot obine valorile pentru setrile curente ale atributelor i pentru diveri ali parametrii utiliznd funciile corespunztoare "Get" cum ar fi glGetlntegerv(), glGetFloatv(), glGetPolygonStipple(). Spre exemplu, se poate afla setarea curent a culorii cu glGetFloatv(GL_CURRENT_COLOR, colorArray); Tabloul colorArray va fi setat n urma acestui apel cu culoarea curent. Similar se poate afla dimensiunea curent a punctului (GL_POINT_SIZE) sau a liniei (GL_LINE_WIDTH_RANGE). De asemenea se poate afla dac anumite proceduri, cum ar fi antialiasing-ul, sunt activate sau dezactivate. Exemple n continuare vor fi date cteva exemple ilustrative pentru utilizarea primitivelor geometrice i a atributelor acestora. Exemplul 1 38

/*Un cerc din puncte de dimensiune un pixel */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> #include <math.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); void myinit(void) { glClearColor(1.0, 1.0, 1.0, 1.0); glShadeModel(GL_FLAT); } void CALLBACK display(void) { int i; double PI = 3.1415926535; double raza =2.0; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glBegin(GL_POINTS); for (i = 0; i < 360; i+=5) glVertex2f(raza*cos(PI*i/180.0), raza*sin(PI*i/180.0)); glEnd(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); else glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); 39

} int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 200, 200); auxInitWindow ("Un cerc din puncte"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Observaii: Ceea ce se obine la rularea acestui program este afiat n figura 3.11. Ce trebuie remarcat n acest exemplu este felul cum s-au furnizat coordonatele punctelor n corpul glBegin/glEnd. ntr-un ciclu for s-a apelat funcia glVertex() de 360/5 ori. Coordonatele punctelor de pe cerc s-au dat n coordonate polare. Mai trebuie remarcat c n funcia myReshape() s-au stabilit 10 uniti pe fiecare ax i s-a urmrit ca raza cercului(2) s se ncadreze n aceste dimensiuni.

Figura 3.11

40

Figura 3.12 Exemplul 2 S modificm acum acest exemplu astfel nct punctele de pe cerc s aib dimensiuni cresctoare. Ceea ce se modific este funcia display(). Rezultatul rulrii este artat n figura 3.12. void CALLBACK display(void) { int i ; double PI = 3.1415926535; double raza =2.0; GLfloat size=0.5; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); for (i = 0; i < 360; i+=10) { glBegin(GL_POINTS); glVertex2f(raza*cos(PI*i/180.0), raza*sin(PI*i/180.0)); glEnd() ; size+=0.125; //incrementeaz dimensiunea punctului glPointSize(size); } glFlush() ; } Observaii: Ceea ce trebuie remarcat aici este faptul c n corpul glBegin/glEnd nu au efect dect instruciunile pentru caracteristicile vrfurilor. Astfel c urmtorul cod nu ar fi condus la rezultatul ateptat, dei nu ar fi aprut eroare la compilare. glBegin(GL_POINTS); for (i = 0; i < 360; i+=5) glVertex2f(raza*cos(PI*i/180.0), raza*sin(PI*i/180.0)); size+=0 .125; //incrementeaz dimensiunea punctului glPointSize(size); glEnd() ; Exemplul 3 Exemplul 1 se poate modifica pentru desenarea unui cerc cu linie continu, prin simpla modificare a parametrului funciei glBegin() n GL_LINE_LOOP (figura 3.13). Dac se folosete parametrul GL_LINE_STRIP atunci nu este unit primul punct cu ultimul punct al liniei frnte din care s-a construit cercul. Acesta este un exemplu despre cum se construiete o curb dintr-o linie frnt. Pentru ca linia care formeaz cercul s fie mai neted, vrfurile vor fi alese i mai apropiate. Cu toate c cercul este format dintr-un contur nchis, el nu are atribut de umplere. Pentru aceasta este suficient s se nlocuiasc parametrul GL_LINE_LOOP, al funciei glBegin() cu parametrul GL_POLYGON. Rezultatul obinut n acest caz este artat n figura 3.14.

41

Figura 3.13

Figura 3.14 Exemplul 4 Se reia acum exemplul anterior dar cercul va fi umplut cu un model (figura 3.15). n continuare se poate vedea felul n care a fost declarat tabloul care conine modelul de umplere.

Figura 3.15 Codul programului este urmtorul: 42

#include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> #include <math.h> void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); void CALLBACK display(void) { int i; double PI = 3.1415926535; double raza =3.0; GLubyte model[] = { 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFc, 0x3F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xF1, 0x8F, 0xFF, 0xFF, 0xe3, 0xc7, 0xFF, 0xFF, 0xc7, 0xe3, 0xFF, 0xFF, 0x8e, 0x71, 0xFF, 0xFF, 0x1c, 0x38, 0xFF, 0xFe, 0x39, 0x9c, 0x7F, 0xFc, 0x73, 0xce, 0x3f, 0xF8, 0xe7, 0xe7, 0x1f, 0x01, 0xce, 0x73, 0x80, 0x01, 0xce, 0x73, 0x80, 0xF8, 0xe7, 0xe7, 0x1f, 0xFc, 0x73, 0xce, 0x3f, 0xFe, 0x39, 0x9c, 0x7F, 0xFF, 0x1c, 0x38, 0xFF, 0xFF, 0x8e, 0x71, 0xFF, 0xFF, 0xc7, 0xe3, 0xFF, 0xFF, 0xe3, 0xc7, 0xFF, 0xFF, 0xF1, 0x8F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFc, 0x3F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 0xFF, 0xFe, 0x7F, 0xFF, 43

}; glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glEnable (GL_POLYGON_STIPPLE); glPolygonStipple (model); glBegin(GL_POLYGON); for (i = 0; i < 360; i+=5) glVertex2f(raza*cos(PI*i/180.0), raza*sin(PI*i/180.0)); glEnd(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); else glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 200, 200); auxInitWindow ("Un cerc cu model"); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Exemplul 5 Exemplul urmtor construiete un cub din patrulatere. Cubul este animat (rotit), utilizndu-se funcia IdleFunctionO. Indiferent de poziia cubului n timpul rotaiei, muchiile spate sunt reprezentate cu linie punctat iar muchiile fa cu linie continu. /*Un cub care se rotete i care are muchiile spate desenate cu linie punctat */ 44

#include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> #include <math.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK IdleFunction(void); void CALLBACK display(void); void cub(GLfloat latura); void myinit(void) { glClearColor(1.0, 1.0, 1.0, 1.0); glShadeModel(GL_FLAT); } void CALLBACK IdleFunction(void) { glRotatef(30,1,1,1); display(); Sleep(300); } void CALLBACK display(void) { GLint factor=10; GLushort pattern=0x255; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glLineStipple(factor, pattern); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glEnable(GL_LINE_STIPPLE); cub(0.5); glCullFace(GL_BACK); glDisable(GL_LINE_STIPPLE); cub(0.5); glFlush(); } 45

void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-1.0, 1.0, -1.0*(GLfloat)h/(GLfloat)w, 1.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0); else glOrtho(-1.0*(GLfloat)w/(GLfloat)h, 1.0*(GLfloat)w/(GLfloat)h, -1.0, 1.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 200, 200); auxInitWindow ("Un cub"); myinit(); auxReshapeFunc (myReshape); auxIdleFunc(IdleFunction); auxMainLoop(display); return(0); } void cub(GLfloat latura) //funcia care n cubul //cu latura de 2Xlatura i centrat n origine //ordinea specificrii vrfurilor este invers rotirii acelor de ceasornic { glBegin(GL_QUAD_STRIP); glVertex3f(-latura, latura, latura); glVertex3f(-latura, -latura, latura); glVertex3f(latura, latura, latura); glVertex3f(latura, -latura, latura); glVertex3f(latura, latura, -latura); glVertex3f(latura, -latura, -latura); glVertex3f(-latura, latura, -latura); glVertex3f(-latura, -latura, -latura); glVertex3f(-latura, latura, latura); glVertex3f(-latura, -latura, latura); glEnd(); glBegin(GL_QUADS); glVertex3f(-latura, latura, latura); glVertex3f(latura, latura, latura); glVertex3f(latura, latura, -latura); 46

glVertex3f(-latura, latura, -latura); glEnd(); glBegin(GL_QUADS); glVertex3f(-latura, -latura, latura); glVertex3f(-latura, -latura, -latura); glVertex3f(latura, -latura, -latura); glVertex3f(latura, -latura, latura); glEnd(); } Observaii: In figura 3.16 sunt capturate dou poziii diferite n timpul rotaiei. Se constat c acele muchii care intervin i n poligoanele fa i n cele spate sunt desenate cu ambele tipuri de linii. Pentru a se masca acest lucru s-ar putea alege o grosime mai mare pentru linia continu. S analizm codul aplicaiei. n primul rnd s constatm c funcia cub () pstreaz orientarea trigonometric pentru toate patrulaterele. Dac se schimb orientarea direct (funcia glFrontFace () care este comentat n aplicaie) atunci poligoanele spate vor fi desenate cu linie continu i cele fa cu linie ntrerupt. Deoarece funcia glPoligonMode() nu ne permite specificarea de tipuri diferite de linii pentru poligoanele fa i cele spate, s-a desenat cubul de dou ori.

Figura 3.16 Prima dat s-au eliminat poligoanele fa i s-a activat linia punctat pentru desenarea poligoanelor spate. A doua oar s-au eliminat poligoanele spate i s-a dezactivat linia punctat. In ceea ce privete linia punctat, ea apare neuniform, deoarece fiecare muchie cu linie punctat intervine n desenarea a dou poligoane.

3.2 Reprezentarea curbelor i a suprafeelor curbe

47

Deoarece curbele nu pot fi descrise cu exactitate prin ecuaii lineare, n OpenGL nu exist funcii simple pentru desenarea curbelor, aa cum exist pentru puncte sau pentru drepte. O modalitate de a desena o curb este de a o aproxima prin puncte sau prin segmente de dreapt, cum s-a putut de altfel vedea ntr-unui din exemplele anterioare care reprezenta cercul cu linie continu. Reprezentarea cercului este ns o problem simpl avnd n vedere c se cunoate ecuaia sa. O soluie pentru modelarea curbelor ar fi deci de a se memora un set de puncte de pe curb. Reprezentarea s-ar putea face prin unirea punctelor prin linii n cazul n care acestea sunt suficient de apropiate. Soluia este costisitoare avnd n vedere numrul mare al punctelor ce ar trebui memorate pentru o curb. Pentru un set de puncte prin care ar trebui s treac curba se poate realiza o interpolare utiliznd pentru aceasta polinomul Newton. i aceast soluie este costisitoare avnd n vedere gradul mare al polinomului care rezult. O alt metod este de a genera curbele utiliznd funciile polinomiale Bezier pentru care OpenGL dispune de evaluatori. In acest caz sunt suficiente cteva puncte de control care aproximeaz forma curbei i evaluatorii determin puncte succesive pentru curba Bezier respectiv. Reprezentarea se face prin linii. Biblioteca GLU dispune chiar de o interfa pentru reprezentarea curbelor, folosind pentru aceasta ecuaiile NURBS (Non-Uniform Raional B-Spline). In acest subcapitol se va discuta despre reprezentarea curbelor Bezier i spline (NURBS). Utilitatea lor n realizarea aplicaiilor grafice este cu att mai mare cu ct permit programarea interactiv n reprezentarea curbelor. Mutnd punctele de control utilizatorul unei aplicaii poate modifica forma curbei. n ceea ce privete reprezentarea suprafeelor, problemele i soluionarea lor sunt asemntoare cu cele ale curbelor. Pentru reprezentarea unei suprafee curbe la care nu se cunoate o ecuaie presupune determinarea unui set de puncte pe suprafa i aproximarea reprezentrii prin triunghiuri. Soluia presupune mult memorie pentru salvarea coordonatelor triunghiurilor i nu este interactiv. Inginerul francez Pierre Bezier a fost primul care a venit cu o soluie care permite realizarea ntr-o manier necostisitoare a unor aplicaii interactive, prin inventarea ecuaiilor care-i poart numele. Interfaa OpenGL dispune de posibilitatea de evaluare a polinoamelor Bezier, prin evaluatori. Pentru reprezentarea unei suprafee Bezier de ordinul 3 este necesar o matrice de 16 puncte care aproximeaz forma suprafeei. Pe baza acestei matrice de puncte se determin ecuaiile Bezier i apoi, funcie de gradul de precizie, mai multe sau mai puine puncte de pe suprafa. Ca i n cazul curbelor, interfaa NURBS a bibliotecii GLU pune la dispoziie o metod de reprezentare a suprafeelor care generalizeaz curbele spline. Despre aceste metode se va discuta n continuare. n sfrit, biblioteca GLU are de asemenea funcii pentru generarea reprezentrilor poligonale ale obiectelor cvadrice. Aceste funcii pot genera de asemenea normalele pentru iluminare i coordonatele de texturare pentru obiectele cvadrice. Pentru a se nelege fundamentul matematic pentru reprezentarea curbelor i a suprafeelor curbe se recomand studierea capitolului respectiv din cartea "Sisteme de prelucrare grafic".

3.2.1 Evaluatori
48

Evaluatorii asigur o modalitate de a specifica puncte de pe o curb sau de pe o suprafa, utiliznd doar punctele de control. Curba sau suprafaa pot fi redate apoi cu precizia dorit. Suplimentar, pot fi determinate i normalele la suprafa. Punctele determinate de evaluatori pot fi utilizate pentru reprezentare n mai multe moduri a unei suprafee - reprezentarea unui set de puncte de pe suprafa, reprezentarea unei suprafee wireframe, reprezentarea unei suprafee cu iluminare i umbrire. Evaluatorii pot fi utilizai pentru a descrie orice curb sau suprafa polinomial de orice grad. Interfaa GLU care asigur o interfa de nivel ridicat NURBS are la baz tot evaluatorii. Ea conine o mulime de proceduri complicate, dar redarea final se realizeaz tot cu evaluatorii. Evaluatorii permit specificarea funciilor polinomiale de una sau dou variabile ale cror valori determin coordonatele vrfurilor primitivelor, coordonatele normalelor, coordonatele texturilor. Pentru oricare din aceste grupuri de valori, poate fi dat o hart polinomial specificat n termenii de baz Bezier. Odat definite i activate, hrile sunt invocate n unul din dou moduri posibile. Prima modalitate este de a determina o singur evaluare a fiecrei hri activate prin specificarea unui punct n domeniul hrii utiliznd funcia glEvalCoord(). Aceast comand se d ntre apelurile glBegin() i glEnd() astfel c se folosesc primitivele individuale pentru construirea unei poriuni dintr-o curb sau o suprafa. A doua metod este de a specifica o matrice de puncte n spaiu utiliznd funcia glEvalMesh(). Fiecare vrf din matricea evaluat este o funcie de polinoamele definite. Funcia glEvalMesh() i genereaz propriile sale primitive i de aceea nu poate fi plasat ntre funciile glBegin () i glEnd (). Interfaa pentru evaluatori asigur o baz pentru construirea unui pachet mai general pentru curbe i suprafee. Un avantaj al asigurrii evaluatorilor n OpenGL n locul unei interfee NURBS mai complexe este acela c aplicaiile care reprezint curbe i suprafee altele dect NURBS sau care utilizeaz proprieti speciale de suprafa au totui acces la evaluatori polinomiali eficieni (care pot fi implementai n hardware-ul grafic) fr a fi nevoie s fie convertii la reprezentri NURBS. n continuare se va descrie pe scurt suportul teoretic pentru curbele i suprafeele Bezier, pentru a nelege mai bine semnificaia evaluatorilor. Evaluatori uni-dimensionali O curb parametric polinomial este descris printr-un vector cu trei elemente: P(u) = [x(u) y(u) z(u)] Parametrul u ia valori de la 0 la 1. Pentru fiecare valoare a lui u se obine un punct P(u) aparinnd curbei. Utiliznd un set de puncte de control se poate obine o curb aproximativ folosind un set de funcii polinomiale obinute pe baza coordonatelor acestor puncte de control. Vom considera cazul general al curbelor Bezier de orice grad. Pentru un set de (n+1) puncte de control care definesc vectorii: Pk = (xk yk zk) k=0, 1, 2, ...n se poate aproxima polinomul vectorial P(u), care reprezint trei ecuaii parametrice (x(u), y(u), z(u)) pentru curba care trece prin punctele de control pk

P (u ) = pk Bk , n (u )
k =0

k=0 Fiecare polinom Bk,n este o funcie polinomial definit ca 49

Bk , n (n) = C (n, k ) u k (1 u ) k 1

iar C(n, k) reprezint coeficienii binomiali n! C ( n, k ) = k!(n k )! Relaiile coordonatelor pot fi scrise n form explicit ca un set de ecuaii parametrice pentru coordonatele curbelor:
x(u ) = xk Bk , n (u ) y (u ) = yk Bk , n (u ) z (u ) = zk Bk , n (u )
i =0 i =0 n i =0 n n

Evaluatori bi-dimensionali

Ecuaiile parametrice pentru suprafee sunt date folosind doi parametrii, u i v. Poziia coordonatelor unui punct de pe suprafa este reprezentat printr-un vector: S(u, v)=[x(u, v) y(u, v) z(u,v)] (3.9) Pentru reprezentarea unor suprafee specificate prin punctele de control se folosesc dou seturi de curbe Bezier. Funciile pentru vectorii parametrici care definesc suprafaa Bezier se obin ca produs cartezian al funciilor de amestec al celor dou seturi de curbe. S (u, v) = pi , k Bi , m (u ) Bk , n ( v )
i =0 k =0 m n

unde pi,k specific un punct de control din cele (m+l)x(n+l) puncte de control care definesc suprafaa.

3.2.2 Curbe Bezier


Exemplul 1 In exemplul urmtor se arat modul de utilizare al evaluatorilor pentru reprezentarea unei curbe Bezier. /* curbe_Bezier.c Programul utilizeaz evaluatorii pentru determinarea punctelor de pe curba Bezier */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void);

50

GLfloat ctrlpoints[4][3] = { { -4.0, -4.0, 0.0}, { -2.0, 4.0, 0.0}, {2.0, 4.0, 0.0}, {4.0, -4.0, 0.0}}; void myinit(void) { glClearColor(1.0, 1.0, 1.0, 1.0); glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]); glEnable(GL_MAP1_VERTEX_3); glShadeModel(GL_FLAT); glLineStipple (1, 0x0F0F); } void CALLBACK display(void) { int i; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord1f((GLfloat) i/30.0); glEnd(); glPointSize(5.0); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); for (i = 0; i < 4; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd(); glEnable(GL_LINE_STIPPLE); glColor3f(1.0, 0.0, 1.0); glBegin (GL_LINE_LOOP); for (i=0; i<4; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); else 51

glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 300, 300); auxInitWindow ("Curbe Bezier"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Observaii: In figura 3.17 se poate vedea rezultatul rulrii programului. Din program se poate vedea c funcia glMaplf() descrie caracteristicile curbei (puncte de control, gradul polinoamelor de amestec, intervalul pentru parametrul w), cu funcia glEnable(GL_MAPl_VERTEX_3) se activeaz un anumit tip de evaluatori, iar apoi se obin puncte pe curb cu funcia glEvalCoordlf().

Figura 3.17

52

Figura 3.18 Exemplul 2 O problem care se pune atunci cnd se lucreaz cu curbe Bezier, este realizarea unor curbe care sunt aproximate de mai mult de patru puncte de control. Ecuaiile curbei permit n acest caz specificarea mai multor puncte de control. Dar implicit n cazul acesta crete i gradul curbei. Dac se mrete doar numrul punctelor de control i nu se actualizeaz i gradul curbei n funcia glMaplf(), rezultatul va fi c se va reprezenta curba doar pentru primele patru puncte de control din tabloul punctelor de control. Exemplul anterior este modificat pentru reprezentarea unei curbe aproximat de 6 puncte de control, (figura 3.18). Se vor da doar funciile myinit() i display() n care sau fcut modificri fa de exemplul anterior. GLfloat ctrlpoints[6][3] = { { -4.0, 0.0, 0.0}, { -3.0, 4.0, 0.0}, { -1.0, 4.0, 0.0}, {1.0, -4.0, 0.0}, {3.0, -4.0, 0.0}, {4.0, 0.0, 0.0}}; void myinit(void) { glClearColor(1.0, 1.0, 1.0, 1.0); glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 6, &ctrlpoints[0][0]); /*funcia definete caracteristicile curbei: - tipul punctelor de control date in vectorul ctrlpoints, si al - datelor de ieire generate de funcia de evaluare glEvalCoordlf - valorile extreme luate de parametrul u (0 si 1 in acest caz) - numrul coordonatelor date pentru fiecare punct de control, in tabloul ctrlpoints - numrul punctelor de control pe baza crora se va determina ordinul curbei (numr puncte-1) -vectorul punctelor de control */ glEnable (GL_MAP1_VERTEX_3) ; //se valideaz un anumit tip de evaluare gl ShadeModel (GL_FLAT) ; //umbrire constanta pe poligoane glLineStipple (1, 0x0F0F); } void CALLBACK display(void) { int i; glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord1f((GLfloat) i/30.0); glEnd(); glPointSize(5.0); 53

glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); for (i = 0; i < 6; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd(); glEnable(GL_LINE_STIPPLE); glColor3f(1.0, 0.0, 1.0); glBegin (GL_LINE_STRIP); for (i=0; i<6; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd(); glFlush(); } Exemplul 3 n exemplul urmtor se deseneaz o curb (figura 3.19) care trece prin aceleai puncte de control ca i curba din exemplul anterior. De data aceasta ns se folosesc dou curbe Bezier de gardul 3 cu continuitate geometric (G1) de ordinul 1 n punctul de contact. Punctul de contact al celor dou curbe este un punct de control introdus suplimentar fa de exemplul anterior. El este punct terminal pentru prima curb i punct iniial pentru cea de a doua curb. Pentru a se obine continuitate geometric de ordinul 0 (G) n punctul de contact este necesar ca ultimul punct de control al primei curbe s coincid cu primul punct de control al celei de a doua curbe (punctul (0, 0, 0) n exemplul nostru). Pentru a avea continuitate geometric de ordinul 1 este necesar ca n punctul de contact tangentele la cele dou curbe s fie coliniare. O caracteristic a curbelor Bezier este c primele dou puncte de control i ultimele dou puncte de control sunt extremitile unor drepte care sunt tangente la curba Bezier. Condiia de continuitate geometric de ordinul 1 revine la condiia ca penultimul punct de control al primei curbe, punctul comun i al doilea punct de control al celei de a doua curbe s fie puncte coliniare. In cazul nostru aceste puncte sunt: {-1.0, 4.0, 0.0}, {0.0, 0.0, 0.0}, {l.0, -4.0, 0.0}. Toate aceste puncte sunt puncte coliniare i se afl pe dreapta de ecuaie y = 4x.

54

Figura 3.19 i pentru acest exemplu se furnizeaz doar partea de cod modificat fa exemplu anterior. GLfloat ctrlpointsl[4][3] = { //sunt date coordonatele celor 4 puncte de control pentru prima curb {-4.0, 0.0, 0.0},{-3.0, 4.0, 0.0},{-1.0, 4.0, 0.0},{0.0, 0.0, 0.0}}; GLfloat ctrlpoints2[4][3] = { //sunt date coordonatele celor 4 puncte de control pentru a doua curb {0.0, 0.0, 0.0}, {1.0, -4.0, 0.0}, {3.0, -4.0, 0.0},{4.0, 0.0, 0.0}}; void myinit(void) { glClearColor (1.0, 1.0, 1.0, 1.0); //culoarea background-ului glShadeModel (GL_FLAT) ; //umbrire constanta pe poligoane glLineStipple (1, 0x0F0F) ; //stilul liniei punctate } void CALLBACK display(void) { int i ; glClear(GL_COLOR_BUFFER_BIT); glColor3 f (0 . 0, 0.0, 0.0); //culoarea curenta de desenare glMaplf(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpointsl[0][0]); glEnable (GL_MAP1_VERTEX_3) ; //se valideaz un anumit tip evaluare glBegin (GL_LINE_STRIP) ; //se deseneaz curba prin segmente dreapta for (i = 0; i <^= 30; i++) glEvalCoordlf ( (GLfloat) i/30 . 0) ; //pentru cele 30 vrfuri determinate de // funcia glEvalCoordlf glEnd() ; glMaplf (GL_MAP1_VERTEX__3, 0.0, 1.0, 3, 4, &ctrlpoints2[0][0]); glBegin (GL_LINE_STRIP) ; //se deseneaz curba prin segmente dreapta for (i = 0; i <= 30; i++) glEvalCoordlf ( (GLf loat) i/30.0) ; //pentru cele 30 vrfuri determinate de //funcia glEvalCoordlf glEnd() ; /*Se afieaz punctele de control. */ glPointSize (5 . 0) ; //de dimensiune 5 glColor3f (1.0, 0.0, 0.0); //culoare roie glBegin (GL_POINTS) ; //pentru prima curba for (i = 0; i < 4; i + +) glVertex3fv(&ctrlpointsl[i][0]); glEnd() ; glBegin (GL_POINTS) ; //pentru a doua curba for (i = 0; i < 4; i++) glVertex3fv(&ctrlpoints2[i] [0] ) ; glEnd() ; //se unesc punctele de control glEnable (GL_LINE_STIPPLE) ; //linie punctat glColor3f(0.0, 1.0, 0.0); glBegin (GL_LINE_STRIP) ; //pentru prima curba 55 de

de de

de

for (i=0; i<4; i++) glVertex3fv(&ctrlpointsl[i][0]); glEnd() ; glBegin (GL_LINE_STRIP) ; //pentru a doua curba for (i=0; i<4; i++) glVertex3fv(&ctrlpoints2[i][0]); glEnd(); glFlush() ; }

3.2.3 Suprafee Bezier


Urmtoarele dou exemple arat modul de utilizare al evaluatorilor bidimensionali pentru reprezentarea suprafeelor. Exemplul 1 In figura 3.20 se poate vedea rezultatul rulrii acestui exemplu.

Figura 3.20 /* Wire_Bezier.c Programul realizeaz o reprezentare Wireframe pentru o suprafaa Bezier, utiliznd evaluatorul bidimensional EvalCoord2f */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); GLfloat ctrlpoints[4][4][3] = { 56

{{-1.5, -1.5, -4.0}, {-0.5, -1.5, -4.0}, {0.5, -1.5, -4.0}, {1.5, -1.5, -4.0}}, {{-1.5, -0.5, -4.0}, {-0.5, -0.5, -2.0}, {0.5, -0.5, -2.0}, {1.5, -0.5, -4.0}}, {{-1.5, 0.5, -4.0}, {-0.5, 0.5, -2.0}, {0.5, 0.5, -2.0}, {1.5, 0.5, -4.0}}, {{-1.5, 1.5, -4.0}, {-0.5, 1.5, -4.0}, {0.5, 1.5, -4.0}, {1.5, 1.5, -4.0}} }; void myinit(void) { glClearColor (1.0, 1.0, 1.0, 1.0); // culoarea background-ului /* funcia glMap2f definete caracteristicile suprafeei Bezier: - tipul punctelor determinate de funcia glEvalCoord2f - intervalul de variaie al parametrului u (0 -l in acest caz) - intervalul valorilor in tabloul ctrlpoints intre doua puncte de control pe direcia u - numrul punctelor de control pe direcia u - intervalul de variaie al parametrului v (0 -l in acest caz) - intervalul valorilor in tabloul ctrlpoints intre doua puncte de control pe direcia v - numrul punctelor de control pe direcia v - tabloul punctelor de control */ glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]); glEnable (GL_MAP2_VERTEX_3 ) ; // validarea tipului de evaluare // GL_MAP2_VERTEX_3 glMapGrid2 f(20, 0.0, 1.0, 20, 0.0, 1.0); // intervalele de eantionare // a suprafeei pentru parametrii u si v. Fiecare parametru variaz ntre 0 i 1 i sunt // 20 de intervale de eantionare. Deci valorile pentru care se calculeaz puncte pe //suprafa sunt pentru u i v variind cu un pas de 1/20. } void CALLBACK display(void) { int i, j; glClear(GL_COLOR_BUFFER_BIT); // se folosete si buffer de refresh si buffer de adncime glColor3f (1.0, 0.0, 0.0); //culoarea curenta glLoadldentity() ; // pentru a nu aplica transformri geometrice // la fiecare redesenare a ferestrei glRotatef (-85.0, 1.0, 1.0, 1.0); //rotaie in jurul axei (1, 1, 1) glTranslatef (0, 0, 4) ; // urmeaz desenarea wireframe a suprafeei //fiecare patch (8X8 patch-uri) este desenat //dintr-o linie frnt n 30 de segmente //de dreapta for (j = 0; j <= 8; j++) { glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0); 57

// evalueaz un punct pe suprafaa pentru valorile u si v ale ale parametrilor glEnd(); glBegin(GL_LINE_STRIP); for (i = 0; i <= 30; i++) glEvalCoord2f((GLfloat)j/8.0, (GLfloat)i/30.0); glEnd(); } glFlush() ; } void CALLBACK myReshape(GLsizei w# GLsizei h) { if (!h) return; glViewport(0, 0, w, h) ; glMatrixMode(GL_PROJECTION); glLoadldentity(); if (w <= h) glOrtho(-4.0/4.0,-4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0); else glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0); glMatrixMode(GL_MODELVIEW); glLoadldentity(); } int main(int argc, char** argv) { auxInitDlsplayMode(AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 300,300); auxInitwindow wireframe"); myinit(); auxReshapeFunc (myReshape) ; auxMainLoop(display); return(0); } Observaii: n exemplul de mai sus se poate remarca asemnarea n utilizarea evaluatorilor unidimensionali i bidimensionali. Pentru a fi mai clar felul n care se declar tabloul punctelor de control se recomand afiarea acestei suprafee fr a se aplica cele dou transformri geometrice (glRotatef, glTranslatef). De asemenea pentru a se obine rezultate mai bune la reprezentare se recomand ncercarea de a reprezenta suprafaa cu mai mult de 8X8 patch-uri. Exemplul 2 n exemplul urmtor se reia reprezentarea suprafeei cu punctele de control specificate anterior dar utiliznd cellalt tip de evaluator bidimensional glEvalMesh2. Se poate constata, c dac n exemplul anterior evaluatorul era folosit n corpul glBegin/glEnd, n acest caz nu mai este necesar acest lucru. Motivul este urmtorul: n primul exemplu evaluatorul furnizeaz coordonate de vrfuri, iar n al doilea caz se i genereaz poligoanele care formeaz suprafaa. Deoarece modul de reprezentare al poligoanelor permite reprezentarea n puncte, linii sau cu umplere (GL_POINT, 58

("Suprafaa Bezier

GL__LINE, GL_FILL) n acest caz suprafaa poate fi reprezentat n toate aceste modaliti (figura 3.21).

Figura 3.21 /* Solid_Bezier.c Programul afieaz o suprafaa Bezier folosind evaluatori bidimensionali */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void initlights(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); // tabloul ctrlpoints definete cele 16 puncte de control ale suprafeei GLfloat ctrlpoints[4][4][3] = { {{-1.5, -1.5, -4.0}, {-0.5, -1.5, -4.0}, {0.5, -1.5, -4.0}, {1.5, -1.5, -4.0}}, {{-1.5, -0.5, -4.0}, {-0.5, -0.5, -2.0}, {0.5, -0.5, -2.0}, {1.5, -0.5, -4.0}}, {{-1.5, 0.5, -4.0}, {-0.5, 0.5, -2.0}, {0.5, 0.5, -2.0}, {1.5, 0.5, -4.0}}, {{-1.5, 1.5, -4.0}, {-0.5, 1.5, -4.0}, 59

{0.5, 1.5, -4.0}, {1.5, 1.5, -4.0}} }; // setri pentru iluminarea suprafeei void initlights(void) { GLfloat ambient[] = { 1.0, 0.6, 0.0, 1.0 }; GLfloat position[] = { 2.0, 2.0, 2.0, 1.0 }; GLfloat mat_diffuse[] = { 1.0, 0.6, 0.0, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_POSITION, position); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); } void CALLBACK display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); //salvare n stiv matrice curent de modelare //trei transformri de modelare //rotaia i translaia poziioneaz suprafaa n fereastra de vizualizare // iar scalarea mrete dimensiunea suprafeei de 1,7 ori glRotatef(-85.0, 1.0, 1.0, 1.0); glTranslatef(0, 0, 6); glScalef(1.7,1.7,1.7); glEvalMesh2(GL_POINT, 0, 20, 0, 20); //specifica modul // de redare al poligoanelor (GL_FILL, GL_POINT, GL_LINE, // si intervalele de eantionare a suprafeei pentru u si v glPopMatrix() ;//scoate din stiv matricea de modelare glFlush() ; } void myinit(void) { glClearColor (1.0, 1.0, 1.0, 1.0); //culoarea background-ului glEnable (GL_DEPTH_TEST) ; //se activeaz ascunderea suprafeelor /* funcia glMap2f definete caracteristicile suprafeei Bezier - tipul punctelor determinate de funcia glEvalCoord2f - intervalul de variaie al parametrului u (0 -l in acest caz) - intervalul valorilor in tabloul ctrlpoints intre doua puncte de control pe direcia u - numrul punctelor de control pe direcia u - intervalul de variaie al parametrului v (0 -l in acest caz) - intervalul valorilor in tabloul ctrlpoints intre doua puncte de control 60

pe direcia v numrul punctelor de control pe direcia v tabloul punctelor de control

*/ glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, &ctrlpoints[0][0][0]); glEnable (GL_MAP2_VERTEX_3 ) ; // validarea tipului de evaluare //GL_MAP2_VERTEX_3 glEnable(GL_AUTO_NORMAL); glEnable (GL_NORMALIZE) ; // pentru iluminare glMapGrid2f (20, 0.0, 1.0, 20, 0.0, 1. 0); //intervalele de eantionare // a suprafeei pentru parametrii u si v //20 de intervale pentru fiecare parametru. //fiecare parametru variaz ntre 0 i 1 initlights () ; /* doar daca se dorete reprezentarea cu iluminare */ } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h) ; glMatrixMode (GL_PROJECTION) ; glLoadldentity(); if (w <= h) glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0) ; else glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0); glMatrixMode(GL_MODELVIEW); glLoadldentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16); auxInitPosition (0, 0, 300, 300); auxInitWindow ("Suprafaa Bezier cu iluminare si atribut de umplere pe poligoane"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Observaii: Ca o concluzie, n primul exemplu suprafaa wireframe este reprezentat prin evaluarea unor puncte pe curbe i prin reprezentarea acestor curbe. In al doilea exemplu evaluatorii determin vertex-urile unor poligoane i reprezint aceste poligoane n oricare din modurile posibile pentru poligoane.

61

3.2.4 Interfaa NURBS


Aa cum am artat, n cazul curbelor Bezier pentru forme mai complicate de curbe sunt necesare mai multe puncte de control. Pentru a aproxima forma unei curbe pe baza acestor puncte, n exemplele anterioare fie am crescut gradul polinoamelor de amestec, fie am asamblat curba din mai multe buci. O soluie pentru construirea curbelor, care ofer o mai mare flexibilitate n modelare este utilizarea interfeei NURBS (Non-Uniform Raional B-Spline) din biblioteca GLU. Curbele NURBS sunt de fapt o metod generalizat care permite descrierea matematic att a curbelor Bezier ct i a altor curbe. Un alt avantaj al acestor curbe este tipul de continuitate n punctele de control. Aa cum s-a vzut, n cazul curbelor Bezier ordinul polinoamelor de amestec crete odat cu numrul punctelor de control. Pentru asamblarea mai multor curbe programatorul este cel care trebuie s aleag astfel punctele de control ca s se obin continuitate de ordinul 1 n punctele de control. In cazul curbelor spline, creterea numrului punctelor de control nu conduce la creterea gradului polinoamelor de amestec. Gradul polinoamelor este controlat de un alt parametru. Indiferent de numrul punctelor de control, n cazul curbelor spline se asigur continuitate de ordinul 2 n noduri (aceasta nseamn c n noduri att derivatele de ordin nti ct i derivatele de ordin 2 sunt egale). Curbele B-spline sunt o clas de curbe spline foarte utile n aplicaiile grafice. Pentru un set de (n+1) puncte de control ph (k variaz de la 0 la n) se pot determina punctele care aparin unei curbe B-spline aproximat prin punctele de control date, utiliznd ecuaia parametric urmtoare: P ( y ) = pk * Nk , t (u )
i =0 n

Se observ c gradul polinoamelor de amestec (care este t-1) este independent de numrul punctelor de control (n), ceea ce reprezint un avantaj al curbelor spline. Funciile de amestec A^, sunt polinoame de gradul (t-l). O metod pentru definirea polinomului folosit pentru funciile de amestec este de a le defini recursiv fa de diferitele subintervale din domeniul de variaie al parametrului u. Domeniul de variaie al parametrului u nu mai este n intervalul [0, 1] ci el este dependent de numrul punctelor de control i de alegerea fcut pentru t. Astfel u variaz n intervalul: 0 - (n-t+2) Numrul total al segmentelor de curb va fi deci de (n-t+2). Fiecare din aceste curbe va fi controlat (ca i form) de t puncte de control din cele (n+l) puncte de control. Dac se consider (n+t) subintervale, se definesc funciile de amestec n mod recursiv: 1, rk u p rk +1 N k ,1 (u ) = altfel 0, u rk r u N k ,1 (u ) = N t , n 1 (u ) + k +1 N k +1,t 1 (u ) rk + t 1 rk rk +1 rk +1 Se observ c polinomul de amestec corespunztor unui punct de control se calculeaz folosind polinoamele de amestec corespunztoare acestui punct i celui 62

urmtor dar de grad mai mic cu 1. Deci pentru fiecare punct de control k, se calculeaz funciile de amestec plecnd de la t=l. Cu ct t este mai mic se fac mai puine calcule. Deoarece numitorii, n calculele recursive pot avea valoarea 0, aceast formulare consider c se evalueaz prin 0 rapoartele 0/0. Poziiile definite de xj- pentru subintervalele lui u sunt referite ca valori nodale, iar punctele corespunztoare lor pe o curb B-spline sunt numite noduri. Cele (n-t+2) segmente de curb vor fi cuprinse ntre aceste noduri. In noduri exist continuitate de ordinul 2, asigurat de modul n care sunt definite curbele B-spline. Spre exemplu, pentru n=6 i t=4 curbele B-spline uniforme pot fi caracterizate n felul urmtor: Tabelul 3.1 numrul punctelor de control: gradul polinoamelor de amestec numrul segmentelor de curb intervalul de variaie al lui u numrul nodurilor valorile nodale numrul subintervalelor n+1=7 t -1 = 3 n-t + 2 = 4 [0,4] 5 0,1,2,3,4 n + t= 10

Valorile nodale pot fi definite n diverse feluri. O distanare uniform a valorilor nodale se obine prin setarea lui rd egal cu j. Trebuie spus .c n cazul n care valorile nodale sunt distanate uniform curbele B-spline se numesc curbe B-spline uniforme. O alt metod de definire uniform a intervalelor este de a seta valorile nodale astfel: 0 pentru j < t rj = j t + 1 pentru t j n n t + 2 pentru j > n Pentru grad 2 (t=3) folosind cinci puncte de control (n4), subintervalele definite ca n relaiile (3.14), parametrul u variaz n intervalul de la 0 la 3, cu valori nodale de la r0 la r7 avnd valorile: r0 = 0 ri = 0 r2 = 0 r3 = 1 r4 = 2 r5 = 3 r6 = 3 r7 = 3 n = 4, t = 3, j [0,7], u [0,3] r0 = 0; ri = 0; r2 = 0; r3 = 1; r4 = 2; r5 = 3; r6 = 3; r7 = 3;

63

Numrul segmentelor de curb n acest caz va fi 3: Q1, Q2, Q3. Curba Q1 va fi controlat de punctele P0, P1, P2 . Curba Q2 va fi controlat de punctele P1, P2, P3. Curba Q3 va fi controlat de punctele P2, P3, P4. Primul punct de control are influen asupra formei curbei spline doar pentru valorile lui u cuprinse n intervalul (0,1). n felul acesta se pot localiza uor punctele n care apar modificri. Dac utilizatorul modific poziia primului punct de control, forma curbei se va modifica n apropierea acestui punct fr a afecta celelalte poriuni ale curbei. Pentru valorile date pentru n i t se poate deci realiza urmtoare schem: Tabelul 3.2 u Curba Polinoam ele care controleaz Punctele care controleaz forma curbei [0,1] Q1 N0, 3 N1,3 N2,3 P0 P1 P2 [1, 2] Q2 N1, 3 N2,3 N3,3 P1 P2 P3 [2,3] Q3 N2,3 N3,3 N4.3 P2 P3 P4

Folosirea curbelor B-spline prezint avantajul c utilizatorul poate specifica orice numr de puncte de control fr a fi nevoie pentru aceasta s creasc gradul curbei. O funcie de grad 3 (funcie cubic n care t=4) poate fi folosit pentru diferite forme de curbe, fr a fi nevoie pentru aceasta de a compune curba din segmente de curb ca n cazul curbelor Bezier. Pentru a modifica forma curbei poate fi adugat orice numr de puncte de control. Nu se aleg valori mai mici pentru t deoarece n cazul n care, spre exemplu, t=l (funcii de amestec de grad 0) curbele spline sunt discontinue pe intervalele de variaie ale lui u. n cazul n care t=2 (funcii de amestec de grad 1) se obine continuitate de ordinul 0 n noduri (curba nu este neted ). In cazul n care t=3 (funcii de amestec de ordin 2) se obine continuitate de ordinul 1 n punctele de jonciune. Pentru t=4 (funcii de amestec de grad 3) se obine continuitate de ordinul 2 n noduri. La fel ca i n cazul curbelor Bezier, specificarea mai multor puncte de control, n poziii apropiate, va conduce la "atragerea" curbei spre poziia respectiv. De asemenea, pentru obinerea unei curbe nchise trebuie s se specifice primul i ultimul punct de control avnd aceleai coordonate. De asemenea, curbele spline se aeaz n interiorul poligonului convex definit de punctele de control.

3.2.5 Curbe NURBS


64

Exemplul 1 n acest exemplu se vor utiliza aceleai puncte de control care s-au utilizat n exemplul 2 de la curbe Bezier. Ceea ce trebuie pus n vederea programatorilor este felul n care se calculeaz numrul nodurilor i valorile acestora. De asemenea este important felul n care se stabilesc caracteristicile curbei B-spline. n acest exemplu s-au utilizat 6 puncte de control deci n=5. Deoarece s-a dorit continuitate de ordinul 2 s-au utilizat polinoame de gradul 3 deci t=4. Ca urmare a relaiilor 3.14 numrul intervalelor nodale este n+t=9 (deci 10 noduri de la r0 la r9). Valorile nodurilor calculate conform relaiilor 3.14 sunt: r0=0; ri=0; r2=0; r3=0; r4=l; r5=2; r6=3; r7=3; r8=3; r9=3 Trebuie subliniat c dac valorile nodale i numrul acestora sunt alese aleator, rezultatele nu sunt controlabile. Forma curbei pentru valorile nodale alese ca mai sus, va fi asemntoare cu cea a curbei Bezier pentru aceleai puncte de control (figura 3.22).

Figura 3.22 /* Curba_spline.c Programul utilizeaz biblioteca GLUT pentru redarea unei curbe spline */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); GLUnurbsObj *theNurb; // curba este un obiect de tipul GLUnurbsObj void myinit(void) { glShadeModel (GL_FLAT); glLineStipple (1, 0x0F0F); //stilul liniei ntrerupte theNurb = gluNewNurbsRenderer(); // obiectul de tip GLUnurbsObj gluNurbsProperty (theNurb, GLU_SAMPLING_TOLERANCE, 10.0); 65

} /* Funcia afieaz o curba B-spline. */ void CALLBACK display(void) { int i; GLfloat ctrlpoints[6][3] = {{ -4.0, 0.0, 0.0}, { -3.0, 4.0, 0.0}, { -1.0, 4.0, 0.0}, {1.0, -4.0, 0.0}, {3.0, -4.0, 0.0}, {4.0, 0.0, 0.0}}; GLfloat knots[10] = {0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0, 3.0}; glClearColor (1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f (0.0, 0.0, 0.0); gluBeginCurve(theNurb); gluNurbsCurve(theNurb, 10, knots, 3, &ctrlpoints[0][0], 4, GL_MAP1_VERTEX_3); gluEndCurve(theNurb); glPointSize(5.0); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); for (i = 0; i < 6; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd(); glEnable(GL_LINE_STIPPLE); glColor3f(1.0, 0.0, 1.0); glBegin (GL_LINE_STRIP); for (i=0; i<6; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); else glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); 66

glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 300, 300); auxInitWindow ("Curba B-spline"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Exemplul 2 Pentru a exemplifica faptul c interfaa NURBS permite obinerea de curbe de forme complicate, fr a fi nevoie pentru aceasta s se creasc gradul polinoamelor de amestec sau s se calculeze poziia punctelor de control pentru a asigura continuitatea dorit n punctele de contact, vom mai prezenta un exemplu. Se vor da doar funciile care au suferit modificri fa de exemplul anterior. n figura 3.23 se poate vedea rezultatul rulrii programului.

Figura 3.23 /* Funcia afieaz o curba B-spline. */ void CALLBACK display(void) { int i; // 6 puncte de control n=5 GLfloat ctrlpoints[17][3] = GLfloat ctrlpoints[17][3] = {{ 1.0, 0.0, 0.0}, { 2.0, 1.0, 0.0}, { 1.0, 3.0, 0.0}, { -1.0, 2.0, 0.0}, { -2.0, 0.0, 0.0}, { -1.0, -2.0, 0.0}, { 1.0, -3.0, 0.0}, { 3.0, -1.0, 0.0}, { 4.0, 1.0, 0.0}, { 5.0, 3.0, 0.0}, { 0.0, 5.0, 0.0}, { -3.0, 3.0, 0.0}, 67

{ -4.0, -1.0, 0.0}, { -2.0, -5.0, 0.0}, { 2.0, -6.0, 0.0}, { 4.0, -3.0, 0.0}, { 6.0, 0.0, 0.0}}; // 21 noduri, n+t=20subintervale, valorile sunt calculate dup relaia de mai sus GLfloat knots[21] = {0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 14.0, 14.0, 14.0}; glClearColor(1.0,1.0,1.0, 1.0); //culoarea background-ului glClear(GL_COLOR_BUFFER_BIT); glColor3f (0.0, 0.0, 0.0); //culoarea curenta de desenare // ncepe corpul de redare al curbei Spline gluBeginCurve(theNurb); gluNurbsCurve (theNurb, // pointer obiect NURBS 21, knots, //numr noduri, tablou noduri 3, // intervalul de valori dintre doua puncte de control consecutive &ctrlpoints [ 0 ] [ 0 ] , // vector puncte de control 4, // ordinul curbei, t=4 GL_MAP1_VERTEX_3 ) ; // tip evaluator gluEndCurve(theNurb); /* Se afieaz punctele de control. */ glPointSize(5. 0) ; //de dimensiune 5 glColor3f (1.0, 0.0, 0.0); //culoare roie glBegin(GL_POINTS) ; for (i = 0; i < 17; i++) glVertex3fv(&ctrlpoints[i][0]); glEnd() ; //se unesc punctele de control glEnable(GL_LINE_STIPPLE) ; glColor3f(1.0, 0.0, 1.0); glBegin (GL_LINE_STRIP); for (i=0; i<17; i + +) glVertex3fv(&ctrlpoints[i][0]); glEnd() ; glFlush() ; } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h) ; glMatrixMode(GL_PROJECTION); glLoadldentity(); if (w <= h) glOrtho(-7.0, 7.0, -7.0*(GLfloat)h/(GLfloat)w, 7.0*(GLfloat)h/(GLfloat)w, -7.0, 7.0) ; else glOrtho(-7.0*(GLfloat)w/(GLfloat)h, 7.0*(GLfloat)w/(GLfloat)h, -7.0, 7.0, -7.0, 7.0); glMatrixMode(GL_MODELVIEW); glLoadldentity();
Suprafee NURBS

68

Vom relua redarea suprafeei definit prin punctele de control din exemplul de la "Suprafee Bezier". Modul de utilizare al interfeei NURBS pentru reprezentarea suprafeelor NURBS este foarte asemntor cu cel pentru redarea curbelor NURBS. Trebuie creat un obiect de tipul GLUnurbsObj, utiliznd funcia gluNewNurbsRenderer. Apoi se definesc caracteristicile pentru obiectul creat folosind funcia gluNUrbsProperty pentru fiecare atribut definit. Desenarea suprafeei se face n corpul gluBeginSurf ace (theNurb) / gluEndSurface (theNurb) utiliznd funcia gluNurbsSurface (gluNurbsCurve pentru curbe NURBS). Ca i n cazul curbelor trebuie definit tabloul punctelor de control i tabloul nodurilor. In funcie de numrul punctelor de control (n+1, m+1) i al ordinului (s sau t) pe fiecare direcie se va stabili i numrul nodurilor (n+s+l sau m+t+l) pentru fiecare direcie. n cazul exemplului urmtor valorile sunt urmtoarele: Tabelul 3.3 Parametrul n Numrul punctelor de control pe direcia u m Numrul punctelor de control pe direcia v Ordinul s pe direcia u Ordinul t pe direcia v Gradul polinoamelor de amestec pe direcia u (s-1) Gradul polinoamelor de amestec pe direcia v (t-1) Numrul subintervalelor pe direcia u (n+s) Numrul subintervalelor pe direcia v (m+s) Numrul nodurilor pe direcia u (puncte control+ordin=n+s+l) Numrul nodurilor pe direcia v (puncte control+ordin=m+t+l) Valoare 3 4 3 4 4 4 3 3 7 7 8 8

Pentru calcularea valorilor nodurilor se folosesc aceleai relaii ca i n cazul curbelor (3.14). Desigur c se pot reprezenta i suprafee de forme mult mai complicate. Exemplul 1 /* Supf_spline_solid2.c Afieaz o suprafaa spline folosind biblioteca GLUT */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void myinit(void); 69

void CALLBACK display(void); void CALLBACK myReshape(GLsizei w, GLsizei h); // tabloul ctrlpoints definete cele 16 puncte de control ale suprafeei GLfloat ctrlpoints[4][4][3] = { {{-1.5, -1.5, -4.0}, {-0.5, -1.5, -4.0}, {0.5, -1.5, -4.0}, {1.5, -1.5, -4.0}}, {{-1.5, -0.5, -4.0}, {-0.5, -0.5, -2.0}, {0.5, -0.5, -2.0}, {1.5, -0.5, -4.0}}, {{-1.5, 0.5, -4.0}, {-0.5, 0.5, -2.0}, {0.5, 0.5, -2.0}, {1.5, 0.5, -4.0}}, {{-1.5, 1.5, -4.0}, {-0.5, 1.5, -4.0}, {0.5, 1.5, -4.0}, {1.5, 1.5, -4.0}} }; GLUnurbsObj *theNurb; /* Iniializarea buffer-ului de adncime si a atributelor materialului si sursei de lumina Iniializarea suprafeei NURBS */ void myinit(void) { GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_diffuse[] = { 1.0, 0.2, 1.0, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; GLfloat light0_position[] = { 1.0, 0.0, -1.0, 0.0 }; GLfloat light1_position[] = { -1.0, 0.1, 0.0, 0.0 }; GLfloat lmodel_ambient[] = { 0.3, 0.3, 0.3, 1.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glEnable(GL_AUTO_NORMAL); theNurb = gluNewNurbsRenderer(); gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0); gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL); //sau GLU_OUTLINE_POLYGON } 70

void CALLBACK display(void) { GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glRotatef(-85.0, 1.0, 1.0, 1.0); glTranslatef(0, 0, 6); glScalef(1.7,1.7,1.7); gluBeginSurface(theNurb); gluNurbsSurface(theNurb, 8, //numrul nodurilor n direcia u knots, // tabloul nodurilor n direcia u 8, //numrul nodurilor n direcia v knots, 4 * 3, // offsetul ntre puncte de control succesive n direcia u n tabloul //ctrlpoints 3, // offsetul ntre puncte de control succesive n direcia v n tabloul ctrlpoints &ctrlpoints[0][0][0], // tabloul punctelor de control 4, // ordinul curbei s n direcia u, gradul polinoamelor de amestec este s-1 4, // ordinul curbei t n direcia v, gradul polinoamelor de amestec este t-1 GL_MAP2_VERTEX_3); gluEndSurface(theNurb); glPopMatrix(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w, 4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0); else glOrtho(-4.0*(GLfloat)w/(GLfloat)h, 4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); 71

auxInitPosition (0, 0, 300, 300); auxInitWindow ("Suprafaa B-Spline"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Observaii: Se poate observa c forma suprafeei obinute este aceeai cu a suprafeei Bezier (figura 3.24). n figura 3.24 se poate vedea i reprezentarea wireframe n cazul n care se folosete constanta GLU_OUTLINE_POLYGON n locul constantei GLU_FILL n funcia gluNurbsProperty pentru parametrul GLU_DISPLAY_MODE.

Figura 3.24 Exemplul 2 Se va exemplifica i o form mai complicat. Se vor da doar acele funcii care au suferit modificri fa de exemplul anterior. Reprezentarea suprafeei se poate vedea n figura 3.25.

Figura 3.25 72

GLfloat ctrlpoints[4][8][3] = { {{-4.5, -1.5, -4.0}, {-3.0, -1.5, -2.0}, {-1.5, -1.5, -0.0}, {0.0, -1.5, -2.0}, {1.5, -1.5, -4.0}, {3.0, -1.5, -2.0}, {4.5, -1.5, -0.0}, {6.0, -1.5, -2.0}}, {{-4.5, 0.0, -4.0}, {-3.0, 0.0, -2.0}, {-1.5, 0.0, -0.0}, {0.0, 0.0, -2.0}, {1.5, 0.0, -4.0}, {3.0, 0.0, -2.0}, {4.5, 0.0, -0.0}, {6.0, 0.0, -2.0}}, {{-4.5, 1.5, -4.0}, {-3.0, 1.5, -2.0}, {-1.5, 1.5, -0.0}, {0.0, 1.5, -2.0}, {1.5, 1.5, -4.0}, {3.0, 1.5, -2.0}, {4.5, 1.5, -0.0}, {6.0, 1.5, -2.0}}, {{-4.5, 3.0, -4.0}, {-3.0, 3.0, -2.0}, {-1.5, 3.0, -0.0}, {0.0, 3.0, -2.0}, {1.5, 3.0, -4.0}, {3.0, 3.0, -2.0}, {4.5, 3.0, -0.0}, {6.0, 3.0, -2.0}}, }; GLUnurbsObj *theNurb; void CALLBACK display(void) { // punctele de control GLfloat s_knots[12] = {0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0 }; GLfloat t_knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; glClearColor(1.0, 1.0, 1.0, 1.0); //culoarea background-ului glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); // transformri geometrice pentru poziionarea i // dimensionarea suprafeei glRotatef(-85.0, 1.0, 1.0, 1.0); glTranslatef(0, 0, 6); glScalef(1.7,1.7,1.7); gluBeginSurface(theNurb) ; // ncepe redarea suprafeei gluNurbsSurface (theNurb, //obiectul NURBS 12 , //numrul nodurilor n direcia u s_knots, // tabloul nodurilor n direcia u 8, //numrul nodurilor n direcia v t_knots, // tabloul nodurilor n direcia u 4 * 3, // offsetul ntre puncte de control succesive n direcia u n tabloul ctrlpoints 3, // offsetul ntre puncte de control succesive n direcia v n tabloul ctrlpoints &ctrlpoints [0] [0] [0] , //tabloul punctelor de control 4, // ordinul curbei s n direcia u, gradul polinoamelor de amestec este s-1 4 , // ordinul curbei t n direcia v, gradul polinoamelor de amestec este t-1 GL_MAP2_VERTEX_3 ); // GL_MAP2_VERTEX_3 sau GL_MAP2_COLOR_4 73

gluEndSurf ace (theNurb) ; // se termin redarea suprafeei glPopMatrix(); glFlush() ; * } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(O, 0, w, h); glPopMatrix(); glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-7.0, 7.0, -7.0*(GLfloat)h/(GLfloat)w, 7.0*(GLfloat)h/(GLfloat)w, -7.0, 7.0); else glOrtho(-7.0*(GLfloat)w/(GLfloat)h, 7.0*(GLfloat)w/(GLfloat)h, -7.0, 7.0, -7.0, 7.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 300, 300); auxInitWindow ("Suprafaa B-Spline"); myinit(); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); }

3.3 Suprafee cvadrice

Suprafeele cvadrice sunt suprafee definite printr-o ecuaie de gradul al doilea. Biblioteca GLU dispune de funcii pentru reprezentarea acestui tip de suprafee (sfere, cilindrii, discuri i poriuni de discuri). 74

Pentru a crea un obiect de tip cvadric, se utilizeaz funcia gluNewQuadric(). Pentru distrugerea obiectului creat, atunci cnd acesta nu mai este necesar, se folosete funcia gluDeleteQuadric(). Pentru a specifica alte valori dect cele implicite, n legtur cu stilul de redare al acestor suprafee se utilizeaz anumite funcii: - gluQuadricNormals() : dac se vor genera normale la suprafee, iar dac da, se specific dac vor fi specificate relativ la vrfuri sau la suprafee. - gluQuadricTexture(): dac se genereaz coordonate pentru texturare. - gluQuadricOrientation(): care fee vor fi considerate exterioare i care interioare. - gluQuadricDrawStyle() : stilul de desenare al cvadricelor - cu puncte, linii sau poligoane. Dup ce s-a specificat stilul de redare, se apeleaz funciile corespunztoare tipului de cvadric ce se reprezint: gluSphere(), gluCylinder(), gluDisk() sau gluPartialDisk(). Dac se dorete mrirea sau micorarea obiectului, este recomandat s se specifice noile dimensiuni dect s se foloseasc funcia de scalare glScalef(). Motivul este creterea vitezei de reprezentare, avnd n vedere, c dac se utilizeaz funcia de scalare are loc o renormailzare a normalelor la suprafee. Pentru o redare a iluminrii ct mai precis se recomand valori ridicate pentru parametrii loops i stacks. n continuare se vor da prototipurile tuturor acestor funcii. Funcii pentru controlarea obiectelor GLUquadricObj* gluNewQuadric (void); Funcia permite crearea unei cvadrice. void gluDeleteQuadric (GLUquadricObj *state); Funcia permite tergerea unei cvadrice. Funcii pentru modificarea felului n care sunt desenate cvadricele void gluQuadricNormals (GLUquadricObj *quadObject, Glenum normals) ; Parametrul normals poate lua urmtoarele valori: Tabelul 3.4 GLU_NONE GLU_FLAT Nu se genereaz normale pentru iluminare Normalele sunt generate pentru fiecare fa, rezultnd o iluminare poligonal constant pe poligoane GLU_SMOOTH Normalele sunt generate pentru fiecare vrf, rezultnd o iluminare GOURAUD.
-

voidgluQuadricTexture(GLUquadricObj*quadObject, GLboolean textureCoords); Funcia activeaz (GL_TRUE) sau dezactiveaz (GL_FALSE) generarea coordonatelor de texturare. void gluQuadricOrientation (GLUquadric *quadObject, GLenum orientation); Funcia controleaz direcia normalelor pentru iluminare. Acestea pot avea orientarea spre exteriorul obiectelor (GLU_OUTSIDE) sau spre interiorul acestora (GLU_INSIDE). void gluQuadricDrawStyle (GLUquadricObj *quadObject, GLenum 75

drawStyle); Funcia specific tipul primitivelor OpenGL utilizate pentru reprezentarea cvadricelor. Parametrul drawStyle poate lua urmtoarele valori:

Tabelul 3.5 GLU__FILL Cvadricele au atribut de umplere i pentru generarea lor sunt utilizate poligoane. GLU__LINE Cvadricele sunt reprezentate wireframe utiliznd primitivele pentru reprezentarea liniilor GLU__SILHOUETTE Cvadricele sunt reprezentate utiliznd primitivele pentru linii; sunt desenate doar muchiile exterioare. GLU POINT Cvadricele sunt reprezentate utiliznd ca primitiv punctul Funcii pentru specificarea tipului cvadricei void gluCylinder(GLUquadricObj *qobj, GLdouble baseRadius, GLdouble topRadius,GLdouble height, GLint slices, GLint stacks); - Funcia genereaz un cilindru avnd centrul bazei n originea sistemului de axe. Funcia poate fi utilizat i pentru generarea conurilor, prin specificarea uneia dintre cele dou raze ca fiind 0. - Slices reprezint numrul poligoanelor care se genereaz n jurul cilindrului. - stacks reprezint numrul poligoanelor generate n lungul cilindrului (figura 3.26). Aceast valoare va crete atunci cnd se dorete o iluminare mai bun.

Figura 3.26

76

Figura 3.27 void gluDisk(GLUquadricObj *qobj, GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops); - Discurile (figura 3.27) sunt forme plane care au forma unui CD (sau dischet). Funcia poate fi utilizat i pentru generarea cercurilor. - innerRadius reprezint raza interioar; - outerRadius reprezint raza exterioar. - slices reprezint numrul sectoarelor generate. - loops reprezint numrul cercurilor concentrice generate la reprezentarea discurilor. void gluPartialDisk(GLUquadricObj *qobj, GLdouble innerRadius, GLdouble outerRadius, Glint slices, GLint loops, GLdouble startAngle, GLdouble sweepAngle); - Funcia este utilizat pentru reprezentarea unui sector dintr-un disc. Pentru aceasta se specific valorile unghiurilor ntre care se ncadreaz sectorul. Funcia poate fi utilizat i pentru generarea unui sector dintr-un cerc. void gluSphere(GLUquadricObj *qobj, Gldouble radius, GLint slices, GLint stacks); - Funcia reprezint o sfer. - slices determin numrul longitudinilor generate, - stacks pe cel al latitudinilor generate Ia reprezentarea sferei. Exemplu: n exemplul urmtor se arat felul n care se pot utiliza funciile GLU pentru redarea cvadricelor. n figura 3.28 se pot vedea obiectele pe care le deseneaz programul urmtor.

Figura 3.28 /* cvadrice.c Programul arat modul de utilizare al cvadricelor din GLU pentru desenare de cilindri, conuri, sfere, disk-uri, cercuri, arce de cerc, sectoare de disk. */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void initlights(void); 77

void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); GLUquadricObj * quadObj ; //obiect de tip cvadric // setri pentru iluminarea suprafeei void initlights(void) { GLfloat ambient[] = { 1.0, 0.6, 0.0, 1.0 }; GLfloat position0[] = { -3.0, 0.0, 2.0, 0.0 }; GLfloat position1[] = { 1.0, 0.0, 1.0, 0.0 }; GLfloat mat_diffuse[] = { 1.0, 0.6, 0.0, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_POSITION, position0); glLightfv(GL_LIGHT1, GL_AMBIENT, ambient); glLightfv(GL_LIGHT1, GL_POSITION, position1); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); } void CALLBACK display(void) {//terge ecranul glClearColor(1.0, 1.0, 1.0, 1.0); glClear (GL_COLOR_BUFFER_BIT); //Stabilete atributele, comune pentru toate cvadricele. quadObj = gluNewQuadric () ; //genereaz cvadric gluQuadricDrawStyle (quadObj, GLU_FILL) ; //atribut de umplere gluQuadricNormals (quadObj ,GLU_SMOOTH) ; //iluminare GOURAUD //reprezint sfera glPushMatrix(); glTranslatef (-15.0, 0.0, 0.0); gluSphere(quadObj, 2.5, 20.0, 20); glPopMatrix(); //reprezint cilindru glPushMatrix () ; glRotatef(30, 1, 1, 0); glTranslatef (-11.0, 1.5, 0.0); gluCylinder(quadObj, 2.0, 2.0, 4.0, 20.0, 20); glPopMatrix(); //reprezint conul glPushMatrix(); glRotatef(30, 1, 1, 0); glTranslatef (-5.0, 0.8, 0.0); gluCylinder(quadObj, 2.0, 0.0, 5.0, 20.0, 20); glPopMatrix(); //reprezint disk-ul glPushMatrix(); glTranslatef (1.0, 0.0, 0.0); gluDisk (quadObj, 1.0, 2.5, 20, 20); 78

glPopMatrix(); //reprezint cercul glPushMatrix(); glTranslatef (7.0, 0.0, 0.0); gluDisk (quadObj, 0.0, 2.5, 20, 20); glPopMatrix(); //reprezint sectorul de disk glPushMatrix(); glTranslatef (11.0, 0.0, 0.0); gluPartialDisk (quadObj, 1.0, 2.5, 20, 20, 10.0, 90.0); glPopMatrix(); //reprezint sectorul de cerc glPushMatrix(); glTranslatef (15.0, 0.0, 0.0); gluPartialDisk (quadObj, 0.0, 2.5, 20, 20, 10.0, 90.0); glPopMatrix(); glFlush() ; } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-8.0, 8.0, -8.0*(GLfloat)h/(GLfloat)w, 8.0*(GLfloat)h/(GLfloat)w, -8.0, 8.0); else glOrtho(-8.0*(GLfloat)w/(GLfloat)h, 8.0*(GLfloat)w/(GLfloat)h, -8.0, 8.0, -8.0, 8.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (10, 10, 750, 300); auxInitWindow ("Cvadrice"); initlights(); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); }

3.4 Primitive raster

79

OpenGL nu este doar o interfa complet pentru aplicaiile de grafic vectorial 3D ci este, de asemenea, un foarte bun motor de procesare a imaginilor (utilizate n aplicaiile de grafic punctual sau raster). Primitivele conin explicit informaii de culoare pentru fiecare pixel pe care-1 conin. In Windows se utilizeaz denumirea de bitmap att pentru bitmap-urile monocrome ct i pentru cele color. n OpenGL, spre deosebire de Windows, se face distincie ntre bitmap-uri i pixelmap-uri. OpenGL lucreaz deci cu dou tipuri de primitive raster: - Bitmap-urile care utilizeaz un singur bit (0 sau 1) pentru fiecare pixel. Ele sunt utilizate, n principal, ca tablouri 2D de mti la nivel de bit pentru a determina care pixeli s fie actualizai. Culoarea curent, setat cu funcia glColor() este utilizat pentru a determina noua culoare a pixelilor corespunztori valorii 1 din bitmap, n timp ce pixelii corespunztori biilor 0 sunt transpareni. - Pixelmap-urile (imagini) sunt blocuri de pixeli (tablouri 2D) cu informaii complete de culoare pentru fiecare pixel. n ceea ce privete fiierele de imagini se subliniaz c OpenGL nu nelege formatele de imagini, cum ar fi JPEG, PNG, sau GIF-uri. Pentru ca OpenGL s poat utiliza informaiile coninute n aceste formate de fiiere, fiierul trebuie s fie citit i decodificat pentru a obine informaia de culoare, i plecnd de aici OpenGL poate rasteriza valorile culorilor. Fluxul de procesare al pixelilor
Date vrfuri Date pixeli Liste de display Operaii cu pixeli Memorare textur Bufferul de cadru

Evaluator polinomial

Operaii pe vrfuri

Rasterizare

Operaii pe fragment

Figura 3.29 n figura 3.29 se d procesarea n cascad a primitivelor geometrice i de asemenea a pixelilor. Pixelii sunt citii din memoria principal, sunt procesai pentru a se obine formatul intern pe care-1 utilizeaz OpenGL, care poate include modificri de culoare sau nlocuiri de octei. Dup aceasta, este procesat fiecare pixel din imagine prin operaiile pe fragment din ultima seciune a fluxului de procesare, i n final rasterizate n buffer-ul de cadru. 80

Suplimentar redrii n buffer-ul de cadru, pixelii pot fi copiai din buffer-ul de cadru napoi n memoria gazd, sau transferai n memoria de mapare a texturii. Pentru performane mai bune, reprezentarea intern a tabloului de pixeli va fi n concordan cu hardware-ul. Spre exemplu, pentru un buffer de cadru de 24 bii, RGB 8-8-8 va fi probabil o potrivire bun, dar RGB 10-10-10 ar fi o potrivire rea. Atenie: Pentru valori neimplicite, memorarea i transferul pixelilor se face foarte ncet. n figura 3.30, pe lng fluxul de procesarea pixelilor sunt specificate i funciile OpenGL utilizate n fiecare etap.
glBitmap() CPU Modul de pstrare al pixelilor glDrawPixels()
Operaii de transfer pixel Pixel Map

Rasterizare Pixel Zoom

Operaii pe fragment

Buffer de cadru

Memorie textur

glCopyText*Image()

glReadPixel(), glCopyPixel()

Figura 3.30 Bitmap-urile i pixmap-urile sunt cele dou primitive care nu sunt afectate de operaiile geometrice care au loc n fluxul operaiilor anterior rasterizrii.

3.4.1 Reprezentarea imaginilor bitmap


Un bitmap specific un dreptunghi complectat cu 0 i 1, i este mult utilizat pentru descrierea caracterelor care pot fi plasate la o locaie proiectat 3D (prin poziia raster curent). Fiecare 1 din bitmap produce un fragment ale crui valori asociate sunt cele ale poziiei raster curente, n timp ce pentru fiecare 0 nu se produce nici un fragment. Comanda glBitmap() specific de asemenea offset-urile care controleaz cum este plasat bitmap-ul n funcie de poziia raster curent i cum poziia raster curent este modificat dup ce se deseneaz bitmap-ul (astfel determinnd poziiile relative ale bitmap-uilor succesive).
Poziionarea primitivelor raster

glRasterPos3f( x, y, z) poziia raster (figura 3.31) este afectat de transformri ca i poziia geometric; primitiva bitmap nu se afieaz dac poziia raster este n exteriorul viewportului. Imaginile sunt poziionate prin specificarea poziiei raster, care mapeaz colul stnga jos al unei primitive imagine la un punct din spaiu. Poziiile raster sunt transformate i decupate la fel ca vrfurile. Dac o poziie raster se pierde prin decuparea fa de viewport, nu mai este rasterizat nici un fragment din primitiva bitmap.
-

81

Poziie raster

Figura 3.31

Poziia raster

Redarea Bitmap-urilor

glBitmap (width, height, xorig, zorig, xmove, zmove, bitmap) ; funcia red bitmap-ul n culoarea curent; dup redarea primitivei, poziia raster curent este actualizat. Bitmap-urile sunt utilizate ca o masc pentru a determina care pixeli s fie actualizai. Un bitmap este specificat ca un tablou mpachetat de bii ntr-un tablou de tip byte. Pentru fiecare valoare de 1 dintr-un bitmap, este generat un fragment n culoarea curent i apoi este procesat de operaiile pe fragment. Bitmap-urile pot avea propria lor origine, care asigur o poziie relativ fa de poziia raster curent. Suplimentar, dup ce se red bitmap-ul, poziia raster este actualizat n mod automat prin offset-ul furnizat n (xmove, ymove). Dac originea bitmap-ului este (0,0) atunci colul stnga jos al bitmap-ului va fi plasat n poziia raster curent. Dac originea bitmap-ului este diferit de (0,0) atunci poziia raster curent va fi utilizat pentru plasarea originii bitmap-ului. Dac poziia raster curent este n exteriorul viewport-ului, chiar dac pentru aceast poziie s-ar putea reprezenta parial bitmap-ul, totui el nu este redat deloc. Deci, din acest punct de vedere, primitivele raster nu se comport la fel cu primitivele vectoriale, care sunt decupate fa de viewport.
width

height

yorig xorig

Figura 3.32 82

Coordonatele originii bitmap-ului se stabilesc relativ la colul stnga-jos al bitmap-ului. Pentru figura 3.32 coordonatele originii sunt (xorig=2, yorig=2). Dimensiunea bitmap-ului este height=32, width=32. Bitmap-urile sunt utile n mod particular pentru redarea font-urilor de tip bitmap, despre care se va discuta n continuare. n acest caz facilitatea de actualizare a poziiei raster curente este utilizat din plin. Exemplul 1 Exemplul urmtor red bitmap-ul din figura 3.33, succesiv n fereastra aplicaiei. Dimensiunea ferestrei iniial este de 200X200 pixeli. Pentru viewport-ul aplicaiei, de 10X10 uniti, va rezulta c fiecare unitate are 20 de pixeli. Bitmap-ul fiind de 32X32 pixeli, vom stabili prin program o repetare a bitmap-ului din 2 n 2 uniti, adic un bitmap la 40 de pixeli. Distana dintre dou bitmap-uri succesive va fi de 8 pixeli. n figura 3.34 se poate vedea cum va arta fereastra aplicaiei.

Figura 3.33 Mai trebuie subliniat felul n care se specific un bitmap. Bitul 7 din primul octet al tabloului care descrie bitmap-ul corespunde pixelului stnga jos al bitmap-ului. Deci descrierea bitmap-ului ncepe cu primul rnd din partea de jos a bitmap-ului.

Figura 3.34 n continuare, se d codul aplicaiei. /*utilizarea bitmap-urilor n OpenGL*/ #include "glos.h" #include <GL/gl.h> 83

#include <GL/glu.h> #include <GL/glaux.h> #include <math.h> void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); void CALLBACK display(void) { int i, j; GLubyte model[] = { 0x03, 0xc0, 0, 0, 0x0f, 0xf0, 0, 0, 0x1e, 0x78, 0, 0, 0x39, 0x9c, 0, 0, 0x77, 0xee, 0, 0, 0x6f, 0xf6, 0, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, 0x73, 0xce, 0, 0, 0x73, 0xce, 0, 0, 0x3f, 0xfc, 0, 0, 0x1f, 0xf8, 0, 0, 0x0f, 0xf0, 0, 0, 0x03, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); for(i=-5; i<5; i+=2) for(j=-5; j<5; j+=2) 84

{ glRasterPos2i(i,j); glBitmap(32, 32, 0.0, 0.0, 0.0, 0.0, model); } glFlush(); } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); else glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 200, 200); auxInitWindow ("O fereastr cu bitmap-uri"); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); }

3.4.2 Reprezentarea fonturilor prin bitmap-uri


n OpenGL, pentru redarea caracterelor, se pot utiliza fonturi vectoriale sau fonturi bitmap. Fonturile vectoriale sunt construite din segmente de dreapt i se preteaz pentru dispozitivele vectoriale (plotere spre exemplu). Fonturile bitmap construiesc fiecare caracter ca un bitmap. Pentru a se facilita utilizarea fonturilor, n OpenGL se utilizeaz listele de display. Fiecare list de display conine doar un apel glBitmap(), pentru redarea caracterului corespunztor. Listelor de display le sunt asociate n mod unic, identificatori (numere) care pentru caracterele fontului pot fi alese ca valori succesive. n felul acesta pentru redarea unui text trebuie apelate listele de display corespunztoare caracterelor din textul respectiv. Pentru construirea bitmapurilor corespunztoare fiecrui caracter dintr-un font exist dou posibiliti: Se declar tabloul de tip unsigned byte (tipul GLubyte n OpenGL) care conine caracterele respective. 85

Se construiesc bitmap-urile corespunztoare fiecrui caracter pe baza fontului curent din sistemul de ferestre cu care se lucreaz. Sistemele de ferestre au pentru aceasta funcii proprii. Windows-ul, spre exemplu, dispune de funcia wglUseFontBitmaps(). i n acest caz, se utilizeaz pentru manevrarea fontului tot listele de display. Fiecare caracter este memorat ntr-o list de display care este parte a unui set creat la procesarea fontului. n continuare, se vor exemplifica ambele modaliti.

Construirea unui caracter i afiarea sa

Vom ncepe cu exemplificarea modului n care primitivele bitmap sunt utilizate n OpenGL pentru construirea i afiarea unui caracter. n acest caz nu apar modificri fa de afiarea obinuit a unui bitmap. Se construiete tabloul care conine caracterul. Se ine seama de faptul c limea bitmap-ului trebuie s fie un numr par de octei. Pentru caracterul "E" afiat de exemplul nostru (figura 3.35), utilizm un bitmap de 10X12. Avem nevoie de un tablou de octei, cte doi octei pentru fiecare linie a bitmapului. Din acest tablou, pentru construirea bitmap-ului vor fi utilizai doar primii 10 bii din fiecare rnd. Originea bitmap-ului se va considera colul stnga jos al bitmap-ului. Ce mai trebuie remarcat, este faptul c funcia glRasterPos2i () utilizeaz coordonate logice iar offset-ul pentru actualizarea poziiei curente, din funcia glBitmap() este dat n pixeli. n cazul acestui exemplu, fereastra are 200X200 pixeli (uniti fizice). Funcia myReshape () stabilete cte 10 uniti logice pe fiecare ax, n intervalul [-5, 5]. Deci fiecrei uniti logice i corespund 20 uniti fizice (pixeli). Pentru a deplasa cu o unitate fiecare caracter, n funcia glBitmap, actualizarea poziiei curente s-a fcut cu 20 pixeli pe axa x i cu 0 pixeli pe axa y.

Figura 3.35 Exemplu: /* Programul este un exemplu de utilizare a primitivei bitmap * in OpenGL, pentru desenarea fonturilor. */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> 86

void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); // tabloul care conine litera E, 2 octei X 12 rnduri GLubyte litera_E[24] = { 0xff, 0xc0, 0xff, 0xc0, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xff, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xff, 0xc0, 0xff, 0xc0}; void CALLBACK display(void) { glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glClearColor (1.0, 1.0, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f (0.0, 0.0, 0.0); glRasterPos2i (-2.0, 0.0); //poziia curent pentru primul bitmap // dat n uniti logice (sunt 10 uniti pe axa x n intervalul(-5, 5)) glBitmap (10, 12, 0.0, 0.0, 20.0, 0.0, litera_E); // deplasarea poziiei curente este dat n pixeli - 20 de pixeli pe axa x glBitmap (10, 12, 0.0, 0.0, 20.0, 0.0, litera_E); glBitmap (10, 12, 0.0, 0.0, 20.0, 0.0, litera_E); glBitmap (10, 12, 0.0, 0.0, 20.0, 0.0, litera_E); glFlush(); } // proiecie ortogonal //se mapeaz 10 uniti pe fiecare ax, o unitate are 20 pixeli void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); else glOrtho (-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 200, 200); auxInitWindow ("Bitmap_E"); auxReshapeFunc (myReshape); 87

auxMainLoop(display); return(0); }

Figura 3.36 n figura 3.36 este dat fereastra afiat de aceast aplicaie. Funcii pentru manevrarea listelor de display utilizate pentru fonturile bitmap. Pentru utilizarea fonturilor bitmap n OpenGL, anumite funcii pentru listele de display au o relevan deosebit. Trebuie subliniat c aceste funcii se utilizeaz la fel i pentru fonturile vectoriale. Acestea sunt: - void glNewList( GLuint list, GLenum mode ); - void glEndList(void); Funciile glNewListO i glEndListO creeaz lista de display cu identificatorul list. Parametrul mode stabilete modul de compilare al listei de display. - GLuint glGenLists( GLsizei range ); Funcia creeaz un set de liste de display, cu identificatori succesivi i care sunt goale (nu conin nici o comand). Funcia returneaz identificatorul primei liste de display n, iar celelalte liste vor avea identificatorii n+J, n+2,..., n+range-1. Parametrul range este numrul listelor de display create. - void glListBase( GLuint base ); Funcia glListBase() seteaz baza listelor de display, pentru funcia glCallLists. - void glCallLists( GLsizei n, GLenum type, const GLvoid *lists ); Funcia execut o list de liste de display. Parametrul n este numrul listelor de display care vor fi executate. Parametrul type este tipul elementelor din lists. Parametrul lists este adresa unui tablou cu numele ofseturilor n listele de display. - void glCallList( GLuint list ); Funcia execut lista de display al crui identificator (ntreg) este dat ca parametru. - void glDeleteLists( GLuint list, GLsizei range ); Funcia terge un grup de liste de display ("range" liste de display) avnd identificatori succesivi, ncepnd cu identificatorul list. 88

Un font, aa cum probabil se tie, este un ir de caractere, fiecare caracter avnd asociat un numr de identificare, de obicei acesta fiind codul ASCII al caracterului. Fiecare caracter are i o anumit form grafic, aceasta fiind coninut n bitmap-ul asociat caracterului respectiv. Spre exemplu, caracterul 'A' are codul ASCII 65 (41H), caracterul 'B' are codul ASCII 66 (42H), caracterul 'C are codul ASCII 67 (43H), .a.m.d. La modul cel mai simplu, listele de display asociate cu afiarea caracterelor pot avea ca identificatori chiar codurile ASCII ale caracterelor. n acest caz, pentru afiarea irului "ABC" se vor executa listele de display avnd identificatorii 65, 66, 67. Pentru aceasta se poate apela funcia glCallLists(). Parametrul n va conine lungimea irului de caractere, 3 n cazul nostru, iar tabloul lists va conine codurile ASCII ale caracterelor. - glCallLists(3, GL_UNSIGNED_BYTE, "ABC"); Avnd acum n vedere faptul c exist mai multe tipuri de fonturi, avnd corpuri de caractere diferite, utilizarea codurilor ASCII nu mai pare a fi o soluie convenabil. Se poate ns proceda n felul urmtor: pentru fiecare font se adaug un offset, fa de care se stabilesc identificatorii fiecrei liste de display. Deoarece numrul maxim al caracterelor dintr-un font nu depete 255, un offset de 1000, spre exemplu, este o soluie convenabil. In felul acesta un font va utiliza liste de display cu identificatorii cuprini ntre 1000 i 1255, urmtorul font va utiliza liste cu identificatorii cuprini ntre 2000 i 2255, .a.m.d. Pentru stabilirea offset-ului se poate utiliza comanda glListBase(). Deoarece este necesar ca listele de display corespunztoare caracterelor dintr-un font s aib identificatori succesivi se va utiliza pentru aceasta comanda glGenLists(). Spre exemplu, dac se dorete un font cu toate cele 255 de caractere apelul va fi: - glGenLists(255); Funcia va stabili identificatori unici pentru fiecare list de display. Dac funcia nu gsete un bloc de 255 de identificatori succesivi, va returna 0. Pentru a terge o parte din listele de display se poate utiliza funcia glDeleteLists(). Cum se utilizeaz aceste funcii pentru fonturile bitmap, se va vedea n cele dou exemple care vor urma.
Construirea intern a unui font

nainte de toate, trebuie spus c exemplul urmtor se bazeaz pe exemplul din fiierul font.c, care face parte din exemplele pentru utilizarea bibliotecii OpenGL, existente n nucleul de instalare pentru Visual C 6.0, preluate din OpenGL Programming Guide. n acest exemplu, tabloul rasters[] conine toate cele 95 de caractere ASCII tipribile (coduri ASCII cuprinse ntre 32 i 127), inclusiv spaiul. Fiecare caracter este construit n tabloul rasters, aa cum s-a construit i caracterul E din exemplul anterior. Listele de display sunt construite n funcia makeRasterFont(). Fiecare list de display are asociat ca identificator codul ASCII al caracterului la care se adaug un offset obinut de funcia glGenLists() (apelat n funcia makeRasterFont()), i conine ca i comand funcia glBitmap(). Dup afiarea fiecrui caracter, poziia curent este actualizat prin adugarea unui offset pe axa x, de 10 pixeli. n figura 3.7 se poate vedea fereastra aplicaiei. 89

Figura 3.37 Exemplu: /* Aplicaia afieaz texte n OpenGL, utiliznd un font bitmap. Pentru construirea caracterelor fontului utilizeaz glBitmap() i alte funcii pentru primitive raster. Aplicaia utilizeaz de asemenea listele de display. */ #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h> void makeRasterFont(void); void printString(char *s); void CALLBACK myReshape(GLsizei w, GLsizei h); void CALLBACK display(void); GLubyte rasters[][13] = { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //caracterul spaiu {0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, //caracterul ! {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36}, {0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00}, {0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18}, {0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70}, 90

{0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e}, {0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c}, {0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30}, {0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00}, {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03}, {0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c}, {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18}, {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e}, {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e}, {0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c}, {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff}, {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e}, {0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06}, {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60}, 91

{0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e}, {0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18}, {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc}, {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff}, {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff}, {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e}, {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e}, {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06}, {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3}, {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3}, {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3}, {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e}, {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c}, {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe}, {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e}, {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff}, {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3}, {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3}, {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}, {0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c}, {0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60}, {0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c}, 92

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18}, {0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70}, {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}, {0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03}, {0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e}, {0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0}, {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, {0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00}, {0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0}, {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78}, {0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00}, {0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00}, {0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00}, {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, 93

{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, {0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f}, {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, {0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00} }; GLuint fontOffset; void makeRasterFont(void) { GLuint i; glPixelStorei(GL_UNPACK_ALIGNMENT, 1); fontOffset = glGenLists (128); for (i = 32; i < 127; i++) { glNewList(i+fontOffset, GL_COMPILE); glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, rasters[i-32]); glEndList(); } } void printString(char *s) { glPushAttrib (GL_LIST_BIT); glListBase(fontOffset); glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); glPopAttrib (); } void CALLBACK display(void) { int i, j; char teststring[33]; glClearColor(1.0, 1.0, 1.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 0.0); glShadeModel (GL_FLAT); makeRasterFont(); 94

for (i = 32; i < 127; i += 32) { glRasterPos2i(20, 200 - 18*i/32); for (j = 0; j < 32; j++) teststring[j] = (char) (i+j); teststring[32] = 0; printString(teststring); } glRasterPos2i(20, 100); printString("Aceasta este o aplicate pentru"); glRasterPos2i(20, 82); printString("ilustrarea afirii irurilor."); glRasterPos2i(20, 64); printString("de caractere dintr-un font bitmap."); glRasterPos2i(20, 46); printString("Sunt utilizate listele de display."); glFlush (); } void CALLBACK myReshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho (0.0, w, 0.0, h, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char** argv) { auxInitDisplayMode (AUX_SINGLE | AUX_RGB); auxInitPosition (0, 0, 400, 200); auxInitWindow ("Font bitmap"); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); }
Crearea textelor n OpenGL cu fonturi Windows

Aa dup cum s-a artat, aplicaiile Windows beneficiaz de funcii suplimentare (aparinnd sistemului) pentru utilizarea fonturilor sistemului. Funcia wglUseFontBitmaps() creeaz un set de liste de display pentru a fi utilizate ntr-un context de redare OpenGL. Fontul obinut se bazeaz pe fontul curent selectat n contextul de dispozitiv. BOOL wglUseFontBitmaps ( HDC hdc, 95

//contextul de dispozitiv al crui font se va utiliza DWORD first, // caracterul corespunztor primei liste de display DWORD count, // numrul caracterelor ce vor fi plasate n listele de display DWORD 1istBase // specific identificatorul listei de display a // primului caracter din font ); Exemplu: n exemplul urmtor se arat cum se pot afia caractere n OpenGL utiliznd un font bitmap construit pe baza fontului curent din contextul de dispozitiv curent. Pentru aceasta s-a utilizat funcia wglUseFontBitmaps(), care construiete cte o list de display pentru fiecare caracter al fontului. Fiecare list de display nu conine altceva dect o funcie glBitmap care construiete bitmap-ul corespunztor caracterului respectiv. Spre deosebire de aplicaia anterioar, funcia makeRasterFont este nlocuit de funcia CreazaFontBitmap(), cu acelai rol. Funcia printstring() este nlocuit de funcia AfiseazaSirBitmap(), cu acelai rol. Rezultatul rulrii programului este afiat n figura 3-38. Codul aplicaiei este dat n continuare.

Figura 3.38 /* Aplicaia arat felul n care sunt redate fonturile * n aplicaii OpenGL care utilizeaz ferestrele Windows */ #include <windows.h> #include "glos.h" #include <GL/gl.h> #include <GL/glu.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; void CALLBACK myReshape(GLsizei w, GLsizei h); void SetDCPixelFormat(HDC hdc); 96

GLuint CreazaFontBitmap(HGLRC hdc, HFONT font, char *typface, int height, int weight, DWORD italic); void StergeFontBitmap(GLuint font); void AfiseazaSirBitmap(GLuint font, char *s); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static char szAppName[] = "Fonturi" ; HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (wndclass) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; hwnd = CreateWindow (szAppName, "Fonturi bitmap", WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 50, 50, 300, 300, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { static HDC hDC ; static HGLRC hRC; static GLuint base; HFONT font; switch (iMsg) 97

{ case WM_SIZE: myReshape(LOWORD(lParam), HIWORD(lParam)); break; case WM_CREATE: hDC=GetDC(hwnd); SetDCPixelFormat(hDC); hRC=wglCreateContext(hDC); wglMakeCurrent(hDC,hRC); break; case WM_PAINT: { glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); base=CreazaFontBitmap(hDC, font, "Ariel", 0, 0, FALSE); glRasterPos2i(-4, 0); AfiseazaSirBitmap(base, "123456789!%&'()*+,-"); glRasterPos2i(-4,-1); AfiseazaSirBitmap(base, "OpenGl"); glRasterPos2i(-4,-2); AfiseazaSirBitmap(base, "Prelucrare grafica- Tehnologia Informatiei"); glFlush(); ValidateRect(hwnd, NULL); } break; case WM_DESTROY: StergeFontBitmap(base); DeleteObject(font); wglMakeCurrent(hDC, NULL); wglDeleteContext(hRC); PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } void CALLBACK myReshape(GLsizei w, GLsizei h) { if (!h) return; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho (-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w, 5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0); else glOrtho (-5.0*(GLfloat)w/(GLfloat)h, 98

5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0); glMatrixMode(GL_MODELVIEW); } void SetDCPixelFormat(HDC hdc) { int nPixelFormat; static PIXELFORMATDESCRIPTOR pfd={ sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW| PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, 24, 0,0,0,0,0,0, 0,0, 0,0,0,0, 32, 0, 0, PFD_MAIN_PLANE, 0, 0,0,0}; nPixelFormat=ChoosePixelFormat(hdc, &pfd); SetPixelFormat(hdc, nPixelFormat, &pfd); } GLuint CreazaFontBitmap(HDC hdc, HFONT font, char *typface, int height, int weight, DWORD italic) { GLuint base; if((base=glGenLists(255))==0) return(0); if(stricmp(typface, "symbol")==0) font=CreateFont(height, 0, 0, 0, weight, italic, FALSE, FALSE,SYMBOL_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, DEFAULT_PITCH, typface); else font=CreateFont(height, 0, 0, 0, weight, italic, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, DEFAULT_PITCH, typface); SelectObject(hdc, font); wglUseFontBitmaps(hdc, 0, 255, base); return(base); } void StergeFontBitmap(GLuint base) { 99

if (base==0) return; glDeleteLists(base, 255); } void AfiseazaSirBitmap(GLuint base, char *s) { if(base==0) return; if(s==NULL) return; glPushAttrib(GL_LIST_BIT); glListBase(base); glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s); glPopAttrib(); }

3.4.3 Redarea pixmap-urilor


Imaginile care folosesc mai mult de dou culori sunt numite pixmap-uri (prescurtarea de la "pixel map" din limba englez). Pixmap-urile sunt utilizate n principal, n OpenGL, ca imagini de fundal sau ca texturi. Un pixmap este un grup de valori destinat memoriei video. Un pixmap (dreptunghi de pixeli) este similar cu un bitmap, cu excepia faptului c, de obicei, valorile reprezint culori, dei este alocat spaiu i pentru alte tipuri de date cum ar fi valori ale adncimii. n OpenGL, pixmapurile sunt, n general, fie imagini n index de culoare (8 bii/pixel) fie imagini RGB (24 bii/pixel).
Funcia de redare a pixmap-urilor

Pentru redarea pixmap-urilor, OpenGL dispune de o singur funcie, i anume glDrawPixels(). Spre deosebire de funcia pentru desenarea bitmap-urilor glBitmap(), aceast funcie nu permite specificarea unei originii a pixmap-ului i nici a unui offset pentru poziia raster curent. Utiliznd glDrawPixels valorile memorate ca un bloc de date n memoria gazd sunt transmise spre memoria video. void glDrawPixels (GLsizei width, //dimensiunea dreptunghiului de pixeli GLsizei height, //care se va nscrie n memoria video GLenum format, // formatul datelor pentru un pixel GLenum type, // tipul datelor pentru pixeli const GLvoid *pixels) ; //un pointer spre tabloul de pixeli Funcia glDrawPixels red pixelii avnd colul stnga jos al imaginii n poziia raster curent. Un bloc de pixeli din memoria gazd CPU este transmis spre OpenGL cu un format i un tip de date specificat. Pentru fiecare pixel din imagine, se genereaz un 100

fragment utiliznd culoarea restabilit din imagine, i n continuare este procesat. Odat obinute, valorile rezultate produc un dreptunghi de fragmente. Localizarea acestui dreptunghi este controlat de poziia raster curent, care este tratat ca un punct (incluznd culoarea i coordonatele texturii), cu excepia faptului c este setat cu o comand separat (glRasterPos) care nu apare ntre glBegin() i glEnd(). Dimensiunea dreptunghiului este determinat de limea i nlimea specificat precum i de setarea parametrilor de zoom ai dreptunghiului de pixeli (setai cu glPixelZoom). Exist numeroase formate i tipuri de date pentru specificarea depozitrii n memorie a pixmap-urilor. Cele mai bune performane se obin prin utilizarea formatului i a tipului care se potrivete hardware-ului. OpenGL permite formate diferite pentru imagini incluznd: - Imagini RGB sau RGBA coninnd un triplet RGB pentru fiecare pixel. Parametrul format este GL_RGB sau GL_RGBA, i specific valorile exacte pentru rou, verde i albastru pentru fiecare pixel din imagine. - Imagini color. Parametrul format este GL_COLOR_INDEX i arat c fiecare valoare din pixmap este un index n paleta de culori curent a Windows-ului. - Imagini intensitate care conin doar intensitatea pentru fiecare pixel. Aceste imagini sunt convertite intern n imagini RGB n tonuri de gri. Parametrul format este GL_LUMINANCE sau GL_LUMINANCE_ALPHA. In acest format, fiecare valoare este mapat la o valoare de intensitate, valoarea maxim corespunznd albului iar valoarea minim corespunznd negrului, iar valorile intermediare diferitelor tonuri de gri. - Imagini adncime (format este GL_DEPTH_COMPONENT) care conin valoarea adncimii (coordonata z) pentru fiecare pixel, valoare nscris i n buffer-ul de adncime, corespunztor buffer-ului de cadru care conine culoarea corespunztoare fiecrui pixel. Acesta este util n ncrcarea buffer-ului de adncime cu valori i apoi redarea imaginilor color corespunztoare cu activarea testului de adncime. - Imagini stencil (format este GL_STENCIL_INDEX) care copiaz mti ablon n buffer-ul stencil. Aceasta permite o modalitate uoar pentru a ncrca o masc per pixel complicat. Parametrul type descrie datele pentru tabloul pixels. Acestea ar putea fi valori ca: GL_FLOAT, GL_INT, GL_BYTE (valori cu semn ntre -128 i 127), GL_BITMAP (dou valori 0 i 1) GL_UNSIGNED_BYTE (valori fr semn ntre 0 i 255) sau pixeli cu toate componentele de culoare mpachetate ntr-un tip ca GL_UNSIGNED_SHORT_5_6_5. Parametrul pixels indic adresa de memorie a datelor.
Citirea pixelilor

Aa cum se pot transmite pixeli spre framebuffer (buffer-ul de cadru), se pot i citi valorile pixelilor napoi din framebuffer n memoria gazd pentru realizarea memorrii sau procesrii imaginilor. O aplicaie evident a acestei funcii este salvarea imaginilor create n fiiere. O alt aplicaie ar putea fi realizarea unor efecte speciale cu maparea texturilor. Funcia care realizeaz citirea pixelilor de pe ecran este glReadPixels(). void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei 101

height, GLenum format, GLenum type, GLvoid *pixels); Funcia citete din framebuffer un dreptunghi de pixeli al crui col stnga-jos are poziia specificat prin (x, y). Dimensiunea dreptunghiului este dat de parametrii width i height. Pixelii se convertesc n mod automat din formatul framebuffer n formatul i tipul cerut i sunt plasai n memoria intern la adresa pixels. Pixelii citii din framebuffer sunt procesai prin modurile de transfer i depozitare.
Copierea pixelilor n buffer-ul de cadru

Suplimentar, pixelii pot fi copiai dintr-o locaie n alta a buffer-ului de cadru utiliznd funcia glCopyPixels(). De o asemenea funcie este nevoie, spre exemplu, atunci cnd sunt mrite anumite poriuni din imagine. Pixelii sunt procesai de modurile de transfer i depozitare nainte de a fi returnai n buffer-ul de cadru. void glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); Parametrii (x, y) reprezint poziia colului stnga jos a dreptunghiului de pixeli care se copiaz. Dimensiunile acestui dreptunghi sunt date de parametrii width i height. Datele sunt copiate ntr-o nou poziie din buffer-ul de cadru, care este poziia raster curent. Parametrul type este fie GL_COLOR, GL_STENCIL sau GLJDEPTH i specific ce valori se copiaz. Spre exemplu dac type este GL_COLOR se vor copia valori RGB sau indeci de culoare.
Scalarea pixmap-urilor

In afara ajustrii culorilor unei imagini, folosind funciile de mapare a culorilor, un alt atribut care poate fi modificat este dimensiunea unei imagini. Pentru aceasta se utilizeaz funcia glPixelZoom(). n mod normal fiecare pixel al imaginii este redat pe un pixel al dispozitivului de ieire. Funcia accept doi parametrii n virgul mobil, care specific factorii de scalare ai imaginii pe axele x i y. void glPixelZoom(Glfloat zoomx, Glfloat zoomy); Pentru valori egale ale factorilor de scalare imaginea este scalat pstrnd proporiile pe cele dou axe. Valori supraunitare ale factorilor de scalare conduc la o mrire a imaginii iar valori subunitare conduc la o micorare a imaginii. Dac se utilizeaz valori negative se va realiza n plus i o oglindire a imaginii dup axa respectiv n jurul poziiei raster curente. Exemplu 1: glPixelZoomd(1.0, 1.0); //nu scaleaz imaginea glPixelZoom( -l .0, 1.0); //oglindete imaginea pe orizontal glPixelZoom (1.0, -2.0); //oglindete imaginea pe vertical, i dubleaz //dimensiunea pe vertical glPixelZoom(0 .33, 0.33); //red imaginea la 1/3 din dimensiune Exemplu 2: n exemplul urmtor o imagine de 16 X 16 pixeli va fi copiat n colul stnga jos al ferestrei i scalat la 32 x 32 pixeli. 102

int pozx, pozy; glPixelZoom(2.0, 2.0); glRasterPos2i(0, 0); glCopyPixels(pozx-8, pozy-8, 16, 16, GL_COLOR);
Remaparea culorilor

Atunci cnd o imagine este transferat din memorie n buffer-ul de cadru sau invers din buffer-ul de cadru n memorie, OpenGL poate realiza unele operaii asupra ei. Spre exemplu, domeniile componentelor de culoare pot fi alterate. n mod obinuit, componenta rou este cuprins ntre 0.0 i 1.0, dar este posibil s dorii memorarea ei n alte domenii, sau este posibil ca datele utilizate de la diferite sisteme grafice s utilizeze alte domenii de valori. Se pot crea mapri pentru a asigura conversii arbitrare ale indecilor de culoare sau ale componentelor de culoare n timpul transferrii pixelilor. Conversiile asemntoare celor asigurate n timpul transferrii pixelilor la i de la buffer-ul de cadru sunt numite moduri de transfer a pixelilor (pixel-transfer modes). Aceste conversii sunt controlate de funciile glPixelTransfer#() i glPixelMap#(). Alte moduri de conversie ce pot fi controlate includ buffer-ul de cadru din care se citesc pixelii, i orice mrire ce se face asupra pixelilor la scrierea lor n buffer-ul de cadru. Buffer-ele de culoare, adncime i stencil dei au multe similitudini, nu se comport identic i cteva moduri au cazuri speciale pentru buffer-e speciale. Dac se utilizeaz formatul GL_COLOR_INDEX, se pot remapa culorile din pixmap sau bitmap utiliznd funciile glPixelMap() sau glPixelTransfer(). Funcia glPixelTransfer() permite specificarea scalarii i a offset-urilor pentru valori RGB sau color index. Spre exemplu codul urmtor arat modul de cretere a luminozitii unei imagini cu 10%. glPixelTransferf(GL_RED_SCALE, 1.1); glPixelTransferf(GL_GREEN_SCALE, 1.1); glPixelTransferf(GL_BLUE_SCALE, 1.1); n mod similar, pentru a deplasa indecii de culoare ai unui bitmap la intrri definite special pentru bitmap-ul respectiv, se folosete apelul urmtor: glPixelTransferi(GL_INDEX_OFFSET, bitmap_entry); Exemplu: Exemplul urmtor reia aplicaia de la redarea bitmap-urilor. Aceeai imagine este redat acum ca pixmap, utiliznd funcia glDrawPixels(). n continuare sunt date doar funciile display() i main(), care au suferit modificri fa de aplicaia anterioar. Cele dou culori ale bitmap-ului sunt remapate la diferii indeci. Pentru valori diferite ale offset-ului, cele dou culori cu care sunt redate bitmap-ul se vor modifica. void CALLBACK display(void) { int i, j; //urmeaz tabloul cu bitmap-ul 32X32 bii void CALLBACK display(void) { int i, j; GLubyte model[] = { 103

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x03, 0xc0, 0, 0, 0x0f, 0xf0, 0, 0, 0x1e, 0x78, 0, 0, 0x39, 0x9c, 0, 0, 0x77, 0xee, 0, 0, 0x6f, 0xf6, 0, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0, 0x73, 0xce, 0, 0, 0x73, 0xce, 0, 0, 0x3f, 0xfc, 0, 0, 0x1f, 0xf8, 0, 0, 0x0f, 0xf0, 0, 0, 0x03, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; glClearIndex(10.0); glClear(GL_COLOR_BUFFER_BIT); glPixelTransferi(GL_UNPACK_ALIGNMENT, 10); glPixelTransferi(GL_INDEX_OFFSET, 16); for(i=-5; i<5; i+=2) for(j=-5; j<5; j+=2) { glRasterPos2i(j,i); glDrawPixels(32, 32, GL_COLOR_INDEX, model); } glFlush(); } int main(int argc, char** argv) 104

GL_BITMAP,

{ auxInitDisplayMode (AUX_SINGLE | AUX_INDEX); auxInitPosition (0, 0, 200, 200); auxInitWindow ("O fereastr cu bitmap-uri"); auxReshapeFunc (myReshape); auxMainLoop(display); return(0); } Observaii: Pentru valorile din aplicaie ale culorilor, fundalul este gri foarte deschis, bitmap-ul este redat n combinaia de culori galben i albastru (figura 3.39). Trebuie remarcat c funcia auxInitDisplayMode() s-a modificat pentru a lucra cu modelul de culoare index (AUX_INDEX). De asemenea pentru stabilirea culorii background-ului sa folosit funcia glClearIndex(). Bitmap-ul s-a redat cu funcia glDrawPixels() dar utiliznd tipul de date GL_BITMAP, i formatul GL_COLOR_INDEX.

Figura 3.39
Tabele de mapare a culorilor

Uneori este necesar s se aplice corecii ale culorilor care sunt mai complicate dect simpla scalare liniar sau offset-ul. O aplicaie este corecia gamma, n care intensitatea fiecrei valori de culoare este ajustat pentru a compensa iregularitile de pe monitor sau imprimant. Funcia glPixelMap() permite realizarea acestui lucru. void glPixelMap (GL_enum map, GL_int mapsize, const TYPE *values) / Funcia realizeaz o mapare al crui nume simbolic este indicat de map. Valoarea simbolic map poate lua 10 valori: GL_PIXEL_MAP_I_TO_I - se realizeaz o mapare a indecilor de culoare la indeci de culoare; GL_PIXEL__MAP_S_TO_S - se realizeaz o mapare a indecilor ablon (stencil) la indeci stencil; GL_PIXEL_MAP_I_TO_R - se realizeaz o mapare a indecilor de culoare la componente rou; GL_PIXEL_MAP_I_TO_G - se realizeaz o mapare a indecilor de culoare la componente verde; GL_PIXEL_MAP_I_TO_B - se realizeaz o mapare a indecilor de culoare la componente albastru; 105

GL_PIXEL_MAP_I_TO_A - se realizeaz o mapare a indecilor de culoare la componente alfa; GL_PIXEL_MAP_R_TO_R - se realizeaz o mapare a componentelor rou la componente rou; GL_PIXEL_MAP_G_TO_G - se realizeaz o mapare a componentelor verde la componente verde; GL_PIXEL_MAP_B__TO_B - se realizeaz o mapare a componentelor albastru la componente albastru; GL_PIXEL_MAP_A_TO_A - se realizeaz o mapare a componentelor alfa la componente alfa; Parametrul mapsize arat dimensiunea maprii care se va realiza. Parametrul values este un pointer spre tabloul care conine valorile pentru mapare. Exemplu: In exemplul urmtor se arat felul cum se poate realiza o corecie gamma. GLfloatl 1ut[256]; GLf loat gamma_value; int i ; gamma_value=l. 7; //Pentru monitoare video NTSC //se ncarc tabela de cutare cu valori corespunztoare // monitorului cu care se lucreaz for(i=0; i<256; i++) lut[i]=pow (i/255.0, 1.0/gamma_value); //se activeaz maparea glPixelTransferi(GL_MAPCOLOR, GL_ TRUE); //se realizeaz maparea glPixelMap(GL_PIXEL_MAP_R_TO_R/ 256, lut); glPixelMap(GL_PIXEL_MAP_G_TO_G/ 256, lut); glPixelMap(GL_PIXEL_MAP_B_TO_B/ 256, lut);
Moduri de memorare sau de transfer a pixelilor

n aceast seciune se arat detalii ale modurilor de memorare i de transferare. O imagine depozitat n memorie conine pentru fiecare pixel ntre unul i patru elemente. Aceste elemente pot fi indexul de culoare sau intensitatea luminoas dar pot fi i componentele rou, verde, albastru i alfa. Aranjamentele posibile pentru datele corespunztoare pixelilor, sau formatele, determin numrul elementelor memorate pentru fiecare pixel i ordinea lor. Unele elemente sunt valori ntregi iar altele sunt valori n virgul mobil cuprinse ntre 0 i 1. Numrul exact de bii utilizat pentru reprezentarea comp0nentelor difer de la un hardware la altul. De aceea uneori este o risip s se memoreze fiecare component ca un numr n virgul mobil pe 32 de bii, mai ales c imaginile pot, uor, conine un milion de pixeli. Elementele pot fi memorate ca diferite tipuri de date, de la octei la ntrebi sau numere n virgul mobil pe 32 de bii. OpenGL definete explicit conversia fiecrei componente, n fiecare format, pentru fiecare din tipurile posibile de date. Trebuie reinut c se pierde din rezoluie atunci cnd se ncearc memorarea pe un numr mai mic de bii. 106

Datele corespunztoare unei imagini sunt memorate n memoria procesorului ca tablouri cu dou sau trei dimensiuni. Deseori, este nevoie s se afieze sau sa se memoreze o subimagine care corespunde unui sudreptunghi dintr-un tablou. Suplimentar, este nevoie s se ia n considerare diferite maini care au diferite convenii de ordonare a octeilor. n sfrit, unele maini au astfel hardware-ul nct este mai eficient s se mute datele nspre i dinspre buffer-ul de cadru dac datele sunt aliniate pe doi octei, patru octei sau opt octei n memoria procesorului. n asemenea cazuri poate fi necesar s se controleze alinierea octeilor. Toate aceste lucruri, descrise n acest subcapitol, sunt controlate de modurile de stocare al pixelilor. Aceste moduri se specific utiliznd comanda glPixelStore#(). De obicei trebuie fcute cteva apeluri succesive ale acestei comenzi pentru a seta valorile ctorva parametrii. void glPixelStore{if}(Glenum pname, TYPE param) ; Funcia afecteaz modurile de depozitare, care intervin n operaiile realizate de funciile: glDrawPixels, glReadPixels, glBitmap, glPolygonStippla, glTexImage i glGetTexImage. Parametrul pname poate lua 12 valori. Dintre acestea, 6 valori intervin n felul n care datele sunt scrise n memorie i deci afecteaz doar comenzile glReadPixels() i glTexImage(). GL_PACK_SWAP_BYTES GL_PACK_LSB_FIRST GL_PACK_ROWLENGTH GL_PACK_SKIP_ROWS GL_PACK_SKIP_PIXELS GL_PACK_ALIGNMENT Celelalte 6 tipuri de valori ale parametrului pname intervin n felul n care sunt citii pixelii din memorie i afecteaz funciile glDrawPixels, glBitmap, glPolygonStipple, glTexImage. GL_UNPACK_SWAP_BYTES GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_ROWS GL_UNPACK_SKIP_PIXELS GL_UNPACK_ALIGNMENT Valorile #SWAP_BYTES controleaz ordinea octeilor n memorie care poate sau nu s fie inversat dup cum parametrul este true sau false. Acest parametru poate fi ignorat dac nu se lucreaz cu imagini create pe procesoare diferite. Valoarea #LSB_FIRST (low significant bit) este util atunci cnd se lucreaz cu pixmap-uri de un bit sau cu bitmap-uri. Dac parametrul este false, biii sunt preluai din octet ncepnd cu bitul cel mai semnificativ. Atunci cnd dorim s desenm sau s citim un subdreptunghi dintr-un dreptunghi al unui pixmap memorat n memorie, se utilizeaz celelalte valori enumerate. Dac dreptunghiul din memorie este mai mare dect subdreptunghiul care se va desena, trebuie s se specifice lungimea dreptunghiului mai mare cu #ROW_LENGTH. Dac parametrul #ROW_LENGTH este 0 (implicit), atunci se sub nelege c lungimea este valoarea parametrului width specificat n funciile 107

glReadPixels(), glDrawPixels(), glCopyPixels(). Trebuie s se specifice de asemenea numrul rndurilor i al pixelilor care se sar nainte de a se ncepe copierea datelor din subdreptunghi. Aceste numere sunt setate utiliznd parametrii Exemplu: Spre exemplu, pentru a afia o imagine de 200 x 200 pixeli, aflat n centrul unei imagini de 500 x 300 se va utiliza urmtorul cod: glPixelStorei(GL_UNPACK_ROW_LENGTH, 500); glPixelStorei(GL_UNPACK_SKIP_PIXELS, (500-200)/2); glPixelStorei(GL_UNPACK_SKIP_ROWS, (300-200)12); glDrawPixels(200, 200, GL_RGB, GL_UNSIGNED_BYTE, model);

3.5 Utilizarea atributelor de redare n OpenGL


Un obiect poate fi redat cu diferite atribute: a) reprezentare wireframe b) reprezentare wireframe cu poligoanele avnd atribut de umplere; c) reprezentare cu iluminare folosind un model de iluminare constant pe poligoane; d) reprezentare cu iluminare Phong; e) reprezentare cu texturare; f) reprezentare cu texturare. OpenGL poate reda obiectele de la modul wireframe pn la texturarea acestora sau la utilizarea unor modele complexe de iluminare cum ar fi modelul Gouraud. Aa cum s-a mai artat n capitolul introductiv, OpenGL se comport ca o maina de stare. Toate atributele de redare sunt ncapsulate n starea OpenGL: - Stiluri de redare - Umbrire - Iluminare - Maparea texturii De fiecare dat cnd OpenGL proceseaz un vrf, utilizeaz datele memorate n tabelele sale interne de stare pentru a determina cum se va transforma vrful, cum se va lumina, textura, etc.

3.5.1 Controlarea strii OpenGL


Aspectul obiectelor desenate de aplicaiile OpenGL este controlat de starea curent. Fluxul general al oricrei redri OpenGL este de a se seta starea curent, apoi de a se transmite primitiva de redat, i de a se repeta aceti pai pentru fiecare primitiv. pentru fiecare (primitiv de reprezentat) { - se actualizeaz starea OpenGL - se red primitiva } 108

n general, metoda cea mai obinuit de a controla starea OpenGL este de a seta atributele vrfurilor, care includ culoarea, normalele pentru iluminare, coordonatele de texturare. glColor#() / glIndex() glNormal#() glTexCoord#()

3.5.2 Setarea strii curente


Setarea strii OpenGL de obicei include modificarea atributelor de redare, cum ar fi ncrcarea unei texturi sau setarea grosimii unei linii. Alte atribute necesit ns activarea lor. Aceasta se face prin utilizarea funciei glEnable(), i transmiterea numelui strii respective, cum ar fi GL_LIGHTO (pentru activarea sursei de lumin 0) sau GL_POLYGON_STRIP (pentru activarea abloanelor de umplere ale poligoanelor). Exemple: Setarea strii glPointSize(size) ; //stabilete grosimea liniei glLineStipple (repeat, pattern) ; //stabilete stilul liniei glShadeModel (GL_SMOOTH) ; //umbrire Gouraud Activarea atributelor glEnable (GL_LIGHTING) ; //se activeaz reprezentarea cu iluminare glDisable (GL_TEXTURE_2D) ; //se dezactiveaz reprezentarea cu texturare //2D

3.5.3 Interogarea strii i stiva de parametrii


Aa cum s-a mai spus, OpenGL este o main de stare. Ea poate fi pus n diferite stri (sau moduri) care au efect pn cnd sunt schimbate. Fiecare variabil de stare sau mod are o valoare implicit, i n orice punct al programului se poate interoga sistemul cu privire la fiecare din valorile curente ale variabilelor. n mod obinuit, se va folosi una din urmtoarele patru comenzi pentru a afla aceste valori: glGetBooleanv(), glGetDoublev(), glGetFloatv(), glGetIntegerv(). Care dintre aceste comenzi se va alege depinde de tipul datelor care se doresc a fi obinute. Unele variabile de stare au comenzi de interogarea strii mult mai specifice (cum ar fi glGetLight(), glGetError(), glGetPolygonStipple()). Exist de asemenea o stiv pentru valorile parametrilor care pot fi salvai sau restaurai din stiv. Comenzile pentru salvarea respectiv restaurarea din stiva de atribute de stare sunt: glPushAttrib() i glPopAttrib(). Comenzile get i stivele de parametrii fac posibil implementarea diferitelor biblioteci, fiecare fr a interfera cu alt utilizare OpenGL.

109

4 INDRUMAR DE LABORATOR
Programare Grafic OpenGL

4.1 Lucrare de laborator 1. 4.1.1 Introducere n OpenGL


OpenGL (Open Graphic Library) nu este cum s-ar putea crede un limbaj de programare ci un standard de programare al aplicaiilor 3D. A fost primul standard care s-a impus pe pia fiind inclus deja la primele versiuni de Windows95 i WindowsNT4.0. Practic odat cu biblioteca de funcii Win32 a aprut i suportul pentru OpenGL (separat desigur). OpenGL este independent de mediul de programare, fiind definite aceleai tipuri de date i aceleai funcii indiferent dac se programeaz n Visual C, Visual Basic, Delphi, CBuilder .a. Totui se poate observa o oarecare nrudire ntre OpenGL i C pe msur ce se avanseaz n programare i se capt o oarecare experien i familiaritate cu OpenGL. Nu se pot nega nici oarecare asemnri cu Delphi, dar mai puine ca numr i mai subtile. Astfel chiar dac vei nva OpenGL utiliznd Vizual C, vei putea trece relativ rapid i fr dificultai la alt mediu de programare mai familiar, dar care are biblioteci OpenGL. Saltul mai mare se va face dac se va aborda alt standard de programare 3D, Direct 3D spre exemplu, dar avnd concepte comune se va nsui mult mai uor. Ca fapt divers n versiunile Visual C, s-a renunat la un moment dat la actualizare bibliotecii OpenGL, aceasta rmnnd la versiune 1.1, n schimb s-a introdus suport pentru Direct 3D. Alte medii de programare continu nc s includ i s actualizeze bibliotecile OpenGL, i aceasta cu att mai mult cu ct marea parte a distribuiilor de Linux se bazeaz pe acest standard. n Linux s-a impus deja GLUT (OpenGL Utility Toolkit) i mai nou freeGLUT. Deci dac dorii implementare n medii freeware de aplicaii 3D aceasta este soluia. Linkuri utile: http://freeglut.sourceforge.net/ www.opengl.org

4.1.2 Crearea unei aplicaii OpenGL


Pentru a crea o aplicaie OpenGL vom folosi n principal 4 biblioteci : gl.h bibliotec exclusiv dup standardul OpenGL; 110

glu.h bibliotec auxiliar pentru integrarea OpenGL n mediul de programare i nu numai; glaux.h bibliotec auxiliar pentru crearea i testarea rapid de aplicaii OpenGL; glos.h microbibliotec pentru corecia unui mic bug din bibliotecile OpenGL din Visual C.

Alturi de acestea mai avem nevoie de 3 librrii: - glu32.lib - glaux.lib - opengl32.lib Ce se gsesc n directorul LIB al Visual C. n plus sistemul de operare trebuie s includ neaprat n directorul system32 opengl32.dll. Vom utiliza pentru aceste laboratoare Visual C++ 6.0. Programele putnd funciona i n Visual C++ 5.0 , ca de altfel i n Visual Studio Net, i ultima versiune de Visual Studio 2008. Iniial vom lucra n modul consol. Vom proceda astfel: 1. Rulm Visual C++; 2. Din File alegem New; 3. Trecem pe primul tab Files; 4. Alegem i selectm C++ source file; 5. Denumim fiierul xxxx; 6. Scriem programul. 7. Apsam F7 pentru a compila programul. 8. Apsm Yes pentru a crea un spaiu de lucru pentru program. 9. Urmtorul meniu Yes ,salvm modificrile; 10. Din meniul Project alegem Settings ; 11. Alegem tabul Link din fereastra Project Settings ce s-a deschis; 12. La project options scriem librriile folosite de OpenGL glu32.lib, glaux.lib, opengl32.lib cu spaii ntre ele i fr virgul i la sfrit apsm OK. 13. Rulm programul cu F5. Exemplu de program: #include <glos.h> #include <gl\gl.h> #include <gl\glu.h> #include <gl\glaux.h> #include <conio.h> void main() { //initializare modului de afisare //un singur buffer afisare direct pe ecran //culori dup standardul RGBA auxInitDisplayMode(AUX_SINGLE | AUX_RGBA); 111

//poziia si dimensiunile ferestrei de afisare auxInitPosition(100,100,250,250); //initializam fereastra precizand titlul acesteia auxInitWindow("My first OpenGL Program"); // aici se scrie codul OpenGL pentru afiare //stergem fereastra folosind culoarea albastru glClearColor(0.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glFlush(); // Nu inchide! Asteapta apasarea unei taste getch(); } Observai c avem o secven de iniializare a mediului OpenGL: auxInitDisplayMode(AUX_SINGLE | AUX_RGBA); auxInitPosition(100,100,250,250); auxInitWindow("My first OpenGL Program"); i o secven de sfrit care poate lipsi. ntre aceste putnd scrie instruciuni OpenGL de afiare. Avem instruciunea glClearColor() care stabilete culoare de tergere a ferestrei sau a buferului avnd prototipul: void glClearColor(GLclampf rosu, GLclampf verde, GLclampf albastru,GLclampf alpha); GLclampf este un tip de date numeric asemntor cu float din C. Culoare se specific prin componenii ei rosu, verde i albastru, i o component de transparen alpha care dac nu este folosit este setat pe 1, adic complet opac. 1.0f este intensitatea maxim a componentei 0.0f cea minim. Observai c dup fiecare constant numeric de tip float se pune litera f, pentru a se evita ambiguitile i n special mesajele de avertizare (warning) de la compilare. Instruciunea glClear () stabilete buferul care va fi ters prin culoare specificat n glClearColor, ea are prototipul: void glClear(GLbitfield mask); unde mask poate lua valorile: GL_COLOR_BUFFER_BIT; GL_DEPTH_BUFFER_BIT; 112

GL_ACCUM_BUFFER_BIT; GL_STENCIL_BUFFER_BIT. Pentru primele aplicaii GL_COLOR_BUFFER_BIT. -

vom

folosi

doar

cu

masca

Pentru a desena un dreptunghi folosim funcia prototipuri:

glRect cu urmtoarele

void glRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); void glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); void glRecti(GLint x1, GLint y1, GLint x2, GLint y2); void glRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2) Se observ c OpenGL lucreaz att cu date specificate prin tipuri ntregi ct i prin date cu virgul. Rezultatul va fi desenarea unui dreptunghi ce are colul din stnga sus descris de x1,y1 i cel din dreapta jos descris de x2,y2. n OpenGL sistemul de coordonate nu mai este ca cel definit n Windows sau BGI, axa Oy este ndreptat n sus i nu n jos ca n cazul acesta. Axa Oz iese din ecran, Ox este de la stnga spre dreapta. Exerciiu 1. Modificai programul anterior pentru a desena cte patru dreptunghiuri, unul verde, unul rou, unul albastru i unul galben pe un fond negru. Pentru a modifica culoare dreptunghiului se folosete funcia glColor3f() care are prototipul: void glColor3f(GLfloat red, GLfloat green, GLfloat blue);

113

Programare Grafic OpenGL

4.2 Lucrare de laborator 2. 4.2.1 Utilizarea funciilor bibliotecii glaux


Biblioteca glaux este o bibliotec auxiliar, care dei compatibil cu standardul OpenGL nu este prevzut de acesta. Ea fost implementat n special pentru Visual C++, celelalte medii de obicei avnd doar bibliotecile glu i gl, sub acest nume sau altul. Biblioteca glaux ofer funcii de integrare a aplicaiei 3D n mediul de programare. Aplicaiile vor rula iniial o aplicaie de tip consol, aceasta la rndul ei deschiznd o alt fereastr n care va fi afiat grafica OpenGL. Pentru nceput se va dovedi destul de util, codul OpenGL putnd fi testat rapid, dar dac se va dori o aplicaie mai serioas se va renuna la glaux i se vor folosi opiunile de integrare a graficii OpenGL ntr-o aplicaie gen Win32 sau MFC (aceasta prin funciile bibliotecii glu). Funciile disponibile n biblioteca glaux sunt prefixate ntotdeauna de cuvntul aux. Aceste funcii pot fi mprite n trei categorii: - funcii de iniializare care definesc bufferele folosite, poziia ferestrei de afiare, genereaz fereastra; - funcii de interfa cu utilizatorul pentru mouse i tastatura; - funcii pentru desenarea de primitive 3D - se pot desena primitive ca model din srme (wire frame), sau cu suprafa continu (solids).

4.2.2 Funcii de iniializare:


Funcia auxInitDisplayMode realizeaz iniializarea modului grafic folosit de OpenGL ea avnd urmtorul prototip: void auxInitDisplayMode(GLbitfield mask); unde mask este o masc cu diferite opiuni de configurare aceste opiuni sunt: AUX_SINGLE imaginea se va afia prin intermediul unui singur buffer direct legat de ecran; AUX_DOUBLE imaginea va fi desenat mai nti ntr-un buffer auxiliar, fiind afiat apoi pe ecran prin intermediul bufferului principal ; AUX_RGBA culoare va fi specificat prin cele trei componente de culoare rou, verde, albastru i o component de transparen alfa; AUX_INDEX culoare va fi specificat prin index i nu direct; AUX_DEPTH specific c bufferul de adncime folosit va fi pe 32 de bii; AUX_DEPTH16 specific c bufferul de adncime folosit va fi pe 16 de bii; AUX_STENCIL specific c va fi folosit un buffer ablon; AUX_ACCUM specific c va fi folosit un buffer de acumulare; AUX_ALPHA specific c va fi folosit un buffer pentru parametrul de transparen alfa ; AUX_FIXED_332_PAL specific o palet de culoare 3-3-2 pentru fereastr ; 114

n mod obinuit vom folosi aceast funcie astfel : auxInitDisplayMode(AUX_DOUBLE | AUX_RGBA) ; ,pentru a lucra cu dou buffere, evitnd astfel efectul de plpire la animaii sau compoziii complexe ; sau mai simplu : auxInitDisplayMode(AUX_SINGLE | AUX_RGBA) ; , grafica va fi afiat direct pe ecran, relativ nepretenios pentru nceput ; Pentru a specifica poziia ferestrei de afiare se va folosi funcia auxInitPosition cu urmtorul prototip : void auxInitPosition(GLint x, GLint y, GLsizei lungime, GLsizei inaltime); n care sunt specificate coordonatele colului stnga sus i dimensiunile ferestrei. Exemplu: auxInitPosition(10,10,200,200); Pentru a genera efectiv fereastr, inclusiv pentru a preciza titlul acesteia se va folosi funcia auxInitWindow cu urmtorul prototip: void auxInitWindow(GLBYTE *titlul ferestrei); Exemplu: auxInitWindow( Primul program n OpenGL);

4.2.3 Funcii de interfa i de ciclare


Pn acum pentru a putea vedea grafica desenat n fereastr, evitnd nchidere imediat a ferestrei am folosit funcia getch() din biblioteca conio.h. Acelai lucru se poate realiza ns prin folosirea unor funcii de ciclare. Acestea au prototipul : void auxIdleFunc(AUXIDLEPROC NumeleFunctiei); void auxMainLoop(AUXMAINPROC NumeleFunctiei); 115

Funcia auxIdleFunc este apelat atunci cnd programul a terminat de desenat o scen i ateapt alte comenzi, o putem folosi fr probleme pentru afiarea aceleai scene sau pentru generarea de animaii. auxMainLoop este utilizat exclusive pentru ciclri, odat terminat ciclul, acest ciclu este reapelat, totul terminndu-se la nchiderea ferestrei. Variabila NumeleFunctiei este o numele unei funcii definit astfel:
void CALLBACK NumeleFunctiei(void) { //codul OpenGL prin care desenam ceva n mod repetat }

n program putem apela doar odat ori una ori alta din funciile de ciclare. NumeleFunctiei o putem denumi fie Desenare, fie RandareScena, cum anume ni se pare mai sugestiv. Exerciiu 1. Creai un program n care un dreptunghi s se mite de la stnga la dreapta n fereastr. Cnd a ajuns la marginea din dreapta s se opreasc. Odat realizat programul ncercai ca odat ajuns la margine s se ntoarc napoi, repetnd indefinit aceast micare.

4.2.4 Funciile de lucrul cu mouse


Avem o funcie de asociere a unei funcii unui eveniment de mouse aceasta are prototipul : void auxMouseFunc(int button, int mode, AUXMOUSEPROC func); , unde button este definit prin urmtoarele constante: AUX_LEFTBUTTON se refer la butonul stng al mouse-ului; AUX_MIDDLEBUTTON- se refer la butonul din mijloc al mouse-ului; AUX_RIGHTBUTTON se refer la butonul drept al mouse-ului; , mode specific evenimentul n care este implicat butonul precizat anterior : AUX_MOUSEDOWN butonul a fost apsat i este inut apsat; AUX_MOUSEUP butonul a fost eliberat;

n ceea ce privete func aceasta este numele unei funcii i are urmtorul mod de declarare : void CALLBACK MouseFunc(AUX_EVENTREC *event) { // operatii legate de mouse, desenarietc. } Unde event este o variabil de tip structur prin care se transmit informaii despre starea mouse-ului. 116

typedef struct _AUX_EVENTREC { GLint event; GLint data[4]; }

Event specific evenimentul definit prin constantele AUX_MOUSEUP / AUX_MOUSEDOWN ; Data este apelat cu urmtoarele secvene : data[AUX_MOUSEX] coordonata x a pointerului de mouse; data[AUX_MOUSEY] - coordonata y a pointerului de mouse; data[MOUSE_STATUS] starea butoanelor de mouse; Exemplu: void CALLBACK MouseFunc(AUX_EVENTREC *event) { int mousex,mousey; mousex = data[AUX_MOUSEX] ; mousey = data[AUX_MOUSEY] ; } . void main(void) { auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, MouseFunc); } Exerciiu 2. Creai un program pe baza secvenei de mai sus, care la apsarea primului buton al mouse-ului s deseneze un dreptunghi pe ecran cu centrul exact la poziia pointerului de mouse. La fiecare apsare a butonului, la diverse poziii dreptunghiul va fi redesenat.

4.2.5 Funciile de lucru cu tastatura


Pentru a se lucra cu tastatura se folosete funcia cu urmtorul prototip: void auxKeyFunc(GLint key, void(*function(void)); ,la care key este codul tastei crei i se asociaz funcia function. O list de coduri de taste este urmtoarea: 117

AUX_ESCAPE pentru tasta Escape; AUX_SPACE pentru bara de spaiu; AUX_RETURN pentru tasta Enter; AUX_LEFT The pentru tasta spre stnga; AUX_RIGHT pentru tasta spre dreapta; AUX_UP The pentru tasta n sus; AUX_DOWN pentru tasta n jos; AUX_A AUX_Z pentru tastele crora le corespund litere; AUX_0 AUX_9 pentru tastele crora le corespund cifre; Funcia asociat tastei are codul general valabil: void CALLBACK NumeFunctie(void) { }

Exerciiu 3. Scriei un program pentru a deplasa cu tastele sgei un dreptunchi n fereastr. Funciile grafice propriu-zise : Pentru a desena obiecte grafice 3D predefinite se folosesc funciile ce au urmtoarele prototipuri : void auxSolidBox(GLdouble lungime, GLdouble inaltime, GLdouble adancime ); void auxSolidCone(GLdouble raza, GLdouble inaltime); void auxSolidCube(GLdouble lungimeLatura); void auxSolidCylinder(GLdouble raza, GLdouble inaltime); void auxSolidDodecahedron(GLdouble raza); void auxSolidIcosahedron(GLdouble raza); void auxSolidOctahedron(GLdouble raza); void auxSolidSphere(GLdouble raza); void auxSolidTeapot(GLdouble dimensiune); void auxSolidTetrahedron(GLdouble raza); void auxSolidTorus(GLdouble RazaInterioara, GLdouble RazaExterioara); Observai c toate aceste funcii au un anumit mod de contrucie al numelui : aux + ModDeDesenare + TipulCorpuluiGeometric ModDeDesenare poate fi Solid- adic cu suprafa continu sau Wire cu suprafa reprezentat prin linii interconectate. Pentru tipul geometric avem urmtoarele cazuri : - Box - un paralelipiped dreptunghic definit prin lungime, nlime, adncime ; - Cone un cod definit prin raza bazei i nlimea ; 118

Cube un cub definit prin mrimea laturii ; Cylinder un cilindru definit prin raz i nlime; Dodecahedron un dodecaedru definit prin raz sferei cel circumscrie; Icosahedron un icosaedru definit prin raz sferei cel circumscrie; Octahedron un octaedru definit prin raz sferei cel circumscrie; Sphere o sfer definit prin raz; Teapot un ceanic definit de o mrime specific dup care se scaleaz; Tetrahedron un tetraedru definit prin raz sferei cel circumscrie; Torus un tor (un corp de forma unei gogoi) definit prin raz zonei umplute i raza exterioar.

Se observ c la aceste corpuri nu li s-a precizat poziie. Ele vor desenate la poziia actual a centrului sistemului de coordinate. Pentru a modifica poziia se folosete funcia glTranslatef cu prototipul : void glTranslatef(GLfloat x, GLfloat y, GLfloat z ); Unde x, y, z semnific deplasri pe ox, oy, oz ale centrului de referin. Exerciiu 4. Desenai pe ecran n modul Wire toate corpurile 3D precizate mai sus, ncercai s le afiai pe toate n fereastr pentru a acoperi toat fereastra folosii translaii cu ajutorul funciei glTranslate(). Sunt nevoie doar de translaii de ox i oy. Duble buffering Pentru a nltura plpirea ecranului la animaii vei folosi urmtoarele secvene de cod: auxInitDisplayMode(AUX_DOUBLE | AUX_RGBA) ; ,pentru iniializare, iar pentru a afia bufferul secundar se va apela funcia urmtoare, aceasta dup ce s-a desenat tot ce se dorea : auxSwapBuffers();

119

Programare Grafic OpenGL

4.3 Lucrare de laborator 3. 4.3.1 Aplicaii OpenGL n Win32


n laboratorul anterior s-a spus c pentru aplicaii serioase ale OpenGL se va lucra cu aplicaii Win32 sau MFC. n continuare vom prezenta paii ce trebuie urmai pentru a crea o astfel de aplicaie. Este relativ simplu de a crea o aplicaie Win32 necompletat, mai greu ns este crearea codului de baz ce va iniializa grafic OpenGL i mai ales fereastra de aplicaie. Pentru astfel de tipuri de aplicaii nu vom scrie pentru fiecare aplicaie nou codul de la zero, ar fi contraproductiv, vom crea n schimb o aplicaie ablon n care s avem definite elementele generale pe care le dorim a le folosi n orice aplicaie viitoare, urmnd s copiem codul acestei aplicaii ori de cte ori dorim s realizm o aplicaie OpenGL n stilul Win32.

4.3.2 Crearea unei aplicaii Win32 necompletate


Vom folosi pentru aceasta meniurile de creare de proiect specifice Visual C. Vom parcurge urmtorii pai: 1. Din meniul File apsm New; 2. Alegem din tabul Projects Win32 Application; 3. Denumim proiectul n caseta de editare etichetat Project Name; 4. Apsm OK. 5. n fereastra urmtoare alegem - An empty project- i apsm Finish; 6. Mai apare o fereastr de confirmare n care apsm OK Am creat proiectul; 7. Din fereastra de vizualizare din partea stng selectm modul FileView ce specific c se dorete a se vizualiza fiiere; 8. Din meniul File apasm New; 9. Din fereastr selectm tabul files- i de aici alegem -C++ source file-; 10. Denumim fiierul i apsm OK, va aprea o fereastr goal n care vom scrie codul programului. Acesta va conine n primul rnd includerea bibliotecilor: #include <windows.h> //pentru lucrul cu ferestre i funcii Win32 #include "glos.h" #include <gl/gl.h> #include <gl/glu.h> #include <gl/glaux.h> #include <stdio.h> //facultativa #include <string.h>//pentru lucrul cu sirurile de caractere #include <math.h>// pentru lucrul cu funcii matematice Apoi o definire a constantelor i variabilelor globale. const char titlulferestrei[]="OpenGL Afisarea texturarii unui cilindru"; 120

static HGLRC hRC; // dispozitivul de randare - obligatoriu static HDC hDC; // dispozitivul de context suprafaa ferestrei adic obligatoriu Aceste sunt recomandabile a fi definite sau chiar obligatorii. Corpuri de funcii utilizate. Funcia principala de desenare a graficii OpenGL: void CALLBACK deseneaza(void) { // comenzi functii opengl } Funcia de setare modului grafic, esenial pentru crearea unei ferestre compatibile cu OpenGL: void SetDCPixelFormat(HDC hDC) { int nPixelFormat; static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // dimensiunea structurii 1, // Versiunea structurii PFD_DRAW_TO_WINDOW | // deseneaz n ferestre PFD_SUPPORT_OPENGL | // suport grafica OpenGL PFD_DOUBLEBUFFER, // se suporta duble - buffering PFD_TYPE_RGBA, // culoare respecta standardul RGBA 24, // culoare pe 24 de biti 0,0,0,0,0,0, // nefolositi 0,0, // nefolositi 0,0,0,0,0, // nefolositi 32, // Buffer de adncime pe 32 de bii 0, // nefolosit 0, // nefolosit PFD_MAIN_PLANE, // deseneaza in planul principal 0, // nefolosit 0,0,0 }; // nefolositi // Alege un mod ct mai apropiat de cel solicitat in structura nPixelFormat = ChoosePixelFormat(hDC, &pfd); // Stabileste modul grafic asociat contextului de dispozitiv hDC SetPixelFormat(hDC, nPixelFormat, &pfd); }

Funcia de rspuns la redimensionarea ferestrei: 121

void CALLBACK resizefunc(GLsizei w,GLsizei h) { if (w==0) w=1; if (h==0) h=1; glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLsizei w2,h2; if (w>h){ w2=nRange*w/h; h2=nRange; }else { w2=nRange; h2=nRange*h/w; } glOrtho(-w2,w2,-h2,h2,-nRange,nRange); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } Funcia repetat prin intermediul unui timer: Exemplu: void CALLBACK Repeta(void) { if (roteste_on) { a=(a+4)%360; b=(b+4)%360; deseneaza(); } } i cel mai important funcia de gestionare a mesajelor, practic nucleul unei aplicaii Win32: Exemplu: LRESULT CALLBACK WndProc( HWND UINT message, WPARAM wParam, LPARAM lParam) { 122 hWnd,

switch (message) { // Apelata la crearea ferestrei case WM_CREATE: // extragem contextul de dispozitiv hDC = GetDC(hWnd); // selectam modul grafic compatibil OpenGL asociat ferestrei SetDCPixelFormat(hDC); //creem contextul de randare al graficii OpenGL hRC = wglCreateContext(hDC); // asociam contextului de dispozitiv curent contextul de randare //facandu-l pe acesta activ wglMakeCurrent(hDC, hRC); // creem un timer ciclat la un interval de o milisecunda SetTimer(hWnd,10000,1,NULL); break; // La inchiderea ferestrei case WM_DESTROY: // dezactivam timerul KillTimer(hWnd,101); //deselectam contextul de randare din contextul de dispozitiv wglMakeCurrent(hDC,NULL); // stergem contextul de randare wglDeleteContext(hRC); // va iesi din aplicatie odata ce fereastra de aplicatia a disparut PostQuitMessage(0); break; // Apelat la redimensionarea ferestrei case WM_SIZE: //apelam functia de redimensionare a ferestrei resizefunc(LOWORD(lParam), HIWORD(lParam)); break; // apelat prin intermediul timerului o dat la fiecare milisecunda case WM_TIMER: { //functie care se repeta o data la o milisecunda Repeta(); } break; 123

// Apelat la desenarea sau redesenarea ferestrei case WM_PAINT: { // desenam grafica OpenGL propriu-zisa deseneaza(); // afisam buferul secundar in fereastra pe ecran SwapBuffers(hDC); // validam suprafata de desenare ValidateRect(hWnd,NULL); } break; //apelata la apasarea unei taste case WM_KEYDOWN: { switch (keydata) { case 75://executa ramura la apasarea tastei spre stanga ScadeUnghiA(); break; case 77:// executa ramura la apasarea tastei spre dreapta CresteUnghiA(); break; case 72:// executa ramura la apasarea tastei in sus ScadeUnghiB(); break; case 80:// executa ramura la apasarea tastei in jos CresteUnghiB(); break; case 57:// executa ramura la apasarea barei de spatiu AltCorp(); break; } } break // apelata la micare cursorului mouselui case WM_MOUSEMOVE: //Roteste Corpul pe 2 axe cat timp butonul stang este tinut apasat { int mx,my; mx=LOWORD(lParam); my=HIWORD(lParam); if (wParam==MK_LBUTTON) { a=a_+(mmy-my)*2; b=b_+(mmx-mx)*2; deseneaza(); 124

} }break; //apelata la apsarea butonului stang al mouse-lui case WM_LBUTTONDOWN://Activeaza rotatia prin mouse //fixand punctul de referinta { int mx,my; mx=LOWORD(lParam); my=HIWORD(lParam); a_=a; b_=b; mmx=mx; mmy=my; } break; //apelata la apasarea butonului drept al mouse-ului case WM_RBUTTONDOWN://Schimba corpul prin clic dreapta mouse { AltCorp(); } break; //apelata la apasarea butonului din mijloc al mouselui case WM_MBUTTONDOWN: //Roteste automat si in mod continuu corpul //activarea dezactivarea facandu-se prin butonul //de mijloc al mouse-ului { roteste_on=!roteste_on; } break; default: // daca nu s-a apelat nici o alta ramura // apelam functia de procesare implicita a mesajelor return (DefWindowProc(hWnd, message, wParam, lParam)); } return (0L); }

n locul funciei main() din C, C++ vom avea urmtoare secven, care rmne aproape indentic pentru orice aplicaie Win32 vom crea de acum ncolo: int APIENTRY WinMain( HINSTANCE 125 hInstance,

HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; // mesaj window WNDCLASS wc; // clasa fereastr. HWND hWnd; // pointer - indice la o fereastr // initializam parametrii ferestrei: wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = windowtitle; // Inregistram clasa fereastra if(RegisterClass(&wc) == 0) return FALSE; // Creem fereastra aplicatiei hWnd = CreateWindow( windowtitle, windowtitle, // OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN WS_CLIPSIBLINGS, 100, 100, width0, height0, NULL, NULL, hInstance, NULL); // daca fereastra nu s-a creat functia WinMain va returna FALSE if(hWnd == NULL) return FALSE; // Afisam fereastra aplicatiei ShowWindow(hWnd,SW_SHOW); UpdateWindow(hWnd); // Procesam mesajele spre aplicatie prin intermediul unei bucle while( GetMessage(&msg, NULL, 0, 0)) 126

{ TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;// inchidem ciclul returnand un parametru al mesajului } Exerciiu. Pe baza unei aplicaii ablon disponibile pe calculatorul pe care lucrai. Construii un program care la inerea apsat a butonului stng al mouselui s deplaseze un dreptunghi care s fie afiat tot timpul cu centrul sub pointerul mouseului.

127

Programare Grafic OpenGL

4.4 Lucrare de laborator 4. 4.4.1 Primitive grafice OpenGL


n momentul de fa din laboratoarele precedente stpnim iniializarea i crearea unui mediu pentru OpenGL att folosind biblioteca glaux ct i Win32. Cu toate aceste nu prea se tie s se deseneze prea mult n OpenGL cu excepia ctorva elemente de baz. Pentru a desena orice corp n OpenGL indiferent de ct de complex este, este nevoie de utilizarea unui set de primitive. Acestea sunt elemente grafice de baz.

4.4.2 Desenarea de puncte


Pentru a se desena un punct se folosete urmtoarea secven: glBegin(GL_POINTS); // va desena un punct la coordonatele (50,50,50) glVertex3f(50.0f, 50.0f, 50.0f); glEnd(); Se observ folosirea unei funcii de nceput de desenare glBegin la care specificm ce anume se va desena. O funcie de finalizare a secvenei de desenare glEnd(). ntotdeauna aceste funcii vor lucra n pereche, iar ntre ele nu vor fi permise dect anumite operaii de desenare. Una dintre acestea este specificare unui vrf ce se face cu funcia glVertex3f care are urmtorul prototip: void glVertex3f(GLfloat x, GLfloat y, GLfloat z); Unde x,y,z sunt coordonatele punctului sau vrfului. Aceast funcie are o multitudine de alte abordri, aceasta fiind cea mai folosit. Alt funcie este specificare culorii glColorf3f avnd prototipul: void glColor3f(GLfloat rosu, GLfloat verde,GLfloat albastru); Aceasta precede un vrf, sau vrfuri crora le specific culoarea putnd tot la fel de bine sta i n afara perechii glBegin glEnd.

4.4.3 Desenarea de linii


Pentru a desena o linie folosim secventa: glBegin(GL_LINES); glVertex3f(0.0f, 0.0f, 0.0f);//primul capat al liniei glVertex3f(50.0f, 50.0f, 50.0f);//al doilea capat al liniei glEnd(); 128

Se observ c i de aceast dat s-a specificat n glBegin tipul de primitiv dorit. Fcnd aceast practic i precizm secvenei cum va interpreta vrfurile ce se afl n interiorul perechii glBegin glEnd. Oricare dou perechi de vrfuri luate n ordine vor specifica o nou linie. Exemplu : glBegin(GL_LINES); glVertex3f(0.0f, 0.0f, 0.0f);//primul capat al liniei 1 glVertex3f(50.0f, 50.0f, 50.0f);//al doilea capat al liniei 1 glVertex3f(0.0f, 20.0f, 0.0f);//primul capat al liniei 2 glVertex3f(50.0f, 40.0f, 50.0f);//al doilea capat al liniei 2 glVertex3f(20.0f, 0.0f, 0.0f);//primul capat al liniei 3 glVertex3f(10.0f, 30.0f, 50.0f);//al doilea capat al liniei 3 glEnd(); Dac este un vrf necuplat acesta va fi ignorat. Pentru desenarea unor linii la care ultimul capt este nceput pentru o nou linie se folosete constanta GL_LINE_LOOP specificat n glBegin(). Pentru a desena un mnunchi de linii n care un punct s fie originea unui grup de linii se folosete constanta GL_LINE_STRIP. La GL_LINE_LOOP primul vertex este nceputul nlnuirii de linii i ultimul sfritul. La GL_LINE_STRIP primul vertex(vrf) este originea mnunchiului de linii i celelalte vertexuri capete de linie. Exercitiu 1. Desenai din linii un hexagon centrat pe ecran. Exerciiu 2. Desenai folosind GL_LINE_STRIP un mnunchi de linii care s semene cu razele de lumin emise de o stea.( De acum ncolo vom folosi abordare desenai cnd ne vom referi la crearea unui program care s deseneze un anume lucru, sau ori de cte ori ne referim la construcia unei scene 3D.)

4.4.4 Desenarea unui triunghi


Pentru a desena un triunghi avem la dispoziie trei constante: GL_TRIANGLES deseneaz triungiuri independente grupuri de trei vrfuri luate n ordine constituie un triunghi; GL_TRIANGLE_STRIP deseneaz triunghiuri interconectate ultimele dou vrfuri al oricrui triughi sunt vrfuri de generare ale urmtorului; GL_TRIANGLE_FAN deseneaz triunghiuri interconectate sub forma unui evantai la care primul vrf al primului triunghi este comun tuturor celorlalte triunghiuri ; Dei sunt disponibile o varietate de alte poligoane pe care le poate genera OpenGL, din punct de vedere hardware triunghiurile sunt procesate cel mai rapid. De aceea la creare unui obiect din elemente este indicat ca acestea s fie triunghiuri, sau o alt abordare ar fi descompunerea poligoanelor complexe n triunghiuri. 129

Exerciiu 3. Desenai o piramid folosind evantaiul de triunghiuri, fr de desena i baza. Fiecare fa desenata va avea alt culoare.

4.4.5 Desenarea unui patrulater


Pentru a desena un patrulater se folosesc constantele : GL_QUADS deseneaz un patrulater independent; GL_QUAD_STRIP deseneaz nite patrulatere interconectate, ultimele dou vrfuri fiind primele dou ale urmtorului patrulater;

4.4.6 Desenarea unui poligon


Pentru a desena un poligon se folosete constanta GL_POLYGON, fiecare vrf va fi cte un col al poligonului ultimul vrf fiind automat unit cu primul pentru crearea unui contur nchis. Aceasta este valabil i pentru patrulatere.

4.4.7 Funcii grafice auxiliare


n acest moment au fost expuse toate primitivele grafice de baz i cu toate acestea mai rmn de precizat elemente tipice pentru primitive : mrimea punctului, grosimea liniei, model de linie, model de poligon, renunarea la desenarea unei fee,desenarea umplut sau doar conturat a unei primitive nchise. Aceste lucruri i altele vor fi expuse n continuare.

4.4.8 Modificare mrimii punctului


Spre deosebire de puncte afiate pe un ecran punctele din OpenGL au dimensiuni. Punctele au o forma de ptrat cnd sunt mrite i nu de cerc cum s-ar putea crede. Pentru a modifica mrimea unui punct se folosete secvena urmtoare : GLfloat sizes[2]; GLfloat step; // pastreaza limitele intre care //variaza marimea punctului // pastreaz pasul de incrementare al marimii

// se citesc valorile stocate implicit glGetFloatv(GL_POINT_SIZE_RANGE,sizes); glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step); De obicei limitele mrimii variaz ntre 0.5 i 10.0, iar pasul de incrementare al mrimii este de 0.125. 130

Pentru a seta mrimea punctului se folosete aceast apelare : glPointSize(MarimeaPunctului);

4.4.9 Modificare parametrilor liniei


Pentru a afla limitele ntre care variaz grosimea liniei, precum i pasul de incrementare al grosimii se folosete o secven asemntoare ca la punct: GLfloat sizes[2];// intervalul de valori GLfloat step; //pasul // Get supported line width range and step size glGetFloatv(GL_LINE_WIDTH_RANGE,sizes); glGetFloatv(GL_LINE_WIDTH_GRANULARITY,&step); Pentru a seta grosimea liniei vom apela funcia: glLineWidth(GrosimeLinie); , naintea desenrii liniilor ce vor avea grosimea precizat. Pentru a modifica modelul liniei spre exemplu pentru a trasa o linie segmentat sau compus din puncte, sau alt model. Folosim secvena : GLushort model = 0x5555; GLint factor = 4; glEnable(GL_LINE_STIPPLE); glLineStipple(factor,model); La care model semnific o secven de 16 bii fiecare bit semnificnd absena sau prezen unui segment din linie, segment de lungime specificat de factor-.

4.4.10 Modificare parametrilor figurilor nchise


Pentru a specifica faptul c tranziiile de culoare de pe suprafaa poligonului se fac liniar sau fin se va folosi funcia cu prototipul : void glShadeModel( GLenum mod); Unde mod poate fi una dintre constantele: 131

GL_FLAT aspect mai necizelat al tranziiei de culoare; GL_SMOOTH aspect lin, fin al tranziiei de culoare; Pentru a specifica c poligoanele (prin acest termen se face referire la toate figurile nchise fie ele triunghiuri, patrulater) vor fi desenate astfel nct cele din spate s fie acoperite de cele din fa se va folosi urmtoarele secvene : glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); , pentru tergerea ecranului. Se observ c se terge i bufferul de adncime n care sunt pstrate poziiile punctelor desenate n raport cu axa oz. glEnable(GL_DEPTH_TEST); , pentru a activa opiunea de folosire a buferului de adncime. Uneori pentru a crete viteza de procesare dorim s nu mai fie desenate suprafeele interioare ale corpurilor. n acest sens se va folosi o funcie care s specifice care poligoane vor constitui faa poligonului i care spatele. Esenial n acest proces este ordinea n care sunt definite vrfurile unui polygon. Ea poate fi n sensul acelor de ceas sau invers. Secvena care specific c spatele poligoanelor nu va fi desenat este: glEnable(GL_CULL_FACE); glFrontFace(GL_CW);// fata poligonului este cea n care vrfurile // sunt definite n sensul acelor //definim poligoane conform acestei reguli glFrontFace(GL_CCW); // fata poligonului este cea n care vrfurile // sunt definite contrar sensului acelor //definim poligoane conform acestei reguli Pentru a specifica modul n care este desenat poligonul vom folosi secvenele: glPolygonMode(GL_BACK,GL_LINE);// spatele este desenat numai conturat glPolygonMode(GL_FRONT,GL_LINE);// faa este desenat numai conturat glPolygonMode(GL_FRONT,GL_FILL);// faa este desenata umpluta Primul parametru poate lua valorile : GL_FRONT se refera doar la faa poligonului GL_BACK se refera la spatele poligonului GL_FRONT_AND_BACK se refera la ambele suprafee ale poligonului 132

Al doilea parametru poate lua valorile : GL_POINT - se deseneaz numai vrfurile; GL_LINE - se deseneaz numai conturul; GL_FILL se deseneaz suprafaa umplut;

Pentru a specifica c se va folosi un efect de umplere vom folosi secvenele de iniializare : glEnable(GL_POLYGON_STIPPLE); glPolygonStipple(model); Unde model este o matrice 32x32 de bii. Fiecare bit reprezentnd un punct din model. Acest model este repetat pe verticala i pe orizontala suprafeei poligonale la care se aplic acoperind-o n ntregime. GLubyte model[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x0f, 0x00, 0x1f, 0xe0, 0x1f, 0x80, 0x1f, 0xc0, 0x0f, 0xc0, 0x3f, 0x80, 0x07, 0xe0, 0x7e, 0x00, 0x03, 0xf0, 0xff, 0x80, 0x03, 0xf5, 0xff, 0xe0, 0x07, 0xfd, 0xff, 0xf8, 0x1f, 0xfc, 0xff, 0xe8, 0xff, 0xe3, 0xbf, 0x70, 0xde, 0x80, 0xb7, 0x00, 0x71, 0x10, 0x4a, 0x80, 0x03, 0x10, 0x4e, 0x40, 0x02, 0x88, 0x8c, 0x20, 0x05, 0x05, 0x04, 0x40, 0x02, 0x82, 0x14, 0x40, 0x02, 0x40, 0x10, 0x80, 0x02, 0x64, 0x1a, 0x80, 0x00, 0x92, 0x29, 0x00, 133

0x00, 0xb0, 0x48, 0x00, 0x00, 0xc8, 0x90, 0x00, 0x00, 0x85, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00}; Un exemplu de definire de model. Pentru construcia unui poligon se aplic o serie de reguli. nclcarea acestor reguli crea probleme pe plcile video mai vechi dar pentru cele noi aceste restricii nu mai sunt valabile. n orice caz este bine s fie respectate pentru o mai bun portabilitate a codului OpenGL. Astfel : Laturile poligonului nu trebuie s se intersecteze. Poligonul trebuie s fie convex. Vrfurile poligonului trebuie s se afle n acelai plan.

Exerciiu 4. Creai un poligon hexagonal care s fie umplut cu un model, care s reprezinte o fa zmbitoare (smiley).

134

Programare Grafic OpenGL

4.5 Lucrare de laborator 5. 4.5.1 Transformri geometrice n OpenGL


n OpenGL transformrile geometrice pe care le suport un set de puncte, respectiv un corp 3D format din acestea, sunt mediate de o matrice de transformri cu patru coloane i patru linii. nmulind vectorul de patru elemente ce specific punctul cu o astfel de matrice se obine un nou vector care reprezint punctul ce a suferit transformrile. Am spus patru elemente i nu trei pentru c primele trei sunt coordonatele x, y, z ale punctului i a patra valoare este un coeficient de scalare w. Prin nmulirea unei matrice corespunztoare de transformri cu un punct se pot face rotaii, translaii, scalri. Acestea sunt transformri clasice realizate prin funciile OpenGL, dar lucrnd direct cu matricea se pot realiza transformri personalizate ca de exemplu crearea de umbre. Nu exist un acces direct la matrice dar n schimb exist unul mediat, matricea poate fi ncrcat, descrcat, ncrcat ntr-o stiv, descrcat dintr-o stiv, iniializat cu matricea unitate, i n plus o mediere de gradul doi n care modificam matricea prin nmuliri cu matrice ce specific translaii, rotaii, etc. Orice transformare de coordonate n OpenGL se realizeaz prin nmulirea matricei de lucru cu o matrice ce specific o transformare.

4.5.2 ncrcarea i descrcarea din stiv a unei matrice


Matricea de lucru poate fi salvat ntr-o stiv, ca mai apoi cnd se dorete revenirea la starea iniial s fie descrcat din stiv n matricea de lucru curent. Aceasta este util pentru a pstra o stare a sistemului la un moment pentru ca mai apoi s se revin la ea. De exemplu am fcut nite transformri i acestea vor fi comune unui grup de obiecte ce urmeaz, dar pentru aceste obiecte se mai dorete nc o transformare pentru orientare de exemplu, nainte de a face rotaia vom salva starea matricei ca dup afiarea obiectului s se revin la starea iniial. Pentru a salva matricea de transformare prin ncrcarea ei n stiv se folosete funcia: glPushMatrix( ); , care nu are parametri. Iar pentru a descrca matricea de transformare salvat din stiv se folosete o funcie asemntoare: glPopMatrix( );

135

De obicei acestea vor lucra mpreun. O apelare glPushMatrix fiind urmat mai jos n program de glPopMatrix. Pentru a ncrca matricea unitate se folosete funcia: glLoadIdentity( ); ,care anuleaz orice transformare anterioar. Mai exist o funcie care specific la care tip de matrice se refer: void glMatrixMode(GLenum mode); unde mode poate fi definit de una din constantele: GL_MODELVIEW se refer la matricea ce afecteaz modul de vizualizare a obiectului ; GL_PROJECTION se refer la matricea de proiecie; GL_TEXTURE - se refer la matricea prin care se realizeaz texturarea : Exemplu : glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(0.0f, 0.0f, -300.0f); glColor3f(1, 1, 0); auxSolidSphere(30.0f); glRotatef(a, 0.0f, 1.0f, 0.0f); glColor3f(0,0,1.0); glTranslatef(105.0f,0.0f,0.0f); auxSolidSphere(15.0f); glColor3f(0.7,0.6,0.8); glRotatef(b,0.0f, 1.0f, 0.0f); glTranslatef(30.0f, 0.0f, 0.0f); auxSolidSphere(6.0f); glPopMatrix();// glFlush();

136

4.5.3 Transformri elementare de coordonate


OpenGL pune la dispoziie trei tipuri de transformri prin intermediul urmtoarelor funcii: glRotatef pentru rotaii; glTranslatef pentru translaii; glScalef pentru scalri; glRotatef are urmtorul prototip: void glRotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z); ,unde angle reprezint valoarea unghiului de rotaie exprimat n grade, unghi ce semnific o rotaie invers acelor de ceas ; x, y, z reprezint unul din punctele ce definesc axa de rotaie, cellalt fiind poziia curent a centrului sistemului de referin ; glTranslatef are urmtorul prototip : void glTranslatef(GLfloat x, GLfloat y, GLfloat z ); ,unde x, y, z sunt valori ale tranlaiei pe cele trei axe de coordonate. glScalef are urmtorul prototip : void glScalef(GLfloat x, GLfloat y, GLfloat z); ,unde x, y, z sunt valori ale factorilor de contracie respectiv dilatare a corpului pe cele trei axe de coordonate . Trebuie reinut faptul c orice transformare este aditiv i se perpetueaz dac nu se folosesc funciile glPushMatrix, glPopMatrix sau glLoadIdentity. Pentru funciile de rotaii pentru a nu aprea confuzii este bine s se fac rotaii numai cte pe o axa odat astfel : Pentru a roti pe axa Ox cu un unghi de 45 de grade vom avea secvena : glRotatef (45.0f, 1.0f, 0.0f, 0.0f) ; ,pentru oy avem ceva asemntor : glRotatef( 45.0f, 0.0f, 1.0f, 0.0f).

137

Exerciiu 1. Creai un program care folosind glaux, s afieze un cub (auxWireCube) i apoi apsnd tastele sgei pentru stnga dreapta s se fac o rotaie pe ox, sus-jos pe oy, si a z pe oz. Exerciiu 2. Creai un program pentru simularea sistemului Soare, Lun, Pmnt. Acest sistem se va afla n rotaie, Luna se va nvrti de dou ori mai repede n jurul Pmntului dect Pmntul n jurul Soarelui. Soarele va fi o sfer galben, Luna o sfer cenuie iar Pmntul o sfer albastr. Exerciiu 3. Creai un atom cu electroni nucleul va fi compus din 2 sfere albastre i dou sfere roii. Vor fi 4 electroni ce se vor roti fiecare pe o orbit proprie, fiecare cu raze diferite. Electronii vor fi sfere galbene. Exerciiu 4. Creai o compoziie format dintr-un cub, iar n fiecare col al su va fi desenat o sfer.

4.5.4 Configurarea mediului vizual


Dac vei crea programe n Win32, de OpenGL, vei avea nevoie s cunoatei o serie de funcii de configurare a mediului vizual. Mai nti se vor expune o serie de secvene de cod n care sunt implicate astfel de funcii: glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f,(GLfloat)w/(GLfloat)h, 1.0, 400.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); n aceast secven avem urmtoarele funcii: glViewport stabilete parametrii ferestrei software de desenare(Viewport) specificai prin poziia colului stnga - sus , i lungimea w, i nlimea h a ferestrei. glMatrixMode(GL_PROJECTION) stabilete c se va lucra cu matricea de proiecie; glLoadIdentity() stabilete c matricea de proiecie va fi resetat la starea iniial; gluPerspective face modificri asupra matricei de proiecie stabilind unghiul percepiei 60.0 de grade, aspectul proieciei adic raportul dintre nlimea i lungimea imaginii, cel mai apropiat i cel mai ndeprtat punct pe oz pe baza crora se stabilete planurile de decupare a scenei, astfel c ce este nafara acestor limite nu este afiat ; glMatrixMode(GL_MODELVIEW) se stabilete c se va lucra cu matricea modelelor 3D ; glLoadIdentity() se seteaz mediul 3D la starea iniial; 138

De obicei o astfel de secven este apelat la fiecare redimensionare a ferestrei, sau nainte de prima afiare a ferestrei aplicaiei. O alt funcie de configurare ar fi urmtoarea: void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz ); , unde eyex, eyey, eyez este poziia observatorului sau mai bine spus a ochiului acestuia; , centerx, centerzy, center z este centrul scenei spre care privete. , upx, upy, upz specfic direcia privirii observatorului. Exemplu: glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(locX, locY, locZ, dirX, dirY, dirZ, 0.0f, 1.0f, 0.0f); n acest exemplu matricea de vizualizare este resetat, i apoi setat n raport cu ochiul observatorului. Folosind aceast funcie putem crea un program prin care s explorm o anumit scen. Exerciiu 5. Modificnd exemplul 4, scriei o secven de program n care la apsarea tastelor sus jos ochiul observatorului s se deplaseze pe oz, iar stnga dreapta pe ox. Vei folosi desigur funcia gluLookAt prezentat mai sus. Mai putei modifica programul astfel nct la apsarea tastelor a z s se modifice upx, s x upy, d - c upz, modificnd astfel i orientarea privirii observatorului.

139

Programare Grafic OpenGL

4.6 Lucrare de laborator 6. 4.6.1 Iluminare, lumini i materiale.


Pn acum s-a lucrat n medii n care nu s-a pus problema iluminrii scenelor, obiectele solide, triunghiurile erau toate uniform colorate, nu conta distana, orientarea acestora. Corpurile care aveau suprafa opac, sferele spre exemplu erau simple pete de culoare mai mult discuri, dect corpuri cu volum. Scopul acestui laborator este chiar rezolvarea acestei probleme. Se vor prezenta att moduri de iluminare, poziionri de spoturi, efecte de iluminare ct i un aspect complementar materialul din care este fcut corpul. La material vor conta proprietile reflexive ale acestuia adic modul cum acesta rspunde la lumin.

4.6.2 Configurarea iluminrii


Iluminarea natural are trei componente principale : componenta ambiental n care lumina nu pare a avea o surs anume ea emannd din toate punctele din spaiu i din nici unul n mod particular, obiectele sunt luminate uniform; componenta difuz la care lumina are o surs anume, dar nu apar suprafee lucioase; componenta de luciu la care lumina este direcional i mai apare i un luciu al suprafeelor; Pentru a configura aceste trei componente se folosete funcia cu urmtorul prototip: void glLightfv( GLenum sursa, GLenum mod, const GLfloat *parametri); ,in care sursa este o constanta de forma GLLightx. Unde x poate lua valori de la 0 la o valoare maxim precizat de constanta GL_MAX_LIGHTS. , mod este tipul componentei de iluminare aceasta poate fi : GL_AMBIENT - pentru specificare componentei ambientale; GL_DIFFUSE - pentru specificare componentei difuze; GL_SPECULAR pentru specificare componentei de luciu; GL_POSITION pentru specificare poziiei sursei de lumin. ar mai i alte moduri dar pentru moment acestea sunt suficiente,

140

, parametri este un vector de patru componente care pentru modurile de iluminare reprezint elementele RGBA adic intensitatea culorii roii, a celei verzi i a celei albastre plus intensitatea componentei alfa toata date prin valori de la 0.0 la 1.0. Pentru poziii parametri specific exact coordonatele x, y i z ale sursei plus o component de scalare care trebuie setat ntotdeauna la 1.0. Exemplu : GLfloat ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f }; GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat specular[] = { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat position[] = { 0.0f, 200.0f, 200.0f, 0.0f }; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, diffuse); glLightfv(GL_LIGHT0, GL_POSITION, position); Se observ modul cum sunt declarai vectorii. Se mai observ folosirea unor funcii de activare a iluminrii pentru iluminarea generala a scenei glEnable(GL_LIGHTING) - iar pentru activarea exclusiv a unei surse glEnable(GL_LIGHT0). n cazul iluminrii ambientale nu se pune problema orientrii suprafeei fa de sursa de lumin. Pentru iluminrii direcionale n schimb orientarea suprafeei devine esenial. n matematic pentru a defini orientare unei suprafee se specific vectorul normal pe acea suprafa, practic o perpendicular care iese din suprafa. Cnd se construiete o suprafa nainte de specifica vrfurile pentru aceea suprafa (glVertex) se va specifica n interiorul secvenei glBegin . glEnd normala la acea suprafa folosind funcia cu prototipul : void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz); , unde nx, ny, nz sunt coordonatele vrfului normalei. Dei OpenGL ofer o modalitate de precizare a normalei unei suprafee nu ofer i o funcie care dnd o serie de vrfuri s calculeze normala pentru suprafaa definite de ele. Din aceasta cauza va trebui definit o funcie de calcul a normalei. Un exemplu de astfel de funcie este :

141

void ReduceToUnit(float vector[3]) { float lungime; // se calculeaz lungimea vectorului lungime = (float)sqrt((vector[0]*vector[0]) + (vector[1]*vector[1]) + (vector[2]*vector[2])); // evitarea impartirii la zero if(lungime == 0.0f) lungime = 1.0f; // se impart toate componentele vectorului la lungime // normalizandu-le vector[0] /= lungime; vector[1] /= lungime; vector[2] /= lungime; } void calcNormal(float vv0[3],float vv1[3],float vv2[3], float out[3]) { float v1[3],v2[3]; static const int x = 0; static const int y = 1; static const int z = 2; // determin doi vectori pe baza a trei puncte v1[x] = vv0[x] - vv1[x]; v1[y] = vv0[y] - vv1[y]; v1[z] = vv0[z] - vv1[z]; v2[x] = vv1[x] - vv2[x]; v2[y] = vv1[y] - vv2[y]; v2[z] = vv1[z] - vv2[z]; // se face produsul vectorial al celor doi vectori // obinndu-se varful normalei out[x] = v1[y]*v2[z] - v1[z]*v2[y]; out[y] = v1[z]*v2[x] - v1[x]*v2[z]; out[z] = v1[x]*v2[y] - v1[y]*v2[x]; //se normalizeaza vectorul ReduceToUnit(out); }

142

Funcia care calculeaz normala este calcNormal, se mai folosete i o funcie de normalizare a vectorilor ReduceToUnit. vv0, vv1, vv3 constituie vrfurile, iar out vrful vectorului normal. Exemplu de folosire: glFrontFace(GL_CW); glColor3f(1,0,0); calcNormal(triunghi[2],triunghi[1],triunghi[0],mynormal); glBegin(GL_TRIANGLES); glNormal3fv(mynormal); glVertex3fv(triunghi[0]); glVertex3fv(triunghi[1]); glVertex3fv(triunghi[2]); calcNormal(triunghi[3],triunghi[2],triunghi[0],mynormal); glNormal3fv(mynormal); glVertex3fv(triunghi[0]); glVertex3fv(triunghi[2]); glVertex3fv(triunghi[3]); calcNormal(triunghi[4],triunghi[3],triunghi[0],mynormal); glNormal3fv(mynormal); glVertex3fv(triunghi[0]); glVertex3fv(triunghi[3]); glVertex3fv(triunghi[4]); calcNormal(triunghi[5],triunghi[4],triunghi[0],mynormal); glNormal3fv(mynormal); glVertex3fv(triunghi[0]); glVertex3fv(triunghi[4]); glVertex3fv(triunghi[5]); glEnd(); glColor3f(1,0,0); glFrontFace(GL_CCW); calcNormal(triunghi[2],triunghi[3],triunghi[4],mynormal); glBegin(GL_QUADS); glNormal3fv(mynormal); glVertex3fv(triunghi[1]); glVertex3fv(triunghi[2]); glVertex3fv(triunghi[3]); glVertex3fv(triunghi[4]); glEnd(); Secvena de mai sus deseneaz o piramida rosie, cu tot cu baz.

143

Se observ folosirea funciei glVertex3fv aceasta este o variant a funciei glVertex3f, numai c n acest caz parametrii x, y, z sunt preluai dintr-un vector cu trei elemente. Acest mod de folosire pentru, acelai tip de aciune, de variante de funcii este o caracteristic OpenGL. Un exemplu ar fi : glVertex2d, glVertex2f, glVertex2i, glVertex2s, glVertex3d, glVertex3f, glVertex3i, glVertex3s, glVertex4d, glVertex4f, glVertex4i, glVertex4s, glVertex2dv, glVertex2fv, glVertex2iv, glVertex2sv, glVertex3dv, glVertex3fv, glVertex3iv, glVertex3sv, glVertex4dv, glVertex4fv, glVertex4iv, glVertex4sv Aceasta pentru a v face o idee de flexibilitate OpenGL, exemplele putnd continua. Crearea automat de normale Pentru corpuri 3D predefinite n OpenGL exist posibilitatea generrii automate a normalelor, astfel: glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); ,tot ce trebuie fcut este s se insereze n program nainte de desenarea corpurilor respective a acestor dou linii de cod. Pentru ce a fost nevoie de normale? Pentru ca refleciile venite de la corp i tonurile de culoare s par naturale, altfel acestea ar fi fost arbitrare fr vreo legtur cu iluminarea n sine.

4.6.3 Configurarea materialului


Odat ce s-au stabilit luminile urmtorul pas este configurarea materialului. Materialul precizeaz modul n care lumina va fi reflectat, difuzat sau emanat de ctre obiect. n acelai timp specificm i culoare suprafeei prin precizarea materialului. Pentru a specifica materialul se poate folosi urmtoarea secven: 144

glMaterialfv (GL_FRONT, GL_AMBIENT, mat_amb); glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_dif); glMaterialfv (GL_FRONT, GL_SPECULAR, mat_spec); glMaterialf (GL_FRONT, GL_SHININESS, 0.7f*128.0f); Observm folosirea funciei glMaterialfv aceasta are prototipul: void glMaterialfv(GLenum fata, GLenum proprietate, const GLfloat *parametri ); , fata poate lua urmtoarele valori: GL_FRONT se refer la fa ; GL_BACK se refer la spate; GL_FRONT_AND_BACK se refer la fa i spate; , proprietate stabilete care aspect al materialului va fi configurat: GL_AMBIENT reflexia luminii ambientale (4 valori); GL_DIFFUSE reflexia luminii difuze(4 valori); GL_SPECULAR reflexia luciului suprafeei(4 valori); GL_EMISSION emisia de lumin de ctre suprafa(4 valori); GL_SHININESS gradul de reflexie lucioas a suprafeei (cu ct este mai mare cu att suprafaa lucioas este mai extins) (o valoare); GL_AMBIENT_AND_DIFFUSE - reflexia luminii ambientale i difuze(4 valori); GL_COLOR_INDEXES se refer la indecii de culoare se pot configura n acelai toate cele trei proprieti reflexive : ambiental, difuz i lucioas. (3valori) , parametrii vor fi patru valori ale componentelor culorii RGBA. glMaterialf este folosit n special pentru a specifica gradul de lucire al suprafeei. Intervalul de valori pentru acest parametru este ntre 1 i 128. 128 este cel mai nalt grad de lucire. Exerciiu1. Realizai un program cu Soarele, Luna i Pmntul, n care soarele s fie o surs de lumin i n acelai timp o sfer galben. Luna va fi o sfer cenuie i Pamntul o sfer albastr. Acestea se vor roti. Exerciiu 2. Construii o molecul de metan (CH4). Atomul de carbon va fi o sfer cenuie. Iar atomii de hidrogen nite sfere albastru deschis de 3 ori mai mici ca atomul de carbon, plasate pe suprafaa acestuia astfel nct cam 40% din ele s fie nglobate n atomul de carbon. Atomii de hidrogen vor fi dispui aproximativ n vrfurile unui tetraedru ce ar avea centrul de greutate n centrul atomului de carbon. Molecula se va putea roti cu tastele sgei dup cele dou axe.

145

Programare Grafic OpenGL

4.7 Lucrare de laborator 7. 4.7.1 Generarea de umbre prin utilizarea matricelor.


Pn acum am realizat efecte de tonuri de culoare dar efectiv nu am generat nici o umbr. Adic avnd un plan, un obiect i o surs de lumin pe acest plan s apar clar definit umbra obiectului. OpenGL nu prevede o funcie sau o configuraie n care s genereze astfel de umbre. Totui printr-o manevrare dibace a matricelor de transformare i a modurilor de afiare se poate genera o umbr dar nu pentru un ntreg ansamblu ci doar pentru fiecare obiect luat n parte. Se folosete urmtorul principiu scena se deseneaz odat normal, i a doua oar se deseneaz corpul a crui umbr se dorete , de data aceasta nainte de desena corpul i schimbm culoare se fie un gri cenuiu cum sunt n general umbrele i i producem o transformare geometric. Astfel corpul va fi turtit pn va fi extrem de subire, turtirea se va face innd seama de poziia sursei de lumin i poziia i orientarea planului pe care se proiecteaz umbra. Acest corp turtit va fi poziionat deasupra planului dar foarte aproape de el exact n poziia unde normal ar trebui s cad umbra. Pentru a genera matricea de transformare vom folosi urmtoare funcie: void MakeShadowMatrix(GLfloat points[3][3], GLfloat lightPos[4], GLfloat destMat[4][4]) { GLfloat planeCoeff[4]; GLfloat dot; // se calculeaz coeficienii ecuaiei planului // pe baza a trei puncte distincte din plan calcNormal(points,planeCoeff); //se determina al patrulea coeficient planeCoeff[3] = - ( (planeCoeff[0]*points[2][0]) + (planeCoeff[1]*points[2][1]) + (planeCoeff[2]*points[2][2])); // facem produsul dintre coordonatele sursei si coeficientii planului dot = planeCoeff[0] * lightPos[0] + planeCoeff[1] * lightPos[1] + 146

planeCoeff[2] * lightPos[2] + planeCoeff[3] * lightPos[3]; // facem proiectiile pe plan // calculand prima coloana a matricei de umbrire destMat[0][0] = dot - lightPos[0] * planeCoeff[0]; destMat[1][0] = 0.0f - lightPos[0] * planeCoeff[1]; destMat[2][0] = 0.0f - lightPos[0] * planeCoeff[2]; destMat[3][0] = 0.0f - lightPos[0] * planeCoeff[3]; // a doua coloana destMat[0][1] = 0.0f - lightPos[1] * planeCoeff[0]; destMat[1][1] = dot - lightPos[1] * planeCoeff[1]; destMat[2][1] = 0.0f - lightPos[1] * planeCoeff[2]; destMat[3][1] = 0.0f - lightPos[1] * planeCoeff[3]; // a treia coloana destMat[0][2] = 0.0f - lightPos[2] * planeCoeff[0]; destMat[1][2] = 0.0f - lightPos[2] * planeCoeff[1]; destMat[2][2] = dot - lightPos[2] * planeCoeff[2]; destMat[3][2] = 0.0f - lightPos[2] * planeCoeff[3]; // a patra coloana destMat[0][3] = 0.0f - lightPos[3] * planeCoeff[0]; destMat[1][3] = 0.0f - lightPos[3] * planeCoeff[1]; destMat[2][3] = 0.0f - lightPos[3] * planeCoeff[2]; destMat[3][3] = dot - lightPos[3] * planeCoeff[3]; } Unde points sunt trei puncte ce definesc planul; lightPos sunt coordonatele sursei de lumina; destMat este matricea de umbrire;

Orice obiect asupra cruia se aplic matricea de umbrire este turtit i poziionat n planul de proiecie al umbrei. Exemplu de utilizarea a matricei de umbrire: void CALLBACK deseneaza(void) { GLfloat ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f }; GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f }; GLfloat specularLight[]={1.0f,1.0f,1.0f,1.0f}; GLfloat lightPos[] = { 0, 50, -100, 1 }; GLfloat specref[]={1.0f,1.0f,1.0f,1.0f}; 147

GLfloat mynormal[3]; GLfloat plan[4][3]={ umbra

//parametrii planului pe care proiectata

{-500,-50,500}, {500,-50,500}, {500,-50,-500}, {-500,-50,-500} }; GLfloat plan_[4][3]={ //parametrii efectivi ai planului unde este desenata //umbra {-500,-49.9,500}, {500,-49.9,500}, {500,-49.9,-500}, {-500,-49.9,-500}}; GLfloat shadowMat[4][4]; GLfloat pi=3.14159f; GLint i,j,lx=100,ly=100; // sursa de lumina se poate roti deasupra n jurul obiectului lightPos[0]=sin(arot[1]*pi*2/360)*40; lightPos[1]=50; lightPos[2]=cos(arot[1]*pi*2/360)*40-150; // generam matricea de umbrire MakeShadowMatrix(plan_,lightPos,shadowMat); glEnable(GL_DEPTH_TEST); // inlaturam fetele invizibile glFrontFace(GL_CCW); // fata poligonului va fi cea definita invers acelor de ceas // activam iluminarea glEnable(GL_LIGHTING); // configuram lumina GL_LIGHT0 glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight); glLightfv(GL_LIGHT0,GL_SPECULAR,specularLight); glLightfv(GL_LIGHT0,GL_POSITION,lightPos); // activam lumina GL_LIGHT0 glEnable(GL_LIGHT0); 148

// activam colorarea indirecta a materialului glEnable(GL_COLOR_MATERIAL); // specificam ce parametri vor fi preluati indirect de material prin glColorf glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); //stergem ecranul glClear(GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT); //specificam materialul glMaterialfv(GL_FRONT,GL_SPECULAR,specref); glMateriali(GL_FRONT,GL_SHININESS,128); // matricea de lucru este cea de vizualizare a modelului glMatrixMode(GL_MODELVIEW); glPushAttrib(GL_LIGHTING_BIT);//Salvam luminile in stiva glDisable(GL_LIGHTING);//Dezactivam luminile glPushMatrix(); glColor3f(1,1,0); glTranslatef(lightPos[0],lightPos[1],lightPos[2]); auxSolidSphere(4.0);//desenam sursa de lumina glPopMatrix(); glPushMatrix(); umbra obiectul glTranslatef(0,0,-150); glRotatef(a,0,1,0); glRotatef(b,1,0,0); auxSolidCube(20.0);//desenam umbra corpului glPopMatrix(); glPopAttrib();//Incarcam luminile din stiva glPushMatrix(); //corpul este rosu glColor3f(1,0,0); // dupa cum vedeti aceleasi transformari 149 glMultMatrixf((GLfloat *)shadowMat);//incarcam matricea de // umbra va fi de un verde nchis glColor3f(0,0.3,0); // facem aceleasi transformari ca si cum am lucra cu |

glTranslatef(0,0,-150); glRotatef(a,0,1,0); glRotatef(b,1,0,0); auxSolidCube(20.0);// desenam corpul glPopMatrix(); glPushMatrix(); // desenam planul pe care se proiecteaza umbra glColor3f(0,1.0,0); glBegin(GL_QUADS); glVertex3fv(plan[0]); glVertex3fv(plan[1]); glVertex3fv(plan[2]); glVertex3fv(plan[3]); glEnd(); glPopMatrix(); glFlush(); } Exerciiu 2. Reutiliznd secvenele de cod precedente creai un ceainic cruia s-i afiai umbra, lumina se va roti deasupra corpului la apsare tastei bara de spaiu. Corpul se va putea roti prin apsarea tastelor sgei. Observai aceast linie de cod : glMultMatrixf((GLfloat *)shadowMat);//incarcam matricea de umbra Prin aceasta nmulim matricea de lucru cu matricea de umbrire, rezultatul fiind depus n matricea de lucru. O alt linie de cod interesant este urmtoarea: glPushAttrib(GL_LIGHTING_BIT); Aceast linie specific c se va salva setrile pentru lumini n stiv pentru a fi apoi recuperate. Se pot salva cu aceeai funcie i parametru corespunztor i ali parametri de stare ai OpenGL. Exemplu: - GL_ACCUM_BUFFER_BIT culoarea de tergere a bufferului; - GL_COLOR_BUFFER_BIT bii de in de setrile de culoare ale OpenGL - GL_CURRENT_BIT bii de stare curent a OpenGL - GL_DEPTH_BUFFER_BIT - bii ce in de configurarea bufferului de adncime 150

GL_ENABLE_BIT - bii ce in de activarea sau dezactivare unei opiuni a mediului OpenGL; GL_EVAL_BIT - bii de evaluatori OpenGL i activarea normalelor generate automat; GL_FOG_BIT - bii ce in de parametrii de cea; GL_HINT_BIT bii ce in calitatea trasrii unei linii,a unui punct, a unui polygon, a ceii; GL_LIGHTING_BIT - bii de in de parametrii de iluminare; GL_LINE_BIT - bii de in de configurarea liniei; GL_LIST_BIT - bii refiritori la listele de afiare ; GL_PIXEL_MODE_BIT bii referitori la modul de desenare al unui punct din imagine; GL_POINT_BIT - bii referitori la desenare unui punct individual; GL_POLYGON_BIT bii referitori la desenarea poligoanelor; GL_POLYGON_STIPPLE_BIT - bii referitori la modelul de umplere a poligoanelor; GL_SCISSOR_BIT - bii referitor la decupari; GL_STENCIL_BUFFER_BIT - bii referitori la bufferul ablon; GL_TEXTURE_BIT - bii referitori la textur; GL_TRANSFORM_BIT - bii referitori la limitele de decupare a scenei; GL_VIEWPORT_BIT - bii referitori la limitele pe Oz ale volumului de decupare.

Exerciiu 3. Creai un program cu dou obiecte un con( auxSolidCone) i un tor (auxSolidTorus) la care s le generai umbrele. La apsare tastei enter va fi selectat conul, la o nou apsare torul i tot aa. Obiectul selectat va putea fi rotit prin tastele sgei. Exerciiu 4. Creai un program cu dou surse de iluminare i un obiect un tetraedru. Generai ambele umbre produse de cele dou surse de lumina, pentru acelai obiect. Imagine a ferestrei programului exemplu : 1

151

Programare Grafic OpenGL

4.8 Lucrare de laborator 8. 4.8.1 Utilizarea listelor


n momentul de fa cunoatei ndeajuns de multe elemente de OpenGL pentru a construi element cu element orice structur v imaginai i orice scen. Cu ceea ce tii pn acum nu putei reutiliza codul OpenGL dect prin simpla lui copiere, nsoit de transformri geometrice, n zona de program n care avei nevoie. Anticipnd aceast nevoie OpenGL a introdus listele de desenare prin care codul de program scris exclusiv n OpenGL este definit odat n cadrul unei liste, i apoi prin apeluri la acea list codul poate fi refolosit. Listele ofer nu numai o metod mai comod de gestionare a codului dar la apelrile listei desenarea se face mai rapid. Aceasta deoarece prin list se pstreaz o structur 3D specificat de acel cod, structur gata de desenare, n timp ce n secvena propriu-zis de cod trebuie efectuate de fiecare dat calcule. Astfel orice operaie ce lucreaz cu mediul OpenGL, sau indirect modific un parametru sau o structur OpenGL este luat n calcul. ns dac secvena respectiv este definit prin anumii parametri independeni de mediul OpenGL, modificarea acestor parametri i apelarea mai apoi a listei nu modific de loc aspectul structurii desenate, doar asupra secvenei de cod originale, i nu asupra listei au efect aceti parametri. Totui este permis orice transformare geometric definit prin matricele OpenGL. Ce ncrcm n listele OpenGL? De obicei structuri geometrice, mai puin materiale, lumini i culori, pentru c uneori pe aceste dorim s le schimbm la reapelri. Pe viitor vom lucru cu liste i la pstrarea unor texturi ncrcate.

4.8.2 Crearea unei liste.


Pentru a crea o lista folosim funciile glNewListglEndList care au prototipurile: void glNewList( GLuint numarlista, GLenum mod); void glEndList( void); , unde numarlista este un numr prin care vom identifica lista creat; mod este modul cum va fi procesat liste putnd lua valorile: GL_COMPILE doar compileaz lista fr a o executa, adic nu va afia nimic pe ecran din ceea ce este prevzut n list; GL_COMPILE_AND_EXECUTE compileaz i execut lista pe loc; 152

Exemplu de definire a unei liste: glNewList (1, GL_COMPILE_AND_EXECUTE); // instructiuni OpenGL glEndList( ); // delimiteaza finalul zonei de definire a listei Atunci cnd nu dorim s gestionm manual numerele de list, sau dorim s evitm redefinirea unei liste din neatenie sau uitare, vom folosi funciile ce au urmtoarele prototipuri: GLuint glGenLists(GLsizei interval); GLboolean glIsList(GLuint numarlista); , glGenLists genereaz primul numr de list, a unei serii continue de numere de list, mrimea acestei serii fiind definite de interval. Acestea sunt doar numere disponibile, alocarea fcndu-se pentru fiecare n parte mai pe urm. ,glIsList returneaz TRUE dac numrul de list specificat a fost folosit la crearea unei liste, altfel FALSE. Pentru a chema n vederea execuiei o list alocat i compilat folosim funcia cu prototipul : void glCallList(GLuint numarlista); De reinut c n cazul apelrii unei liste parametrii modificai de secvena compilat n list rmn modificai i dup revenirea din apel. De aceea dac dorii evitarea acestui lucru este recomandabil folosire funciilor de salvare prin stiv glPushMatrix, glPopMatrix, glPushAttrib, glPopAttrib. Cnd se dorete apelarea mai multor liste la acelai apel se folosete funcia cu prototipul: void glCallLists(GLsizei n, GLenum type, const GLvoid *lists); ,unde n este numrul de liste; type este tipul valorilor din list, aceste valori fiind convertite mai apoi la GLint ; lists este un vector de tipul specificat n type ce conine numerele de lista. Pentru type se pot folosi urmtoarele constante specificatoare de tip, acestea fiind selectate pe criteriul folosirii efective : GL_INT pentru tipul GLint ; GL_UNSIGNED_INT pentru GLuint ; GL_FLOAT pentru GLfloat ; .a. 153

Odat ce nu se mai folosete o list este recomandabil ca aceasta s fie dealocat elibernd memoria asociat mediului OpenGL, memorie care cel mai adesea este mapat chiar n memoria plcii grafice. Pentru aceasta se va folosi funcia cu protipul : void glDeleteLists(GLuint list, GLsizei range); Aceasta va terge un numr specificat de range de liste alocate n mod continuu, ncepnd cu lista specificat de parametrul list. Exemplu : glDeleteLists(10,4); Va terge listele 10,11,12,13. O alt funcie important este definirea bazei listei adic numerele de list vor ncepe de la valoare specificat, la apelarea listelor numerele de list folosite vor fi cele stabilite minus valoare bazei listelor. Exemplu: int lista[10];//un vector de numere de lista int i; for(i = 0; i < 10; i++) //alocam un numar continuu de liste lista[i] = i; // Construim 30 de liste alocand numere de list consecutive // Definim prima lista glNewList(1,GL_COMPILE); glEndList(); // ... a doua lista glNewList(2,GL_COMPILE); glEndList(); // si asa mai departe // ... ultima lista glNewList(29,GL_COMPILE); 154

glEndList(); // executam primele 10 liste de la 0 la 9 glCallLists(10,GL_INT,lista); // setam baza la 10 glListBase(10); // executam urmtoarele 10 liste - de la 10 la 19 glCallLists(10,GL_INT,lista); // setam baza la 20 glListBase(20); // executam ultimele 10 liste de la 20 la 29 glCallLists(10,GL_INT,lista);

O lista de desenare poate conine la rndu-i alte liste de desenare pe care le apeleaz: Exemplu : glNewList(10,GL_COMPILE); // instructiuni OpenGL glCallList(1); glCallList(2); glCallList(5); glCallList(6); glEndList(); Totui exist o serie de comenzi OpenGL care nu sunt salvate prin punerea lor ntr-o list, ceea ce nseamn cu nu vor fi executate la chemarea listei, acestea sunt : glIsList glGenLists glDeleteLists glFeedbackBuffer glSelectBuffer glRenderMode glReadPixels 155

glPixelStore glFlush glFinish glIsEnabled glGet Exerciiu 1. Creai patru tipuri de obiecte din primitive OpenGL un corp prismatic de forma lui L, un corp prismatic nerotunjit de forma lui U, unul de forma lui T i altul de forma lui Z. Aceste corpuri vor avea specificate materiale diferite (folosii glMaterialfv), scena va fi iluminat. Aceste obiecte vor fi pstrate n liste, care la creare vor fi doar compilate. S se afieze pe 4 rnduri, n 7 coloane ntr-o fereastr, corpuri de tipul respectiv, pe fiecare rnd de acelai tip, iar pe coloan corpurile vor avea orientri diferite la alegere. Pe aceeai coloan corpurile vor avea aceeai orientare.

156

Programare Grafic OpenGL

4.9 Lucrare de laborator 9. 4.9.1 Lucrul cu imagini rastru n OpenGL


Ca orice standard grafic OpenGL trebuia s includ i funcii de desenare de imagini de tip rastru. Ce nseamn rastru? nseamn c imaginea este compus din puncte, i nu din entiti grafice scalabile ca n cazul imaginilor vectoriale (wmf), ale fonturilor truetype etc. Un reprezentant important al acestei clase este BMP , un altul este Iconul (iconia). Fiierele Bitmap utilizate de OpenGL trebuie s fie necomprimate avnd culoarea pe 24 de bii. Oricum chiar dac se dispune de astfel de fiiere OpenGL nu are funcii care s le citeasc pentru c nu ofer suport de lucrul de fiiere. Citirea fiierului, alocarea memoriei n care acesta va fi citit este treaba mediului de programare n care este integrat OpenGL. Totui odat ce matricea de pixeli mai corect spus de culori de pixel este ncrcat n memorie, ntr-un vector, aceasta poate fi folosit de ctre OpenGL. Pentru a afia un bitmap pstrat ntr-un vector se poate folosi funcia cu prototipul: void glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap ); , unde width este lungimea imaginii afiate, height este nlimea imaginii; xorig, yorig este poziia zonei de afiare n cadrul imaginii; xmove, ymove valori ale actualizrii poziiei pointerului de rastru ( acesta specific poziia pentru orice grafic de tip rastru n mediul OpenGL) vector la imaginea de tip rastru specificat ca o colecie de octei. Pentru a specifica poziia curent a unui obiect rastru se folosete funcia glRasterPos, care are o multitudine de variante, recomandabil ar fi folosirea funciei cu urmtorul prototip: 157

void glRasterPos3f( GLfloat x, GLfloat y, GLfloat z); , unde x, y, z sunt coordonatele pointerului de rastru. Alte funcii de grafic rastru sunt : glDrawPixels pentru afiarea de imagine de tip rastru; glCopyPixels pentru copierea unei imagini din buffer pe ecran; glReadBuffer specific bufferul din care se citete imaginea; glReadPixels citete ntr-un vector pixeli de pe ecran; glPixelMap specific un mod de interpretarea a culorii pixelilor manipulai; glPixelStore specific cum sunt citii sau scrii pixelii din memorie; glPixelZoom specific cum sunt scalai pixelii; Funcia glDrawPixels este o alt abordare a afirii imaginilor de tip rastru ea are prototipul: void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ); ,unde width este lungimea imaginii, height este nlimea imaginii pstrate n vector; format este formatul pixelilor pstrai n vector; type este tipul elementelor vectorului; pixels este un vector n care este pstrat imagine. n ceea ce privete formatul sunt disponibile urmtoarele opiuni : GL_COLOR_INDEX culoare pixelor este definit pe baz de indici i palet; GL_STENCIL_INDEX - se refer la indici din bufferul ablon; GL_DEPTH_COMPONENT - se refer la indici din bufferul de adncime ; GL_RGBA - se refer la pixeli a cror culoare este dup standardul RGBA; GL_RED - se refer la intensitile componentei roii a culorii pixelilor, fiecare valoare din vector fiind o intensitate; GL_GREEN - acelai lucru dar pentru verde; GL_BLUE - acelai lucru dar pentru albastru; GL_ALPHA - pentru alpha; GL_RGB definete un pixel compus din trei componente rou , verde i albastru, practic o imagine avnd culoarea pe 24 de bii; GL_LUMINANCE se specific culoare pixelului pe baza luminozitii; GL_LUMINANCE_ALPHA specific att luminozitatea ct i alpha ; GL_BGR_EXT specific pixeli a cror culoare este precizat de componenta albastr, verde, roie efectiv n aceast ordine; GL_BGRA_EXT specific pixeli a cror culoare este precizat de componenta albastr, verde, roie, alpha efectiv n aceast ordine. Tipul poate fi precizat prin urmtoarele constante: 158

GL_UNSIGNED_BYTE ntreg pe opt bii fr semn la care corespund tipul OpengGL - GLubyte; GL_BYTE ntreg pe opt bii cu semn la care corespund tipul OpengGL GLbyte; GL_BITMAP cte un bit stocai pe cte un ntreg pe 8 bii; GL_UNSIGNED_SHORT ntreg pe 16 bii fr semn GLushort; GL_SHORT ntreg pe 16 bii cu semn Glshort; GL_UNSIGNED_INT ntreg pe 32 de bii fr semn Gluint; GL_INT - ntreg pe 32 de bii cu semn Glint ; GL_FLOAT tip real n simpl precizie - glFloat;

Exemplu de folosire: glDrawPixels(BitmapInfo->bmiHeader.biWidth, BitmapInfo->bmiHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, BitmapBits); , cu acest apel se afieaz o imagine bitmap citit n memorie, imagine pe 24 de bii. BitmapBits este un vector spre pixelii imaginii, se observ c primi doi parametri specific lungimea i nlimea imaginii. Funcia glPixelStore este deosebit de important cnd se lucreaz cu funciile de afiare prin aceast specificndu-se cum vor fi interpretate valorile din vector. Ea are variantele: void glPixelStoref( GLenum pname, GLfloat param); void glPixelStorei( GLenum pname, GLint param); Unde pname specific tipul modificrii vizate, aceasta prin folosirea unei constante specificator. Aceste constante sunt: GL_PACK_SWAP_BYTES - inverseaz ordinea octeilor componeni ai pixelului (dac param este TRUE); GL_PACK_LSB_FIRST aranjeaz biii dintr-un byte astfel nct astfel nct cel mai puin semnificativ s fie procesat primul; GL_PACK_ROW_LENGTH specific numrul de pixeli dintr-un rnd folosind param; GL_PACK_SKIP_PIXELS nu mai afieaz un numr de pixeli specificat n lparam, afiare ncepnd de la pixelii care urmeaz ; GL_PACK_SKIP_ROWS nu mai afieaz primele param linii ; GL_PACK_ALIGNMENT specific modul de aranjare a datelor n vector, de obicei se folosete valoare 4 grupare de 16 bii adic, se mai pot folosi valorile 1,2, 8 ; 159

GL_UNPACK_SWAP_BYTES schimb ordine octeilor la despachetare bitmapului; GL_UNPACK_ROW_LENGTH la fel ca la mpachetare; GL_UNPACK_SKIP_PIXELS la fel ca la mpachetare; GL_UNPACK_SKIP_ROWS la fel ca la mpachetare; GL_UNPACK_ALIGNMENT la fel ca la mpachetare; Exemplu : glPixelStorei(GL_PACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glReadPixels(0, 0, viewport[2], GL_UNSIGNED_BYTE, bits);

viewport[3],

GL_RGB,

sau glPixelTransferi(GL_UNPACK_ALIGNMENT, 4); glPixelTransferi(GL_INDEX_OFFSET, 1); Folosind glPixelZoom putem scala o imagine, aceast funcie are prototipul: void glPixelZoom( GLfloat xfactor, GLfloat yfactor); , unde xfactor i yfactor sunt indicii de scalare pe orizontal i pe vertical e imaginii, unde valori supraunitare pozitive mrim imaginea, pentru valori subunitare pozitive micorm imaginea iar pentru valori negative inversm n oglind imaginea. Pentru a citi pixeli dintr-un buffer al OpenGL ntr-un vector folosim funcia cu prototipul: void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ); , unde x, y sunt poziia colului din stnga sus de unde va ncepe citirea , width, height sunt lungimea i nlimea zonei citite , format specific att bufferul din care se face citirea ct i componenta dorit, , type este tipul elementelor vectorului; , pixels este vectorul n care va postat imaginea.

160

Specificatori de format : GL_COLOR_INDEX - indice de culoare cnd se utilizeaz paleta; GL_STENCIL_INDEX indice din bufferul ablon; GL_DEPTH_COMPONENT indice din bufferul de adncime; GL_RED componenta roie a culorii din bufferul de culoare ( de adncime) ; GL_GREEN - componenta verde a culorii din bufferul de culoare ( de adncime) ; GL_BLUE - componenta albastr a culorii din bufferul de culoare ( de adncime) ; GL_ALPHA - componenta alfa a culorii din bufferul de culoare ( de adncime) ; GL_RGB culoare efectiva ; GL_RGBA culoare plus indicele alfa; GL_BGR_EXT culoare dar n format BGR; GL_BGRA_EXT culoare plus alfa n format BGRA; GL_LUMINANCE luminozitatea; GL_LUMINANCE_ALPHA luminozitatea plus alfa; De exemplu pentru a salva o anumit regiune dintr-un ecran ntr-un vector, formatul va ales GL_RGB, vectorul respectiv va putea fi scris ca imagine ntr-un fiier bitmap. Tipul type are aceleai caracteristici ca i la glDrawPixels.

glReadbuffer cu prototipul urmtor permite stabilirea unei surse de pixeli color pentru o serie de funcii: void glReadBuffer(GLenum mode); , mode poate lua valorile GL_FRONT_LEFT- buffer de afiare principal stng pentru display stereoscopic; GL_FRONT_RIGHT- buffer de afiare principal drept pentru display stereoscopic; GL_BACK_LEFT- buffer de afiare secundar stng pentru display stereoscopic; GL_BACK_RIGHT- buffer de afiare secundar drept pentru display stereoscopic; GL_FRONT buffer de afiare principal; GL_BACK- buffer de afiare secundar cnd se realizeaz double buffering; GL_LEFT- buffer stng; GL_RIGHT- buffer drept; GL_AUXi buffer auxiliary;

161

In mod obinuit se va folosi apelarea: glReadBuffer(GL_FRONT); Funcia glCopyPixels cu urmtorul prototip permite copierea de pixeli ntre bufferele OpenGL: void glCopyPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type ); , unde x, y, width, height specific regiunea ce se copie i n care se copie, , type specific bufferul n care se copie, bufferul din care se copie fiind specificat prin glReadBuffer. Type poate lua valorile: GL_COLOR destinaia este bufferul de afiare curent; GL_DEPTH destinaia este bufferul de adncime; GL_STENCIL destinaia este bufferul ablon. Exerciiu 1. Alocai un vector de tip GLubyte ( cu funcia malloc) n care s pstrai o imagine pe 24 de bii. Imaginea va conine steagul Romniei culorile rou, galben i albastru. Lungimea imaginii va fi de dou ori nlimea. Afiai steagul. Acelai lucru pentru steagul Franei i Germaniei. Afiai la final imaginea fiecrui steag n acelai ecran. Creai o funcie care s selecteze steagurile. Schimbarea steagului selectat se va face apsnd bara de spaiu. Steagurile au aceeai mrime, sunt desenate pe acelai rnd, Steagul selectat va fi adus mai n fa dect celelalte neselectate.

4.9.2 ncrcarea unei imagini bitmap din fiier


n continuare se va prezenta o funcie de ncrcare ntr-o structur din memorie a unei imagini bitmap pe 24 de bii: struct bmptype{ GLubyte *bits; BITMAPFILEHEADER bmpheader; BITMAPINFOHEADER bmpinfo; }; bmptype imaginebmp; int bmpload(char *bmpfilename,bmptype *bmp) { FILE *fp; int infosize,bitsize; 162

if ((fp = fopen(bmpfilename, "rb")) == NULL) return (NULL); fread(&bmp->bmpheader, sizeof(BITMAPFILEHEADER), 1, fp); if (bmp->bmpheader.bfType != 'MB') { fclose(fp); return (NULL); } else { infosize = bmp->bmpheader.bfOffBits - sizeof(BITMAPFILEHEADER); fread (&bmp->bmpinfo, 1, infosize, fp); if ((bitsize = bmp->bmpinfo.biSizeImage) == 0) bitsize = bmp->bmpinfo.biWidth * (bmp->bmpinfo.biBitCount + 7) / 8 * abs(bmp->bmpinfo.biHeight); bmp->bits = (GLubyte *)malloc(bitsize); fread(bmp->bits, 1, bitsize, fp); fclose(fp); } }

Se observ c se aloc n funcia de citirea a fiierului i memorie pentru vectorul ce conine imaginea. Bmpfilename este numele fiierului de tip bitmap ce se deschide. Exemplu de utilizare: Pentru ncarcare: bmpload(romania.bmp,imaginebmp); Pentru afiare: glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelZoom(1, 1); glRasterPos3f(-15,-11,-20); glDrawPixels(imaginebmp.bmpinfo.biWidth, imaginebmp.bmpinfo.biHeight, GL_RGB, GL_UNSIGNED_BYTE imaginebmp.,bits); 163

Exerciiu 2. Folosind funcia de ncrcare de bitmapuri, ncrcai steagurile oficiale ale Romniei, Marii Britanii, Franei, Germaniei, Grecie, UE i creai un program de selectarea ca cel anterior.

164

Programare Grafic OpenGL

4.10 Lucrare de laborator 10. 4.10.1 Aplicarea texturilor


Pn acum s-au creat obiecte, s-au iluminat, s-au creat efecte de reflexie. Totui obiectele create dei au form i culoare nc nu seamn prea bine cu cele din realitate. Acest lucru se poate rezolva aplicndu-le o textur. Dac se dispune de forma real i de o textur potrivit, combinate cu un efect de iluminare i o modalitate de creare realistic a umbrelor , imaginea obiectului simulat fa de cel real va fi greu sau chiar imposibil de deosebit cu ochiul liber. Ceea ce ofer OpenGL este o imagine care se apropie n proporie de 80 90 % de imaginea obiectului real. n jocurile actuale aceasta valoare poate fi mpins pn la 95%, iar n editoarele specializate, profesionale de grafic 3D aceasta poate fi mpins pn la 98-99% i chiar 99.7% diferenele fiind practic insesizabile. Ce nseamn o textur? O textur este o imagine bidimensional ( sau unidimensional) care acoper o anumit suprafa a unui corp, n special cea vizibil, mulndu-se de obicei dup forma corpului. Texturarea este procesul de asociere dintre o anumit suprafa i o imagine. n OpenGL pentru texturare se pot folosi imagini uni- i bidimensionale.

4.10.2 Texturarea unidimensional


Texturarea unidimensional sau 1D folosete drept textur un singur rnd de pixeli. Este o texturare nepretenioas rapid. Ea poate fi utilizat pentru texturarea unui curcubeu sau a inelelor unei planete (Saturn de exemplu). Pentru a specifica o texturare 1D se folosete funcia cu prototipul: void glTexImage1D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); , unde target specific tipul texturii totdeauna egal cu GL_TEXTURE_1D, level specific nivelul de detaliu al texturii , 0 este nivelul de baz, internalformat, poate fi o valoare 1,2,3 sau 4 sau una din constantele : GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_ALPHA12, GL_ALPHA16, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, GL_LUMINANCE12, GL_LUMINANCE16, GL_LUMINANCE_ALPHA, GL_LUMINANCE4_ALPHA4, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12, GL_LUMINANCE16_ALPHA16, GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, GL_INTENSITY12, GL_INTENSITY16, GL_RGB, GL_R3_G3_B2, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12, 165

GL_RGB16, GL_RGBA, GL_RGBA2, GL_RGBA4, GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2, GL_RGBA12 sau GL_RGBA16. width lungime liniei de culoare, sau a dimensiuni texturii ; border grosimea marginii poate fi 0 sau 1 ; format este formatul pixelilor texturii poate fi : GL_COLOR_INDEX GL_RED GL_GREEN GL_BLUE GL_ALPHA GL_RGBA GL_BGR_EXT GL_BGRA_EXT GL_LUMINANCE GL_LUMINANCE_ALPHA constante descrise n laboratoarele precedente. type este tipul elementelor vectorului n care este definit textura; pixels este chiar vectorul n care se afl textura; Exemplu : glTexParameteri(GL_TEXTURE_1D, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_LINEAR); glTexImage1D(GL_TEXTURE_1D, GL_UNSIGNED_BYTE, textura); GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MIN_FILTER, 0, 3, 8, 0, GL_RGB,

Se observ folosirea funciei de configurare a modului de texturare. n exemplu se specific o tranziie liniar pentru zon texturat mai mare, respectiv mai mic dect rezoluia texturii. Pentru a activa texturarea 1D se folosete urmtoarea linie de cod : glEnable(GL_TEXTURE_1D); , aceasta se plaseaz n program naintea oricrei afiri de obiecte texturate 1D. Pentru a specifica poziia n cadrul texturii pe baza creia se va textura o regiune se folosete funcia cu prototipul : void glTexCoord1f( GLfloat poz); , poz este o valoare cuprins ntre 0.0 i 1.0 respectiv nceputul texturii i sfritul ei. 166

4.10.3 Texturarea 2D
Pentru a textura un obiect cu o textur bidimensional (o imagine) se poate folosi funcia cu prototipul : void glTexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); ,unde target va fi ntotdeauna egal cu GL_TEXTURE_2D, level nivelul de detaliu al texturrii 0 nivel de baz imaginea original, n nivel redus al detaliului fa de imaginea de baz ; internalformat acelai ca la texturarea 1D ; width, height lungimea, nlimea texturii ; border grosimea marginii poate fi 0 sau 1; format acelai ca la texturarea 1D; type - acelai ca la texturarea 1D; pixels textura bidimensional sub forma unui vector ; Exemplu : glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glTexImage2D(GL_TEXTURE_2D, 0, 3, info->bmiHeader.biWidth, info->bmiHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb); Pentru a specifica coordonatele texturii vom folosi o varianta a funciei glTexCoord : void glTexCoord2f( GLfloat s, GLfloat t); Coordonatele unei texturi sunt date prin folosirea indicilor s,t,r,q. Pentru texturi 2D sunt utili doar s,t. acestea specificnd coordinate n cadrul texturii. Ei variaz ntre 0.0 i 1.0, valori prin care parcurge ntreaga suprafa a texturii. Pentru texturi se pot seta anumii parametri de texturare prin intermediul funciei cu prototipul: void glTexParameteri(GLenum target, GLenum pname, GLint param); 167

,unde target poate lua valorile GL_TEXTURE_1D sau GL_TEXTURE_2D, n funcie de textura la care ne referim; pname poate lua una din valorile : GL_TEXTURE_MIN_FILTER specific comportarea texturrii cnd suprafaa texturat are o ntindere n pixeli mai mic dect cea a texturii; GL_TEXTURE_MAG_FILTER - specific comportarea texturrii cnd suprafaa texturat are o ntindere n pixeli mai mare dect cea a texturii ; GL_TEXTURE_WRAP_S specific modul de texturare dup s cnd zona texturat este mai mare dect textura folosit ; GL_TEXTURE_WRAP_T - specific modul de texturare dup s cnd zona texturat este mai mare dect textura folosit ; param specific o valoare pentru proprietatea specificat n pname: pentru GL_TEXTURE_MIN_FILTER / GL_TEXTURE_MAG_FILTER poate fi una valorile GL_NEAREST returneaz pixelul cel mai aproape de centru; GL_LINEAR - aproximeaz liniar textura; GL_NEAREST_MIPMAP_NEAREST pixelul se obine din texturi mipmap GL_LINEAR_MIPMAP_NEAREST pixelul se obine din texturi mipmap GL_NEAREST_MIPMAP_LINEAR pixelul se obine din texturi mipmap GL_LINEAR_MIPMAP_LINEAR pixelul se obine din texturi mipmap pentru GL_TEXTURE_WRAP_S / GL_TEXTURE_WRAP_T se pot alege valorile: GL_CLAMP dac s-a depit textura nu se mai deseneaz nimic; GL_REPEAT dac s-a depit textura se reia aceeai textur prin repetare; O alt funcie de configurare ar fi glTexEnv cu prototipul : void glTexEnvi( GLenum target, GLenum pname, GLint param); La care: target este scopul funciei aceste trebuie s fie GL_TEXTURE_ENV( Env vine de la Environment ce se traduce prin mediu, adic mediul OpenGL) pname trebuie s fie setat or pe GL_TEXTURE_ENV_MODE or pe GL_TEXTURE_ENV_COLOR param poate fi una din constantele : GL_MODULATE realizeaz un produs ntre textur i bufferul de afiare; GL_DECAL textura este afiata direct pe ecran; GL_BLEND - textura este combinat cu o culoare nainte de a fi afiat pe ecran; Pentru GL_TEXTURE_ENV_COLOR se va specifica culoarea de combinare ;

168

n mod obinuit se folosete apelarea : glTexEnvi(GL_TEXTURE_ENV, GL_DECAL); GL_TEXTURE_ENV_MODE,

Un alt aspect este generarea automat a coordonatelor texturilor. Pentru a activa aceast obiune se folosesc secvenele: glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); Pentru a configura generarea : static GLint s_vector[4] = { 2, 0, 0, 0 }; static GLint t_vector[4] = { 0, 0, 2, 0 }; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeniv(GL_S, GL_OBJECT_PLANE, s_vector); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeniv(GL_T, GL_OBJECT_PLANE, t_vector); Un s_vector i t_vector sunt folosii ca parametri ntr-o expresie care genereaz valoare efectiv a coordonatei texturii pe suprafaa texturat astfel : g= v[0]*x+v[1]*y+v[2]*z+v[3]*w; ,unde g este coordonata de texturare generat, x,y,z,w coordinate ale punctului de pe suprafa, v este vectorul specificat n exemplu fie prin s_vector fie prin t_vector. Exerciiu 1. Texturai o piramid cu o textur care s creeze efectul de trepte. Mai nti calculai texturile i afiai apoi ncercai o generare automat a coordonatelor de texturare. Exerciiu 2. Creai un cilindru pe care s-l texturai.

169

4.10.4 Utilizarea texturilor mipmap


Texturile mipmap se folosesc pentru a crete vitez de procesare, pentru suprafee ndeprtate se folosesc texturi cu rezoluie inferioar, n timp ce pentru a aceleai suprafee apropiate se folosesc texturi cu cea mai bun rezoluie disponibile. OpenGL genereaz plecnd de la o imagine de baz texturi cu rezoluii njumtite, pe cte nivele se dorete. Pentru a specifica folosirea texturilor mipmap respectiv generarea acestora se poate folosi o secven asemntoare cu urmtoarea:

// pentru texturi 1D glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); gluBuild1DMipmaps(GL_TEXTURE_1D, 3, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, roygbiv_image); // pentru texturi 2D glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, info->bmiHeader.biWidth, info->bmiHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb); Aceste funcii au prototipurile: int gluBuild1DMipmaps( GLenum target, GLint components, GLint width, GLenum format,GLenum type, const void *data ); int gluBuild2DMipmaps( GLenum target, GLint components, GLint width, GLint height, GLenum format, GLenum type, 170

const void *data ); Se observ c sunt aceeai parametrii de la glTexImage. Texturile care vor fi generate vor trebui ncrcate cu glTexImage specificnd prin level nivelul mipmap utilizat. Este recomandat ca la ncrcarea texturilor s se foloseasc liste de afiare care reduc mult timpul de procesare. Exerciiu 3. Desenai un dreptunghi care va fi texturat cu o imagine de nalt rezoluie. Imaginea va fi centrat pe ecran, la apsare tastei sus imaginea se va apropia, la apsare tastei jos imaginea se va deprta. Utilizai mipmap i listele de afiare pentru a optimiza programul.

171

Programare Grafic OpenGL

4.11 Lucrare de laborator 11. 4.11.1 Cuadrice


Alternativa la obiectele grafice predefinite n glaux sunt o serie de obiecte definite n glu, obiecte care sunt grupate sub denumirea de cuadrice. Acestea sunt: - gluSphere deseneaz o sfer; - gluCylinder deseneaz un cilindru; - gluDisk deseneaz un disc; - gluPartialDisk deseneaz un fragment de disc; Spre deosebire de sfera desenat prin glaux sfera generat prin cuadrice poate fi configurat, calitatea obiectului, a formei, poate fi mbuntit, desigur cu timpi de procesare suplimentari. Pentru a putea afia o cuadric mai nti trebuie creat, iar la sfrit dup ce s-a ncheiat lucrul cu ea trebuie dealocat. Astfel avem funciile cu urmtoarele prototipuri : pentru crearea de cuadrice: GLUquadricObj* gluNewQuadric( void); pentru dealocarea de cuadrice: void gluDeleteQuadric( GLUquadricObj *state ); , exemplu: myquadric=gluNewQuadric(); gluDeleteQuadric(myquadric);

, pentru a configura o cuadrica vom folosi secvena: gluQuadricDrawStyle(myquadric,GLU_FILL);//1 gluQuadricNormals(myquadric,GLU_SMOOTH); //2 gluQuadricOrientation(myquadric,GLU_OUTSIDE); //3 gluQuadricTexture(myquadric,GL_TRUE); //4 172

Linia 1 specific c modelul va fi acoperit n ntregime. Linia 2 specific c normalele vor fi generate pentru un aspect lin, fin al suprafeei. Linia 3 specific orientarea normalelor cuadricei spre exterior; Linie 4 specific c cuadrica va fi texturat. Aceste funcii au urmtoarele prototipuri: void gluQuadricDrawStyle( GLUquadricObj *qobj, GLenum drawStyle); void gluQuadricNormals( GLUquadricObj *qobj, GLenum normals); void gluQuadricOrientation( GLUquadricObj *quadObject, GLenum orientation); void gluQuadricTexture( GLUquadricObj *quadObject, GLboolean textureCoords); unde drawStyle specific stilul de desenat al cuadricei: GLU_FILL cuadrica va fi desenata prin poligoane umplute; GLU_LINE cuadrica va fi desenata din linii; GLU_SILHUETTE cuadrica este desenata prin linii, cu cteva excepii, n care unele linii nu se mai traseaz; GLU_POINT cuadrica este desenat numai prin vrfurile poligoanelor componente; pentru normals sunt disponibile dou opiuni: GLU_NONE nu se genereaz normale ; GLU_FLAT pentru fiecare faet a cuadricei se genereaz cte o normal ; GLU_SMOOTH este generat cte o normal pentru fiecare vrf al cuadricei ; pentru orientation avem : GLU_INSIDE normalele sunt orientate spre interior ; GLU_OUTSIDE normalele sunt orientate spre exterior ; pentru texturare exist doar dou opiuni GL_TRUE sau GL_FALSE. Funciile care deseneaz efectiv cuadricele au prototipurile: void gluSphere( GLUquadricObj *qobj, GLdouble radius, GLint slices, GLint stacks); void gluCylinder( GLUquadricObj *qobj, GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks); void gluDisk( GLUquadricObj *qobj, GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops); 173

void gluPartialDisk( GLUquadricObj *qobj, GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops, GLdouble startAngle, GLdouble sweepAngle); Se observ c slices este caracteristic pentru toate cuadricele acesta specific numrul de buci n care va fi descompus corpul geometric, cu ct acesta este mai mare cu att aspectul corpului va fi mai precis. Al doilea element de descompunere este stacks sau loops, care descompune pe cealalt ax analizabil corpul geometric. Pentru a defini parametrii efectivi geometrici pentru sfer s-a dat doar raza Radius, pentru cilindru raza bazei baseRadius, raza captului superior topRadius, i nlimea. Pentru disc s-a dat doar raza intern innerRadius i cea extern outerRadius. Pentru discul parial s-a dat i unghiul de nceput al seciunii startAngle i valoarea unghiului de acoperit sweepAngle. Exerciiu 1. Creai patru cuadrice cte una de acelai tip, i cam de aceleai dimensiuni i afiai-le pe toate n aceeai fereastr. Exerciiu 2.Pentru programul precedent la apsare barei de spaiu, toate cuadricele vor fi afiate pe rnd n cele patru stiluri de desenare. Exerciiu 3.Pentru cuadrica de tip sfer, setai iluminarea,o lumin, i materialul sferei. Alegei stilul de desenare plin. Prin tastele direcionale, cretei sau scdei cu o unitate numrul de slices sau de stacks, i afiai schimbarea. Exerciiu 4. Pentru o sfer ncercai s o texturai cu bitmapul numit moon.bmp. Afiai. Acum ncercai s creai o secven de program astfel nct prin tastele direcionale s rotii sfera. Vei folosi texturarea i ncrcarea de bitmapuri din laboratoarele anterioare. Exerciiu 5. Creai modelul Soare, Luna, Pmnt, fiecare fiind o cuadrica. Soarele va fi o sfer galben lucioas. Pentru Lun si Pamant se folosesc texturile moon.bmp i earth.bmp. La rularea programului sferele s se afle n micare. Luna va avea o raz jumtate din raza Pmntului. Iar Soarele o raz de trei ori cte cea Pmntului. Pe baza funciei glLookAt i a tastelor direcionale deplasai-v prin sistemul solar creat.

174

Exemplu de texturare a Lunii:

Exemplu de texturare a Terrei:

Exemplu de texturare a unui cilindru:

175

Programare Grafic OpenGL

4.12 Lucrare de laborator 12. 4.12.1 Lucrul cu bufferele n OpenGL


Operaiile de afiare n OpenGL se fac prin intermediul bufferelor. Acestea sunt zone de memorie care acoper (mapeaz) suprafaa ferestrei de lucru, fiecrui pixel din fereastra de lucru corespunzndu-i un pixel din buffer. Exist mai multe tipuri de buffere. Exist un buffer de afiare numite buffer de culoare,un buffer de culoare secundar pentru creterea calitii animaiei,un buffer de adncime, un buffer ablon (stencil), un buffer de acumulare.

4.12.2 Bufferul de culoare


La bufferul de culoare fiecare element din buffer constituie culoarea unui pixel, fie ea un indice de culoare, fie un set de componente de culoare RGBA. n OpenGL pentru a realiza minimum de afiare grafic avem nevoie doar de un buffer de culoare numit i buffer principal, buffer frontal sau buffer vizibil. Ori de cte ori se face o desenare vizibil, aceasta se face n acest buffer, dac desenm n alt buffer trebuie s transferm informaia din bufferele respective n acest buffer pentru a o face vizibil. Pentru a preciza c desenare se face direct n acest buffer n glaux folosim secvena: auxInitDisplay(AUX_SINGLE | AUX_RGBA) ; La animaii sau la desenarea de scene complexe observm c se produc plpiri, aceasta deoarece n timpul desenrii se reactualizeaz n permanen suprafaa ecranului prin citirea acestui buffer, astfel chiar dac suntem n mijlocul unei desenri, se va afia pe ecran coninutul bufferului. Pentru a evita acest lucru vom folosi dou buffere cel vizibil, discutat anterior, i unul invizibil un buffer secundar. Odat ce s-a specificat c se lucreaz cu dou buffere toate desenele ce se vor face din acel moment vor fi desenate n bufferul invizibil. Astfel vom desena tot ce dorim n bufferul secundar iar dup ce operaiile de desenare s-au terminat vom transfera datele din acest buffer n bufferul principal ce este vizibil. Acest transfer este ndeajuns de rapid pentru a se evita plpirea. n glaux pentru a specifica c se va lucra cu dou buffere se folosete secvena: auxInitDisplay(AUX_DOUBLE | AUX_RGBA) ; , iar n Win32, acest mod de lucru este implicit, dar cu toate acestea trebuie specificat prin folosirea constantei PFD_DOUBLEBUFFER. Pentru a transfera datele din bufferul invizibil n cel vizibil se folosete o funcie care n glaux este : auxSwapBuffers( ) ; 176

iar n Win32 : SwapBuffers(hDC) ; , unde hDC este dispozitivul de context ataat ferestrei aplicaiei. Totui dac se dorete schimbarea setrii implicite prin care desenarea se face n bufferul secundar. Se poate folosi funcia cu prototipul : void glDrawBuffer( GLenum mode ); ,unde mode specific bufferul n care OpenGL va desena acesta fiind specificat prin urmtoarele constante: GL_NONE nu se va desena n nici un buffer; GL_FRONT_LEFT specific bufferul principal stng pentru aplicaii stereoscopice; GL_FRONT_RIGHT - specific bufferul principal drept pentru aplicaii stereoscopice; GL_BACK_LEFT - specific bufferul secundar stng pentru aplicaii stereoscopice; GL_BACK_RIGHT specific bufferul secundar drept pentru aplicaii stereoscopice; GL_FRONT specific bufferul principal; GL_BACK specific bufferul secundar; GL_LEFT - specific bufferul stng att cel principal ct i cel secundar, pentru aplicaii stereoscopice; GL_RIGHT specific bufferul drept att cel principal ct i cel secundar, pentru aplicaii stereoscopice; GL_FRONT_AND_BACK - specific att bufferul principal ct i cel secundar, ct i bufferele stng i drept ale acestora; GL_AUXi specific un buffer auxiliar i, i fiind o valoare ntre 0 i GL_AUX_BUFFERS; n mod implicit pentru lucrul cu un singur buffer mode este setat la GL_FRONT, iar pentru lucrul cu dou buffere mode este setat la GL_BACK. Exerciiu 1. Creai o aplicaie n care animai un corp folosind glaux. Setai mai nti utilizare unui mod de lucru cu un singur buffer, apoi cu dou buffere. Observai schimbrile n calitatea animaiei.

177

4.12.3 Bufferul de adncime


Atunci cnd se creeaz o scen complex, sau un obiect compus din mai multe poligoane, se dorete ca poligoanele din spate s nu apra desenate peste cele din fa. Sau la intersecii de suprafee s se deseneze partea din suprafa vizibil i nu cea invizibil. Acest lucru s-a rezolvat prin ataarea la bufferul de culoare a unui buffer de adncime. n bufferul de adncime se pstreaz poziia pe oz, a punctului desenat n bufferul de culoare cu o anumit precizie. Astfel dac se va desena o nou obiect, adncimea punctelor noului obiect va fi comparat cu cea din bufferul de adncime, dac va fi mai mic aceste puncte( condiie ce se analizeaz pentru fiecare punct n parte) vor fi desenate n bufferul de culoare i se va actualiza valorile de adncime din bufferul de adncime, altfel nici unul dintre aceste buffere nu va fi modificat. Pentru a activa folosirea bufferelor de adncime se va utiliza secvena: glEnable(GL_DEPTH_TEST); Pentru a stabili condiia de alterare a bufferelor, se va folosi funcia cu urmtorul prototip: void glDepthFunc( GLenum func ); , unde func este o condiie, care implicit este GL_LESS adic dac adncime sau coordonat pe Oz a pixelului este mai mic dect a celui anterior desenat ( la poziia respectiv de pe ecran, buffer) atunci acesta va fi desenat pot fi precizate i alte condiii prin urmtoarele constante: GL_NEVER - afiare nu este permis; GL_LESS afiarea este permis dac Z nou < Z vechi; GL_EQUAL afiarea este permis dac Z nou = Z vechi. GL_LEQUAL afiarea este permis dac Z nou <= Z vechi. GL_GREATER afiarea este permis dac Z nou > Z vechi. GL_NOTEQUAL afiarea este permis dac Z nou difer de Z vechi. GL_GEQUAL afiarea este permis dac Z nou >= Z vechi. GL_ALWAYS modificare este permis oricnd. Pe lng aceste funcii mai sunt disponibile i altele pentru configurarea lucrului cu buffere de adncime n OpenGL acestea au urmtoarele prototipuri: void glDepthRange( GLclampd znear, GLclampd zfar );

, care stabilete limitele ntre care se ncadreaz factorii de adncime n mod implicit acestea fiind 0.0 pentru znear i 1.0 pentru zfar; void glClearDepth( GLclampd depth); 178

, care stabilete valoare de tergere a bufferului de adncime, implicit aceasta fiind egal 1.0. Atunci cnd se terge bufferul de culoare trebuie s se tearg i cel de a adncime altfel, la o nou scen vor fi luate n considerare adncimile punctelor precedente, aceasta se face cu secvena: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); Crearea efectului de secionare folosind bufferul de adncime Putem folosi urmtoarea secven: glDrawBuffer(GL_NONE); glBegin(GL_POLYGON); glVertex3f(-100.0, 100.0, cutting_plane); glVertex3f(100.0, 100.0, cutting_plane); glVertex3f(100.0, -100.0, cutting_plane); glVertex3f(-100.0, -100.0, cutting_plane); glEnd(); glDrawBuffer(GL_BACK); , ia funcioneaz n felul urmtor nainte de secven desenm corpul, apoi desenm un plan de secionare ntr-un buffer de culoare inexistent, fiind afectat doar planul de adncime, tot ce este n spatele planului de secionare nu v-a mai fi afiat, planul efectiv va fi invizibil. Se observ c dup trasarea acestui plan, se revine la modul normal de afiare. Aceast secven nltur prin secionare doar partea din spate. Exerciiu 2. Creai un program care s secioneze un corp afind doar partea din spate, acest corp va fi un ceainic (auxSolidTeapot), vei folosi secvena precedent, plus funcia glDepthFunc ( ). Precizia de calculare a adncimii pentru acest buffer poate fi de 16bii sau de 32 de bii, valoare implicit este de 32 de bii. Cu ct aceast precizie este mai mare scena va putea fi mai complex.

179

4.12.4 Folosirea bufferului ablon


Bufferul ablon (stencil) permite pstrarea anumitor zone din fereastr. Astfel dac se proiecteaz un simulator de zbor, sau de curse, bordul avionului, sau cel al mainii rmne neschimbat comparativ cu mediul exterior, pentru aceasta se poate folosi bufferul ablon. Bufferul ablon are o abordare asemntoare cu a bufferului de adncime, avnd cu toate aceste a serie de funcii specifice. Pentru a activa bufferul ablon vom folosi secvena: glEnable(GL_STENCIL_TEST); n Win32 la specificatorul de format pentru pixel trebuie setat cStencilBits la 1( adic fiecrui pixel i se va asocia doar un singur bit n ablon) Pentru se specifica n glaux folosirea bufferului de tip ablon se folosete secvena: auxInitDisplay( AUX_STENCIL); AUX_RGB | AUX_DOUBLE | AUX_DEPTH |

n plus se mai folosesc funciile: void glClearStencil(GLint s); , care stabilete valoare prin care se va terge bufferul ablon; void glStencilFunc(GLenum func, GLint ref, GLuint mask) , stabilete care puncte vor fi nlocuite i care pstrate, - func este acelai cal glDepthFunc - ref este o valoare de refein a bufferului ablon; - mask este valoarea prin care se specific o condiie suplimentar pentru pstrarea unui pixel; void glStencilMask(GLuint mask) , seteaz condiia de modificare a unui pixel, de obicei se folosete valoarea 1, pentru masc; void glStencilOp(GLenum fail, GLenum zfail, GLzpass) , stabilete testele pentru trecerea prin ablon: fail specific ce se ntmpl dac pixelul nu a trecut de testul ablon aceasta este definit prin constantele : GL_KEEP se pstreaz valoarea din ablon; GL_ZERO se seteaz cu 0 valoarea din ablon; GL_REPLACE se nlocuiete valoarea din ablon; 180

GL_INCR se incrementeaz valoarea din ablon; GL_DECR se decrementeaz valoarea din ablon; GL_INVERT neag pe bii valoare din ablon; zfail stabilete aciunea ce se ntreprinde dac testul ablon este trecut dar nu sa trecut de testul de adncime (aciunea este descris de aceleai constante de mai nainte) ; zpass stabilete aciunea ce se ntreprinde dac s-a trecut de testul ablon i de testul de adncime ; Exemplu : glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); sau glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);

n plus mai este secvena de tergere complet a bufferului ablon: glClear(GL_STENCIL_BUFFER_BIT); Exerciiu 3. Creai un program n care s animai un corp solid. Corpul va fi vzut printr-o deschidere circular poziionat n mijlocul ecranului. Vei folosi bufferele ablon.

4.12.5 Folosirea bufferului de acumulare


Bufferul de acumulare poate fi folosit la cumularea, adunare de imagini de afiare, peste alte imagini, putnd fi folosit pentru a simula efecte de inerie a vederii la care marginile corpului n micare sunt vizualizate nceoat, suprapus. Sau mai poate fi folosit pentru o trecere mai lin de la muchiile ce delimiteaz un corp la mediul ambiant (anti aliasing). Pentru a activa folosirea bufferului de acumulare se folosete: pentru Win32 se seteaz cAcumBits la o valoare diferit de 0, pentru glaux se folosete secvena: auxInitDisplayMode(AUX_RGB | AUX_DOUBLE | AUX_DEPTH | AUX_ACCUM); , se observ folosirea constantei AUX_ACCUM.

181

Pentru a specifica modul cum se face acumularea n acest buffer se folosete funcia cu prototipul : void glAccum( GLenum op, GLfloat value ); ,unde op specific acest mod prin constantele: GL_ACCUM valoare componentelor culorii (0.0 1.0) este citit din bufferul surs specificat prin glReadBuffer, nmulit cu value i adunat la valoarea din bufferul de acumulare; GL_LOAD - valoare componentelor culorii (0.0 1.0) este citit din bufferul surs specificat prin glReadBuffer, nmulit cu value i scris direct n bufferul de acumulare nlocuind valoare precedent; GL_ADD - adun valoare specificat de value la fiecare component a culorii (RGBA) specificat n bufferul de acumulare; GL_MULT - nmulete fiecare component a culorii din bufferul de acumulare cu value i produsul obinut este pus n bufferul de acumulare; GL_RETURN transfer datele din bufferul de acumulare n bufferul de afiare, mai nti nmulind fiecare componenet cu value i normaliznd-o pentru intervalul 0.0-1.0. , value este o valoare ntre 0.0 i 1.0 prin care configureaz acumularea; Exemplu: // se deseneaz scena ce va fi ncetosata draw_frame(0); // transferm in bufferul de acumulare 50% din intensitatea pixelilor //din scena glAccum(GL_LOAD, 0.5); // redesenam de zece ori scena in la momente de timp successive // si acumulam in bufferul de acumulare 5% din intensitatea pixelor din // aceste secvente cadru for (i = 1; i <= 10; i ++) { draw_frame(-i); glAccum(GL_ACCUM, 0.05); }; // afisam continutul bufferului de acumulare glAccum(GL_RETURN, 1.0); Exerciiu 4. Creai un program pe baza secvenei prezentate n care un corp n rotaie sau alt gen de micare s prezinte astfel de nceori ca urmare a ineriei ochiului.

182

Programare Grafic OpenGL

4.13 Lucrare de laborator 13 4.13.1 Efecte speciale n OpenGL


OpenGL punea la dispoziia programatorului o serie de efecte speciale predefinite, din care dou ceaa (fog) i mbinarea(blend) sunt cele mai utilizate. Dei au fost concepute viznd n principal scopul specificat prin denumire n anumite configuraii se pot crea i alte genuri de efecte surprinztoare cu ajutorul acestora dou i lucrul cu bufferul de acumulare sau componenta alfa a culorii.

4.13.2 Crearea efectului de cea


Efectul de cea n OpenGL se manifesta ca o diminuare a culorii obiectelor scenei, pn la dispariia complet a acestora. Culorile obiectelor sunt alterate prin culoarea ceii fcndu-se o trecere gradual de la culoarea corpului la cea a ceii. Trecerea poate fi mai lin sau mai abrupt n funcie de parametrii configurabili ai ceii. Totui ceaa n OpenGL, nu este mai mult dect acest lucru. nchipuirea c prin cea sar dispune de nite mase de aburi sub forma unor nori sau pcle care s-ar putea dispune convenabil n faa sau printre obiecte, nu este situaia de fapt a ceii standard din OpenGL. Totui efectul prezentat anterior se poate obine cu mai mult efort prin folosirea unor combinaii de efecte. Ceaa se poate configura pentru fiecare obiect n parte sau pentru un grup de obiect. Pentru a activa ceaa se folosete secvena: glEnable(GL_FOG); , iar pentru a o dezactiva: glDisable(GL_FOG); Pentru a configura ceaa se poate folosi secvena : glFogf(GL_FOG_MODE, GL_LINEAR); glFogfv(GL_FOG_COLOR, fog_color); Funcia glFogf specific modul de estompare al luminii ce traverseaz ceaa, ea are urmtorul prototip: void glFogf( GLenum pname, GLfloat param); , unde pname specfic parametrul configurat: GL_FOG_MODE - specific funcia de estompare( atenuare) folosit, pentru aceasta param poate lua valorile: GL_LINEAR funcie liniara; GL_EXP funcie exponenial; 183

GL_EXP2 funcie exponenial ptratic; GL_FOG_DENSITY specific densitatea ceii implicit param este 1.0, acesta trebuie s fie pozitiv folosit pentru atenuarea exponenial; GL_FOG_START - pentru a specifica poziia pe oz de nceput al ceii,care implicit este 0.0, folosit pentru atenuare liniar; GL_FOG_END pentru a specifica poziia pe oz de deprtare a zonei de cea , implicit este 1.0, folosit pentru atenuare liniar ; GL_FOG_INDEX - pentru a specifica indicele de cea, implicit este 0.0; GL_FOG_COLOR - pentru a specifica culoarea ceii - unde param este un vector de patru elemente este folosit n combinaie cu varianta glFogfv sau glFogiv a funciei. O alt secven folosit este : glHint (GL_FOG_HINT, GL_NICEST); ,care specific calitatea maxim a efectului de cea n dauna vitezei de procesare, alt variant ar fi fost folosire constantei GL_FASTEST care pune accentul de vitez. Exemplu de folosire a ceii:

184

n care ceaa s-a configurat cu secvena: glEnable(GL_FOG); glFogf(GL_FOG_MODE,GL_LINEAR); glFogfv(GL_FOG_COLOR,fog_color); glFogf(GL_FOG_DENSITY, FogDensity); glFogf (GL_FOG_START, -maxim(30,400.0*(1-FogDensity))); glFogf (GL_FOG_END, maxim(30,400.0*(1-FogDensity))); Exerciiu 1.Creai un program n care s putei selecta cele trei tipuri de extompri specifice ceii liniar, exponenial, exponenial ptratic prin apsare unei taste. Vei lucra cu glaux, desennd un singur corp. Adugai programului i opiunea de a apropia deprta corpul.

4.13.3 Crearea efectului de mbinare


Cu ajutorul efectului de mbinare(blend) se pot crea corpuri transparente, de diferite culori, chiar cu anumite efecte de iluminare. Pentru a activa opiunea de mbinare se poate folosi secvena: glEnable(GL_BLEND); Pentru a configura mbinarea se folosete funcia cu prototipul: void glBlendFunc( GLenum sfactor, GLenum dfactor );

, unde sfactor specific sursa de culoare i poate lua valorile: - GL_ZERO culoare surs va fi negru (0,0,0,0) -GL_ONE culoare surs va fi alb(1,1,1,1); - GL_SRC_COLOR culoare surs propriu-zis; - GL_DST_COLOR culoare surs este nmulit prin culoare destinaie; - GL_ONE_MINUS_DST_COLOR culoarea surs este nmulit cu 1 minus culoarea destinaiei; - GL_SRC_ALPHA culoarea sursei este nmulit cu alfa sursei; - GL_ONE_MINUS_SRC_ALPHA culoarea sursei este nmulit cu 1 minus alfa sursei; - GL_DST_ALPHA- culoarea sursei este nmulit cu alfa destinaiei - GL_ONE_MINUS_DST_ALPHA culoarea sursei este nmulit cu 1 minus alfa destinaiei; - GL_SRC_ALPHA_SATURATE culoarea sursei este nmulit cu minimul dintre alfa sursei i 1 minus alfa destinaiei; ,iar dfactor specific culoarea destinaiei lund valori descrise de constante asemntoare: 185

GL_ZERO GL_ONE GL_SRC_COLOR GL_ONE_MINUS_SRC_COLOR GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA GL_DST_ALPHA GL_ONE_MINUS_DST_ALPHA. dar de data acesta referitoare la destinaie. Exemplu: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPushMatrix(); glTranslatef(0.0, 0.0, -15.0); glRotatef(-rotation, 0.0, 1.0, 0.0); // desenam ceainicul netransparent glDisable(GL_BLEND); glColor3f(1.0, 1.0, 0.0); auxSolidTeapot(1.0); glPopMatrix(); glPushMatrix(); glTranslatef(0.0, 0.0, -10.0); glRotatef(rotation, 0.0, 1.0, 0.0); // desenam ceainicul transparent glEnable(GL_BLEND); // se observa ca alfa este setat la 0.25 glColor4f(1.0, 1.0, 1.0, 0.25); auxSolidTeapot(1.0); glPopMatrix();

186

Exemplu de program de mbinare:

Exerciiu 2. Creai un program n care n interiorul unui cub transparent s fie poziionat un cub netransparent, rotit puin fa de cel transparent. Exerciiu 3. Modificnd programul precedent creai dou cuburi transparente unul coninndu-l pe cellalt i al doilea pe un al treilea netransparent. Aceste cuburi vor fi centrate i se vor roti n direcii diferite.

187

Programare Grafic OpenGL

4.14 Lucrare de laborator 14. 4.14.1 Curbe Bezier i Nurbs


Pn acum cu primitivele de care dispunem putem desena curbe, suprafee curbe doar prin nite structuri complicate de cod. ns mediul OpenGL pune la dispoziie nite structuri ce permit generarea unor asemenea curbe doar prin specificare unor centre de curbare i a capetelor curbelor,respectiv a marginilor suprafeelor. O abordare este cea prin evaluatori prin care construim curbe i suprafee i gestionm manual parametrii generai, o alta este folosind structurile NURBS, n care totul este prelucrat automat.

4.14.2 Curbele i suprafeele Bezier


Teoria matematic i formulele ce stau n spatele generrii acestor curbe sunt destul de complexe pentru a fi expus aici. n acest sens vom aborda acest subiect dintro perspectiv practic adic se dorete crearea unei structuri se va explica exact secvenele de cod folosite. Exemplu: glMap1f(GL_MAP1_VERTEX_3, // tipul curbei desenate 0.0f, // limita inferioar a intervalului 100.0f, // limita superioar a intervalului 3, // distanta dintre puncte n vectori nNumPoints, // numrul de puncte de control &ctrlPoints[0][0]); // vectorul punctelor de control // activm evaluatorul glEnable(GL_MAP1_VERTEX_3); // genereaz curba cu o precizie de o sut de diviziuni glBegin(GL_LINE_STRIP); for(i = 0; i <= 100; i++) { // genereaz un vrf pe baza evaluatorului specificat glEvalCoord1f((GLfloat) i); } glEnd(); Numrul de diviziuni poate di crescut n funcie de precizia grafic dorit.

188

Funcia glMap1f configureaz un evaluator de curbe unidimensional ea are urmtorul prototip: void glMap1f( GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points ); , unde target specific rezultatul dorit a fi obinut fie c se refer la nite vrfuri, fie la normale, fie la culori, fie la coordonate de texturare, el este definit prin constantele: GL_MAP1_VERTEX_3 se refer la nite vrfuri definite prin x, y, z (glVertef3f); GL_MAP1_VERTEX_4 se refer la nite vrfuri definite prin x, y, z, w(glVertef4f) ; GL_MAP1_INDEX - se refer la colori definite prin index; GL_MAP1_COLOR_4 se refer la culori RGBA(glColor4f); GL_MAP1_NORMAL se refer la o normal definit prin coordonatele vrfului x, y, z (glNormal3f); GL_MAP1_TEXTURE_COORD_1 se refer la coordonatele unei texturri cu texturi unidimensionale (glTexCoord1f); GL_MAP1_TEXTURE_COORD_2 se refer la coordonatele unei texturri cu texturi bidimensionale(glTexCoor21f) ; GL_MAP1_TEXTURE_COORD_3 se refer la coodonatele unei texturri cu texturi specificate prin s, t, r(glTexCoord3f); GL_MAP1_TEXTURE_COORD_4 se refer la coordonatele unei texturri cu texturi specificate prin s, t, r, q(glTexCoord4f); , u1,u2 valoare inferioar, respectiv superioar a maprii liniare a punctelor de pe curb ; , stride numrul de componente ale unui punct definit n vectorul points ; , order numrul de puncte de control ; , points vectorul punctelor de control ; Apoi urmeaz funcia prin care activm generarea automat e elementelor grafice prin evaluatori. glEnable(tip_element_grafic); , unde tipul este acelai ca i target. Urmeaz generarea efectiv a punctelor de ctre funcia cu prototipul: void glEvalCoord1f( GLfloat u ); , unde u este o valoare din intervalul u1, u2, cu semnificaie specificat anterior, la prototip, i-n secvena de program. 189

Exerciiu 1. Creai un program care s genereze o curb alctuit din o sut de diviziuni, aceast curb este definit de 4 puncte de control. Cu ajutorul mouselui selectai cte un punct de control la care s-i schimbai poziia, apoi s-l deselectai.

4.14.3 Evaluatori pentru suprafee.


Sunt practic identici cu cei de la curbe, diferena fiind c mai apare a coordonat. Exemplu: glMap2f(GL_MAP2_VERTEX_3, // tipul evaluatorului 0.0f, // limita inferiora a coordonatei u 10.0f, // limita superiora a coordonatei u 3, // numarul de componente al unui element al vectorului 3, // numrul de puncte de control pe direcia u 0.0f, // limita inferiora a coordonatei v 10.0f, // limita superiora a coordonatei v 9, // distanta dintre dou elemente consecutive pe v 3, // numrul de puncte de control pe direcia v &ctrlPoints[0][0][0]); // vectorul cu puncte // activam evaluatorul glEnable(GL_MAP2_VERTEX_3); // genereaz punctele suprafeei glMapGrid2f(10,0.0f,10.0f,10,0.0f,10.0f); // afieaz suprafaa sub forma unei reele de linii glEvalMesh2(GL_LINE,0,10,0,10); Funcia glMap2f are prototipul: void glMap2d( GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points ); , pentru target se vor folosi practic aceleai constante cu diferena c n loc de MAP1 vom avea MAP2; , restul sunt similare cu cele de la glMap1d; Funcia glMapGrid2f care genereaz punctele suprafeei are prototipul: 190

void glMapGrid2f( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 ); , unde un ,vn sunt numrul de diviziuni pe u i pe v; , u1,u2 sunt limitele intervalului de generare pe u( adic de la ce coordonat se ncepe generarea punctelor pe u); ,v1, v2 - sunt limitele intervalului de generare pe v;

Funcia glEvalMesh2 genereaz efectiv suprafaa. Are urmtorul prototip : void glEvalMesh2( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 ); , unde mode este definit prin constantele: GL_POINT se deseneaz doar punctele; GL_LINE se va desena o suprafa din linii; GL_FILL se va desena o suprafa continu; , i1,i2 intervalul de puncte definite n grid ce se vor afia pe u ; ,j1,j2 intervalul de puncte definite n grid ce se vor afia pe v ; Exerciiu 2. Generai o suprafa plin folosind o matrice de 3 x 3 puncte de control. Numrul de diviziuni va fi de 30 x 30. Se va selecta prin apsarea barei de spaiu n mod ciclic modul de desenare al suprafeei din cele trei moduri existente.

4.14.4 Curbele i suprafeele de tip NURBS


Acest tip de curbe este similar tipului Bezier, cu unele diferene de calcul efectiv al curbelor i de implementare OpenGL. Denumirea NURBS provine de la iniialele denumirii complete a acestui gen de curbe Non-Uniform Rational B-Spline. Curbele NURBS sunt definite n biblioteca glu i sunt apelate doar dup ce au fost create. Asfel pentru a crea o structur NURBS se folosete secvena : GLUnurbsObj *pNurb = NULL; //declaram structura pNurb = gluNewNurbsRenderer();// creem structura , la fel cnd nu se mai folosete se dealoc structura prin secvena : if(pNurb) // daca este alocata o dealocam 191

gluDeleteNurbsRenderer(pNurb); Pentru a configura o structur NURBS folosim funcia cu prototipul: void gluNurbsProperty(GLUnurbsObj *nobj, GLenum property, GLfloat value ); ,unde nobj este structura NURBS, , property este proprietatea ce se configureaz, ea este definit prin constantele: GLU_SAMPLING_TOLERANCE - specific lungimea maxim n pixeli pentru eantionarea curbei implicit este 50 , folosit mpreun cu GLU_PATH_LENGTH ; GLU_DISPLAY_MODE specific modul cum va fi desenat suprafaa sau curba - GLU_FILL trasare complet, GLU_OUTLINE_POLYGON - trasare din linii, GLU_OUTLINE_PATCH - trasarea acelor linii specificate de utilizator; GLU_CULLING genereaz eliminarea suprafeelor din afara zonelor stabilite de afiare daca este setat pe GL_TRUE, implicit este setat cu GL_FALSE; GLU_PARAMETRIC_TOLERANCE specific distana maxim n pixeli, cnd este folosit abordarea parametric, implicit este 0.5 ; GLU_SAMPLING_METHOD stabilete metoda de eantionare: GLU_PATH_LENGTH este setarea implicit,alta ar fi GLU_PARAMETRIC_ERROR, definit de GLU_PARAMETRIC_TOLERANCE, i GLU_DOMAIN_DISTANCE definit prin numrul de puncte pe u i pe v ; GLU_U_STEP specific numrul de puncte pe direcia u, pe unitate, implicit este 100.0 ; GLU_V_STEP specific numrul de puncte pe direcia v, pe unitate, implicit este 100.0 ; GLU_AUTO_LOAD_MATRIX - apeleaz automat prin internet serverul OpenGL pentru a genera matricele, de proiecie, afiare. Exemplu : gluNurbsProperty(pNurb, GLU_SAMPLING_TOLERANCE, 25.0f); gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, (GLfloat)GLU_FILL); Pentru a genera o curb NURBS se folosete funcia cu prototipul: void gluNurbsCurve( GLUnurbsObj *nobj, GLint nknots, GLfloat *knot, GLint stride, GLfloat *ctlarray, GLint order, GLenum type ); 192

,un nobj este strutura NURBS, ,nknots este numrul de noduri, ,knot este un vector de noduri, ,stride este distana dintre punctele de control din vector, ,ctlarray este vectorul de generare al curbei NURBS, ,order este ordinul curbei nurbs implicit 4, ,type este tipul evaluatorului folosit definit mai sus este setat la GL_MAP1_VERTEX3, cel mai frecvent. Aceast funcie se ncadreaz ntre gluBeginCurve(nobj) gluEndCurve(nobj).

Pentru a genera o suprafa NURBS se folosete o secven de genul : gluBeginSurface(pNurb); // creaz suprafaa gluNurbsSurface(pNurb, // structura NURBS 8, Knots, // numrul de noduri i vectorul de noduri pe s 8, Knots, // numrul de noduri i vectorul de noduri pe t 4 * 3, // Distanta dintre punctele de control pe s 3, // Distanta dintre punctele de control pe t &ctrlPoints[0][0][0], // vector cu punctele de control 4, 4, // ordinal curbei pe s i pe t GL_MAP2_VERTEX_3); // tipul evaluatorului folosit gluEndSurface(pNurb); Aceast funcie are prototipul: void gluNurbsSurface( GLUnurbsObj *nobj, GLint sknot_count, GLfloat *sknot, GLint tknot_count, GLfloat *tknot, GLint s_stride, GLint t_stride, GLfloat *ctlarray, GLint sorder, GLint torder, GLenum type );

193

Exerciiu 3. Realizai aceleai programe de la exerciiu 1 i 2 dar folosind curbe NURBS. Exerciiu 4. Realizai o suprafa NURBS ondulat texturat cu o imagine ncrcat din fiier.

Exemple de aplicaie NURBS :

194

5 BIBLIOGRAFIE
5

1. Dave Astle, Kevin Hawkins Beginning OpenGL Game Programming , Premier Press, Boston, 2004; 2. Paul Martz,OpenGL(R) Distilled (OpenGL), Addison Wesley Professional, 2006; 3. Richard S. Wright Jr., Michael R. Sweet ,OpenGL Super Bible, Waite Group Press. ,2007; 4. Rodica Baciu , Programarea Aplicaiilor Grafice 3D cu OpenGL, Editura Albastr, Cluj-Napoca 2005; 5. The Red Book of OpenGL 6. http://www.opengl.org 7. http://www.sgi.com/software/opengl 8. http://www.cs.utah.edu/~narobins/opengl.html 9. www.mesa3d.org/

195

ELEMENTE INTRODUCTIVE

1.1 Sistemul grafic OpenGL ................................................................. 3 1.2 Sisteme grafice pentru grafica 3D .................................................. 4 1.3 Caracteristici OpenGL .................................................................... 6

BAZELE PROGRAMRII N OPENGL

8
10 11 18 28 29 33 48 50 56 62 64 81 85 100 108 109 109 110 110 114 114 115 116 117 120 120 128 128 128 129 130 130

2.1 Arhitectura OpenGL ....................................................................... 8 2.2 Descriere general OpenGL, GLU i GLAUX .............................. 10 2.2.1 OpenGL Utility Library (GLU) 2.2.2 Biblioteci disponibile 2.3 GLAUX ......................................................................................... 12 2.3.1 Funciile callback GLAUX

PRIMITIVE GEOMETRICE 26
3.1 Primitive geometrice OpenGL ...................................................... 26 3.1.1 Formatul comenzilor OpenGL 3.1.2 Specificarea primitivelor geometrice OpenGL 3.1.3 Atribute ale primitivelor de ieire 3.2 Reprezentarea curbelor i a suprafeelor curbe ........................... 47 3.2.1 Evaluatori 3.2.2 Curbe Bezier 3.2.3 Suprafee Bezier 3.2.4 Interfaa NURBS 3.2.5 Curbe NURBS 3.3 Suprafee cvadrice ....................................................................... 74 3.4 Primitive raster ............................................................................. 79 3.4.1 Reprezentarea imaginilor bitmap 3.4.2 Reprezentarea fonturilor prin bitmap-uri 3.4.3 Redarea pixmap-urilor 3.5 Utilizarea atributelor de redare n OpenGL ................................ 108 3.5.1 Controlarea strii OpenGL 3.5.2 Setarea strii curente 3.5.3 Interogarea strii i stiva de parametrii

INDRUMAR DE LABORATOR

110

4.1 Lucrare de laborator 1. ............................................................... 110 4.1.1 Introducere n OpenGL 4.1.2 Crearea unei aplicaii OpenGL 4.2 Lucrare de laborator 2. ............................................................... 114 4.2.1 Utilizarea funciilor bibliotecii glaux 4.2.2 Funcii de iniializare: 4.2.3 Funcii de interfa i de ciclare 4.2.4 Funciile de lucrul cu mouse 4.2.5 Funciile de lucru cu tastatura 4.3 Lucrare de laborator 3. ............................................................... 120 4.3.1 Aplicaii OpenGL n Win32 4.3.2 Crearea unei aplicaii Win32 necompletate 4.4 Lucrare de laborator 4. ............................................................... 128 4.4.1 Primitive grafice OpenGL 4.4.2 Desenarea de puncte 4.4.3 Desenarea de linii 4.4.4 Desenarea unui triunghi 4.4.5 Desenarea unui patrulater 4.4.6 Desenarea unui poligon

196

4.4.7 Funcii grafice auxiliare 4.4.8 Modificare mrimii punctului 4.4.9 Modificare parametrilor liniei 4.4.10 Modificare parametrilor figurilor nchise 4.5 Lucrare de laborator 5. ............................................................... 135 4.5.1 Transformri geometrice n OpenGL 4.5.2 ncrcarea i descrcarea din stiv a unei matrice 4.5.3 Transformri elementare de coordonate 4.5.4 Configurarea mediului vizual 4.6 Lucrare de laborator 6. ............................................................... 140 4.6.1 Iluminare, lumini i materiale. 4.6.2 Configurarea iluminrii 4.6.3 Configurarea materialului 4.7 Lucrare de laborator 7. ............................................................... 146 4.7.1 Generarea de umbre prin utilizarea matricelor. 4.8 Lucrare de laborator 8. ............................................................... 152 4.8.1 Utilizarea listelor 4.8.2 Crearea unei liste. 4.9 Lucrare de laborator 9. ............................................................... 157 4.9.1 Lucrul cu imagini rastru n OpenGL 4.9.2 ncrcarea unei imagini bitmap din fiier 4.10 Lucrare de laborator 10. ........................................................... 165 4.10.1 Aplicarea texturilor 4.10.2 Texturarea unidimensional 4.10.3 Texturarea 2D 4.10.4 Utilizarea texturilor mipmap 4.11 Lucrare de laborator 11. ........................................................... 172 4.11.1 Cuadrice 4.12 Lucrare de laborator 12. ........................................................... 176 4.12.1 Lucrul cu bufferele n OpenGL 4.12.2 Bufferul de culoare 4.12.3 Bufferul de adncime 4.12.4 Folosirea bufferului ablon 4.12.5 Folosirea bufferului de acumulare 4.13 Lucrare de laborator 13 ............................................................ 183 4.13.1 Efecte speciale n OpenGL 4.13.2 Crearea efectului de cea 4.13.3 Crearea efectului de mbinare 4.14 Lucrare de laborator 14. ........................................................... 188 4.14.1 Curbe Bezier i Nurbs 4.14.2 Curbele i suprafeele Bezier 4.14.3 Evaluatori pentru suprafee. 4.14.4 Curbele i suprafeele de tip NURBS

130 130 131 131 135 135 137 138 140 140 144 146 152 152 157 162 165 165 167 170 172 176 176 178 180 181 183 183 185 188 188 190 191

BIBLIOGRAFIE

195

197

You might also like