141
VI Open Graphics Library (OpenGL) C# S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 1 VI Open Graphics Library (OpenGL) C# OpenGL je standardni programski interfejs aplikacije (API Application Programming Interface) namenjen razvoju aplikacija u oblasti dvodimenzionalne i trodimenzionalne računarske grafike. OpenGL standard razvijen je i utvrđen 1992. godine od strane vodećih kompanija, koje čine OpenGL Architecture Review Board, kao efektivni hardversko-nezavisni interfejs, pogodan za realizaciju na različitim platformama. Za osnovu standarda iskorišćena je programska biblioteka IRIS GL, koju je razvila kompanija Silicon Graphics Inc (SGI). Većina proizvođača hardvera i softvera podržava OpenGL. Implementacije OpenGL standarda postoje za veliki broj platformi. Velika rasprostranjenost OpenGL standarda se bazira na sledećim osobinama: Stabilnost. Dopune i izmene standarda održavaju kompatibilnost sa prethodnim verzijama. Prenosivost. OpenGL aplikacije garantuju istovetan vizuelni rezultat nezavisno od tipa korišćenog operativnog sistema i hardvera. Lakoća upotrebe. OpenGL poseduje intuitivan i jednostavan interfejs koji omogućava razvoj efektivnih aplikacija uz manji programerski napor. Obično aplikacije koje se oslanjanju na OpenGL sadrže manji broj redova programskog kôda nego kada se koriste druge grafičke biblioteke. Specifičnosti korišćenog hardvera kao i obezbeđivanje kompatibilnosti sa različitom opremom realizovane su na nivou OpenGL implementacije. Verzija standarda koja će biti obrađena je OpenGL 2.1 verzija standarda. Više informacija o OpenGL standardu se može pronaći na Internet adresi: http://www.opengl.org/ . 6.1 Arhitektura OpenGL programske biblioteke OpenGL se sastoji od: specifikacije i implementacije. Specifikacija propisuje funkcionalnost, a implementacija realizuje specifikovanu funkcionalnost. Implementacija OpenGL standarda može biti softverska ili hardverska, slika 6.1.1. OpenGL dozvoljava softversku emulaciju (softversku implementaciju) funkcionalnosti koju hardver ne implementira. Softverska implementacija koristi raspoloživi grafički sistem (npr. GDI na Windows plaftormi) za iscrtavanje, dok hardverska koristi OpenGL kompatibilni hardver za iscrtavanje. Obično grafički hardver daje različite nivoe ubrzavanja: od hardverske realizacije generisanja linija i poligona do moćnih grafičkih procesora sa podrškom za različite operacije nad geometrijskim podacima.

Op Engl

Embed Size (px)

Citation preview

Page 1: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 1

VI Open Graphics Library (OpenGL) C# OpenGL je standardni programski interfejs aplikacije (API – Application Programming Interface) namenjen razvoju aplikacija u oblasti dvodimenzionalne i trodimenzionalne računarske grafike.

OpenGL standard razvijen je i utvrđen 1992. godine od strane vodećih kompanija, koje čine OpenGL Architecture Review Board, kao efektivni hardversko-nezavisni interfejs, pogodan za realizaciju na različitim platformama. Za osnovu standarda iskorišćena je programska biblioteka IRIS GL, koju je razvila kompanija Silicon Graphics Inc (SGI).

Većina proizvođača hardvera i softvera podržava OpenGL. Implementacije OpenGL standarda postoje za veliki broj platformi. Velika rasprostranjenost OpenGL standarda se bazira na sledećim osobinama:

� Stabilnost . Dopune i izmene standarda održavaju kompatibilnost sa prethodnim verzijama.

� Prenosivost. OpenGL aplikacije garantuju istovetan vizuelni rezultat nezavisno od tipa korišćenog operativnog sistema i hardvera.

� Lako ća upotrebe . OpenGL poseduje intuitivan i jednostavan interfejs koji omogućava razvoj efektivnih aplikacija uz manji programerski napor. Obično aplikacije koje se oslanjanju na OpenGL sadrže manji broj redova programskog kôda nego kada se koriste druge grafičke biblioteke. Specifičnosti korišćenog hardvera kao i obezbeđivanje kompatibilnosti sa različitom opremom realizovane su na nivou OpenGL implementacije.

Verzija standarda koja će biti obrađena je OpenGL 2.1 verzija standarda. Više informacija o OpenGL standardu se može pronaći na Internet adresi:

http://www.opengl.org/.

6.1 Arhitektura OpenGL programske biblioteke OpenGL se sastoji od: specifikacije i implementacije. Specifikacija propisuje funkcionalnost, a implementacija realizuje specifikovanu funkcionalnost. Implementacija OpenGL standarda može biti softverska ili hardverska, slika 6.1.1. OpenGL dozvoljava softversku emulaciju (softversku implementaciju) funkcionalnosti koju hardver ne implementira. Softverska implementacija koristi raspoloživi grafički sistem (npr. GDI na Windows plaftormi) za iscrtavanje, dok hardverska koristi OpenGL kompatibilni hardver za iscrtavanje. Obično grafički hardver daje različite nivoe ubrzavanja: od hardverske realizacije generisanja linija i poligona do moćnih grafičkih procesora sa podrškom za različite operacije nad geometrijskim podacima.

Page 2: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 2

a) softverska b) hardverska

Slika 6.1.1 Tipovi implementacija OpenGL biblioteke za Windows platformu, preuzeto iz [1]

OpenGL metode realizovane su po modelu klijent-server . Aplikacija (klijent) poziva OpenGL metode, a OpenGL (server) ih interpretira i izvršava. Server se može nalaziti na tom istom računaru, na kom se nalazi i klijent ili na drugom računaru.

OpenGL iscrtava grafičke objekte u baferu kadra (frame buffer) uzimajući u obzir izabrane režime iscrtavanja. Svaki režim može se menjati nezavisno od drugih. Definisanje primitiva, izbor režima i druge operacije opisuju se pomoću komandi u obliku poziva OpenGL metoda.

Grafički objekti se definišu skupom temena (vertex). Temenu se pridružuju podaci (npr. koordinate, boja i dr.) koji se nazivaju atributima .

Uprošćeni proces prezentacije grafike, slika 6.1.2, se sastoji od sledećih koraka:

� poziva metoda OpenGL API od strane aplikacije (klijenta), � skladištenja zadatih metoda – komandi u Command baferu, � pražnjenja Command bafera (ili programski ili automatski), � izvršavanja komandi, u redosledu njihovog pojavljivanja, � primene transformacije i osvetljenja, � rasterizacije – pretvaranja 3D scene u 2D projekciju, � upis rasterizovane scene u bafer kadra grafičke kartice (iscrtavanje).

Pravi proces uključuje još neke dodatne korake, ali oni nisu neophodni za razumevanje načina rada OpenGL programske biblioteke. Čitaocima koje to zanima se preporučuje da pogledaju u literaturi [1].

Slika 6.1.2 Uprošćeni OpenGL proces prezentacije grafike, preuzeto iz [1]

Page 3: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 3

6.1.1 Organizacija OpenGL C# implementacije OpenGL implementacija je organizovana kao jedna programska biblioteka

Tao.OpenGl i predstavlja deo Tao Framework skupa programskih biblioteka. Sve bazne metode su implementirane u klasi Gl, a metode openGL Utility (GLU) biblioteka (videti poglavlje 5.1.1) su implmentirane u klasi Glu . Klase pripadaju Tao.OpenGl imenskog prostora (namespace).

Funkcionalnost osnovne biblioteke na Windows platformi je implementirana u Tao.OpenGl.dll dinamičkoj programskoj biblioteci. Da bi se mogle koristiti OpenGL metode potrebno je u zaglavlju Program.cs fajla dodati sledeći programski kôd:

using Tao.OpenGl;

Veoma je bitno naglasiti da ceo skup Tao Framework skup biblioteka predstavlja samo C# wrapper odgovarajućih biblioteka implementiranih korišćenjem nativnog programskog jezika (konkretno za OpenGL u pitanju je C programski jezik).

6.1.2 Sintaksa OpenGL metoda Nazivi OpenGL metoda su deskriptivni i obično pružaju informacije o klasi u kojoj su implementirane, broju i tipu parametara. Nomenklatura OpenGL metoda je (sa * su označeni opcioni elementi):

tip <prefiks><naziv><brojP*><tipP*><v>(tip1 param1 ,…,tipN paramN)

gde su: tip – OpenGL tip podataka koji vraća metoda, <prefiks> – karakter koji se želi prikazati, <naziv> - naziv metode, <brojP> - broj parametara dozvoljene vrednosti su: 1, 2, 3, 4. Ovaj

element je opcion i pojavljuje se samo ako su tipovi parametara isti,

<tipP> - OpenGL tip podataka. Dozvoljene su sledeće vrednosti: b, s, i, f, d, ub, us, ui. Vrednosti predstavljaju skraćene oznake OpenGL tipova. Na primer, b odgovara byte tipu podataka, i odgovara int tipu podataka itd. Ovaj element je opcion i pojavljuje se samo ako su tipovi parametara isti,

<v> - oznaka da se kao parametar metode koristi pokazivač na niz

vrednosti. Ovaj element je opcion i pojavljuje se samo ako su tipovi parametara isti,

tip1, ..., tipN – OpenGL tipovi podataka parametara 1 .. N, param1, ..., paramN – nazivi parametara 1 .. N.

Page 4: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 4

Primer metode sa oznakama prikazan je na slici 6.1.2.1. Ovakva nomenklatura u značajnoj meri olakšava pamćenje naziva metoda, kao i broja i tipa parametara.

6.1.3 OpenGL tipovi podataka Za razliku od C verzije (videti poglavlje 5.1.3) C# ne poseduje upotpunosti ekvivalent #typedef direktivi (koja se koristi u C verziji) pa zato se koriste C# tipovi podataka. Većina tipova je ekvivalentna njihovim C verzijama. C pokazivači se opisuju IntPtr tipom podataka. Razlika postoji i kod nizova koji su poseban tip u C#.

Sve konstante definisane u klasi Gl počinju prefiksom „GL_“. Odgovarajuće konstante klasa Glu i Glut analogno imaju prefikse „GLU_“ i „GLUT_“.

6.1.4 OpenGL promenljive stanja OpenGL specifikacija definiše OpenGL kao automat stanja . Definisan je veliki broj promenljivih stanja koje se mogu uključiti/isključiti pozivom metode Gl.glEnable / Gl.glDisable (npr. Gl.glEnable(Gl.GL_LIGHTING) koja uključuje proračun osvetljenja u sceni). Ako je promenljiva stanja uključena, ponovni pozivi uključenja iste promenljive se ignorišu. Analogno važi i za isključivanje promenljive. OpenGL razlikuje dva tipa promenjlivih stanja: klijentske (client) i serverske (server). Klijentske su vezane za stanja na strani klijenta, dok su serverske vezane za stanja na strani servera. Ako nije naglašeno, sve promenljive stanja opisane u daljem tekstu su serverske promenljive stanja.

public static void glEnable(int cap ) public static void glDisable(int cap )

gde je: cap – simbolička konstanta promenljive stanja koja se uključuje/isključuje.

Kompletan spisak promenljivih stanja i odgovarajućih konstanti može se videti u dokumentaciji.

Metoda glIsEnabled se koristi za ispitivanje da li određena promenljiva stanja uključena ili ne.

public static int glIsEnabled(int cap )

gde je: cap – konstanta promenljive stanja za koju se ispituje stanje.

Često postoji potreba da se stanje sistema sačuva/restaurira. OpenGL specifikacija definiše FIFO stek stanja sistema, koji omogućava realizaciju gore

Slika 6.1.2.1 Primer OpenGL funkcije

glColor3f(…) GL komanda broj i tip parametara klasa

Page 5: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 5

navedenih metoda. Stekom se manipuliše korišćenjem metoda glPushAttrib i glPopAttrib .

void glPushAttrib(int mask) void glPopAttrib()

gde je: mask – bitwise OR kombinacija konstanti promenljivih stanja. Npr.

Gl.glPushAttrib(Gl.GL_TEXTURE_BIT | Gl.GL_LIGHTING_BIT) snjima stanje rada sa teksturama i osvetljenjem.

6.1.5 OpenGL greške Tokom izvršavanja OpenGL metoda mogu nastati greške. OpenGL registruje samo mali podskup mogućih grešaka. Ovakav pristup se bazira na činjenici da bi registrovanje i provera svih mogućih grešaka opasno ugrozila performansu. OpenGL signalizira greške preko numeričkih vrednosti koje se u OpenGL terminologiji nazivaju zastavicama (flags). OpenGL zastavice su prikazane u tabeli 6.1.5.1. Ako dođe do grešaka sistem nastavlja sa radom, a metode koje su izazvale grešku se ignorišu. Jedini izuzetak je zastavica GL_OUT_OF_MEMORY kada je rezultat metode nedefinisan.

Naziv Opis GL_INVALID_ENUM Enum argument je van opsega. GL_INVALID_VALUE Numerički argument je van opsega. GL_INVALID_OPERATION Trenutno stanje sistema ne dozvoljava izvršenje metode. GL_STACK_OVERFLOW Izvršenje metode izaziva stack overflow. GL_STACK_UNDERFLOW Izvršenje metode izaziva stack underflow. GL_OUT_OF_MEMORY Za izvršenje OpenGL metode sistema nema dovoljno

slobodno memorije. GL_TABLE_TOO_LARGE Zadata tabela je suviše velika. GL_NO_ERROR Nema greške – uspešno izvršena OpenGL metoda.

Tabela 6.1.4.1 Zastavice grešaka (error flags)

Za utvrđivanje koja zastavica je postavljena koristi se metoda glGetError koja vraća vrednost iz tabele 6.1.4.1. Za dobijanje deskriptivnog tekstualnog opisa greške koristi se metoda gluErrorString .

public static int glGetError() public static string gluErrorString(int errorCode )

gde je: errorCode – konstanta greške, videti tabelu 6.1.4.1

Page 6: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 6

Ako se desilo više grešaka tada se one mogu dobiti sukcesivnim pozivima metode glGetError sve dok povratna vrednost metode ne bude vrednost: GL_NO_ERROR. S toga je uobičajno da se poziv ove metode nalazi unutar petlje.

6.1.6 openGL Utility Toolkit (GLUT) OpenGL omogućava prezentaciju računarske grafike nezavisno od konkretnog hardvera, i kao takav se može posmatrati kao softverski interfejs prema grafičkom hardveru. Pošto OpenGL vrši prezentaciju grafike, on ne sadrži u sebi nikakve specijalne komande za rad sa prozorima ili prihvat ulaznih podataka od korisnika. Oslanjanje na neku konkretnu platformu postaje problem ako se želi pisati prenosiv (portable) programski kôd, jer tada treba nekako apstrahovati platformske specifičnosti rukovanja prozorima, ulazno-izlaznim uređajima i dr. S toga su napravljene prenosive biblioteke koje obezbeđuju često korišćene metode za međusobno delovanje računara i korisnika, kao i za prikaz informacija preko podsistema prozora. Najpopularnija biblioteka je openGL Utility Toolkit (GLUT). GLUT nije u sastavu OpenGL standarda, ali se uključuje u sve njegove distribucije i postoje realizacije za različite platforme. GLUT predstavlja samo minimalni skup metoda za pravljenje OpenGL aplikacija.

GLUT je kreirao Mark Kilgard, inženjer SGI, sa ciljem da se omogući programerima da pišu u potpunosti prenosive aplikacije. GLUT omogućava rukovanje prozorima, rad sa pop-up menijima, prihvat ulaznih podataka sa tastature, miša i džojstika i dr. Razvoj GLUT programske biblioteke (nije open source) je napušten za Windows platformu. Razvoj je nastavljen kroz open source projekat freeglut . U primerima biće korišćena freeglut programska biblioteka, koja se može preuzeti sa Internet adrese: http://freeglut.sourceforge.net/.

Nomenklatura GLUT biblioteke je ista kao i kod drugih OpenGL programskih biblioteka i sve metode imaju prefiks „glut“, a konstante „GLUT_“.

Da bi se mogla koristiti GLUT programska biblioteka potrebno je: 1. instalirati freeglut biblioteku, 2. podesiti razvojno okruženje za rad sa freeglut bibliotekom, 3. u zagavlje fajl/ova dodati sledeći programski kôd:

using Tao.FreeGlut;

S obzirom na portabilnost, GLUT programska biblioteka ne može u potpunosti realizovati sve specifičnosti platforme. GLUT programska biblioteka je izabrana da bi se čitalac fokusirao na OpenGL programiranje računarske grafike i pisanje prenosivih aplikacija.

U daljem tekstu programski kôd i detalji će se odnositi na implementaciju pomoću C# programskog jezika na Windows platformi.

Page 7: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 7

5.1.7 Primer GLUT aplikacije U daljem tekstu biće prezentovan programski kôd aplikacije koja prikazuje prozor plave boje koristeći se OpenGL i GLUT programskim bibliotekama. U listingu 5.1.7.1 prikazan je programski kôd ove aplikacije.

/************************************************** ********************* * Modul: Program.cs * Autor: Srdjan Mihic * Namena: kreiranje jednostavnog prozora oslanja juci se na OpenGL i GLUT ************************************************** **********************/ using System; using System.Collections.Generic; using System.Text; // OpenGL i FreeGlut namespaces using Tao.OpenGl; using Tao.FreeGlut; namespace GLUT_prozor { class Program { /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu - plavu pozadinu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { // obrisi prozor sa trenutno aktivnom bojom z a brisanje ekrana Gl .glClear( Gl .GL_COLOR_BUFFER_BIT); // prekopiraj sadrzaj iz zadnjeg bafera u fra me bafer Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { // podesi boju za brisanje ekrana // R G B A Gl .glClearColor(0.0f, 0.0f, 1.0f, 1.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda // Parametri: args /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); // inicijalizuj GLUT // koristi double-buffer i RGBA model boja Glut .glutInitDisplayMode( Glut .GLUT_SINGLE | Glut .GLUT_RGBA); // podesi velicinu prozora Glut .glutInitWindowSize(800, 600); // kreiraj prozor sa naslovom "GLUT prozor"

Page 8: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 8

Glut .glutCreateWindow( "GLUT prozor" ); // za rendering koristi RenderScene metodu Glut .glutDisplayFunc(RenderScene); // inicijalizuj potrebne promenljive SetupRenderingContext(); // pokreni GLUT glavnu petlju Glut .glutMainLoop(); } } }

Listing 6.1.7.1 Jednostavan GLUT prozor plave boje

Svaka GLUT aplikacija (main metoda) prolazi kroz sledeće faze: � inicijalizacija GLUT programske biblioteke, � incijalizacija parametara prozora, � kreiranje prozora, � registrovanje obrađivača događaja (callback metode), � podešavanja OpenGL konteksta, � pokretanje glavne petlje.

Metoda glutInit vrši inicijalizaciju GLUT biblioteke, opciono sa prosleđnim argumentima komandne linije. Poziv ove metode mora prethoditi pozivu bilo koje druge GLUT ili OpenGL metode. U upotrebi je najčešće verzija metode bez parametara.

public static void glutInit(ref int argcp , StringBuilder[] argv )

public static void glutInit()

gde su: argc – nemodifikovani argc argument main metode,

argv – nemodifikovani argv argument main metode.

Inicijalizacija prozora se sastoji od podešavanja odgovarajućih bafera kadra, početnog pozicije i dimenzija prozora.

Metoda glutInitDisplayMode definiše parametre kadra: model boja i tip baferovanja. Postoje dva tipa baferovanja – single i double . Single tip baferovanja direktno iscrtava u bafer kadra, što najčešće dovodi do treperenja (flickering). Ovaj tip baferovanja se veoma retko koristi. Najčešće se koristi double baferovanje kod kojeg se iscrtava u zadnji bafer (offscreen buffer). Nakon završenog iscrtavanja sadržaj zadnjeg bafera se prekopira u bafer kadra. Ovo se realizuje pomoću metode glutSwapBuffers .

Postoji nekoliko vrsta bafera. Gore navedeni baferi se nazivaju baferima boje (color buffers). Postoji još i bafer dubine kadra (depth buffer), koji definiše rastojanje objekata od korisnika.

public static void glutSwapBuffers() public static void glutInitDisplayMode(int mode)

Page 9: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 9

gde su: mode – bitwise OR kombinacija konstanti. Neke od često korišćenih vrednosti su: • GLUT_RGBA – RGBA mod. Ovaj mod je podrazumevani ako se

ne navede nijedan drugi. • GLUT_RGB - alias za GLUT_RGBA. • GLUT_INDEX – indeksni mod boja. • GLUT_SINGLE – single tip baferovanja. Ovaj tip baferovanja je

podrazumevani. • GLUT_DOUBLE - double tip baferovanja. • GLUT_ALPHA – mod sa alfa komponentom. • GLUT_DEPTH – prozor sa baferom dubine.

Metoda glutInitWindowSize se koristi za zadavanje početnih dimenzija prozora. Početna pozicija prozora na ekranu se može zadati pomoću glutInitWindowPosition metode. Argumenti u pozivima ovih metoda predstavljaju predlog željenih vrednosti koje ne moraju nužno biti prihvaćene.

public static void glutInitWindowSize(int width , int height ) public static void glutInitWindowPosition(int x , int y )

gde su: width – širina prozora izražena u pikselima, height - visina prozora izražena u pikselima, x – broj piksela od leve ivice ekrana. Podrazumevana vrednost je -1, što

znači da od upravljača prozora (window manager) zavisi gde će se prozor pojaviti. Izabrana vrednost bi trebalo da bude pozitivan broj ne veći od širine ekrana.

y – broj piksela od gornje ivice ekrana. Podrazumevana vrednost je -1, što znači da od upravljača prozora (window manager) zavisi gde će se prozor pojaviti. Izabrana vrednost bi trebalo da bude pozitivan broj ne veći od visine ekrana.

Nakon zadavanja parametara prozora potrebno je kreirati prozor pozivom metode glutCreateWindow. Kreiranom prozoru se implicitno pridružuje OpenGL kontekst. Odmah po izvršenju ove metode nad kontekstom se mogu izvršavati OpenGL metode. Prozor je skriven sve dok se ne uđe u glavnu petlju. Metoda glutCreateWindow vraća identifikator prozora koji je interesantan u sistemima sa više prozora. GLUT dozvoljava kreiranje i potprozora korišćenjem metode glutCreateSubWindow.

public static int glutCreateWindow(string name)

public static int glutCreateSubWindow(int win , int x , int y ,

Page 10: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 10

int width , int height )

gde su: name – naslov prozora koji se prikazuje u naslovnoj liniji (titlebar),

win – identifikator parent prozora,

x – x pozicija potprozora,

y – y pozicija potprozora,

width – širina potprozora,

height – visina potprozora.

GLUT bibliteka omogućava definisanje obrađivača događaja preko tzv. metoda sa povratnim pozivom (callback function). Metode sa povrtanim pozivom su realizovane u C# kao delegati (delegates). Kontrola svih događaja i pozivanje potrebnih metoda obavlja se unutar glavne (beskonačne) petlje. Postoji veliki broj događaja na koje se može reagovati, tako da će biti prezentovani u okviru odgovarajućih poglavlja. Esencijalna metoda je glutDisplayFunc koja registruje metodu za iscrtavanje sadržaja prozora. Ta metoda se poziva kad god sadržaj prozora treba da se prikaže.

public static void glutDisplayFunc( DisplayCallback func ) public delegate void Glut.DisplayCallback()

gde je: func – naziv metode za iscrtavanje sadržaja prozora.

U primeru iz listinga 6.1.7.1 za prikaz sadržaja prozora registrovana je RenderScene metoda. Unutar ove metode se pozivaju metode: glClear i glutSwapBuffers. glClear metoda briše sadržaj prozora pritom popunjavajući ga trenutno aktivnom bojom za brisanje prozora (clear color). Nakon toga se pozivom glutSwapBuffers novi sadržaj zadnjeg bafera prenosi u bafer kadra.

public static void glClear(int mask)

gde je:

mask – bitwise OR kombinacija konstanti raspoloživih bafera. Često korišćene vrednosti su:

� GL_COLOR_BUFFER_BIT – nalaže ispunu sadržaja kolor bafera bojom definisanom sa glClearColor,

� GL_DEPTH_BUFFER_BIT – nalaže čišćenje bafera dubine.

Uobičajno je da se podešavanja OpenGL konteksta enkapsuliraju metodom SetupRenderingContext. U primeru iz listinga 6.1.7.1 se u ovoj metodi podešava boja kojom će biti prebrisan sadržaj prozora (boja pozadine). Metoda glClearColor definiše boju za brisanje prozora. Podrazumevana boja za brisanje je crna boja.

Page 11: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 11

public static void glClearColor(float red, float green, float blue, float alpha)

gde su: red, green, blue – RGB komponente boje [0.0 – 1.0],

alpha – alfa tj. prozirnost.

U glavnu (beskonačnu) petlju u aplikaciji se ulazi pozivom metode glutMainLoop . Unutar ove petlje se obrađuju događaji. Petlja se izvršava do izlaska iz aplikacije.

6.2 Ispis teksta OpenGL podržava dva tipa ispisa karaktera: outline (stroke) i bitmap. Outline karakter se reprezentuje kao vektorska grafika, dok se bitmap karakter reprezentuje kao rasterska grafika. Prvi tip ispisa je pogodan kada se želi manipulisati karakterom kao sa poligonima – primena različitih transformacija, izvlačenje treće dimenzije, primena efekata i dr. Za razliku od prvog, drugi ispis je daleko brži, ali nudi manju moć manipulacije. Izbor tipa ispisa zavisi od konkretnog problema. Postoji mogućnost ispisa teksta oslanjajući se na teksture, videti poglavlje 6.9.

GLUT omogućava ispis teksta samo predefinisanim fontovima. Ako je potrebno ispisati tekst proizvoljnim fontom tada se moraju koristiti metode specifične za platformu. Za ispis bitmap karaktera tada se koristi wglUseFontBitmaps , a za ispis outline karaktera wglUseFontOutlines . Ove metode zahtevaju poznavanje specifičnosti Windows platforme, kao i korišćenje metoda specifičnih za Windows platformu. Metode su implementirane u klasi Wgl u programskoj biblioteci Tao.Platform.Windows . Više informacija o ovim metodama se može naći na Internet adresi: http://msdn2.microsoft.com/en-us/library/ms673957.aspx .

Alternativno, za OpenGL ispis teksta nezavisan od platforme može se iskoristiti open source programska biblioteka FTGL, koja se može preuzeti sa Internet adrese: http://homepages.paradise.net.nz/henryj/code/#FTGL.

Freeglut programska biblioteka nudi i metode glutBitmapString i glutStrokeString koje omogućavaju ispis bitmap i outline stringova. Ove metode nisu deo standardne GLUT programske bibiloteke.

6.2.1 Ispis bitmap teksta Za ispis bitmap teksta koriste se metode glutBitmapCharacter i glutBitmapWidth.

Metoda glutBitmapCharacter ispisuje bitmap karakter koristeći zadati font.

Page 12: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 12

public static void glutBitmapCharacter(IntPtr font , int character )

gde su: font – naziv fonta, predefinisan, za detalje videti [1, str. 40], character – karakter koji se želi prikazati.

Metoda glutBitmapWidth određuje širinu bitmap karaktera.

public static int glutBitmapWidth(IntPtr font , int character )

gde su: font – naziv fonta, predefinisan, za detalje videti [1, str. 40], character – karakter za koji se želi odrediti širina.

Horizontalan ispis bitmap teksta se realizuje tako što pomeri bitmap kurzor na željenu poziciju. Zatim se pozivom metode glutBitmapCharacter ispisuje karakter. Ova metoda pomera bitmap kurzor za širinu karaktera. Svaki drugi ispis bitmap teksta zahteva ručno pozicioniranje bitmap kurzora.

6.2.2 Primer ispisa bitmap teksta U listingu 6.2.2.1 prikazan je primer ispisa bitmap teksta. Primer ispisuje tekst „Dobrodosli u“ horizontalno u centru prozora i „OpenGL“ horizontalno i vertikalno u centru prozora, slika 6.2.2.1. U odnosu na prethodni primer, videti poglavlje 6.1.6, dodate su: metoda za promenu veličine – ChangeSize, metode za ispis horizontalnog i vertikalnog bitmap teksta, kao i metode za manipulaciju nad projekcijom.

/************************************************** ********************* * Modul: Program.cs * Autor: Srdjan Mihic * Namena: ispis bitmap teksta ************************************************** **********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace GLUT_bitmap_tekst { class Program {

Slika 6.2.2.1 Rezultat

aplikacije iz listinga 6.2.2.1

Page 13: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 13

// definisemo promenljive koje sadrze naziv fonta // moguce su sledece vrednosti: // Glut.GLUT_BITMAP_8_BY_13 // Glut.GLUT_BITMAP_9_BY_15 // Glut.GLUT_BITMAP_TIMES_ROMAN_10 // Glut.GLUT_BITMAP_TIMES_ROMAN_24 // Glut.GLUT_BITMAP_HELVETICA_10 // Glut.GLUT_BITMAP_HELVETICA_12 // Glut.GLUT_BITMAP_HELVETICA_18 static IntPtr font1 = Glut .GLUT_BITMAP_8_BY_13; static IntPtr font2 = Glut .GLUT_BITMAP_HELVETICA_18; static float fontHeight1 = 13.0f; static float fontHeight2 = 18.0f; // dimenzije prozora static float windowWidth = 320.0f; static float windowHeight = 240.0f; static float halfWindowWidth = windowWidth/2; /////////////////////////////////////////////////// ///////////////////// // Naziv: CalculateBitmapTextWidth // Namena: metoda utvrdjuje sirinu tekst a // Parametri: font i tekst // Povratna vrednost: sirina /////////////////////////////////////////////////// ///////////////////// static int CalculateBitmapTextWidth( IntPtr font, string text) { int width = 0; foreach ( char c in text) width += Glut .glutBitmapWidth(font, c); return width; } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderBitmapTextH // Namena: metoda iscrtava string horizo ntalno text // pozivajuci glutBitmapChar acter metodu // Parametri: pozicija (pos_x, pos_y, depth ), font i tekst /////////////////////////////////////////////////// ///////////////////// static void RenderBitmapTextH( float pos_x, float pos_y, float depth, IntPtr font, string text) { Gl .glRasterPos3f(pos_x, pos_y, depth); foreach ( char c in text) Glut .glutBitmapCharacter(font, c); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderBitmapTextV // Namena: metoda iscrtava string vertik alno text pozivajuci // glutBitmapCharacter metodu za svaki karakter // Parametri: pozicija (pos_x, pos_y, depth ), font i tekst /////////////////////////////////////////////////// ///////////////////// static void RenderBitmapTextV( float pos_x, float pos_y, float depth, float fontHeight, IntPtr font, string text) {

Page 14: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 14

foreach ( char c in text) { pos_y -= fontHeight; Gl .glRasterPos3f(pos_x, pos_y, depth); Glut .glutBitmapCharacter(font, c); } } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { // obrisi prozor sa trenutno aktivnom bojom za bris anje ekrana Gl .glClear( Gl .GL_COLOR_BUFFER_BIT); // ispisi tekst u levo, centriran RenderBitmapTextH(-halfWindowWidth, fontHeigh t1, 0.0f, font1, "Dobrodosli u" ); // ispisi tekst centriran i vertikalno i horizontal no RenderBitmapTextH(CalculateBitmapTextWidth(fo nt2, "OpenGL" )/(-2.0f), 0.0f, 0.0f, font2, "OpenGL" ); // ispisi vertikalni tekst centriran RenderBitmapTextV(CalculateBitmapTextWidth(fo nt2, "O" )/(-2.0f), -0.5f*fontHeight1, 0.0f, fontHeight2, font2, "OpenGL" ); Glut .glutSwapBuffers(); // double-buffering } /////////////////////////////////////////////////// ///////////////////// // Naziv: ChangeSize // Namena: obradjuje promenu dimenzija p rozora // Parametri: nova sirina i visina /////////////////////////////////////////////////// ///////////////////// static void ChangeSize( int width, int height) { float halfWidth = windowWidth/2.0f; float halfHeight = windowHeight/2.0f; if (height == 0) height = 1; // ne dozvoli deljenje sa nulom // kreiraj viewport po celom prozoru Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); // izaberi Projection Matrix Gl .glLoadIdentity(); // resetuj Projection Matrix float aspectRatio = ( float )width/ ( float )height; // izracunaj odnos sirina/visina // definisemo orto. projekciju tako da odrzava odno s sirine i visine // tj. ako je visina >= od sirine tada koristimo si rinu i – // izracunamo visinu na osnovu pocetnog odnosa visi ne/sirine,i obratno if (width <= height) // definisi ortogonalnu projekciju { halfWindowWidth = halfWidth; Gl .glOrtho(-halfWidth, halfWidth, // na osnovu odnosa sirina/visina -halfWidth/aspectRatio, halfWidth/a spectRatio, 1.0, -1.0); }

Page 15: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 15

else { halfWindowWidth = halfHeight * aspectRatio; Gl .glOrtho(-halfWindowWidth, halfWindowWidth, -halfHeight, halfHeight, 1.0, -1.0); } Gl .glMatrixMode( Gl .GL_MODELVIEW); // izaberi ModelView Matrix Gl .glLoadIdentity(); // resetuj ModelView Matrix } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { // podesi boju za brisanje ekrana Gl .glClearColor(0.0f, 0.0f, 1.0f, 1.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda // Parametri: args // Povratna vrednost: int /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); // inicijalizuj GLUT // koristi double-buffer i RGB model boja Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB); Glut .glutInitWindowSize(( int )windowWidth, // podesi velicinu prozora ( int )windowHeight); // kreiraj prozor sa naslovom "GLUT bitmap te kst" Glut .glutCreateWindow( "GLUT bitmap tekst" ); // za rendering koristi RenderScene metodu Glut .glutDisplayFunc(RenderScene); // za resize koristi ChangeSize metodu Glut .glutReshapeFunc(ChangeSize); SetupRenderingContext(); // inicijalizuj potrebne promenljive Glut .glutMainLoop(); // pokreni GLUT glavnu petlju } } }

Listing 6.2.2.1 Ispis bitmap teksta

GLUT obezbeđuje način da se definiše koja metoda treba da bude pozvana kada se promeni veličina prozora, tj. registruje povratni poziv za preračunavanje projekcije. Pored toga, ta metoda se poziva i kod inicijalnog kreiranja prozora. Ako se ne definiše ova metoda tada dolazi do deformacije objekata koji se iscrtavaju prilikom izmene dimenzija prozora. GLUT koristi metodu glutReshapeFunc za registrovanje metode koja se poziva prilikom promene dimenzija prozora.

public static void glutReshapeFunc(

Page 16: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 16

ReshapeCallback func ) public delegate void Glut.ReshapeCallback( int width , int height ) gde su:

func – naziv metode koja će biti pozivana kada prozor promeni veličinu, width i height – nove dimenzije prozora.

Metoda ChangeSize definiše kako će se skalirati prozor pri promeni veličine prozora od strane korisnika. U ovoj metodi koriste se metode glMatrixMode i glLoadIdentity koje će biti detaljno objašnjene u poglavlju 6.5. Uobičajno je da metoda ChangeSize ima sledeću formu:

� Provera korektnosti novih dimenzija prozora. Ova provera uključuje proveru da li je nova vrednost visine prozora jednaka nuli. Ako jeste tada se ova vrednost svodi na najbližu validnu vrednost – jedan piksel.

� Definisanje mapiranja logičkih koordinata u fizičke koordinate – definisanje viewport-a korišćenjem metode glViewport.

� Definisanje projekcije. Projekcijom se definiše koji deo 3D prostora će biti predstavljen unutar prozora. Postoje dve vrste projekcija: ortogonalna i projekcija u perspektivi. Obe projekcije će biti detaljno opisane kod odgovarajućih OpenGL metoda kojima se definišu.

Metoda glViewport definiše mapiranje kliping (clipping) prozora u fizički prozor aplikacije – mapiranje logičkog koordinatnog sistema u fizički (slika 6.2.2.1). U primeru 6.2.2.1 kliping prozor se definiše da bude sâm prozor.

public static void glViewport(int x , int y , int width , int height )

gde su: x, y – donja leva koordinata, najčešće (0,0), width – širina kliping prozora., height – visina kliping prozora.

Slika 6.2.2.1 Mapiranje logičkih u fizičke koordinate prozora, preuzeto iz [3]

Page 17: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 17

Metoda glOrtho definiše kliping prozor sa ortogonalnom projekcijom , slika 6.2.2.2. Prostor je definisan preko šest parametara – dimenzija kvadra. U ortogonalnoj projekciji svi objekti koji su istih dimenzija prikazuju se u istoj veličini bez obzira gde se nalaze. Najčešće ova projekcija se koristi u CAD i arhitektonskom dizajnu.

public static void glOrtho(double left , double right , double bottom , double top , double near , double far )

gde su: left, right – minimum/maksimum po x-osi, bottom, top – minimum/maksimum po y-osi, near, far – minimum/maksimum po z-osi.

Slika 6.2.2.2 Ortogonalna projekcija, preuzeto iz [3]

Pored glOrtho metode u upotrebi je i metoda gluOrtho2D , koja definiše „2D“ projekciju. Metoda gluOrtho2D predstavlja specijalni slučaj gde su parametar near jednak -1, a parametar far jednak 1.

public static void gluOrtho2D(double left , double right , double bottom , double top ) gde su:

left, right – minimum/maksimum po x-osi, bottom, top – minimum/maksimum po y-osi.

Pomoćna metoda CalculateBitmapTextWidth izračunava širinu teksta zadatog preko parametra string, koristeći se GLUT funkcijom glutBitmapWidth. Pomoćne metode RenderBitmapTextH i RenderBitmapTextV ispisuju tekst horizontalno, odnosno vertikalno. Ispisani tekst pokazuje primer ravnanja teksta uz levu ivicu, i centralno (gde je potrebno je izračunati širinu teksta i podeliti sa dva). Za pozicioniranje bitmap kurzora koristi se familija metoda kojoj pripada glRasterPos3f metoda, a koja će biti opisana u poglavlju 6.3.1.

Page 18: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 18

6.2.3 Ispis outline teksta Za ispis outline teksta koriste se metode glutStrokeCharacter i glutStrokeWidth.

Metoda glutStrokeCharacter ispisuje outline karakter, a metoda glutStrokeWidth određuje širinu outline karaktera.

public static void glutStrokeCharacter(IntPtr font , int character )

public static int glutStrokeWidth(IntPtr font ,

int character )

gde su: font – naziv fonta, predefinisan, za detalje videti [1, str. 42], character – karakter koji se želi prikazati/izračunati širina.

Horizontalan ispis outline teksta se realizuje tako što pomeri koord. sistem na željenu poziciju korišćenjem metode glTranslatef. Zatim se pozivom metode glutStrokeCharacter ispisuje karakter. Ova metoda pomera koord. sistem za širinu karaktera. Svaki drugi ispis outline teksta zahteva ručno pozicioniranje koord. sistema. Transformacije koord. sistema biće detaljno objašnjene u poglavlju 6.5.

6.2.4 Primer ispisa outline teksta

Listing 6.2.4.1 i slika 6.2.4.1 prikazuju primer ispisa sličnog teksta (kao u primeru 6.2.2.1), ali korišćenjem outline fontova. Ovaj primer demonstrira: ispis outline teksta, definisanje debljine linije i projekcije u perspektivi. Metode glPushMatrix i glPopMatrix biće detaljno objašnjenje u poglavlju 6.5.

/************************************************** ********************* * Modul: Program.cs * Autor: Srdjan Mihic * Namena: ispis outline teksta ************************************************** **********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut;

Slika 6.2.4.1 Izlaz listinga 6.2.4.1

Page 19: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 19

namespace GLUT_outline_tekst { class Program { // promenljive koje sadrze nazive fontova, moguce s u sledece vrednosti: // Glut.GLUT_STROKE_ROMAN // Glut.GLUT_STROKE_MONO_ROMAN static IntPtr font1 = Glut .GLUT_STROKE_ROMAN; static IntPtr font2 = Glut .GLUT_STROKE_MONO_ROMAN; static float fontHeight1 = 120.0f; static float fontHeight2 = 120.0f; // dimenzije prozora static float windowWidth = 800.0f; static float windowHeight = 600.0f; static float halfWindowWidth = windowWidth/2; /////////////////////////////////////////////////// ///////////////////// // Naziv: CalculateStrokeTextWidth // Namena: metoda utvrdjuje sirinu tekst a // Parametri: font i tekst // Povratna vrednost: sirina /////////////////////////////////////////////////// ///////////////////// static int CalculateStrokeTextWidth( IntPtr font, string text) { int width = 0; foreach ( char c in text) width += Glut .glutStrokeWidth(font, c); return width; } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderStrokeTextH // Namena: metoda iscrtava string horiz. text pozivajuci // glutBitmapCharacter metodu za svaki karakter // Parametri: pozicija (pos_x, pos_y, depth ), font i tekst /////////////////////////////////////////////////// ///////////////////// static void RenderStrokeTextH( float pos_x, float pos_y, float depth, IntPtr font, string text) { Gl .glPushMatrix(); Gl .glTranslatef(pos_x, pos_y, depth); foreach ( char c in text) Glut .glutStrokeCharacter(font, c); Gl .glPopMatrix(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderStrokeTextV // Namena: metoda iscrtava string vertik alno text pozivajuci // glutStrokeCharacter metodu za svaki karakter // Parametri: pozicija (pos_x, pos_y, depth ), font i tekst /////////////////////////////////////////////////// ///////////////////// static void RenderStrokeTextV( float pos_x, float pos_y, float depth, float fontHeight, IntPtr font, string text) {

Page 20: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 20

foreach ( char c in text) { Gl .glPushMatrix(); pos_y -= fontHeight; Gl .glTranslatef(pos_x, pos_y, depth); Glut .glutStrokeCharacter(font, c); Gl .glPopMatrix(); } } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { // obrisi prozor sa trenutno aktivnom bojom za bris anje ekrana Gl .glClear( Gl .GL_COLOR_BUFFER_BIT); // ispisi tekst u levo, centriran RenderStrokeTextH(CalculateStrokeTextWidth(fo nt1, "Dobrodosli u" )/ (-2.0f), fontHeight1, -2000.0f , font1, "Dobrodosli u" ); // ispisi tekst centriran i vertikalno i horizontal no RenderStrokeTextH(CalculateStrokeTextWidth(fo nt2, "OpenGL" )/(-2.0f), 0.0f, -2000.0f, font2, "OpenGL" ); // ispisi vertikalni tekst centriran RenderStrokeTextV(CalculateStrokeTextWidth(fo nt2, "O" )/(-2.0f), -0.5f*fontHeight1, -2000.0 f, fontHeight2, font2, "OpenGL" ); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: ChangeSize // Namena: obradjuje promenu dimenzija p rozora // Parametri: nova sirina i visina /////////////////////////////////////////////////// ///////////////////// static void ChangeSize( int width, int height) { halfWindowWidth = width/2.0f; if (height == 0) height = 1; // ne dozvoli deljenje sa nulom // kreiraj viewport po celom prozoru Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); // selektuj Projection Matrix Gl .glLoadIdentity(); // resetuj Projection Matrix // izracunaj odnos sirina/visina double aspectRatio = ( double )width / ( double )height; Glu .gluPerspective(45.0, aspectRatio, 1.0, 10000.0); // kliping u perspektivi Gl .glMatrixMode( Gl .GL_MODELVIEW); // selektuje ModelView Matrix Gl .glLoadIdentity(); // resetuj ModelView Matrix }

Page 21: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 21

/////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////// ///////////////////////// static void SetupRenderingContext() { // podesi boju za brisanje ekrana Gl .glClearColor(0.0f, 0.0f, 1.0f, 1.0f); Gl .glLineWidth(4.0f); // namesti debljinu linije na 4 } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda // Parametri: args // Povratna vrednost: int /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); // inicijalizuj GLUT Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB); Glut .glutInitWindowPosition(300, 300); Glut .glutInitWindowSize(( int )windowWidth, ( int )windowHeight); Glut .glutCreateWindow( "GLUT outline tekst" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); SetupRenderingContext(); Glut .glutMainLoop(); } } }

Listing 6.2.4.1 Ispis outline teksta

Za razliku od prethodnog primera u primeru iz listinga 6.2.4.1 korišćena je projekcija u perspektivi , slika 6.2.4.2. U perspektivi objekti koji su dalji od posmatrača se prikazuju manjim i obratno. Ova projekcija omogućava stvaranje realističnog utiska sveta. Metoda gluPerspective definiše projekciju u perspektivi.

public static void gluPerspective(double fovy , double aspect , double zNear , double zFar )

gde su: fovy – ugao tj. dubina vidnog polja (field-of-view), aspect – odnos širine i visine, zNear, zFar – dubina po z-osi.

Page 22: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 22

Slika 6.2.4.2 Projekcija u perspektivi, preuzeto iz [3]

S obzirom da se tekst ispisuje kao vektorska grafika, moguće je definisati

debljinu linije korišćenjem metode glLineWidth, koja je detaljno opisana u poglavlju 6.4.1.

Pomoćna metoda CalculateStrokeTextWidth izračunava širinu teksta zadatog preko parametra string, koristeći se GLUT funkcijom glutStrokeWidth. Pomoćne metode RenderStrokeTextH i RenderStrokeTextV ispisuju tekst horizontalno, odnosno vertikalno na zadatim koordinatama. Ispisani tekst pokazuje primer centriranog teksta (potrebno je izračunati širinu teksta i podeliti sa dva).

6.3 OpenGL iscrtavanje objekata OpenGL omogućava iscrtavanje sledećih grafičkih objekata u prostoru: tačaka, linija, trouglova, poligona, punih tela (sfera, kvadra i dr.) i mesh objekata. Ovo poglavlje se sastoji iz četiri sekcije: sekcija o tačkama i linijama, sekcija o poligonima, sekcije o mesh objektima i sekcije o punim telima.

6.3.1 Crtanje ta čaka i linija Osnovna jedinica iscrtavanja u OpenGL standardu je tačka (vertex). Tačka je određena sa tri koordinate Dekartovog pravouglog koordinatnog sistema (pravilo desne ruke).

Tačka se definiše u OpenGL standardu pozivom neke od metode iz familije metoda glVertex . Često korišćene metode iz ove familije su:

void glVertex3f(float x , float y , float z ) void glVertex2f(float x , float y ) void glVertex3fv(float[] vertex)

gde su: x,y,z – koordinate tačke, glVertex2f podrazumeva z = 0,

vertex – (x,y,z) kao niz.

Da bi se tačka, a i bilo koja primitiva, iscrtala na ekranu potrebno je poziv glVertex metode enkapsulirati između para metoda glBegin i glEnd . Ove dve metode definišu tip primitive i enkapsuliraju niz poziva metoda glVertex. Za iscrtavanje tačaka mora biti prosleđena vrednost Gl.GL_POINTS kao argument glBegin metode. Listing 6.3.1.1 prikazuje programski kod koji iscrtava tri tačke.

Page 23: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 23

Gl.glBegin(Gl.GL_POINTS);

Gl.glVertex3f(0.0f, 0.0f, 50.0f);

Gl.glVertex3f(50.0f, 50.0f, 50.0f);

Gl.glVertex3f(-50.0f, 50.0f, 50.0f);

Gl.glEnd();

Listing 6.3.1.1 Programski kôd za crtanje tri tačke

Podrazumevana vrednost veličine tačke iznosi jedan piksel (kvadratnog oblika!). Ako se želi promeniti veličina tačke tada je potrebno pozvati metodu glPointSize .

void glPointSize(float size )

gde je: size – veličina tačke.

Veličina tačke ne može biti proizvoljna i zavisi od OpenGL implementacije. Najmanja i najveća podržana veličina tačke je sadržana u promenljivoj stanja: Gl.GL_POINT_SIZE_RANGE, a korak – inkrement u Gl.GL_POINT_SIZE_GRANULITY. Listing 6.3.1.2 prikazuje programski kôd za utvrđivanje podržanih veličina tačke:

float[] min_max = new float[2]; float[] korak = new float[1]; Gl.glGetFloatv(Gl.GL_POINT_SIZE_RANGE, min_max);

Gl.glGetFloatv(Gl.GL_POINT_SIZE_GRANULARITY,

korak);

Listing 6.3.1.2 Programski kôd za utvrđivanje podržanih veličina tačke

Na tačku ne deluje perspektiva tj. tačka je iste veličine bez obzira gde je pozicionirana u prostoru.

Crtanje linija se realizuje korišćenjem metode glVertex za definisanje temena linija enkapsulirane glBegin/glEnd metodama sa parametrima Gl.GL_LINES, Gl.GL_LINE_STRIP i Gl.GL_LINE_LOOP.

GL_LINES iscrtava niz odvojenih linija definisanih preko svojih temena. S obzirom da je linija definisana sa dve tačke, ukupan broj tačaka mora biti paran. Linija se povlači između dva susedna temena (po redosledu navođenja poziva glVertex metode). Listing 6.3.1.3 prikazuje primer crtanja dve linije.

Page 24: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 24

Gl.glBegin(Gl.GL_LINES);

Gl.glVertex3f(0.0f, 0.0f, 0.0f);

Gl.glVertex3f(50.0f, 50.0f, 50.0f);

Gl.glVertex3f(20.0f, 10.0f, 5.0f);

Gl.glVertex3f(-50.0f, -50.0f, -50.0f);

Gl.glEnd();

Listing 6.3.1.3 Programski kôd za crtanje dve linije

GL_LINE_STRIP iscrtava otvorenu poliliniju. Ne postoji ograničenje da broj temena mora biti paran broj, kao kod GL_LINES. Segment polilinije se povlači između dva susedna temena (po redosledu navođenja poziva glVertex metode). Listing 6.3.1.4 prikazuje primer crtanja slova M.

Gl.glBegin(Gl.GL_LINE_STRIP);

Gl.glVertex2f(0.0f, 0.0f);

Gl.glVertex2f(0.0f, 50.0f);

Gl.glVertex2f(15.0f, 0.0f);

Gl.glVertex2f(30.0f, 50.0f);

Gl.glVertex2f(30.0f, 0.0f);

Gl.glEnd();

Listing 6.3.1.4 Programski kôd za crtanje polilinije u obliku slova M

GL_LINE_LOOP iscrtava zatvorenu poliliniju. Razlika između GL_LINE_STRIP i GL_LINE_LOOP je u tome što za ista temena druga iscrtava i segment koji spaja prvo i poslednje teme. Listing 6.3.1.5 prikazuje primer crtanja trougla (polovine slova M).

Gl.glBegin(Gl.GL_LINE_LOOP);

Gl.glVertex2f(0.0f, 0.0f);

Gl.glVertex2f(0.0f, 50.0f);

Gl.glVertex2f(15.0f, 0.0f);

Gl.glEnd();

Listing 6.3.1.5 Primer crtanja zatvorene polilinije u obliku trougla

Page 25: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 25

Podrazumevana debljina linije iznosi jedan piksel, a može se promeniti pozivom metode glLineWidth .

void glLineWidth(float width )

gde je: width – debljina linije.

Slično kao i kod definisanja veličine tačke, i debljina linije ne može biti proizvoljna i zavisi od OpenGL implementacije. Najmanja i najveća podržana debljina linije je sadržana u promenljivoj stanja: GL_LINE_WIDTH_RANGE, a korak – inkrement u GL_LINE_WIDTH_GRANULARITY. Listing 6.3.1.6 prikazuje programski kôd za utvrđivanje podržanih debljina linije.

float[] min_max = new float[2]; float[] korak = new float[1]; Gl.glGetFloatv(Gl.GL_LINE_WIDTH_RANGE, min_max);

Gl.glGetFloatv(Gl.GL_LINE_WIDTH_GRANULARITY,

korak);

Listing 6.3.1.6 Programski kôd za utvrđivanje podržanih debljina linije

Linija se može iscrtavati prema šablonu (pattern), kao npr. isprekidana linija. U režim iscrtavanja prema šablonu ulazi se sa: Gl.glEnable (Gl.GL_LINE_STIPPLE). Zatim se poziva metoda glLineStipple , koja je oblika:

void glLineStipple(int factor , short pattern )

gde su: factor – faktor skaliranja šablona (koliko puta se povećava širina

šablona, npr. ako je factor jednak pet tada jednom pikselu šablona odgovara pet piksela ispune linije).

pattern – šablon definisan kao niz bitova (1 – ima linije, 0 – nema linije. npr. 0101010101010101 crta svaku drugu tačku linije – tačkasta linija). Šablon se parsira s desna na levo!

Za izlazak iz režima se koristi metoda glDisable sa argumentom GL_LINE_STIPPLE. Listing 6.3.1.7 prikazuje primer crtanja isprekidane linije korišćenjem šablona.

// sablon: isprekidana linija ushort sablon = 0x5555;

// udji u rezim rada sa sablonima

Page 26: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 26

Gl.glEnable(Gl.GL_LINE_STIPPLE);

Gl.glLineStipple(1, sablon); // def. sablon

// crtanje linija Gl.glBegin(Gl.GL_LINES);

Gl.glVertex2f(-80.0f, y);

Gl.glVertex2f(80.0f, y);

Gl.glEnd();

// izadji iz rezima rada sa sablonima Gl.glDisable(Gl.GL_LINE_STIPPLE);

Listing 6.3.1.7 Primer crtanja isprekidane linije

Pomoću linija se može nacrtati bilo koje grafički objekat, ali tako nacrtan objekat ne može biti ispunjen bojom, niti mu se može pridružiti tekstura. Za grafički objekat iscrtan pomoću linija se kaže se da je wireframe objekat.

6.3.2 Crtanje poligona U ovom poglavlju biće prezentovano crtanje poligona: trouglova, četvorouglova i n-touglova.

Crtanje trouglova se realizuje korišćenjem metode glVertex za definisanje temena trouglova enkapsulirane sa glBegin/glEnd metodama sa nekim od parametara: Gl.GL_TRIANGLES, Gl.GL_TRIANGLE_STRIP i Gl.GL_TRIANGLE_FAN.

GL_TRIANGLES iscrtava niz odvojenih trouglova definisanih preko svojih temena. S obzirom da je trougao definisan sa tri tačke, ukupan broj tačaka mora biti umnožak broja tri. Trougao određuju tri susedna temena (po redosledu navođenja poziva glVertex metode). Redosled iscrtavanja linija okvira trougla nije određen redosledom navođenja temena, već u smeru suprotnom od smera kretanja kazaljke na satu (counterclockwise, CCW). Listing 6.3.2.1 prikazuje primer crtanja dva odvojena trougla.

Gl.glBegin(Gl.GL_TRIANGLES); Gl.glVertex2f(0.0f, 0.0f); Gl.glVertex2f(0.0f, 50.0f); Gl.glVertex2f(15.0f, 0.0f); Gl.glVertex3f(10.0f, 10.0f, 10.0f); Gl.glVertex3f(25.0f, 50.0f, 5.0f); Gl.glVertex3f(15.0f, 10.0f, -5.0f); Gl.glEnd();

Page 27: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 27

Listing 6.3.2.1 Programski kôd za crtanje dva odvojena trougla GL_TRIANGLE_STRIP iscrtava niz trouglova koji imaju zajedničke ivice. Ova

primitiva se najčešće koristi za iscrtavanje mesh objekata. Svaki trougao, osim prvog, u nizu je određen sa prethodna dva temena u nizu i jednim novim temenom. N trouglova se opisuju preko GL_TRIANGLE_STRIP sa N+2 temena. Listing 6.3.2.2 prikazuje primer crtanja kvadrata pomoću dva trougla.

Gl.glBegin(Gl.GL_TRIANGLE_STRIP);

Gl.glVertex2f(0.0f, 0.0f);

Gl.glVertex2f(0.0f, 50.0f);

Gl.glVertex2f(50.0f, 0.0f);

Gl.glVertex2f(50.0f, 50.0f);

Gl.glEnd();

Listing 6.3.2.2 Programski kôd za crtanje kvadrata pomoću trouglova (strip)

GL_TRIANGLE_FAN iscrtava niz trouglova koji svi imaju jedno zajedničko teme. Svaki trougao, osim prvog, se definiše sa jednim temenom. Listing 6.3.2.3 prikazuje primer crtanja šestougla stranica dužine deset jedinica (square_root_3 je konstanta koja sadrži vrednost kvadratnog korena iz broja tri). Temena se iscrtavaju u smeru kretanja kazaljki na satu (clockwise, CW).

Gl.glBegin(Gl.GL_TRIANGLE_FAN);

Gl.glVertex2f(0.0f, 0.0f);

Gl.glVertex2f(-10.0f, 0.0f);

Gl.glVertex2f(-5.0f, -5.0f * square_root_3);

Gl.glVertex2f(5.0f, -5.0f * square_root_3);

Gl.glVertex2f(10.0f, 0.0f);

Gl.glVertex2f(5.0f, 5.0f * square_root_3);

Gl.glVertex2f(-5.0f, 5.0f * square_root_3);

Gl.glVertex2f(-10.0f, 0.0f);

Gl.glEnd();

Listing 6.3.2.3 Primer crtanja pravilnog šestougla pomoću trouglova (fan)

Page 28: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 28

Trouglovi uglavnom predstavljaju najbrži način za definisanje/crtanje objekata, jer je njihovo iscrtavanje hardverski ubrzano (hardware acclerated) kod svakog OpenGL kompatibilnog hardvera.

Crtanje četvorouglova se realizuje korišćenjem metode glVertex za definisanje temena četvorougla enkapsulirane sa glBegin/glEnd metodama sa nekim od parametara: GL_QUADS ili GL_QUAD_STRIP. Ove primitive se iscrtavaju u smeru kretanja kazaljke na satu (CW). Sva temena četvorougla moraju ležati u istoj ravni!

GL_QUADS crta niz planarnih četvrouglova. Četvorougao je definisan sa četiri temena, tako da ukupan broj tačaka mora biti umnožak broja četiri. Listing 6.3.2.4 prikazuje primer crtanja kvadrata stranice dimenzija petdeset jedinica.

Gl.glBegin(Gl.GL_QUADS);

Gl.glVertex2f(0.0f, 0.0f);

Gl.glVertex2f(0.0f, 50.0f);

Gl.glVertex2f(50.0f, 50.0f);

Gl.glVertex2f(50.0f, 0.0f);

Gl.glEnd();

Listing 6.3.2.4 Programski kôd za crtanje kvadrata pomoću GL_QUADS

GL_QUAD_STRIP crta niz četvorouglova koji imaju zajedničke ivice. U mnogome je ekvivalentan GL_TRIANGLE_STRIP primitivi. Za svaki četvorougao, osim prvog, potrebno je definisati dva temena. Listing 6.3.2.5 prikazuje primer crtanja pravougonika pomoću dva kvadrata.

Gl.glBegin(Gl.GL_QUAD_STRIP);

Gl.glVertex2f(0.0f, 0.0f);

Gl.glVertex2f(0.0f, 50.0f);

Gl.glVertex2f(50.0f, 0.0f);

Gl.glVertex2f(50.0f, 50.0f);

Gl.glVertex2f(100.0f, 0.0f);

Gl.glVertex2f(100.0f, 50.0f);

Gl.glEnd();

Listing 6.3.2.5 Programski kôd za crtanje pravougonika preko GL_QUAD_STRIP

Crtanje planaranih poligona se realizuje pozivom glBegin sa argumentom Gl.GL_POLYGON i navođenjem temena unutra glBegin/glEnd sekcije. Iscrtavanje poligona je u CCW smeru. Dozvoljeni su samo konveksni poligoni (zbog različitih

Page 29: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 29

optimizacija koje su moguće samo nad konveksim poligonima). Konkavni poligoni se dobijaju spajanjem više konveksnih poligona. Listing 6.3.2.6 prikazuje primer pravilnog šestougla.

Gl.glBegin(Gl.GL_POLYGON);

Gl.glVertex2f(-10.0f, 0.0f);

Gl.glVertex2f(-5.0f, -5.0f * square_root_3);

Gl.glVertex2f(5.0f, -5.0f * square_root_3);

Gl.glVertex2f(10.0f, 0.0f);

Gl.glVertex2f(5.0f, 5.0f * square_root_3);

Gl.glVertex2f(-5.0f, 5.0f * square_root_3);

Gl.glEnd();

Listing 6.3.2.6 Primer crtanja pravilnog šestougla pomoću GL_POLYGON

Ispuna poligona može biti outline ili solid. Outline (wireframe) ispuna poligona crta samo njegove ivice, dok solid dodatno ispunjava poligon zadatom bojom. Za izbor tipa ispune poligona koristi se metoda glPolygonMode , koja ima oblik:

void glPolygonMode(int face , int mode)

gde su: face – specifikuje da li se odnosi na lice (front-facing polygons) ili naličje

(back-facing polygons). mode – da li se iscrtavaju kao okvir (Gl.GL_LINE) ili sa ispunom

(Gl.GL_FILL).

Ispuna poligona može biti prema nekom šablonu. U režim ispune poligona šablonom se ulazi pozivom glEnable sa argumentom Gl.GL_POLYGON_STIPPLE. Analogno sa šablonom za linije, šablon za ispunu poligona predstavlja bitmapa (videti poglavlje 5.3.1) dimenzija 32x32 piksela. Za definisanje samog šablona koristi se metoda glPolygonStipple , koja ima oblik:

void glPolygonStipple(byte[] bitmap ) void glPolygonStipple(IntPtr bitmap )

gde je: bitmap – bitmapa koja definiše šablon.

Listing 6.3.2.7 prikazuje primer korišćenja režima ispune poligona šablonom.

// udji u rezim ispune poligona sablonom

Page 30: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 30

Gl.glEnable(Gl.GL_POLYGON_STIPPLE);

// definisi sablon

Gl.glPolygonStipple(sablon);

// kod koji iscrtava poligon

.

.

.

// izadji iz rezima ispune poligona sablonom

Gl.glDisable(Gl.GL_POLYGON_STIPPLE);

Listing 6.3.2.7 Primer ispune poligona šablonom

Prilikom crtanja objekata pomoću primitiva prikaz ivica (Gl.GL_LINE mode) unutar objekata uglavnom nije poželjan. OpenGL nudi metodu glEdgeFlag kojom se može definisati da li su unutrašnje ivice vidljive.

void glEdgeFlag(int flag )

gde je: flag – vrednost iscrtavanja unutrašnjih linija objekta. Početna vrednost je

Gl.GL_TRUE. Listing 6.3.2.8 prikazuje programski kôd koji demonstrira iscrtavanje gore

navedenih grafičkih primitiva.

/************************************************** ********************* * Modul: Program.cs * Autor: Srdjan Mihic * Namena: demonstracija OpenGL primitiva i punih tela ************************************************** **********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace OpenGL_primitive { class Program { enum MenuItem { POINTS = 0, LINES, LINE_STRIP, LINE_LOOP, TRIANG LES, TRIANGLE_STRIP, TRIANGLE_FAN, Q UADS, QUAD_STRIP, POLYGON }; // dimenzije prozora static float windowWidth = 300.0f; static float windowHeight = 300.0f; // Globalna promenljiva koja definise koju primitiv u nacrtati static MenuItem selectedMenuItem = MenuItem .POINTS;

Page 31: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 31

/////////////////////////////////////////////////// /////////////////// // Naziv: ProcessMenu // Namena: rad sa menijem // Parametri: identifikator odabrane stavke /////////////////////////////////////////////////// /////////////////// static void ProcessMenu( int value) { selectedMenuItem = ( MenuItem )value; // preuzmi izabranu primitivu Glut .glutPostRedisplay(); // refresh } /////////////////////////////////////////////////// /////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// /////////////////// static void RenderScene() { const float square_root_3 = 1.73f; Gl .glClear( Gl .GL_COLOR_BUFFER_BIT); switch (selectedMenuItem) { case MenuItem .POINTS: // tacke { // podesi najvecu velicinu tacke float [] min_max_velicina = new float [2]; // ocitaj iz promenljive stanja GL_POINT_SIZE_RANGE // minimalnu i maksimalnu velicinu (min = prvi el. niza, max = // drugi el. niza) Gl .glGetFloatv( Gl .GL_POINT_SIZE_RANGE, min_max_velicina); // podesi maksimalnu velicinu tacke Gl .glPointSize(min_max_velicina[1]); // iscrtaj 3 tacke Gl .glBegin( Gl .GL_POINTS); Gl .glVertex3f(0.0f, 0.0f, 50.0f); Gl .glVertex3f(50.0f, 50.0f, 50.0f); Gl .glVertex3f(-50.0f, 50.0f, 50.0f); Gl .glEnd(); break ; } case MenuItem .LINES: // linije { float [] min_max = new float [2]; float [] korak = new float [1]; // podesi debljinu linije da bude za jedan korak de blja od osnovne Gl .glGetFloatv( Gl .GL_LINE_WIDTH_RANGE, min_max); Gl .glGetFloatv( Gl .GL_LINE_WIDTH_GRANULARITY, korak); Gl .glLineWidth(min_max[0] + korak[0]); Gl .glBegin( Gl .GL_LINES); Gl .glVertex3f(0.0f, 0.0f, 0.0f); Gl .glVertex3f(50.0f, 50.0f, 50.0f); Gl .glVertex3f(20.0f, 10.0f, 5.0f); Gl .glVertex3f(-50.0f, -50.0f, -50.0f); Gl .glEnd();

Page 32: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 32

break ; } case MenuItem .LINE_STRIP: // otvorena polilinija sa sablonom { ushort pattern = 0xF2E3; // 11110010111000011 <=> -- --- - ---- Gl .glEnable( Gl .GL_LINE_STIPPLE); Gl .glLineStipple(1, ( short )pattern); Gl .glBegin( Gl .GL_LINE_STRIP); Gl .glVertex2f(0.0f, 0.0f); Gl .glVertex2f(0.0f, 50.0f); Gl .glVertex2f(15.0f, 0.0f); Gl .glVertex2f(30.0f, 50.0f); Gl .glVertex2f(30.0f, 0.0f); Gl .glEnd(); Gl .glDisable( Gl .GL_LINE_STIPPLE); break ; } case MenuItem .LINE_LOOP: // zatvorena polilinija Gl .glBegin( Gl .GL_LINE_LOOP); Gl .glVertex2f(0.0f, 0.0f); Gl .glVertex2f(0.0f, 50.0f); Gl .glVertex2f(15.0f, 0.0f); Gl .glEnd(); break ; case MenuItem .TRIANGLES: // trouglovi Gl .glBegin( Gl .GL_TRIANGLES); Gl .glVertex2f(0.0f, 0.0f); Gl .glVertex2f(0.0f, 50.0f); Gl .glVertex2f(15.0f, 0.0f); Gl .glVertex3f(10.0f, 10.0f, 10.0f); Gl .glVertex3f(25.0f, 50.0f, 5.0f); Gl .glVertex3f(15.0f, 10.0f, -5.0f); Gl .glEnd(); break ; case MenuItem .TRIANGLE_STRIP: // trouglovi strip Gl .glBegin( Gl .GL_TRIANGLE_STRIP); Gl .glVertex2f(0.0f, 0.0f); Gl .glVertex2f(0.0f, 50.0f); Gl .glVertex2f(50.0f, 0.0f); Gl .glVertex2f(50.0f, 50.0f); Gl .glEnd(); break ; case MenuItem .TRIANGLE_FAN: // trouglovi fan - sestougao preko linija { Gl .glPolygonMode( Gl .GL_FRONT, Gl .GL_LINE); Gl .glBegin( Gl .GL_TRIANGLE_FAN); Gl .glVertex2f(0.0f, 0.0f); Gl .glVertex2f(-10.0f, 0.0f); Gl .glVertex2f(-5.0f, -5.0f * square_root_3); Gl .glVertex2f(5.0f, -5.0f * square_root_3); Gl .glVertex2f(10.0f, 0.0f); Gl .glVertex2f(5.0f, 5.0f * square_root_3);

Page 33: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 33

Gl .glVertex2f(-5.0f, 5.0f * square_root_3); Gl .glVertex2f(-10.0f, 0.0f); Gl .glEnd(); break ; } case MenuItem .QUADS: // cetvorouglovi Gl .glBegin( Gl .GL_QUADS); Gl .glVertex2f(0.0f, 0.0f); Gl .glVertex2f(0.0f, 50.0f); Gl .glVertex2f(50.0f, 50.0f); Gl .glVertex2f(50.0f, 0.0f); Gl .glEnd(); break ; case MenuItem .QUAD_STRIP: // quads strip Gl .glBegin( Gl .GL_QUAD_STRIP); Gl .glVertex2f(0.0f, 0.0f); Gl .glVertex2f(0.0f, 50.0f); Gl .glVertex2f(50.0f, 0.0f); Gl .glVertex2f(50.0f, 50.0f); Gl .glVertex2f(100.0f, 0.0f); Gl .glVertex2f(100.0f, 50.0f); Gl .glEnd(); break ; case MenuItem .POLYGON: // poligon Gl .glBegin( Gl .GL_POLYGON); Gl .glVertex2f(-10.0f, 0.0f); Gl .glVertex2f(-5.0f, -5.0f * square_root_3); Gl .glVertex2f(5.0f, -5.0f * square_root_3); Gl .glVertex2f(10.0f, 0.0f); Gl .glVertex2f(5.0f, 5.0f * square_root_3); Gl .glVertex2f(-5.0f, 5.0f * square_root_3); Gl .glEnd(); break ; default : // za ostale nista ne radi break ; } Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ChangeSize // Parametri: width i height /////////////////////////////////////////////////// /////////////////// static void ChangeSize( int width, int height) { if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); if (width <= height) Gl .glOrtho (-100.0f, 100.0f, -100.0f*height/width, 100.0f*height/width, -100.0f, 100.0f); else Gl .glOrtho (-100.0f*width/height,

Page 34: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 34

100.0f*width/height, -100.0f, 100.0f, -100.0f, 100.0f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// /////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// /////////////////// static void SetupRenderingContext() { // boja pozadine je crna, a boja ispisa je bela Gl .glClearColor(1.0f, 1.0f, 1.0f, 1.0f); Gl .glColor3f(0.0f, 0.0f, 0.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda // Parametri: args // Povratna vrednost: int /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB); Glut .glutInitWindowSize(( int )windowWidth, ( int )windowHeight); Glut .glutCreateWindow( "OpenGL primitive i puna tela" ); Glut .glutDisplayFunc(RenderScene); // Kreiraj meni Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "GL_POINTS" , ( int ) MenuItem .POINTS); Glut .glutAddMenuEntry( "GL_LINES" , ( int ) MenuItem .LINES); Glut .glutAddMenuEntry( "GL_LINE_STRIP" , ( int ) MenuItem .LINE_STRIP); Glut .glutAddMenuEntry( "GL_LINE_LOOP" , ( int ) MenuItem .LINE_LOOP); Glut .glutAddMenuEntry( "GL_TRIANGLES" , ( int ) MenuItem .TRIANGLES); Glut .glutAddMenuEntry( "GL_TRIANGLE_STRIP" , ( int ) MenuItem .TRIANGLE_STRIP); Glut .glutAddMenuEntry( "GL_TRIANGLE_FAN", ( int ) MenuItem .TRIANGLE_FAN); Glut .glutAddMenuEntry( "GL_QUADS", ( int ) MenuItem .QUADS); Glut .glutAddMenuEntry( "GL_QUAD_STRIP", ( int ) MenuItem .QUAD_STRIP); Glut .glutAddMenuEntry( "GL_POLYGON", ( int ) MenuItem .POLYGON); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); SetupRenderingContext(); Glut .glutReshapeFunc(ChangeSize); Glut .glutMainLoop(); } } }

Listing 6.3.2.6 Primer crtanja grafičkih primitiva Slika 6.3.2.1 prikazuje rezultat rada aplikacije navedenog u listingu 6.3.2.6.

Svaka slika – rezultat iz aplikacije je uokviren radi lakšeg uočavanja.

Page 35: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 35

PREPORUKE ZA KORIŠĆENJE: � koristiti trouglove umesto četvorouglova i poligona, jer:

o uvek su planarni, o uvek su konveksni,

� voditi računa da kombinovanje primitiva koje se iscrtavaju u suprotnim smerovima značajno uspora iscrtavanje.

a) GL_POINTS b) GL_LINES c) GL_LINE_STRIP

d) GL_LINE_LOOP e) GL_TRIANGLES f) GL_TRIANGLE_STRIP

g) GL_TRIANGLE_FAN h) GL_QUADS i)GL_QUAD_STRIP j) GL_POLYGON

Slika 6.3.2.1 Rezultat rada aplikacije iz listinga 6.3.2.8

6.3.3 Crtanje mesh objekata Za crtanje mesh objekata se najčešće koriste trouglovi, iz već navedenih razloga. Svi poligonalni objekti se mogu nacrtati preko trouglova. Kao jednostavan primer biće prezentovano crtanje kupe preko trouglova. Listing 6.3.3.1 i slika 6.3.3.1 prikazuju primer crtanja kupe preko trouglova. Primer je preuzet iz [3].

/************************************************** ********************* * Modul: Program.cs * Autor: Richard S. Wright Jr. * Preuzeto: OpenGL SuperBible 4ed * Prilagodio: Srdjan Mihic * Namena: demonstracija kupe sa triangle_strip , depth test i cullinga ************************************************** **********************/ using System; using System.Collections.Generic;

Page 36: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 36

using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace Kupa { class Program { // Rotacija po x i y osi static float xRot = 0.0f; static float yRot = 0.0f; // indikatori izabranih tehnika i mehanizma static bool culling = false ; static bool outline = false ; static bool depthTesting = false ; // stavke menija enum MenuItem { CULLING = 0, OUTLINE, DEPTH_TESTING }; /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessMenu // Namena: rad sa menijem // Parametri: identifikator odabrane stavke /////////////////////////////////////////////////// /////////////////// static void ProcessMenu( int value) { switch (( MenuItem )value) { case MenuItem .DEPTH_TESTING: depthTesting = !depthTesting; break ; case MenuItem .CULLING: culling = !culling; break ; case MenuItem .OUTLINE: outline = !outline; break ; default : break ; } Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// /////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// /////////////////// static void RenderScene() { const float GL_PI = 3.1415f; const float fullCircle = 2.0f * GL_PI; const float step = GL_PI / 8.0f; float x, y, angle; // Koordinate i ugao rotacije

Page 37: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 37

int pivot = 1; // Naizmenicna promena boje poligona // Ocisti sadrzaj kolor bafera i bafera dubine Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); // Ako je izabrano back face culling ukljuci ga i o bratno if (culling == true ) { Gl .glEnable( Gl .GL_CULL_FACE); // ispisi C ako je backface culling ukljucen Gl .glColor3f(1, 1, 1); Gl .glRasterPos2i(-100, 90); // prozor je dimenzija 200x200 Glut .glutBitmapCharacter( Glut .GLUT_BITMAP_HELVETICA_10, 'C' ); } else Gl .glDisable( Gl .GL_CULL_FACE); // Ako je izabrano testiranje dubine ukljuci ga i o bratno if (depthTesting == true ) { Gl .glEnable( Gl .GL_DEPTH_TEST); // ispisi D ako je depth testing ukljucen Gl .glColor3f(1, 1, 1); Gl .glRasterPos2i(-90, 90); // prozor je dimenzija 200x200 Glut .glutBitmapCharacter( Glut .GLUT_BITMAP_HELVETICA_10, 'D' ); } else Gl .glDisable( Gl .GL_DEPTH_TEST); // Ako je izabran rezim iscrtavanja objekta kao wir eframe, // ukljuci ga i obratno if (outline == true ) { Gl .glPolygonMode( Gl .GL_BACK, Gl .GL_LINE); // ispisi L ako je backface culling ukljucen Gl .glColor3f(1, 1, 1); Gl .glRasterPos2i(-80, 90); // prozor je dimenzija 200x200 Glut .glutBitmapCharacter( Glut .GLUT_BITMAP_HELVETICA_10, 'L' ); } else Gl .glPolygonMode( Gl .GL_BACK, Gl .GL_FILL); // Sacuvaj stanje ModelView matrice i primeni rotac ije Gl .glPushMatrix(); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Zapocni iscrtavanje omotaca kupe Gl .glBegin( Gl .GL_TRIANGLE_FAN); // da bi smo dobili omotac a ne krug, postavljamo v rednost z // koordinate na visinu kupe Gl .glVertex3f(0.0f, 0.0f, 75.0f); // dodajemo temena omotaca for (angle = 0.0f; angle < fullCircle; angle += step) { // Izracunavamo x i y koordinatu za sledece teme x = 50.0f * ( float ) Math .Sin(angle); y = 50.0f * ( float ) Math .Cos(angle); // Menjaj boju trouglova naizmenicno (crvena/zelena ) if ((pivot % 2) == 0) Gl .glColor3f(0.0f, 1.0f, 0.0f);

Page 38: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 38

else Gl .glColor3f(1.0f, 0.0f, 0.0f); // Azuriraj stanje boje trouglova ++pivot; // Specifikuj teme na osnovu izracunatog Gl .glVertex2f(x, y); } // Gotovo iscrtavanje omotaca kupe Gl .glEnd(); // Zapocni iscrtavanje osnove kupe Gl .glBegin( Gl .GL_TRIANGLE_FAN); // Centar osnove je u (0,0) Gl .glVertex2d(0.0f, 0.0f); for (angle = 0.0f; angle < fullCircle; angle += step) { // Izracunaj x i y poziciju za sledece teme x = 50.0f * ( float ) Math .Sin(angle); y = 50.0f * ( float ) Math .Cos(angle); // Menjaj boju trouglova (crvena/zelena) if ((pivot % 2) == 0) Gl .glColor3f(0.0f, 1.0f, 0.0f); else Gl .glColor3f(1.0f, 0.0f, 0.0f); // Azutiraj stanje boje trouglova ++pivot; // Specifikuj teme na osnovu izracunatog Gl .glVertex2d(x, y); } // Gotovo iscrtavanje osnove kupe Gl .glEnd(); // Restauriraj stanje ModelView matrice na ono pre crtanja kupe Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// /////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// /////////////////// static void SetupRenderingContext() { // Crna pozadina i zelena boja za crtanje Gl .glClearColor(0.0f, 0.0f, 0.0f, 1.0f ); Gl .glColor3f(0.0f, 1.0f, 0.0f); // Model sencenja na flat (konstantno) Gl .glShadeModel( Gl .GL_FLAT); // TriangleFan je CW, a podrazumevano je da su fron t poligoni CCW // zato moramo da obrnemo smer iscrtavanja front po ligona

Page 39: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 39

Gl .glFrontFace( Gl .GL_CW); } /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessSpecialKeyPress // Namena: metoda obradjuje pritisak na s pecijalne tastere // Parametri: ASCII kod i pozicija misa /////////////////////////////////////////////////// /////////////////// static void ProcessSpecialKeyPress( int key, int x, int y) { switch (key) { case Glut .GLUT_KEY_UP: xRot -= 5.0f; break ; case Glut .GLUT_KEY_DOWN: xRot += 5.0f; break ; case Glut .GLUT_KEY_LEFT: yRot -= 5.0f; break ; case Glut .GLUT_KEY_RIGHT: yRot += 5.0f; break ; }; if (key > 356.0f) xRot = 0.0f; if (key < -1.0f) xRot = 355.0f; if (key > 356.0f) yRot = 0.0f; if (key < -1.0f) yRot = 355.0f; Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ChangeSize // Namena: metoda obradjuje promenu velic ine prozora // Parametri: nove dimenzije prozora /////////////////////////////////////////////////// /////////////////// static void ChangeSize( int w, int h) { float nRange = 100.0f; if (h == 0) h = 1; Gl .glViewport(0, 0, w, h); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); if (w <= h) Gl .glOrtho(-nRange, nRange, -nRange * h / w, nRange * h / w, -nRange, nRange); else Gl .glOrtho(-nRange * w / h, nRange * w / h, -nRange, nRange, -nRange, nRange); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda // Parametri: args // Povratna vrednost: int /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit();

Page 40: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 40

// da bi se moglo vrsiti testiranje dubine po trebno je prilikom // inicijalizacije alocirati bafer za testira nje dubine Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB | Glut .GLUT_DEPTH); Glut .glutCreateWindow( "Demonstracija testiranja dubine i sakrivanja nevidljivih povrsina" ); Glut .glutDisplayFunc(RenderScene); // Kreiraj meni Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "Toggle depth test" , ( int ) MenuItem .DEPTH_TESTING); Glut .glutAddMenuEntry( "Toggle cull backface" , ( int ) MenuItem .CULLING); Glut .glutAddMenuEntry( "Toggle outline back" , ( int ) MenuItem .OUTLINE); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); Glut .glutReshapeFunc(ChangeSize); Glut .glutSpecialFunc(ProcessSpecialKeyPress); SetupRenderingContext(); Glut .glutMainLoop(); } } }

6.3.3.1 Crtanje kupe kao mesh objekta

Gore navedeni primer demonstrira iscrtavanje kupe: aproksimacije kruga kao osnove (pomoću Gl.GL_TRIANGLE_FAN) i aproksimacije omotača (takođe Gl.GL_TRIANGLE_FAN). Susedni trouglovi se iscrtavaju različitim bojama radi lakšeg uočavanja.

FRONT poligoni (poligoni lica) su oni poligoni koji su na „spoljašnjosti“ objekta. BACK poligoni (poligoni naličja) su poligoni „unutrašnjosti“. S toga redosled navođenja temena nije proizvoljan! Ako se temena navode u CW redosledu tada ti poligoni su poligoni lica i obratno (redosled navođenja temena primitiva je prikazan na slici 6.4.3.1). Podrazumevana orijentacija iscrtavanja temena za FRONT poligone je CCW, a za BACK je CW. Pošto Gl.GL_TRIANGLE_FAN ima orijentaciju CW, neophodno je izmeniti orijentaciju iscrtavanja FRONT poligona. Ovo se postiže pozivom metode glFrontFace sa argumentom Gl.GL_CW.

public static void glFrontFace(int mode)

gde je: mode – vrednost orijentacije poligona lica. Moguće su dve vrednosti:

Gl.GL_CW i Gl.GL_CCW. Početna vrednost je Gl.GL_CCW.

Page 41: Op Engl

V Open Graphics Library (OpenGL)

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 41

a) redosled navođenja temena za primitive GL_TRIANGLES (CCW) i GL_TRIANGLE_FAN (CW)

b) redosled navođenja temena za primitive GL_TRIANGLE_STRIP (CCW)

c) redosled navođenja temena za primitive GL_QUAD (CW) i GL_QUAD_STRIP (CW)

Slika 6.3.3.1 Redosled iscrtavanja temena primitiva, preuzeto iz [3]

Depth testing omogućava sakrivanje objekata koji su zaklonjeni nekim drugim objektom (sakrivanje po dubini). Ako nije uključen, tada je zaklonjen onaj objekat koji je ranije nacrtan (sakrivanje po vremenu iscrtavanja). U primeru se to može lepo uočiti, ako se kupa rotira oko ose da se vidi i omotač i osnova, ako nije uključen depth testing osnova će se videti preko omotača.

Back face culling (BFC ) (sakrivanje nevidljivih površina) omogućava značajnu uštedu resursa pošto se nevidljive površine ne iscrtavaju. Utvrđivanje koja površina

Page 42: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 42

se iscrtava se određuje na osnovu orijentacije iscrtavanja temena poligona. Ako je BFC uključen tada se ne iscrtavaju BACK poligoni.

a) kupa sa b) kupa bez c) kupa sa d) kupa sa osnovom testiranjem testiranja sakrivanjem iscrtanom kao dubine dubine nevidljivih površina žičani model

Slika 6.3.3.2 Rezultat rada aplikacije iz listinga 6.3.3.1

Metoda glutSpecialFunc omogućava definisanje metode koja obrađuje ulaz sa tastature i to specijalnih tastera (funkcijski, strelice, home, end, insert, delete, pgup i pgdn). Metoda SpecialKeys definiše ugao rotacije kupe na osnovu pritisnutih kurzorskih strelica. U funkciji RenderScene se vrši rotaciju kupe na osnovu vrednosti dobijenih iz metode SpecialKeys. Metode glPushMatrix i glRotatef će biti detaljno objašnjene u poglavlju 6.5.

6.3.4 Crtanje punih tela i GLUT objekata OpenGL Utility (GLU) programska biblioteka nudi metode za crtanje osnovnih geometrijskih tela, kao i nekih geometrijskih slika. Moguće je nacrtati: sferu, valjak, kupu, krug i prsten. Ovi objekti se nazivaju quadric objektima.

Rad sa quadric objektima se razlikuje od ostalih primitiva. Definisanje parametara iscrtavanja se definiše za jedan „template“ objekat i dalje se primenjuje na sve objekte koji se kreiraju nakon tog „template“ objekta. Životni ciklus (programski kôd) tog objekta je sledeći:

1. Instanciranje novog quadrics objekta sa:

Glu.GLUquadric object = Glu.gluNewQuadric();

2. Podešavanje parametara iscrtavanja. 3. Iscrtavanje objekata sa parametrima definisanim object promenljivom. 4. Oslobađanje memorije sa:

Glu.gluDeleteQuadric(object);

Za podešavanje parametara iscrtavanja na raspolaganju su četiri metode: gluQuadricDrawStyle, gluQuadricOrientation, gluQuad ricNormals i gluQuad-ricTexture .

Metoda gluQuadricDrawStyle definiše način iscrtavanja quadric objekta.

public static void gluQuadricDrawStyle( GLUquadric obj , int drawStyle )

Page 43: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 43

gde su: obj – objekat na koji se metoda primenjuje, drawStyle – način iscrtavanja može biti: Gl.GL_FILL, Gl.GL_LINE,

Gl.GL_POINTS i Gl.GLU_SILHOUETTE. O prva dva stila je bilo reči kod metode glPolygonMode. Gl.GL_POINTS iscrtava objekat samo kao niz temena. Gl.GLU_SILHOUETTE slično kao i Gl.GL_LINE, ali se iscrtavaju samo određene ivice tako da se vidi samo silueta objekta.

Metode gluQuadricNormals i gluQuadricOrientation definišu tip normala, kao i smer – orijentaciju.

public static void gluQuadricNormals( GLUquadric obj , int normals ) public static void gluQuadricOrientation( GLUquadric obj , int orientation )

gde su: obj – quadric objekat za koji se generišu normale, normals – tip normala, može biti:

� Glu.GLU_NONE – ne generišu se normale, � Glu.GLU_FLAT – normale su normalne na površinu (facet), � Glu.GLU_SMOOTH – normale su tako postavljene da se dobija

glatka površina objekta.

orientation – smer normala, može biti: � Glu.GLU_OUTSIDE – smer normala je napolje (najčešće

korišćeno), � Glu.GLU_INSIDE – normale su usmerene u unutrašnjost quadric

objekta. Koristi se ako želi prikazivati unutrašnjost objekta, npr. unutrašnjost kapsule svemirskog broda, koja je modelovana pomoću quadric objekta - sfere.

Metoda gluQuadricTexture omogućava automatsko generisanje koordinata teksture. Rad sa teksturama će biti objašnjen u poglavlju 6.10.

public static void gluQuadricTexture( GLUquadric obj , int textureCoords )

gde su: obj – quadric objekat za koji se generišu koordinate teksture, textureCoords – određuje da li se generišu koordinate teksture. Može biti:

• Glu.GLU_TRUE – generišu se koordinate teksture, • Glu.GLU_FALSE – ne generišu se koordinate teksture.

Page 44: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 44

Sfera se kreira pomoću metode gluSphere . Centar sfere je u koordinatnom početku i sfera se iscrtava u pozitivnom smeru z ose.

public static void gluSphere(GLUQuadric obj , double radius , int slices , int stacks )

gde su: obj – quadric objekat koji definiše parametre iscrtavanja sfere, radius – radijus sfere, slices i stacks – broj segmenata po x odnosno y osi. (sfera se

iscrtava aproksimacijom pomoću trouglova ili četvorouglova (quad stripes))

Valjak se kreira pomoću metode gluCylinder . Centar valjka osnove je u koordinatnom početku i valjak se iscrtava u pozitivnom smeru z ose. Ako je topRadius jednak nuli tada se dobija kupa .

public static void gluCylinder(GLUquadric obj , double baseRadius , double topRadius , double height , int slices , int stacks ) gde su:

obj – objekat koji definiše parametre iscrtavanja, baseRadius – radijus osnove, topRadius – radijus vrha, height – visina valjka, slices i stacks – broj segmenata po x odnosno y osi. (valjak se

iscrtava aproksimacijom pomoću trouglova ili četvorouglova (quad stripes))

Prsten se kreira pomoću metode gluDisk . Centar prstena je u koordinatnom početku i iscrtava se u XY ravni. Ako je innerRadius jednak nuli tada se dobija krug .

public static void gluDisk(GLUquadric obj , double innerRadius , double outerRadius , int slices , int loops )

gde su: obj – objekat koji definiše parametre iscrtavanja, innerRadius – unutrašnji radijus, outerRadius – spoljašnji radijus, slices i loops – broj segmenata po x odnosno y osi. (prsten se

iscrtava aproksimacijom pomoću trouglova ili četvorouglova (quad stripes))

Page 45: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 45

GLUT programska biblioteka nudi metode za iscrtavanje geometrijskih tela: sfere, kocke, kupe, torusa, dodekahedrona, oktahedrona, tetrahedrona, ikosahedrona i čajnika. Metode su redom: glutSolidSphere i glutWireSphere, glutSolidCube i glutWireCube, glutSolidCone i glutWireCone, glutSolidTorus i glutWireTorus, glutSolidDodecahedron i glutWireDodecahedron, glutSolid-Octahedron i glutWireOctahedron, glutSolidTetrahedron i glutWireTetra-hedron, glutSolidIcosahedron i glutWireIcosahedron, glutSolidTeapot i glutWireTeapot . Parametri metoda su slični kao i kod njihovih quadric objekata ekvivalenata.

Listing 6.3.4.1 i slika 6.3.4.1 prikazuju primer iscrtavanja quadric i GLUT objekata.

/************************************************** ********************* * Modul: Program.cs * Autor: Srdjan Mihic * Namena: demonstracija quadric i GLUT primitiva ************************************************** **********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace GLUT_primitive { class Program { enum MenuItem { GLU_SPHERE = 0, GLU_CYLINDER, GLU_DISK, GLUT_SOLID_SPHERE, GLUT_WIRE_SP HERE, GLUT_TEAPOT }; // dimenzije prozora static float windowWidth = 300.0f; static float windowHeight = 300.0f; // Globalna promenljiva koja definise koju primitiv u nacrtati static MenuItem selectedMenuItem = MenuItem .GLU_SPHERE; /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessMenu // Namena: rad sa menijem // Parametri: identifikator odabrane stavke /////////////////////////////////////////////////// /////////////////// static void ProcessMenu( int value) { selectedMenuItem = ( MenuItem )value; // preuzmi izabranu primitivu Glut .glutPostRedisplay(); // refresh } /////////////////////////////////////////////////// /////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// /////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT);

Page 46: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 46

switch (selectedMenuItem) { case MenuItem .GLU_SPHERE: // sfera { Glu . GLUquadric gluObject = Glu .gluNewQuadric(); Glu .gluQuadricNormals(gluObject, Glu .GLU_SMOOTH); Glu .gluSphere(gluObject, 20.0f, 26, 13); Glu .gluDeleteQuadric(gluObject); break ; } case MenuItem .GLU_CYLINDER: // valjak { Glu . GLUquadric gluObject = Glu .gluNewQuadric(); Glu .gluQuadricNormals(gluObject, Glu .GLU_SMOOTH); // u stvari kupa Gl .glPushMatrix(); Gl .glRotatef(90.0f, 0.0f, 1.0f, 1.0f); Glu .gluCylinder(gluObject, 20.0f, 0.0f, 25.0f, 16, 16) ; Glu .gluDeleteQuadric(gluObject); Gl .glPopMatrix(); break ; } case MenuItem .GLU_DISK: // prsten { Glu . GLUquadric gluObject = Glu .gluNewQuadric(); Glu .gluQuadricNormals(gluObject, Glu .GLU_SMOOTH); // u stvari kupa Glu .gluDisk(gluObject, 5.0f, 20.0f, 16, 16); Glu .gluDeleteQuadric(gluObject); break ; } case MenuItem .GLUT_SOLID_SPHERE: // glut sfera Glut .glutSolidSphere(20.0f, 16, 16); break ; case MenuItem .GLUT_WIRE_SPHERE: // glut zicani model sfere Glut .glutWireSphere(20.0f, 16, 16); break ; case MenuItem .GLUT_TEAPOT: // cajnik Glut .glutSolidTeapot(20.0f); break ; default : // za ostale nista ne radi break ; } Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ChangeSize // Parametri: width i height /////////////////////////////////////////////////// /////////////////// static void ChangeSize( int width, int height) { if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity();

Page 47: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 47

if (width <= height) Gl .glOrtho (-100.0f, 100.0f, -100.0f*height/width, 100.0f*height/width, -100.0f, 100.0f); else Gl .glOrtho (-100.0f*width/height, 100.0f*width/height, -100.0f, 100.0f, -100.0f, 100.0f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// /////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// /////////////////// static void SetupRenderingContext() { // boja pozadine je crna, a boja ispisa je bela Gl .glClearColor(1.0f, 1.0f, 1.0f, 1.0f); Gl .glColor3f(0.0f, 0.0f, 0.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB); Glut .glutInitWindowSize(( int )windowWidth, ( int )windowHeight); Glut .glutCreateWindow( "OpenGL primitive i puna tela" ); Glut .glutDisplayFunc(RenderScene); // Kreiraj meni Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "gluSphere" , ( int ) MenuItem .GLU_SPHERE); Glut .glutAddMenuEntry( "gluCylinder" , ( int ) MenuItem .GLU_CYLINDER); Glut .glutAddMenuEntry( "gluDisk" , ( int ) MenuItem .GLU_DISK); Glut .glutAddMenuEntry( "glutSolidSphere" , ( int ) MenuItem .GLUT_SOLID_SPHERE); Glut .glutAddMenuEntry( "glutWireSphere" , ( int ) MenuItem .GLUT_WIRE_SPHERE); Glut .glutAddMenuEntry( "glutTeapot" , ( int ) MenuItem .GLUT_TEAPOT); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); SetupRenderingContext(); Glut .glutReshapeFunc(ChangeSize); Glut .glutMainLoop(); } } }

Listing 6.3.4.1 Crtanje quadric i GLUT objekata

Page 48: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 48

a) gluSphere b) gluCylinder c) gluDisk

d) glutSolidSphere e) glutWiredSphere f) glutSolidTeapot

Slika 6.3.4.1 Rezultat rada aplikacije iz listinga 6.3.4.1

GLU biblioteka omogućava kreiranje parametarskih krivih. Metode za njihovo kreiranje biće objašenje u sledećem poglavlju.

6.3.5 Crtanje parametarskih krivih i zakrpa OpenGL podržava crtanje Bezier-ovih krivih i zakrpa, kao i NURBS krivih i zakrpa.

U prethodnom poglavlju demonstrirano je crtanje geometrijskih tela koja se lako opisuju preko svojih algebarskih jednačina. U opštem slučaju veoma je teško pronaći algebarsku jednačinu za proizvoljnu krivu/zakrpu. Uvidevši ovaj problem Bezier, inženjer u Renou, osmislio je matematički model koji omogućava reprezentaciju proizvoljnih krivih/zakrpa uz veoma mali skup podataka kojima se te krive/zakrpe opisuju. Bezier-ove krive se opisuju preko svojih kontrolnih tačaka.

U režim rada sa 2D Bezier-ovim krivama se ulazi uključivanjem promenljive stanja Gl.GL_MAP1_VERTEX_3 . Zatim je potrebno zadati krivu korišćenjem familije metoda glMap1* . Za evaluaciju tačaka krive koristi se familija metoda glEvalCoord1* . Alternativno se mogu koristiti i metode glMapGrid1* i glEvalMesh1* .

public static void glMap1f(int target , float u1 , float u2 , int stride , int order , float[] points )

public static void glMap1f(int target , float u1 , float u2 , int stride , int order , IntPtr points )

public static void glEvalCoord1f(float u)

gde su: target – mora biti vrednost Gl.GL_MAP1_VERTEX_3, u1 i u2 – početna i krajna vrednost, stride – razmak između kontrolnih tačaka u bajtima, order i points – broj i niz kontrolnih tačaka.

Page 49: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 49

3D Bezier-ove zakrpe se realizuju na analogan način korišćenjem metoda: glMap2*, glMapGrid2* i glEvalMesh2* , kao i promenljive stanja Gl.GL_MAP2_VERTEX_3 .

GLU programska biblioteka omogućava crtanje NURBS krivih i zakrpa. Rad je sličan kao i kod quadrics objekata. Prvo se kreira NURBS (template) objekat pozivom metode gluNewNurbsRenderer . Zatim se radi nad kreiranim NURBS objektom. Po završetku rada potrebno je uništiti objekat pozivom gluDeleteNurbsRenderer .

Parametri NURBS objekta se podešavaju pozivom metode gluNurbsProperty . Ova metoda omogućava podešavanje kvaliteta prikaza objekta, kao i režim iscrtavanje (wireframe ili fill).

Programski kod koji crta NURBS krive/zakrpe se enkapsulira pozivom metoda glBeginCurve/glBeginSurface i glEndCurve/glEndSurface .

NURBS kriva/zakrpa se definiše pozivom metode glNurbsCurve/ glNurbsSurface .

Listing 6.3.5.1 i slika 6.3.5.1 prikazuju primer rada sa parametarskim krivama i zakrpama.

/************************************************** ********************* * Modul: Programs.cs * Autor: Richard S. Wright Jr. * Prilagodio: Srdjan Mihic * Namena: demonstracija parametarskih krvih i zakrpa *************************************************** *********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace Parametarske_krive_zakrpe { class Program { // Stavke menija enum MenuItem { BEZIER_CURVE = 0, BEZIER_SURFACE, NURBS_CURVE, NURBS_SURFACE }; // Podaci za Bezier krivu static int bcNumPoints = 4; static float [, ] bcCtrlPoints = {{ -4.0f, 0.0f, 0.0f }, // pocetna tacka { -6.0f, 4.0f, 0.0f }, // kontrolna tacka { 6.0f, -4.0f, 0.0f }, // kontrolna tacka { 4.0f, 0.0f, 0.0f }}; // krajnja tacka // Podaci za Bezier zakrpu static int bsNumPoints = 3; static float [, ,] bsCtrlPoints = {{{ -4.0f, 0.0f, 4.0f }, { -2.0f, 4.0 f, 4.0f }, { 4.0f, 0.0 f, 4.0f }}, {{ -4.0f, 0.0f , 0.0f },

Page 50: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 50

{ -2.0f, 4.0f , 0.0f }, { 4.0f, 0.0f , 0.0f }}, {{ -4.0f, 0.0f , -4.0f }, { -2.0f, 4.0f , -4.0f }, { 4.0f, 0.0f , -4.0f }}}; // Podaci za NURBS krivu static int ncNumPoints = 4; // 4 X 4 // kriva je u XY ravni [-6,+6] // u v ( x, y, z ) static float [, ] ncCtrlPoints = {{ -6.0f, -6.0f, 0.0f }, { 2.0f, -2.0f , 8.0f }, { 2.0f, 6.0f , 0.0f }, { 6.0f, 6.0f , 0.0f }}; // Cvorovi NURBS krive static float [] ncKnots ={0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,1.0 f, 1.0f}; // Podaci za NURBS zakrpu static int nsNumPoints = 4; // 4 X 4 static float [,,] nsCtrlPoints = { {{ -6.0f, -6.0f, 0.0f}, // u = 0, v = 0 { -6.0f, -2.0f, 0.0f}, // v = 1 { -6.0f, 2.0f, 0.0f}, // v = 2 { -6.0f, 6.0f, 0.0f}}, // v = 3 {{ -2.0f, -6.0f, 0.0f}, // u = 1, v = 0 { -2.0f, -2.0f, 8.0f}, // v = 1 { -2.0f, 2.0f, 8.0f}, // v = 2 // { -2.0f, -2.0f, 0.0f}, // v = 1 // { -2.0f, 2.0f, 0.0f}, // v = 2 { -2.0f, 6.0f, 0.0f}}, // v = 3 {{ 2.0f, -6.0f, 0.0f }, // u = 2, v = 0 { 2.0f, -2.0f, 8.0f }, // v = 1 { 2.0f, 2.0f, 8.0f }, // v = 2 // { 2.0f, -2.0f, 0.0f }, // v = 1 // { 2.0f, 2.0f, 0.0f }, // v = 2 { 2.0f, 6.0f, 0.0f }}, // v = 3 {{ 6.0f, -6.0f, 0.0f}, // u = 3, v = 0 { 6.0f, -2.0f, 0.0f}, // v = 1 { 6.0f, 2.0f, 0.0f}, // v = 2 { 6.0f, 6.0f, 0.0f}}}; // v = 3 // NURBS zakrpa - cvorovi static float [] nsKnots = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f,1.0f,1.0 f,1.0f }; // uglovi rotacije static float xRot = 65.0f; static float yRot = 45.0f; // globalna promenljiva koja definise koju parameta rsku krivu iscrtati static MenuItem selectedMenuItem = MenuItem .BEZIER_CURVE; /////////////////////////////////////////////////// ///////////////////

Page 51: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 51

// Naziv: ProcessSpecialKeyPress // Namena: metoda procesira strelice // Parametri: key, x, y /////////////////////////////////////////////////// /////////////////// static void ProcessSpecialKeyPress( int key, int x, int y) { switch (key) { case Glut .GLUT_KEY_UP: xRot-= 5.0f; break ; case Glut .GLUT_KEY_DOWN: xRot += 5.0f; break ; case Glut .GLUT_KEY_LEFT: yRot -= 5.0f; break ; case Glut .GLUT_KEY_RIGHT: yRot += 5.0f; break ; }; if (key > 356.0f) xRot = 0.0f; if (key < -1.0f) xRot = 355.0f; if (key > 356.0f) yRot = 0.0f; if (key < -1.0f) yRot = 355.0f; Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: ProcessMenu // Namena: metoda obradjuje stavke menija /////////////////////////////////////////////////// ///////////////////// static void ProcessMenu( int value) { selectedMenuItem = ( MenuItem )value; Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glPushMatrix(); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); Gl .glColor3ub(0, 0, 255); switch (selectedMenuItem) { case MenuItem .BEZIER_CURVE: { // Definisi Bezier krivu

Page 52: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 52

Gl .glMap1f( Gl .GL_MAP1_VERTEX_3, // 3D Bezier kriva 0.0f, // Donja granica po U 100.0f, // Gornja granica po U 3, // Rastojanje izmedju podataka bcNumPoints, // broj tacaka ref bcCtrlPoints[0,0]); // niz tacaka // Ukljuci evaluator Gl .glEnable( Gl .GL_MAP1_VERTEX_3); // Nacrtaj krivu Gl .glBegin( Gl .GL_LINE_STRIP); for ( int i = 0; i <= 100; ++i) // Evaluiraj krivu u tacki i Gl .glEvalCoord1f(( float )i); Gl .glEnd(); // Mesto gorenavedene for petlje moze se nacrtati i na sl. nacin //// Mapiraj grid od 100 tacaka od 0 do 100 //Gl.glMapGrid1d(100, 0.0, 100.0); //// Evaluiraj grid //Gl.glEvalMesh1(Gl.GL_LINE,0,100); // Nacrtaj kontrolne tacke Gl .glPointSize(5.0f); Gl .glColor3ub(255, 0, 0); Gl .glBegin( Gl .GL_POINTS); for ( int i = 0; i < bcNumPoints; ++i) Gl .glVertex2fv( ref bcCtrlPoints[i, 0]); Gl .glEnd(); break ; } case MenuItem .BEZIER_SURFACE: { // Definisi Bezier 3D zakrpu Gl .glMap2f( Gl .GL_MAP2_VERTEX_3, // 3D bezier zakrpa 0.0f, // Donja granica po U 10.0f, // Gornja granica po U 3, // Rastojanje izmedju podataka po U 3, // Dimenzija po u-pravcu (red) 0.0f, // Donja granica po V 10.0f, // Gornja granica po V 9, // Rastojanje izmedju podataka po V 3, // dimenzija po U ref bsCtrlPoints[0, 0, 0]); // niz kontrolnih tacaka // Ukljuci evaluator Gl .glEnable( Gl .GL_MAP2_VERTEX_3); // Mapiraj grid od 10 tacaka od 0 do 10 Gl .glMapGrid2f(10, 0.0f, 10.0f, 10, 0.0f, 10.0f); // Evaluiraj grid Gl .glEvalMesh2( Gl .GL_LINE, 0, 10, 0, 10); // Nacrtaj kontrolne tacke // Podesi velicinu tacke da se lakse uoce Gl .glPointSize(5.0f); Gl .glColor3ub(255, 0, 0);

Page 53: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 53

Gl .glBegin( Gl .GL_POINTS); for ( int i = 0; i < bsNumPoints; ++i) for ( int j = 0; j < 3; ++j) Gl .glVertex3fv( ref bsCtrlPoints[i,j,0]); Gl .glEnd(); break ; } case MenuItem .NURBS_CURVE: { // Definisi NURBS objekat Glu . GLUnurbs nurbs = Glu .gluNewNurbsRenderer(); // Podesi parametre NURBS objekta Glu .gluNurbsProperty(nurbs, Glu .GLU_SAMPLING_TOLERANCE, 25.0f); // Glu.gluNurbsProperty(nurbs, Glu.GLU_DISPLAY_MODE , Glu.GLU_OUTLIN E_POLYGON); Glu .gluNurbsProperty(nurbs, Glu .GLU_DISPLAY_MODE, ( float ) Glu .GLU_FILL); Glu .gluBeginCurve(nurbs); Glu .gluNurbsCurve(nurbs, 8, ncKnots, 3, ncCtrlPoints, 4, Gl .GL_MAP1_VERTEX_3); Glu .gluEndCurve(nurbs); // Nacrtaj kontrolne tacke Gl .glPointSize(5.0f); Gl .glColor3ub(255, 0, 0); Gl .glBegin( Gl .GL_POINTS); for ( int i = 0; i < ncNumPoints; ++i) Gl .glVertex3fv( ref ncCtrlPoints[i,0]); Gl .glEnd(); Glu .gluDeleteNurbsRenderer(nurbs); break ; } case MenuItem .NURBS_SURFACE: { Gl .glEnable( Gl .GL_LIGHTING); Gl .glEnable( Gl .GL_LIGHT0); // Definisi NURBS objekat Glu . GLUnurbs nurbs = Glu .gluNewNurbsRenderer(); // Podesi parametre NURBS objekta Glu .gluNurbsProperty(nurbs, Glu .GLU_SAMPLING_TOLERANCE, 25.0f); // Glu.gluNurbsProperty(nurbs, Glu.GLU_DISPLAY_MODE , Glu.GLU_OUTLINE _POLYGON); Glu .gluNurbsProperty(nurbs, Glu .GLU_DISPLAY_MODE, ( float ) Glu .GLU_FILL); // Nacrtaj NURBS zakrpu Glu .gluNurbsSurface(nurbs, // NURBS objekat 8, nsKnots, // Broj i niz cvorova po U 8, nsKnots, // Broj i niz cvorova po V 4 * 3, // Rastojanj po U. 3, // Rastojanje po V

Page 54: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 54

nsCtrlPoints, // Kontrolne tacke 4, 4, // U i V red Gl .GL_MAP2_VERTEX_3); // Tip NURBS zakrpe // Nacrtaj kontrolne tacke Gl .glPointSize(5.0f); Gl .glColor3ub(255, 0, 0); Gl .glBegin( Gl .GL_POINTS); for ( int i = 0; i < nsNumPoints; ++i) for ( int j = 0; j < nsNumPoints; ++j) Gl .glVertex3fv( ref nsCtrlPoints[i, j, 0]); Gl .glEnd(); Glu .gluDeleteNurbsRenderer(nurbs); Gl .glDisable( Gl .GL_LIGHT0); Gl .glDisable( Gl .GL_LIGHTING); break ; } }; Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: ChangeSize // Namena: metoda obradjuje dogadjaj prom ene dimenzija prozora // Parametri: nova sirina i visina prozora /////////////////////////////////////////////////// ///////////////////// static void ChangeSize( int w, int h) { if (h == 0) h = 1; Gl .glViewport(0, 0, w, h); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); Gl .glOrtho(-10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 10.0 f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { Gl .glEnable( Gl .GL_COLOR_MATERIAL); Gl .glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Automatski generisi normale za evaluirane zakrpe Gl .glEnable( Gl .GL_AUTO_NORMAL); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda // Parametri: args // Povratna vrednost: int /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) {

Page 55: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 55

Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE); Glut .glutInitWindowSize(400, 400); Glut .glutCreateWindow( "Demonstracija parametarskih krivih i zakrpa" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); Glut .glutSpecialFunc(ProcessSpecialKeyPress); Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "Bezier-ova kriva" , ( int ) MenuItem .BEZIER_CURVE); Glut .glutAddMenuEntry( "Bezier-ova zakrpa" , ( int ) MenuItem .BEZIER_SURFACE); Glut .glutAddMenuEntry( "NURBS kriva" , ( int ) MenuItem .NURBS_CURVE); Glut .glutAddMenuEntry( "NURBS zakrpa" , ( int ) MenuItem .NURBS_SURFACE); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); SetupRenderingContext(); Glut .glutMainLoop(); } }

}

Listing 6.3.5.1 Demonstracija crtanja parametarskih krivih i zakrpa

6.3.6 Crtanje objekata koriš ćenjem Display List i Vertex Array mehanizama Veoma često postoji potreba za iscrtavanjem više instanci nekog objekta. Enkapsulacija programskog kôda u metode ne daje dovoljno dobre rezultate u aplikacijama gde je bitna performansa. Takođe, često se geometrija nekog objekta ne menja iz frejma u frejm.

OpenGL nudi mehanizam pomoću kojeg se može značajno ubrzati iscrtavanje složenih objekata – Display List (DL) -e. DL mehanizam omogućava enkapsulaciju i kompilaciju komandi za iscrtavanje objekata u komande hardvera. Ovaj mehanizam se bazira na strukturi OpenGL procesa prezentacije grafike (videti poglavlje 6.1). DL predstavlja niz prekompajliranih komandi na strani servera. Obično DL liste se kreiraju u toku inicijalizacije aplikacije.

Definisanje DL listi se realizuje enkapsulacijom programskog kôda za iscrtavanje objekata parom glNewList /glEndList komandi. Sledeći programski kôd prikazuje primer definisanja DL liste.

Gl.glNewList(list_id, Gl.GL_COMPILE);

.

OpenGL programski kôd za isctavanje objekta

.

Gl.glEndList();

Svaka DL lista se jednoznačno identifikuje preko svog naziva koji se navodi kao prvi argument u pozivu glNewList (u primeru je to list_id). Ručna definicija

Page 56: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 56

identifikatora liste nije preporučljiva, jer je podložna grešci. OpenGL programska biblioteka nudi metodu glGenLists koja generiše jedinstvene identifikatore. Metoda glGenLists generiše niz uzastopnih identifikatora. Povratna vrednost iz metode je identifikator prvog objekta.

public static int glGenLists(int range )

gde je:

range – broj identifikatora koji se trebaju generisati.

Metoda glDeleteLists oslobađa zauzete identifikatore i alociranu memoriju za njihovo skladištenje.

public static void glDeleteLists(int list_id , int range )

gde su:

list_id – identifikator DL liste, range – broj identifikatora koji se trebaju osloboditi.

Iscrtavanje DL liste se realizuje korišćenjem metoda glCallList i glCallLists . Razlika između metoda je u tome što poslednja omogućava izvršavanje više DL lista jednim pozivom.

public static void glCallList(int list_id )

public static void glCallLists(int n, int type , IntPtr lists )

gde su:

list_id – identifikator DL liste, lists – niz identifikatora DL lista, type – tip podataka niza lists, obično GL_UNSIGNED_BYTE, n – broj identifikatora niza lists.

Ugnježdavanje poziva iscrtavanja DL listi je dozvoljeno, ali ne i ugnježdavanje poziva kreiranja DL lista! Najviše može biti 64 nivoa hijerarhije.

Listing 6.4.6.1 prikazuje isečak programskog koda primera crtanja 1000 kopija aviona korišćenjem DL mehanizma.

.

.

. // identifikator aviona static int planeDL;

Page 57: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 57

// da li crtamo sa ili bez koriscenja DL lista static bool usingDisplayLists = false ; /////////////////////////////////////////////////// /////////////////// // Naziv: DrawPlane // Namena: metoda iscrtava avion // Napomena: kod preuzet od Richard S. Wright Jr., OpenGL SuperBible /////////////////////////////////////////////////// /////////////////// static void DrawPlane() { Gl .glColor3f(1.0f, 1.0f, 0.0f); Gl .glBegin( Gl .GL_TRIANGLES); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(15.0f, 0.0f, 30.0f); Gl .glVertex3f(15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(15.0f, 0.0f, 30.0f); Gl .glVertex3f(15.0f, 0.0f, 30.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glVertex3f(0.0f, 2.0f, 27.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(0.0f, 2.0f, 27.0f); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(0.0f, 2.0f, 27.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(-30.0f, -0.50f, -57.0f); Gl .glVertex3f(30.0f, -0.50f, -57.0f); Gl .glVertex3f(0.0f, -0.50f, -40.0f); Gl .glVertex3f(0.0f, -0.5f, -40.0f); Gl .glVertex3f(30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, 4.0f, -57.0f); Gl .glVertex3f(0.0f, 4.0f, -57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, -0.5f, -40.0f); Gl .glVertex3f(30.0f, -0.5f, -57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, 4.0f, -57.0f);

Page 58: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 58

Gl .glVertex3f(0.0f, 0.5f, -40.0f); Gl .glVertex3f(3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 0.5f, -40.0f); Gl .glVertex3f(3.0f, 0.5f, -57.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glEnd(); // Of Jet } // /////////////////////////////////////////////////// //////////////// // Naziv: Shutdown // Namena: oslobadjanje DL listi /////////////////////////////////////////////////// ////////////////// static void Shutdown() { Gl .glDeleteLists(planeDL, 1); } //// /////////////////////////////////////////////////// //////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// //////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glPushMatrix(); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); // nacrtaj 1000 aviona for ( int i = -5; i < 5; ++i) for ( int j = -5; j < 5; ++j) for ( int k = -5; k < 5; ++k) { Gl .glPushMatrix(); Gl .glTranslatef(i * 10.0f, k * 10.0f, j * 10.0f); Gl .glScalef(0.1f, 0.1f, 0.1f); // u zavisnosti od izbora crtamo sa ili bez DL if (usingDisplayLists == false ) DrawPlane(); else Gl .glCallList(planeDL); Gl .glPopMatrix(); } Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// //////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi inicijalizacije pre pocetka GLUT petlje /////////////////////////////////////////////////// //////////////////// static void SetupRenderingContext() { Gl .glEnable( Gl .GL_DEPTH_TEST);

Page 59: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 59

Gl .glEnable( Gl .GL_CULL_FACE); Gl .glFrontFace( Gl .GL_CCW); Gl .glClearColor(0.0f, 0.0f, 0.5f, 1.0f); // Kreiraj identifikator liste planeDL = Gl .glGenLists(1); // Kreiraj listu Gl .glNewList(planeDL, Gl .GL_COMPILE); DrawPlane(); Gl .glEndList(); }

.

.

.

Listing 6.4.6.1 Isečak programskog koda za crtanje aviona pomoću DL liste

Iako se DL liste prevashodno koriste za opis statične geometrije, programski kôd koji se enkapsulira može biti bilo koji skup OpenGL komandi sa izuzetkom glNewList/glDeleteList. Naime, nije dozvoljena rekurzija u definiciji DL lista. S obzirom da se OpenGL programski kôd prekompajlira DL liste nisu pogodne za opis geometrije koja se menja tokom izvršavanja. Pošto se DL liste smeštaju u memoriju servera nisu pogodne za objekte sa velikim brojem temena.

OpenGL nudi Vertex Array i Indexed Vertex Array mehanizme za efikasno iscrtavanje objekata čija se geometrija menja u toku izvršavanja i/ili koji imaju veliki broj temena. Ovi mehanizmi koriste nizove temena koji se prosleđuju kao jedini parametar. Ovim se značajno ubrzava iscrtavanje, jer se ne mora pozivati niz OpenGL metoda za svako teme (specifikacija koordinata, koordinata teksture, normala i sl.).

Rad sa vertex array mehanizmom se realizuje kroz sledeće faze: 1. Uključenje klijentske promenljive stanja GL_VERTEX_ARRAY

pozivom metode glEnableClientState . Ova metoda uključuje klijentske promenljive stanja koje su prosleđene kao argument. Suprotna akcija se realizuje pozivom glDisableClientState .

public static void glEnableClientState( int cap )

gde je: cap – simbolička konstanta klijentske promenljive stanja koja

se uključuje.

2. Signalizacije koji niz temena treba da se iscrta pozivom metode glVertexPointer . Ova metoda signalizira OpenGL gde su smešteni podaci, kao i kog su tipa i koliko ih ima. Za specifikaciju normala i boja koriste se analogne metode: glNormalPointer i glColorPointer i sl.

public static void glVertexPointer( int size , int type ,

Page 60: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 60

int stride , IntPtr pointer )

gde su: size – broj koordinata po temenu. Inicijalna vrednost iznosi

četiri,

type – tip koordinate. Dozvoljene vrednosti su: Gl.GL_SHORT, Gl.GL_INT, Gl.GL_FLOAT i Gl.GL_DOUBLE. Inicijalna vrednost je GL_FLOAT,

stride – razmak između susednih temena izražen u

bajtima. Inicijalna vrednost iznosi nula,

pointer – niz temena.

3. Iscrtavanja niza temena pozivom metode glDrawArrays . Ova metoda iscrtava grafičku primitivu definisanu parametrom mode sa count temena počevši od temena sa indeksom first.

public static void glDrawArrays(int mode, int first , int count )

gde su: mode – koju primitivu treba iscrtavati tj. kako tumačiti temena,

first – indeks početnog temena,

count – broj temena koja se iscrtavaju.

4. Isključivanje vertex array mehanizma pozivom glDisableClientState sa argumentom GL_VERTEX_ARRAY.

public static void glDisableClientState( int cap )

gde je: cap – simbolička konstanta klijentske promenljive stanja koja

se isključuje.

U indeksnoj verziji postoje dva niza temena: niz indeksa i niz jedinstvenih temena. Ovaj pristup često obezbeđuje bolju performansu. Naime, u velikom broju slučaja kod mesh objekata broj temena se ponavlja jer se poligoni nastavljaju jedan na drugi. S toga umesto prosleđivanja niza svih temena od kojih se veliki broj ponavlja, prosleđuje se niz jedinstvenih (međusobno različitih) temena i niz indeksa tih temena. Rad sa indeksnom verzijom vertex array mehanizma se razlikuje od obične verzije u fazi tri gde se niz iscrtava pozivom metode glDrawElements .

public static void glDrawElements(int mode,

Page 61: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 61

int count , int type , IntPtr indices )

gde su: mode – koju primitivu treba iscrtavati tj. kako tumačiti temena,

type – tip podataka indeks niza. Dozvoljene vrednosti su: Gl.GL_UNSIGNED_BYTE, Gl.GL_UNSIGNED_SHORT i Gl.GL_UNSIGNED_INT,

count – broj temena koja se iscrtavaju,

indices – niz indeksa.

Listing 6.3.6.2 prikazuje isečak programskog kôda primera iscrtavanja 1000 mesh modela aviona korišćenjem Vertex Array i Indexed Vertex Array mehanizama.

.

.

. // da li crtamo sa ili bez koriscenja indeksne verzije vertex arrays bool g_usingIndexedVertexArrays = false ;

// indeksirana verzija, niz ima elemenata onoliko k oliko je temena = 51 static byte [] indices = { 1, 10, 9,

9, 4, 1, 1, 4, 10, 10, 4, 0, 0, 4, 9, 9, 10, 0, 5, 16, 15, 15, 8, 5, 15, 16, 8, 5, 8, 16, 14, 13, 3, 3, 13, 7, 7, 14, 3, 13, 14, 7, 3, 11, 6, 6, 12, 2, 11, 12, 6};

// razlicitih temena ima 17 static float [] uniqueVertices = { 0.0f, 0.0f, -56.0f, // 0

0.0f, 0.0f, 60.0f, // 1 0.0f, 0.5f, -40.0f, // 2 0.0f, -0.5f, -40.0f, // 3 0.0f, 15.0f, 30.0f, // 4 0.0f, 2.0f, 27.0f, // 5 0.0f, 25.0f, -65.0f, // 6 0.0f, 4.0f, -57.0f, // 7 0.0f, 7.0f, -8.0f, // 8 15.0f, 0.0f, 30.0f, // 9 -15.0f, 0.0f, 30.0f, // 10 3.0f, 0.5f, -57.0f, // 11 -3.0f, 0.5f, -57.0f, // 12

Page 62: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 62

30.0f, -0.5f, -57.0f, // 13 -30.0f, -0.5f, -57.0f, // 14 60.0f, 2.0f, -8.0f, // 15 -60.0f, 2.0f, -8.0f}; // 16

// neindeksirana verzija, 51 teme static float [] vertices = { 0.0f, 0.0f, 60.0f, -15.0f, 0.0f, 30.0f, 15.0f , 0.0f, 30.0f, 15.0f, 0.0f, 30.0f, 0.0f, 15.0f, 30.0f, 0.0f, 0.0f, 60.0f, 0.0f, 0.0f, 60.0f, 0.0f, 15.0f, 30.0f, -15.0f , 0.0f, 30.0f, -15.0f, 0.0f, 30.0f, 0.0f, 15.0f, 30.0f, 0.0f , 0.0f, -56.0f, 0.0f, 0.0f, -56.0f, 0.0f, 15.0f, 30.0f, 15.0f , 0.0f, 30.0f, 15.0f, 0.0f, 30.0f, -15.0f, 0.0f, 30.0f, 0.0f , 0.0f, -56.0f, 0.0f, 2.0f, 27.0f, -60.0f, 2.0f, -8.0f, 60.0f , 2.0f, -8.0f, 60.0f, 2.0f, -8.0f, 0.0f, 7.0f, -8.0f, 0.0f, 2.0f, 27.0f, 60.0f, 2.0f, -8.0f, -60.0f, 2.0f, -8.0f, 0.0f , 7.0f, -8.0f, 0.0f, 2.0f, 27.0f, 0.0f, 7.0f, -8.0f, -60.0f, 2.0f, -8.0f, -30.0f, -0.5f, -57.0f, 30.0f, -0.5f, -57.0f, 0.0f, -0.5f, -40.0f, 0.0f, -0.5f, -40.0f, 30.0f, -0.5f, -57.0f, 0. 0f, 4.0f, -57.0f, 0.0f, 4.0f, -57.0f, -30.0f, -0.5f, -57.0f, 0. 0f, -0.5f, -40.0f, 30.0f, -0.5f, -57.0f, -30.0f, -0.5f, -57.0f, 0.0f, 4.0f, -57.0f, 0.0f, 0.5f, -40.0f, 3.0f, 0.5f, -57.0f, 0.0f, 25.0f, -65.0f, 0.0f, 25.0f, -65.0f, -3.0f, 0.5f, -57.0f, 0.0 f, 0.5f, -40.0f, 3.0f, 0.5f, -57.0f, -3.0f, 0.5f, -57.0f, 0.0f , 25.0f, -65.0f }; /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glPushMatrix(); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Ukljuci rad sa vertex array mehanizmom Gl .glEnableClientState( Gl .GL_VERTEX_ARRAY); // Nacrtaj 1000 aviona for ( int i = -5; i < 5; ++i) for ( int j = -5; j < 5; ++j) for ( int k = -5; k < 5; ++k) { Gl .glPushMatrix(); Gl .glTranslatef(i*10.0f, k*10.0f, j*10.0f); Gl .glScalef(0.1f, 0.1f, 0.1f); // U zavisnosti od izbora crtamo sa ili bez DL if (g_usingIndexedVertexArrays == false ) { Gl .glVertexPointer(3, Gl .GL_FLOAT, 0, vertices); Gl .glDrawArrays( Gl .GL_TRIANGLES, 0, 51); } else { Gl .glVertexPointer(3, Gl .GL_FLOAT, 0, uniqueVertices); Gl .glDrawElements( Gl .GL_TRIANGLES, 51, Gl .GL_UNSIGNED_BYTE, indices); } Gl .glPopMatrix();

Page 63: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 63

} // iskljuci rad sa vertex array mehanizmom Gl .glDisableClientState( Gl .GL_VERTEX_ARRAY); Gl .glPopMatrix(); Glut .glutSwapBuffers(); }

.

.

.

Listing 6.4.6.2 Isečak programskog kôda za crtanje aviona korišćenjem Vertex Array mehanizma

Pored VA mehanizma postoji sličan mehanizam - Vertex Buffer Object (VBO) koji nudi dodatna podešavanja i fleksibilnost i predstavlja fuziju DL i VA mehanizama. Za razliku od VA mehanizma, VBO mehanizam kreira tzv. bafer objekte (buffer objects) na serverskoj strani (što predstavlja sličnost sa DL listama). Metode za pristup i referenciranje podataka u baferima koriste se iste metode kao i kod VA mehanizma.

Ovaj mehanizam omogućava kontrolu nad transferom podataka. Podržane su tri mogućnosti: GL_STREAM_DRAW, GL_STATIC_DRAW i GL_DYNAMIC-_DRAW.

GL_STREAM_DRAW režim radi na isti način kao VA mehanizam – podaci se šalju prilikom svakog iscrtavanja (pozivi metoda: glDrawArrays, glDrawElements). Ovaj režim je pogodan za iscrtavanje animiranih objekata u sceni.

GL_STATIC_DRAW režim šalje podatke grafičkom kontroleru i oni se skladište u memoriji grafičke kartice. Ovaj režim najviše pogoduje za iscrtavanje nedeformabilnih (statičkih) objekata.

Za razliku od prethodnih u GL_DYNAMIC_DRAW režimu drajveri grafičke kartice određuju gde i kako će biti podaci uskladišteni.

Rad sa VBO mehanizmom se realizuje kroz sledeće faze: 1. Uključenje klijentske promenljive stanja GL_VERTEX_ARRAY

pozivom metode glEnableClientState . 2. Kreiranje bafera metodom: glGenBuffers.

public static void glGenBuffers( int size , IntPtr buffers ) public static void glGenBuffers( int size , int[] buffers )

gde su: size – broj bafera koji se alocira,

buffers – niz u koji se smešta niz identifikatora bafera koji se

alociraju.

3. Proglasiti bafer aktivnim pozivom metode glBindBuffer.

Page 64: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 64

public static void glBindBuffer( int target , int buffer ) public static void glBindBuffer( int target , uint buffer )

gde su: target – određuje na koji tip bafera se vezuje. Moguće

vrednosti su: GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER i GL_PIXEL_UNPACK_BUFFER.

buffer – identifikator aktivnog bafera.

4. Inicijalizacija bafera i specifikacija inicijalnih podataka sa glBufferData .

public static void glBufferData( int target , IntPtr size, IntPtr data, int usage ) public static void glBufferData( int target, IntPtr size, IntPtr data, int usage ) gde su:

target – određuje na koji tip bafera se vezuje. Moguće vrednosti

su: GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER i GL_PIXEL_UNPACK_BUFFER,

size – veličina u bajtima objekta u baferu,

data – podaci koji će inicijalno biti kopirani,

usage – specifikuje režim upotrebe: GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ i GL_DYNAMIC_COPY.

5. Deaktiviranje bafera, da ne bi pozivi metoda iscrtavanja sa glBindBuffer gde se umesto podataka šalje 0 (zero pointer).

6. Iscrtavanje sadržaja bafera se realizuje tako što se bafer proglasi aktivnim, a zatim pozivima glVertexPointer i glDrawArrays na sličan način iscrta. Na primer:

// povezi vec kreirani bafer Gl .glBindBuffer( Gl .GL_ARRAY_BUFFER, vbo);

Page 65: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 65

// neophodno zbog vertex array-a - iskljucuje – // postojeci vertexpointer Gl .glVertexPointer(vertexComponentCount, Gl .GL_FLOAT, 0, IntPtr .Zero); // iscrtaj sadrzaj bafera Gl .glDrawArrays( Gl .GL_TRIANGLES, 0, vertexCount);

7. Na kraju potrebno je osloboditi bafer pozivom metode glDeleteBuffers .

public static void glDeleteBufffers(int n, int[] buffers )

public static void glDeleteBufffers(int n, IntPtr buffers )

public static void glDeleteBufffers(int n, ref int buffers )

public static void glDeleteBufffers(int n, uint[] buffers )

public static void glDeleteBufffers(int n, ref uint buffers )

gde su: n – broj bafera koji se oslobađaju,

buffers – niz identifikatora bafera koji se oslobađaju.

8. Isključivanje vertex array mehanizma pozivom glDisableClientState sa argumentom GL_VERTEX_ARRAY.

public static void glDisableClientState( int cap )

gde je: cap – simbolička konstanta klijentske promenljive stanja koja se isključuje.

S obzirom da predstavlja kombinaciju najboljih osobina DL i VA mehanizma

predstavlja preporuku za korišćenje.

6.4 Transformacije objekata U OpenGL standardu transformacije se realizuju pomoću matrica: Viewing , Modeling , Modelview , Projection i Viewport . Redosled primena transformacija je fiksan i identičan redosledu navođenja matrica u prethodnoj rečenici.

Page 66: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 66

Referentni koordinatni sistem je Dekartov pravougli koordinatni sistem, sa pozitivnim pravcem x-ose u desno, pozitivnim pravcem y-ose na gore i pozitivnim pravcem z-ose iz ravni ka korisniku (pravilo desne ruke).

Viewing matrica definiše tačku posmatranja – kameru (transformiše koordinatni sistem). Modeling matrica omogućava transformacije nad modelom i njegovim objektima.

Modelview matrica integriše transformacije koje vrše prethodne dve matrice i olakšava transformacije nad scenom. Ovo proizilazi iz činjenice da sa aspekta posmatrača je svejedno da li se kamera premestila ili su primenjene transformacije nad objektima ako je rezultujući pogled na scenu identičan u oba slučaja, slika 6.4.1.

Nakon ovih transformacija primenjuju se transformacije projekcije. Projection matrica definiše vidljivi volumen, kao i tip projekcije scene na ekran (ortogonalna ili projekcija u perspektivi). Viewport matrica definiše mapiranje 2D projekcije scene u prozor u kojem se prikazuje. Najčešće se manipulacije vrši nad Modelview i Projection matricama. Grafička predstava procesa primena transformacija nad temenom je prikazana na slici 6.4.2.

Slika 6.4.2 Redosled primene transformacija nad temenom, preuzeto iz [3] Izbor matrice nad kojom se vrše transformacije se realizuje pomoću metode

glMatrixMode .

public static void glMatrixMode(int mode)

gde je: mode – koja matrica se selektuje. Između ostalih moguće su vrednosti:

Gl.GL_MODELVIEW, Gl.GL_PROJECTION kojima se selektuje odgovarajuće matrice.

a) pomeranje b) pomeranje kamere koord. sistema

Slika 6.4.1 Ekvivalencija transformacija kamere i koord. sistema, preuzeto iz [3]

Page 67: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 67

Translacija se realizuje pomoću familije metoda glTranslate , od kojih je najčešće korišćena metoda glTranslatef.

public static void glTranslatef(float x , float y , float z )

gde su: x, y, z – pomeraj po x,y,z osama.

Rotacija se realizuje pomoću familije metoda glRotate , od kojih je najčešće korišćena metoda glRotatef.

public static void glRotatef(float angle , float x , float y , float z )

gde su: angle – ugao rotacije izražen u stepenima, x, y, z – vektor u odnosu na koji se vrši rotacija (vektor je definisan sa

(0,0,0) i (x,y,z)).

Skaliranje se realizuje pomoću familije metoda glScale , od kojih je najčešće korišćena metoda glScalef. Uniformno skaliranje se realizuje sa x = y = z.

public static void glScalef(float x , float y , float z )

gde su: x, y, z – faktori skaliranja po svakoj od osa.

Primena transformacija u OpenGL standardu je kumulativna . Samim tim, jednostavna primena transformacija dovodi do nepredvidivih rezultata. Npr. ako se žele iscrtati sfere pozicionirane kao na slici 6.4.3a, kao logična realizacija se nameće sledeći programski kôd:

// translacija za 10 jedinica po y-osi Gl.glTranslatef(0.0f, 10.0f, 0.0f); // iscrtaj prvu sferu Glut.glutSolidSphere(1.0f, 15, 15); // translacija za 10 jedinica po x-osi Gl.glTranslatef(10.0f, 0.0f, 0.0f); // iscrtaj drugu sferu Glut.glutSolidSphere(1.0f, 15, 15);

Problem nastaje što gore navedeni programski kôd zbog kumulativnosti primene transformacija daje rezultat prikazan na slici 6.4.3b.

Page 68: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 68

a) željena pozicija b) rezultujuća pozicija

Slika 6.4.3 Kumulativnost transformacija, preuzeto iz [3]

Da bi se izbegao problem kumulativnosti potrebno je imati mogućnost resetovanja matrice. U te svrhe se koristi metoda glLoadIdentity . Iako korišćenje ove metode rešava gore pomenute probleme sama metoda je zahtevna. Mnogo bi bilo lakše da je moguće nekako sačuvati privremeno stanje matrice, primeniti izmene i posle to stanje vrati. OpenGL definiše matri čni stek (LIFO) za tu namenu i metode glPushMatrix i glPopMatrix . Sve operacije matričnog steka se odnose na trenutno izabranu matricu (korišćenjem metode glMatrixMode). Sledeći programski kôd realizuje poziciju sfera kao na slici 6.4.3a:

// sacuvaj stanje Gl.glPushMatrix(); // translacija za 10 jedinica po y-osi Gl.glTranslatef(0.0f, 10.0f, 0.0f); // iscrtaj prvu sferu Glut.glutSolidSphere(1.0f, 15, 15); // vrati staro stanje Gl.glPopMatrix(); // translacija za 10 jedinica po x-osi Gl.glTranslatef(10.0f, 0.0f, 0.0f); // iscrtaj drugu sferu Glut.glutSolidSphere(1.0f, 15, 15);

Slika 6.4.4 Rezultat rada aplikacije iz listinga 6.4.1 u različitim vremenskim

trenucima

Listing 6.4.1 i slika 6.4.4 prikazuje isečak programskog kôda (RenderScene metodu) simulacije revolucije Zemlje oko Sunca i Meseca oko Zemlje primenom transformacija. Primer je preuzet iz [3]. U primeru se koristi kumulativnost transformacija. Prvo se iscrta Sunce u centru prozora. Zatim se Zemlja zarotira za

Page 69: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 69

fEarthRot ugao u odnosu na Sunce, a onda se Mesec zarotira za fMoonRot ugao u odnosu na Zemlju. Ovo je postignuto upravo korišćenjem kumulativnosti transformacija.

static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); // Sacuvaj stanje ModelView matrice i iscrtaj scenu Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glPushMatrix(); // Transliraj scenu tako da se vidi unutar prozora Gl .glTranslatef(0.0f, 0.0f, -300.0f); // Sunce Gl .glDisable( Gl .GL_LIGHTING); Gl .glColor3ub(255, 255, 0); Glut .glutSolidSphere(15.0f, 30, 17); Gl .glEnable( Gl .GL_LIGHTING); // Pomeri svetlosni izvor nakon iscrtavanja Sunca Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_POSITION, lightPos); // Rotiraj koordinatni sistem da bi iscrtali Zemlju Gl .glRotatef(earthRotation, 0.0f, 1.0f, 0.0f); // Zemlja Gl .glColor3ub(0, 0, 255); Gl .glTranslatef(105.0f, 0.0f, 0.0f); Glut .glutSolidSphere(15.0f, 30, 17); // Rotiraj za ugao Meseca i nacrtaj Mesec Gl .glColor3ub(200, 200, 200); Gl .glRotatef(moonRotation, 0.0f, 1.0f, 0.0f); Gl .glTranslatef(30.0f, 0.0f, 0.0f); Glut .glutSolidSphere(6.0f, 30, 17); // Restauriraj stanje ModelView matrice pre crtanja Gl .glPopMatrix(); // Modelview matrix // Azuriraj ugao rotacije Zemlje i Meseca (korak je 5 stepeni) moonRotation += 15.0f; if (moonRotation > 360.0f) moonRotation = 0.0f; earthRotation += 5.0f; if (earthRotation > 360.0f) earthRotation = 0.0f; Glut .glutSwapBuffers(); }

Listing 6.4.1 Primer primene transformacija – Solarni sistem

OpenGL nudi niz metoda za matrični račun kojima se direktno može menjati aktivna matrica (npr. ModelView). Više o ovim metodama se može naći u [2, 3].

Page 70: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 70

6.5 Kamera i interakcija U ovom poglavlju biće objašnjen rad sa kamerom, kao i mogućnosti interakcije sa korisnikom koje pruža GLUT programska biblioteka.

6.5.1 Rad sa kamerom Za specifikovanje pozicije kamere koristi se Viewing matrica, videti poglavlje 6.5. Pozicioniranje kamere se realizuje korišćenjem metode gluLookAt .

public static void gluLookAt( double eyex , double eyey , double eyez , double centerx , double centery , double centerz , double upx , double upy , double upz )

gde su:

eyex, eyey, eyez – tačka posmatranja, centerx, centery, centerz – vektor koji opisuje pravac i

smer u kome gleda kamera (forward vector), upx, upy, upz – vektor koji određuje pravac i smer na gore

(upward vector).

Pozicija i orijentacija objekta (obično se koristi termin akter), a i kamere, u prostoru se jednoznačno opisuje pomoću tri atributa: pozicije objekta, vektora koji definiše šta je napred (forward vector) i vektora koji definiše šta je iznad (upward vector), slika 6.5.1. Na ovaj način se značajno olakšavaju transformacije nad objekti-ma, npr. ako treba rotirati avion na slici ulevo tada je potrebno izmeniti njegov forward vector. Dodatno, olakšane su i transformacije objekata u odnosu na druge objekte, npr. primer revolucije Zemlje i Meseca oko Sunca – Mesec se rotira u odnosu na Zemlju i sa njom oko Sunca. Lokalni koordinatni sistem objekta određen na ovaj način se naziva frame of reference.

Interakcija sa korisnikom je omogućena GLUT metodama: glutKeyboardFunc, glutKeyboardUpFunc, glutGetModifiers, glutSpecialFunc, glutSpecialUpFunc, glutMouseFunc, glutMotionFunc, glutPassiveMotionFunc, glutEntryFunc i glutIgnoreKeyRepeat.

Slika 6.5.1 Jednoznačno određivanje pozicije i orijentacije objekta u prostoru

Page 71: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 71

6.5.2 Interakcija korisnika sa tastaturom Interakcija korisnika sa tastaturom se realizuje preko metoda: glutKeyboardFunc, glutKeyboardUpFunc, glutSpecialFunc i glutSpecialUpFunc.

Metoda glutKeyboardFunc omogućava registrovanje callback metode za obradu pritisnutih ASCII karaktera na tastaturi, dok metoda glutKeyboardUpFunc omogućava registrovanje callback metode za obradu otpuštanja ASCII karaktera na tastaturi. Ako je potrebno očitati stanje modifikatorskih (Alt-Ctrl-Shift) tastera tada se koristi metoda glutGetModifiers . Ova metoda daje validne rezultate ako se poziva iz obrađivača događaja sa tastature i miša.

public static void glutKeyboardFunc( KeyboardCallback func )

public delegate void Glut.KeyboardCallback( byte key , int x , int y ) public static void glutKeyboardUpFunc( KeyboardUpCallback func ) public delegate void Glut.KeyboardUpCallback( byte key , int x , int y )

public static int glutGetModifiers()

gde su: key – ASCII karakter koji je pritisnut/se otpušta, x,y – koordinate miša prilikom pritiskanja/otpuštanja.

Povratna vrednost od glutGetModifiers je broj jedan ili OR kombinacija sledećih vrednosti: Glut.GLUT_ACTIVE_SHIFT, Glut.GLUT_ACTIVE_CTRL i Glut.GLUT_ACTIVE_ALT.

Metoda glutSpecialFunc omogućava registrovanje callback metode za obradu pritiska specijalnih karaktera na tastaturi (funkcijski tasteri, Home, Delete, Insert, End, PgUp, PgDn i kurzorske strelice). Metoda glutSpecialUpFunc omogućava registrovanje callback metode za obradu otpuštanja specijalnog karaktera na tastaturi.

public static void glutSpecialFunc( SpecialCallback func ) public delegate void Glut.SpecialCallback( int key , int x , int y ) public static void glutSpecialUpFunc( SpecialUoCallback func )

Page 72: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 72

public delegate void Glut.SpecialUpCallback( int key , int x , int y )

gde su: key – specijalni karakter koji je pritisnut/se otpušta, moguće vrednosti su:

Glut.GLUT_KEY_F1, Glut.GLUT_KEY_F2, Glut.GLUT_KEY_F3, Glut.GLUT_KEY_F4, Glut.GLUT_KEY_F5, Glut.GLUT_KEY_F6, Glut.GLUT_KEY_F7, Glut.GLUT_KEY_F8, Glut.GLUT_KEY_F9, Glut.GLUT_KEY_F10, Glut.GLUT_KEY_F11, Glut.GLUT_KEY_F12, Glut.GLUT_KEY_LEFT, Glut.GLUT_KEY_UP, Glut.GLUT_KEY_RIGHT, Glut.GLUT_KEY_DOWN, Glut.GLUT_KEY_PAGE_UP, Glut.GLUT_KEY_PAGE_DO, Glut.GLUT_KEY_HOME, KEY_END, i Glut.GLUT_KEY_INSERT,

x,y – koordinate miša prilikom pritiskanja/otpuštanja.

GLUT parsira pritisnut taster sve dok se ne otpusti. Ovakvo ponašanje nije uvek pogodno. Npr. ako je pritisnuto više tastera odjednom, ovakav mehanizam registruje samo pritisak prvog tastera. S toga, metoda glutIgnoreKeyRepeat omogućava isključivanje procesiranja držanja pritisnutog tastera.

public static void glutIgnoreKeyRepeat( int repeatMode )

gde je: repeatMode – nula vrednost uključuje ponavljanje, dok vrednost

različita od nule isključuje ponavljanje.

6.5.3 Interakcija korisnika sa mišem Interakcija korisnika sa mišem realizuje se preko metoda: glutMouseFunc, glutMotionFunc i glutPassiveMotionFunc.

Metoda glutMouseFunc omogućava registrovanje callback metode za obradu pritiska tastera miša. Ako je potrebno reagovati na pomeranje kurzora pomoću miša tada se koriste metode glutMotionFunc i glutPassiveMotionFunc . Razlika između ovih metoda je u tome što glutPassiveMotionFunc ne registruje stanje dugmadi miša prilikom pomeranja. Metoda glutEntryFunc omogućava definisanje reakcije na napuštanje/ulazak kurzora miša u/van prozor/a.

public static void glutMouseFunc( MouseCallback func ) public delegate void Glut.MouseCallback( int button , int state , int x , int y ) public static void glutMotionFunc(

Page 73: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 73

MotionCallBack func )

public delegate void Glut.MotionCallback(

int x , int y )

public static void glutPassiveMotionFunc( PassiveMotionCallback func ) public delegate void Glut.PassiveMotionCallback( int x , int y ) public static void glutEntryFunc(

EntryCallback func )

public delegate void Glut.EntryCallback(int state )

gde su: button – dugme miša. Moguće su sl. vrednosti:

Glut.GLUT_LEFT_BUTTON, Glut.GLUT_MIDDLE_BUTTON ili Glut.GLUT_RIGHT_BUTTON,

x,y – koordinate miša prilikom pritiskanja/otpuštanja, state – stanje dugmeta miša. Moguće su sl. vrednosti:

Glut.GLUT_LEFT ili Glut.GLUT_ENTERED za metodu glutEntryFunc, a za glutMouseFunc: Glut.GLUT_UP ili Glut.GLUT_DOWN.

6.5.4 Primer upravljanja kamerom pomo ću tastature i miša U dalje tekstu biće prezentovan primer upravljanja kamerom korišćenjem W,A,S,D tastera i strelica za pomeranje, kao i pomeranjem miša za rotaciju pogleda. Programski kod primera prikazan je u listingu 6.5.4.1. Rezultat rada aplikacije je prikazan na slici 6.5.4.1. U primeru se koriste i metode glutFullScreen , glutReshapeWindow i glutSetCursor koje prebacuju prikaz preko celog ekrana, menjaju dimenzije prozora i menjaju izgled kurzora, istim redosledom.

/************************************************** ********************* * Modul: Program.cs * Autor: Srdjan Mihic * Namena: demonstracija GLUT metoda za interakci ju za pomeranje kamere ************************************************** **********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace Kamera { class Program

Page 74: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 74

{ // dimenzije prozora static float windowWidth = 640.0f; static float windowHeight = 320.0f; static float halfWindowWidth = g_windowWidth / 2; static float halfWindowHeight = g_windowHeight / 2; static bool fullscreen = false ; // globalna promenljiva koja definise kameru static Camera camera = new Camera(); // brzina pomeranja kamere static float speed = 0.01f; // pomeraj napred-nazad i levo-desno static float deltaMove = 0.0f; static float deltaStrafe = 0.0f; // pogled iz prvog ili treceg lica static bool thirdPersonView = false ; /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessMenu // Namena: rad sa menijem // Parametri: identifikator odabrane stavke /////////////////////////////////////////////////// /////////////////// static void ProcessMenu( int value) { thirdPersonView = !thirdPersonView; // toggle Glut .glutPostRedisplay(); // refresh } /////////////////////////////////////////////////// /////////////////// // Naziv: DrawMarkers // Namena: crta objekte u okolini kao viz uelne markere /////////////////////////////////////////////////// /////////////////// static void DrawMarkers() { // iscrtaj neka tela cisto kao orijentire u prostor u Gl .glColor3ub(0, 0, 255); Gl .glPushMatrix(); Gl .glTranslatef(60.0f, 5.0f, -78.0f); Glut .glutSolidCube(5.0f); Gl .glPopMatrix(); Gl .glPushMatrix(); Gl .glTranslatef(-60.0f, 12.0f, 8.0f); Glut .glutSolidSphere(15.0f, 16, 16); Gl .glPopMatrix(); Gl .glPushMatrix(); Gl .glTranslatef(41.0f, -2.0f, -8.0f); Glut .glutSolidCone(3.0f, 10.0f, 16, 16); Gl .glPopMatrix(); Gl .glPushMatrix(); Gl .glTranslatef(12.0f, 0.0f, -12.0f); Glut .glutSolidTorus(4.0f, 5.0f, 16, 16); Gl .glPopMatrix(); }

Page 75: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 75

/////////////////////////////////////////////////// /////////////////// // Naziv: DrawGrid // Namena: crta grid kao wireframe (Tron film!) /////////////////////////////////////////////////// /////////////////// static void DrawGrid() { // iscrtaj niz linija paralelnih sa x i z osama Gl .glColor3ub(0, 255, 255); // Nacrtaj grid sa celijom dimenzija 1x1 u XZ ravni for ( float i = -88; i <= 88; ++i) { Gl .glBegin( Gl .GL_LINES); Gl .glVertex3f(-88.0f, 0.0f, i); Gl .glVertex3f(88.0f, 0.0f, i); Gl .glVertex3f(i, 0.0f, -88.0f); Gl .glVertex3f(i, 0.0f, 88.0f); Gl .glEnd(); } } /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessNormalKeyPress // Namena: metoda procesira WASD // Parametri: key, x, y /////////////////////////////////////////////////// /////////////////// static void ProcessNormalKeyPress( byte key, int x, int y) { switch (( char )key) { case 'a' : deltaStrafe = -speed; break ; case 'd' : deltaStrafe = speed; break ; case 'w' : deltaMove = speed; break ; case 's' : deltaMove = -speed; break ; } Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessNormalKeyPressRelease // Namena: metoda procesira otpustanje WA SD // Parametri: key, x, y /////////////////////////////////////////////////// /////////////////// static void ProcessNormalKeyPressRelease( byte key, int x, int y) { switch (( char )key) { case 'a' : case 'd' : deltaStrafe = 0.0f;

Page 76: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 76

break ; case 'w' : case 's' : deltaMove = 0.0f; break ; } Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessSpecialKeyPress // Namena: metoda procesira strelice // Parametri: key, x, y /////////////////////////////////////////////////// /////////////////// static void ProcessSpecialKeyPress( int key, int x, int y) { // ocitaj stanje ALT, CTRL i SHIFT tastera int modifierState = Glut .glutGetModifiers(); switch (key) { // pritisnut taster za pomeranje napred-nazad -> na mesti pomeraj case Glut .GLUT_KEY_LEFT : // ako su pritisnuti alt i ctrl dupliraj brzinu if (modifierState == ( Glut .GLUT_ACTIVE_CTRL | Glut .GLUT_ACTIVE_ALT)) deltaStrafe = -2*speed; else deltaStrafe = -speed; break ; case Glut .GLUT_KEY_RIGHT : // ako su pritisnuti alt i ctrl dupliraj brzinu if (modifierState == ( Glut .GLUT_ACTIVE_CTRL | Glut .GLUT_ACTIVE_ALT)) deltaStrafe = 2*speed; else deltaStrafe = speed; break ; case Glut .GLUT_KEY_UP : // ako je pritisnut i shift dupliraj brzinu - simul acija trcanja if (modifierState == Glut .GLUT_ACTIVE_SHIFT) deltaMove = 2*speed; else deltaMove = speed; break ; case Glut .GLUT_KEY_DOWN : // ako je pritisnut i shift dupliraj brzinu - simul acija trcanja if (modifierState == Glut .GLUT_ACTIVE_SHIFT) deltaMove = -2*speed; else deltaMove = -speed; break ; // pritisak na F4 siri prikaz na ceo ekran, i obrat no case Glut .GLUT_KEY_F4: if (g_fullscreen == false ) Glut .glutFullScreen();

Page 77: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 77

else Glut .glutReshapeWindow(( int )windowWidth, ( int )windowHeight); fullscreen = !fullscreen; break ; case Glut .GLUT_KEY_F10 : Environment .Exit(0); break ; } Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessSpecialKeyPressRelease // Namena: metoda procesira otpustanaja s trelice // Parametri: key, x, y /////////////////////////////////////////////////// /////////////////// static void ProcessSpecialKeyPressRelease( int key, int x, int y) { switch (key) { // otpusten taster za pomeranje levo-desno -> reset uj pomeraj case Glut .GLUT_KEY_LEFT : case Glut .GLUT_KEY_RIGHT : deltaStrafe = 0.0f; break ; // otpusten taster za pomeranje napred-nazad -> res etuj pomeraj case Glut .GLUT_KEY_UP : case Glut .GLUT_KEY_DOWN : deltaMove = 0.0f; break ; case Glut .GLUT_KEY_F10 : Environment .Exit(0); break ; } Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessMouseMovement // Namena: metoda procesira kretanje misa /////////////////////////////////////////////////// /////////////////// static void ProcessMouseMovement( int x, int y) { float lastRotationZ = 0.0f; const float angleScale = 2000.0f; // ako je centar ekrana nema nikakve rotacije if (x == halfWindowWidth && y == halfWindowHeight) return ; // izracunaj ugao // pomeranje po x osi treba da rotira oko y-ose // pomeranje po y osi treba da rotira oko z-ose float angleY = (halfWindowWidth - x) / angleScale; float angleZ = (halfWindowHeight - y) / angleScale; // ne dopusta se rotacija veca od 360/-360 stepeni if (lastRotationZ + angleZ < -1.0f || lastRotationZ + angleZ > 1.0f) return ;

Page 78: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 78

// zapamti ugao lastRotationZ += angleZ; camera.RotateViewByMouse(angleY, angleZ); Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); // podesi kameru if (deltaMove != 0) camera.Move(deltaMove); if (deltaStrafe != 0) camera.Strafe(deltaStrafe); camera.Update(); camera.Look(); // nacrtaj grid DrawGrid(); // nacrtaj neke objekte kao orijentire u prostoru DrawMarkers(); // nacrtaj objekat - korisnika // objekat da bi bio u trecem licu mora biti ispred kamere! if (thirdPersonView == true ) { Gl .glTranslatef(g_camera.ViewX, 0.0f, g_camera.ViewZ) ; Gl .glColor3ub(255, 255, 0); Glut .glutSolidIcosahedron(); } Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ChangeSize // Namena: obradjuje promenu dimenzija pr ozora /////////////////////////////////////////////////// /////////////////// static void ChangeSize( int width, int height) { if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); Glu .gluPerspective(45.0f,( float )width/( float )height, 1.0f, 150.0f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi inicijalizacije pre pocetka GLUT petlje /////////////////////////////////////////////////// /////////////////////

Page 79: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 79

static void SetupRenderingContext() { Gl .glClearColor(0.0f, 0.0f, 0.0f, 1.0f); camera.Position(0.0f, 1.5f, 6.0f, 0.0f, 1.5f, 0.0f, 0.0f, 1.0f, 0.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGBA); Glut .glutInitWindowSize(( int )windowWidth, ( int )windowHeight); Glut .glutCreateWindow( "Demonstracija rada sa kamerom" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); Glut .glutDisplayFunc(RenderScene); Glut .glutIdleFunc(RenderScene); // iskljuci prikaz kurzora Glut .glutSetCursor( Glut .GLUT_CURSOR_NONE); // meni za toggle pogled iz prvog/treceg lica Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "Prvo ili Trece lice" , 0); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); // ignorisacemo pristnut taster Glut .glutIgnoreKeyRepeat(1); // procesiramo strelice i WASD slova Glut .glutKeyboardFunc(ProcessNormalKeyPress); Glut .glutSpecialFunc(ProcessSpecialKeyPress); Glut .glutKeyboardUpFunc(ProcessNormalKeyPressRelease); Glut .glutSpecialUpFunc(ProcessSpecialKeyPressRelease); // procesiramo pomeranje misha Glut .glutPassiveMotionFunc(ProcessMouseMovement); SetupRenderingContext(); Glut .glutMainLoop(); } } }

Listing 6.5.4.1 Primer interakcije sa korisnikom – upravljanje kamerom

Page 80: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 80

Slika 6.5.4.1 Rezultat primera iz listinga 6.5.4.1

U gore navedenom primeru koristi se klasa Camera, koja enkapsulira funkcionalnost kamere. Listinzi 6.5.4.2 i 6.5.4.3. prikazuje programski kôd ove klase.

using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; namespace Kamera { class Camera { / / pozicija kamere private float m_positionX, m_positionY, m_positionZ; // pogled kamere private float m_viewX, m_viewY, m_viewZ; // up vektor private float m_upVectorX, m_upVectorY, m_upVectorZ; // strafe vektor private float m_strafeX, m_strafeY, m_strafeZ; public float ViewX { get { return m_viewX; } } public float ViewY { get { return m_viewY; } } public float ViewZ { get { return m_viewZ; } } public Camera() { } public Camera( float positionX, float positionY, float positionZ, float viewX, float viewY, float viewZ, float upVectorX, float upVectorY, float upVectorZ) { m_positionX = positionX; m_positionY = positionY; m_positionZ = positionZ; m_viewX = viewX; m_viewY = viewY; m_viewZ = viewZ; m_upVectorX = upVectorX; m_upVectorY = upVectorY; m_upVectorZ = upVectorZ; } // pozicioniranje kamere public void Position(

Page 81: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 81

float positionX, float positionY, float positionZ, float viewX, float viewY, float viewZ, float upVectorX, float upVectorY, float upVectorZ) { m_positionX = positionX; m_positionY = positionY; m_positionZ = positionZ; m_viewX = viewX; m_viewY = viewY; m_viewZ = viewZ; m_upVectorX = upVectorX; m_upVectorY = upVectorY; m_upVectorZ = upVectorZ; } // rotiraj pogled za ugao angle public void RotateView( float angle, float x, float y, float z) {

float newViewX, newViewY, newViewZ; float viewX = m_viewX - m_positionX; float viewY = m_viewY - m_positionY; float viewZ = m_viewZ - m_positionZ; float cosTheta = ( float ) Math .Cos(angle); float sinTheta = ( float ) Math .Sin(angle);

newViewX = (cosTheta + (1 - cosTheta) * x * x)* viewX; newViewX += ((1 - cosTheta) * x * y - z * sinThe ta)* viewY; newViewX += ((1 - cosTheta) * x * z + y * sinThe ta)* viewZ; newViewY = ((1 - cosTheta) * x * y + z * sinThe ta)* viewX; newViewY += (cosTheta + (1 - cosTheta) * y * y)* viewY; newViewY += ((1 - cosTheta) * y * z - x * sinThe ta)* viewZ; newViewZ = ((1 - cosTheta) * x * z - y * sinThe ta)* viewX; newViewZ += ((1 - cosTheta) * y * z + x * sinThe ta)* viewY; newViewZ += (cosTheta + (1 - cosTheta) * z * z)* viewZ;

m_viewX = m_positionX + newViewX; m_viewY = m_positionY + newViewY; m_viewZ = m_positionZ + newViewZ;

} public void RotateViewByMouse( float angleY, float angleZ) { // izracunaj normalu tj. vektor oko kojeg rotiramo float viewX = m_viewX - m_positionX; float viewY = m_viewY - m_positionY; float viewZ = m_viewZ - m_positionZ; float axisX = ((viewY * m_upVectorZ) - (viewZ * m_upVect orY)); float axisY = ((viewZ * m_upVectorX) - (viewX * m_upVect orZ)); float axisZ = ((viewX * m_upVectorY) - (viewY * m_upVect orX)); // normalizacija vektora float magnitude =( float ) Math .Sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ); axisX = axisX / magnitude; axisY = axisY / magnitude; axisZ = axisZ / magnitude; RotateView(angleZ, axisX, axisY, axisZ); RotateView(angleY, 0.0f, 1.0f, 0.0f); }

Page 82: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 82

// pomeri kameru levo/desno public void Strafe( float speed) { // dodaj pomeraj poziciji m_positionX += m_strafeX * speed; m_positionZ += m_strafeZ * speed; // dodaj pomeraj pogledu m_viewX += m_strafeX * speed; m_viewZ += m_strafeZ * speed; } // pomeri kameru napred/nazad public void Move( float speed) { float viewX = m_viewX - m_positionX; float viewY = m_viewY - m_positionY; float viewZ = m_viewZ - m_positionZ; // normalizacija vektora float magnitude = ( float ) Math .Sqrt(viewX * viewX + viewY * viewY + viewZ * viewZ); viewX = viewX / magnitude; viewY = viewY / magnitude; viewZ = viewZ / magnitude; // pomeri poziciju i pogled m_positionX += viewX * speed; m_positionZ += viewZ * speed; m_viewX += viewX * speed; m_viewZ += viewZ * speed; } public void Update() { float viewX = m_viewX - m_positionX; float viewY = m_viewY - m_positionY; float viewZ = m_viewZ - m_positionZ; float axisX = ((viewY * m_upVectorZ) - (viewZ * m_upVect orY)); float axisY = ((viewZ * m_upVectorX) - (viewX * m_upVect orZ)); float axisZ = ((viewX * m_upVectorY) - (viewY * m_upVect orX)); // normalizacija vektora float magnitude =( float ) Math .Sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ); m_strafeX = axisX / magnitude; m_strafeY = axisY / magnitude; m_strafeZ = axisZ / magnitude; } public void Look() { Glu .gluLookAt(m_positionX, m_positionY, m_positionZ, m_viewX, m_viewY, m_viewZ, m_upVectorX, m_upVectorY, m_upVectorZ); } } }

Listing 6.5.4.2 Camera.cs

Page 83: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 83

Pored ovih metoda GLUT definiše i metode za rad sa spejsbolom, džojstikom i tabletom.

6.6 Boja i sen čenje objekata OpenGL koristi RGB model boja za specifikovanje boje. Svaka od komponenti se opisuje jednim bajtom koji definiše intenzitet te komponente. Koristi se i RGBA model boja, koji predstavlja RGB model proširen Alpha komponentom koja definiše prozirnost (transparency).

U OpenGL standardu boja se definiše pomoću familije metoda glColor . Najčešće se koriste sledeće metode:

public static void glColor3f(float R, float G, float B) public static void glColor4f(float R, float G, float B, float alpha ) public static void glColor3ub(byte R,byte G,byte B)

gde su: R,G,B,alpha – RGBA komponente boje, kod metoda sa parametrima

float tipa podataka vrednosti su normalizovane [0.0f, 1.0f], dok byte verzije su u opsegu [0, 255]. Metode koje nemaju alpha kao parametar podrazumevaju alpha jednako 1.0f, odnosno 255.

Svi objekti koji iscrtavaju posle poziva glColor metode biće iscrtani u boji koju je taj poziv specifikovao. Boja se uvek odnosi na tačku – teme objekta. Tako da ako su dva temena nekog objekta obojena različitim bojama, postavlja se pitanje koje će boje biti linija koja ih povezuje, odnosno kojom bojom će biti ispunjen poligon kojem temena pripadaju. Ovo direktno zavisi od tipa senčenja.

OpenGL podržava dva tipa senčenja: flat i smooth . Ako u sceni ne postoji osvetljenje flat tip senčenja (homogeno (Lambert) senčenje) će liniju između dva temena obojiti bojom drugog temena, dok smooth senčenje (Gouraud senčenje) će obojiti liniju prelivom boja temena. Slično se realizuje senčenje poligona, sa razlikom da u definisanju senčenja učestvuje više temena. Pravila za homogeno senčenje se mogu naći u [2]. Slike 6.6.1 i 6.6.2 prikazuju tipove senčenja primenjene na poligon, odnosno liniju.

Page 84: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 84

a) smooth tip senčenja b) flat tip senčenja

Slika 6.6.1 Tipovi senčenja na primeru trougla

a) smooth tip senčenja b) flat tip senčenja

Slika 6.6.2 Tipovi senčenja na primeru linije

Model senčenja se definiše pomoću metode glShadeModel , koja ima oblik:

public static void glShadeModel(int mode)

gde je: mode – tip senčenja objekta. Dozvoljene vrednosti su: Gl.GL_SMOOTH i

Gl.GL_FLAT. Podrazumevana vrednost je Gl.GL_SMOOTH.

Listing 6.6.1 prikazuje programski kôd aplikacije koja demonstrira tipove senčenja na primeru definisanja boje ispune trougla, slika 6.6.1. Primer je preuzet iz [3].

/************************************************** ********************* * Modul: Programs.cs * Autor: Richard S. Wright Jr. * Prilagodio: Srdjan Mihic * Namena: demonstracija tipova sencenja *************************************************** *********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace Sencenje { class Program { // stavke menija enum MenuItem {FLAT = 0, SMOOTH};

Page 85: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 85

/////////////////////////////////////////////////// /////////////////// // Naziv: ProcessMenu // Namena: rad sa menijem // Parametri: identifikator izabrane stavke /////////////////////////////////////////////////// /////////////////// static void ProcessMenu( int value) { if (value == ( int ) MenuItem .FLAT) Gl .glShadeModel( Gl .GL_FLAT); else Gl .glShadeModel( Gl .GL_SMOOTH); Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu - plavu pozadinu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT); // Nacrtaj trougao Gl .glBegin( Gl .GL_TRIANGLES); // teme crvene boje Gl .glColor3ub(255, 0, 0); Gl .glVertex3f(0.0f,200.0f,0.0f); // teme zelene boje (dole desno) Gl .glColor3ub(0, 255, 0); Gl .glVertex3f(200.0f,-70.0f,0.0f); // teme plave boje (dole levo) Gl .glColor3ub(0, 0, 255); Gl .glVertex3f(-200.0f, -70.0f, 0.0f); Gl .glEnd(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: ChangeSize // Namena: podesava projekciju prilikom promene dimenzija prozora // Parametri: nova sirina i visina prozora /////////////////////////////////////////////////// ///////////////////// static void ChangeSize( int width, int height) { float windowHeight, windowWidth; if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); // Zadrzi odnos sirine i visine if (width <= height) { windowHeight = 250.0f*height/width; windowWidth = 250.0f; } else

Page 86: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 86

{ windowWidth = 250.0f*width/height; windowHeight = 250.0f; } Gl .glOrtho(-windowWidth, windowWidth, -windowHeight, windowHeight, 1.0f, -1.0f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { Gl .glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda // Parametri: args // Povratna vrednost: int /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB | Glut .GLUT_DEPTH); Glut .glutInitWindowSize(800, 600); Glut .glutCreateWindow( "Definisanje tipa sencenja trougla" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); // meni za izbor tipa sencenja trougla Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "FLAT tip sencenja" , ( int ) MenuItem .FLAT); Glut .glutAddMenuEntry( "SMOOTH tip sencenja" , ( int ) MenuItem .SMOOTH); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); SetupRenderingContext(); Glut .glutMainLoop(); } } }

Listing 6.6.1 Demonstracija tipova senčenja na primeru senčenja trougla

6.7 Materijali U OpenGL standardu materijal se opisuje preko svojih reflektivnih karakteristika. Materijal se opisuje preko tri svetlosne komponente: ambijentalne, difuzne i spekularne.

Ambijentalno svetlo osvetljava objekte jednako i „kao“ da je sveprisutno tj. ne dolazi iz nekog konkretnog pravca. Primer ovog osvetljenja je dnevna svetlost.

Page 87: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 87

Difuzno svetlo osvetljava objekte iz nekog konkretnog pravca. Svetlosni zraci se prelamaju i rasipaju na površini objekta. Ova komponenta svetla kreira senke. Primer ovog osvetljenja je stona lampa.

Spekularno svetlo (specular highlight), slično kao i difuzno svetlo, dolazi iz nekog pravca, ali refleksija je pod mnogo oštrijim uglom i nema rasipanja. Ova svetlost kreira veoma jako osvetljene površine na objektu – odsjaj.

Pored ovih osnovnih komponenti može se definisati i emisiona komponenta. Ona predstavlja boju koju materijal isijava.

Materijal se definiše pomoću familije metoda glMaterial , od kojih se najčešće koristi: public static void glMaterialfv(int face ,int pname, IntPtr params ) public static void glMaterialfv(int face ,int pname, float[] params ) gde su:

face – tip orijentacije (tip poligona, videti poglavlje 6.4.2) nad kojim se primenjuje materijal. Dozvoljene vrednosti su: Gl.GL_FRONT, Gl.GL_BACK ili Gl.GL_FRONT_AND_BACK. Početna vrednost je Gl.GL_FRONT_AND_BACK,

pname – koja komponenta se podešava sa param parametrom. Moguće vrednosti su: Gl.GL_AMBIENT, Gl.GL_DIFFUSE, Gl.GL_SPECULAR, Gl.GL_EMISSION, Gl.GL_SHININESS, Gl.GL_COLOR_INDEXES, i Gl.GL_AMBIENT_AND_DIFFUSE. Početna vrednost je Gl.GL_AMBIENT_AND_DIFFUSE,

params – parametar čija semantika zavisi od pname, uglavnom je boja.

Ovakav način navođenja materijala za svaki objekat nije uvek pogodan. OpenGL nudi alternativni način definisanja materijala – color tracking . Color tracking podrazumeva definisanje materijala preko poziva glColor metode.

U color tracking režim se ulazi pozivom metode glEnable sa argumentom Gl.GL_COLOR_MATERIAL. Funkcijom glColorMaterial se specifikuje na koje orijentacije poligona i koje komponente osvetljenja se boja materijala odnosi (parametri ove metode su isti sa prva dva parametra metode glMaterialfv). U praksi se najčešće koristi ovakav način definisanja materijala.

public static void glColorMaterial(int face , int mode)

gde su: face – tip orijentacije (tip poligona, videti poglavlje 6.4.2) nad kojim se

primenjuje materijal. Dozvoljene vrednosti su: Gl.GL_FRONT, Gl.GL_BACK ili Gl.GL_FRONT_AND_BACK. Početna vrednost je Gl.GL_FRONT_AND_BACK,

Page 88: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 88

mode – koja komponenta se podešava sa param parametrom. Moguće vrednosti su: Gl.GL_AMBIENT, Gl.GL_DIFFUSE, Gl.GL_SPECULAR, Gl.GL_AMBIENT_AND_DIFFUSE, i Gl.GL_EMISSION. Početna vrednost je Gl.GL_AMBIENT-_AND_DIFFUSE.

Listinzi 6.7.1, 6.7.2 i slika 6.7.1 prikazuju primer aviona kome su pridruženi materijali, u prvom slučaju korišćenjem color tracking tehnike odnosno korišćenjem glMaterial familije metoda u drugom slučaju. Programski kôd za iscrtavanje aviona preuzet je iz [3].

/************************************************** ********************* * Modul: Program.cs * Autor: Richard S. Wright Jr. * Prilagodio: Srdjan Mihic * Namena: demonstracija color tracking tehnike zadavanja materijala *************************************************** *********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace ColorTracking { class Program { // Uglovi rotacije static float xRot = 0.0f; static float yRot = 0.0f; /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessSpecialKeyPress // Namena: metoda procesira strelice /////////////////////////////////////////////////// /////////////////// static void ProcessSpecialKeyPress( int key, int x, int y) { switch (key) { case Glut .GLUT_KEY_UP: xRot -= 5.0f; break ; case Glut .GLUT_KEY_DOWN: xRot += 5.0f; break ; case Glut .GLUT_KEY_LEFT: yRot -= 5.0f; break ; case Glut .GLUT_KEY_RIGHT: yRot += 5.0f; break ; }; Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); // Sacuvaj stanje modelview matrice Gl .glPushMatrix(); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f);

Page 89: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 89

Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Nose Cone // White Gl .glColor3ub(255, 255, 255); Gl .glBegin( Gl .GL_TRIANGLES); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(15.0f,0.0f,30.0f); // Black Gl .glColor3ub(0,0,0); Gl .glVertex3f(15.0f,0.0f,30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, 60.0f); // Red Gl .glColor3ub(255,0,0); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(-15.0f,0.0f,30.0f); // Body of the Plane // Green Gl .glColor3ub(0,255,0); Gl .glVertex3f(-15.0f,0.0f,30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glColor3ub(255,255,0); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(15.0f,0.0f,30.0f); Gl .glColor3ub(0, 255, 255); Gl .glVertex3f(15.0f,0.0f,30.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); // Left wing Gl .glColor3ub(128,128,128); Gl .glVertex3f(0.0f,2.0f,27.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glColor3ub(64,64,64); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(0.0f,2.0f,27.0f); Gl .glColor3ub(192,192,192); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f,7.0f,-8.0f); // Other wing top section Gl .glColor3ub(64,64,64); Gl .glVertex3f(0.0f,2.0f,27.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f);

Page 90: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 90

// Tail section // Bottom of back fin Gl .glColor3ub(255,128,255); Gl .glVertex3f(-30.0f, -0.50f, -57.0f); Gl .glVertex3f(30.0f, -0.50f, -57.0f); Gl .glVertex3f(0.0f,-0.50f,-40.0f); // top of left side Gl .glColor3ub(255,128,0); Gl .glVertex3f(0.0f,-0.5f,-40.0f); Gl .glVertex3f(30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, 4.0f, -57.0f); // top of right side Gl .glColor3ub(255,128,0); Gl .glVertex3f(0.0f, 4.0f, -57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f,-0.5f,-40.0f); // back of bottom of tail Gl .glColor3ub(255,255,255); Gl .glVertex3f(30.0f,-0.5f,-57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, 4.0f, -57.0f); // Top of Tail section left Gl .glColor3ub(255,0,0); Gl .glVertex3f(0.0f,0.5f,-40.0f); Gl .glVertex3f(3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glColor3ub(255,0,0); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f,0.5f,-40.0f); // Back of horizontal section Gl .glColor3ub(128,128,128); Gl .glVertex3f(3.0f,0.5f,-57.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glEnd(); // Of Jet Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: ChangeSize // Namena: podesavanje projekcije priliko m promene dimenzija /////////////////////////////////////////////////// ///////////////////// static void ChangeSize( int width, int height) { float nRange = 80.0f; if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); if (width <= height) Gl .glOrtho(-nRange, nRange, -nRange * height / width, nRange * height / width, -nRange, nRange) ; else

Page 91: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 91

Gl .glOrtho(-nRange * width / height, nRange * width / height, - nRange, nRange, -nRange, nRange) ; Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi inicijalizacije pre pocetka GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { float [] whiteLight = { 1.0f, 1.0f, 1.0f, 1.0f }; Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glEnable( Gl .GL_CULL_FACE); Gl .glFrontFace( Gl .GL_CCW); // Ukljuci color tracking Gl .glEnable( Gl .GL_COLOR_MATERIAL); // Podesi na koje parametre materijala se odnose po zivi glColor f. Gl .glColorMaterial( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE); // Ukljuci proracun osvetljenja Gl .glEnable( Gl .GL_LIGHTING); // Setuj ambijentalno svetlo Gl .glLightModelfv( Gl .GL_LIGHT_MODEL_AMBIENT, whiteLight); // Plava pozadina Gl .glClearColor(0.0f, 0.0f, 0.5f, 1.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB | Glut .GLUT_DEPTH); Glut .glutInitWindowSize(800, 600); Glut .glutCreateWindow( "Primer rada sa materijalima - color tracking" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); Glut .glutSpecialFunc(ProcessSpecialKeyPress); SetupRenderingContext(); Glut .glutMainLoop(); } } }

Listing 6.7.1 Primer korišćenja color tracking tehnike za definisanje materijala

/************************************************** ********************* * Modul: Program.cs * Autor: Richard S. Wright Jr. * Prilagodio: Srdjan Mihic * Namena: demonstracija glMaterial funkcije za zadavanje materijala *************************************************** *********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl;

Page 92: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 92

using Tao.FreeGlut; namespace Materialfv { class Program { // Uglovi rotacije static float xRot = 0.0f; static float yRot = 0.0f; // boje materijala static float [] g_white = { 1.0f, 1.0f, 1.0f, 1.0f }; static float [] g_black = { 0.0f, 0.0f, 0.0f, 1.0f }; static float [] g_red = { 1.0f, 0.0f, 0.0f, 1.0f }; static float [] g_green = { 0.0f, 1.0f, 0.0f, 1.0f }; static float [] g_cyan = { 0.0f, 1.0f, 1.0f, 1.0f }; static float [] g_yellow = { 1.0f, 1.0f, 0.0f, 1.0f }; static float [] g_orange = { 1.0f, 0.5f, 0.0f, 1.0f }; static float [] g_darkGray = { 0.25f, 0.25f, 0.25f, 1.0f }; static float [] g_gray = { 0.5f, 0.5f, 0.5f, 1.0f }; static float [] g_lightGray = { 0.75f, 0.75f, 0.75f, 1.0f }; static float [] g_purple = { 1.0f, 0.5f, 1.0f, 1.0f }; /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessSpecialKeyPress // Namena: metoda procesira strelice /////////////////////////////////////////////////// /////////////////// static void ProcessSpecialKeyPress( int key, int x, int y) { switch (key) { case Glut .GLUT_KEY_UP: xRot -= 5.0f; break ; case Glut .GLUT_KEY_DOWN: xRot += 5.0f; break ; case Glut .GLUT_KEY_LEFT: yRot -= 5.0f; break ; case Glut .GLUT_KEY_RIGHT: yRot += 5.0f; break ; }; Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glPushMatrix(); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Nacrtaj avion // Nose Cone // White Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_white); Gl .glBegin( Gl .GL_TRIANGLES); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(15.0f,0.0f,30.0f); // Black Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_black);

Page 93: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 93

Gl .glVertex3f(15.0f,0.0f,30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, 60.0f); // Red Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_red); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(-15.0f,0.0f,30.0f); // Body of the Plane // Green Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_green); Gl .glVertex3f(-15.0f,0.0f,30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_cyan); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(15.0f,0.0f,30.0f); Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_yellow); Gl .glVertex3f(15.0f,0.0f,30.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); // Left wing Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_gray); Gl .glVertex3f(0.0f,2.0f,27.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_darkGray); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(0.0f,2.0f,27.0f); Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_lightGray); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f,7.0f,-8.0f); // Other wing top section Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_darkGray); Gl .glVertex3f(0.0f,2.0f,27.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); // Tail section // Bottom of back fin Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_purple); Gl .glVertex3f(-30.0f, -0.50f, -57.0f); Gl .glVertex3f(30.0f, -0.50f, -57.0f); Gl .glVertex3f(0.0f,-0.50f,-40.0f); // top of left side Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_orange); Gl .glVertex3f(0.0f,-0.5f,-40.0f); Gl .glVertex3f(30.0f, -0.5f, -57.0f);

Page 94: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 94

Gl .glVertex3f(0.0f, 4.0f, -57.0f); // top of right side Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_orange); Gl .glVertex3f(0.0f, 4.0f, -57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f,-0.5f,-40.0f); // back of bottom of tail Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_white); Gl .glVertex3f(30.0f,-0.5f,-57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, 4.0f, -57.0f); // Top of Tail section left Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_red); Gl .glVertex3f(0.0f,0.5f,-40.0f); Gl .glVertex3f(3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_red); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f,0.5f,-40.0f); // Back of horizontal section Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE, g_gray); Gl .glVertex3f(3.0f,0.5f,-57.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glEnd(); // Of Jet Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: ChangeSize // Namena: podesavanje projekcije priliko m promene dimenzija /////////////////////////////////////////////////// ///////////////////// static void ChangeSize( int width, int height) { if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); if (width <= height) Gl .glOrtho(-80.0f, 80.0f, -80.0f*height/width, 80.0f* height/width, - 80.0f, 80.0f); else Gl .glOrtho(-80.0f * width / height, 80.0f * width / h eight, -80.0f, 80.0f, -80.0f, 80.0f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi inicijalizacije pre pocetka GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() {

Page 95: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 95

Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glEnable( Gl .GL_CULL_FACE); Gl .glFrontFace( Gl .GL_CCW); // Ukljuci proracun osvetljenja Gl .glEnable( Gl .GL_LIGHTING); // Setuj ambijentalno svetlo Gl .glLightModelfv( Gl .GL_LIGHT_MODEL_AMBIENT, g_white); // Plava pozadina Gl .glClearColor(0.0f, 0.0f, 0.5f, 1.0f); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB | Glut .GLUT_DEPTH); Glut .glutInitWindowSize(800, 600); Glut .glutCreateWindow( "Primer rada sa materijalima - glMaterial" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); Glut .glutSpecialFunc(ProcessSpecialKeyPress); SetupRenderingContext(); Glut .glutMainLoop(); } } }

Listing 6.7.2 Primer korišćenja glMaterialfv metode za definisanje materijala

Slika 6.7.1 Rezultat aplikacije iz listinga 6.7.1

6.8 Osvetljenje Osvetljenje je esencijalno u postizanju realizma modelovane scene. Takođe, svojstva materijala dolaze do izražaja tek kada je u sceni prisutno osvetljenje.

U OpenGL standardu se proračun osvetljenja uključuje pozivom metode glEnable sa argumentom Gl.GL_LIGHTING. Analogno se isključuje proračun osvetljenja.

Page 96: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 96

U proračunu osvetljenja nekog objekat OpenGL ne koristi napredne algoritme kao što je npr. ray-tracing. OpenGL koristi Phong-ov iluminacioni model.

Za proračun osvetljenosti nekog poligona potrebno je poznavati njegov vektor normale. Vektor normale se definiše za svako teme objekta i mora biti normalizovan. Moguće je definisati samo jedan vektor normale za poligon – vektor normale na ravan u kojoj poligon leži (OpenGL dozvoljava samo planarne poligone!). U OpenGL standardu vektor normale se zadaje pomoću familije metoda glNormal , od kojih se najčešće koristi:

public static void glNormal3f(float nx,

float ny , float nz ) gde su:

nx, ny, nz – koordinate normale u normalizovanoj formi [0,1].

Određivanje vektora normale u opštem slučaju nije trivijalan zadatak. Za određivanje vektora normale na nivou poligona koristiće se pomoćna metoda FindFaceNormal :

public static float[] FindFaceNormal( float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) gde su:

nx, ny, nz – izračunati vektor normale, x1,y1,z1,x2,y2,z2,x3,y3,z3 – tri temena koje određuju

ravan poligona.

Transformacije sabijanja/rastezanja modela se primenjuju i na njegove vektore normala, tako da je potrebno izvršiti normalizaciju nad vektorima normala objekta nakon primene transformacija. OpenGL omogućava automatsku normalizaciju pomoću promenljive stanja Gl.GL_NORMALIZE. Međutim, primena automatske normalizacije smanjuje brzinu proračuna osvetljenja zbog računske složenosti. Najbolje je odmah zadavati normalizovane vektore normala.

Za definisanje modela osvetljenja scene koristi se metoda glLightModelfv . Uglavnom, ova metoda se koristi za zadavanje ambijentalnog svetlosnog izvora.

public static void glLightModelfv(int pname, float[] params ) public static void glLightModelfv(int pname, IntPtr params )

gde su: pname – model osvetljenja, ima više vrednosti, najčešće se koristi

Gl.GL_LIGHT_MODEL_AMBIENT.

Page 97: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 97

params – semantiku određuje parametar pname, za gore navedenu vrednost params je boja ambijentalnog osvetljenja scene.

U sceni može postojati najviše jedan globalni ambijentalni svetlosni izvor. Sledeći programski kôd prikazuje definisanje globalnog ambijentalnog svetlosnog izvora plave boje:

float[] globalnoAmbijentalno = { 0.0f, 0.0f, 1.0f, 1.0f }; Gl.glLightModelfv(Gl.GL_LIGHT_MODEL_AMBIENT, globalnoAmbijentalno);

Svetlosni izvor se definiše funkcijom glLightfv , koja ima oblik:

public static void glLightfv(int light , int pname, float[] params )

public static void glLightfv(int light , int pname, IntPtr params )

gde su: light – identifikator svetlosnog izvora – simboličko ime oblika:

Gl.GL_LIGHT<x> gde je:

<x> broj ≤ Gl.GL_MAX_LIGHTS i <x> ≥ 0. pname – model osvetljenja, moguće vrednosti su: Gl.GL_AMBIENT,

Gl.GL_DIFFUSE, Gl.GL_SPECULAR, Gl.GL_POSITION, Gl.GL_SPOT_DIRECTION, Gl.GL_SPOT_EXPONENT, Gl.GL_SPOT_CUTOFF, Gl.GL_LINEAR_ATTENUATION , Gl.GL_QUADRATIC_ATTENUATION , Gl.GL_CONSTANT_ATTENUATION.

params – semantiku određuje parametar pname, npr. za vrednost params jednako Gl.GL_AMBIENT je boja ambijentalne komponente svetlosnog izvora scene.

Nakon specifikovanja svetlosnog izvora potrebno ga je uključiti pozivom metode glEnable sa argumentom Gl.GL_LIGHT<x>, gde je <x> broj svetlosnog izvora. OpenGL specifikacija definiše minimalno osam svetlosnih izvora koje implementacija mora podržavati. Maksimum svetlosnih izvora koje implementacija podržava je sadržan u konstanti Gl.GL_MAX_LIGHTS koja mora biti veća ili jednaka od osam. Na Windows platformi moguće je maksimalno definisati osam svetlosnih izvora. Ako je potrebno na sceni imati više svetlosnih izvora, tada se svetlosni izvori moraju reciklirati ili se mora simulirati efekti osvetljenja.

Svetlosni izvor se pozicionira u sceni pomoću metode glLightfv sa pname jednako Gl.GL_POSITION i kao params se navede pozicija svetlosnog izvora. Pozicija svetlosnog izvora je opisana kao uređena četvorka (x,y,z,w) gde su x,y i z koordinate svetlosnog izvora, a parametar w definiše da li je u pitanju reflektorski

Page 98: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 98

ili direkcioni svetlosni izvor . Vrednost nula odgovara direkcionom, a vrednost jedan reflektorskom svetlosnom izvoru. Ako se ne navede pozicija svetlosnog izvora OpenGL podrazumeva vrednost (0, 0, 1, 0) tj. direkcioni svetlosni izvor u pravcu z-ose. Transformacije nad Modelview matricom se primenjuju i na poziciju svetlosnog izvora. Ako se želi fiksirati pozicija svetlosnog izvora u sceni tada je potrebno poziciju definisati nakon poziva gluLookAt metode i obratno. Sledeći programski kôd definiše i pozicionira direkcioni svetlosni izvor (sa identifikatorom Gl.GL_LIGHT0):

float[] pozicija = {-50.f, 50.0f, 100.0f, 0.0f }; Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, pozicija );

Ostali parametri reflektorskog svetlosnog izvora se definišu korišćenjem Gl.GL_SPOT_DIRECTION, Gl.GL_SPOT_CUTOFF i Gl.GL_SPOT_EXPONENT vrednosti za definisanje smera, cut-off ugla i koeficijenta opadanja intenziteta svetlosti. Cut-off ugao je u opsegu [0o, 90o] ili 180o. Vrednost 180o za ugao je specijalna i označava uniformno rasipanje svetlosti – tačkasti svetlosni izvor . Koeficijent opadanja intenziteta svetlosti, u opsegu [0, 128], definiše koliko će svetlosni snop biti fokusiran (videti poglavlje 4.8). Podrazumevane vrednosti su: za smer (0,0,-1) tj. u smeru –z-ose; za ugao 180o i za koeficijent opadanja intenziteta vrednost 0.

Sledeći programski kôd prikazuje postupak kreiranja reflektorskog svetlosnog izvora, njegovo pozicioniranje i uključivanje:

float[] ambijentalnaKomponenta = { 0.3f, 0.3f, 0.3 f, 1.0f }; float[] difuznaKomponenta = { 0.7f, 0.7f, 0.7f, 1. 0f }; float[] smer = { 0.0f, 0.0f, -1.0f };

// Pridruži komponente svetlosnom izvoru 0 Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambijentalnaKomponenta); Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, difuznaKo mponenta); // Podesi parametre reflektorkskog izvora Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPOT_DIRECTION, sm er); Gl.glLightf(Gl.GL_LIGHT0, Gl.GL_SPOT_CUTOFF, 45.0f );

// Ukljuci svetlosni izvor Gl.glEnable(Gl.GL_LIGHT0); // Pozicioniraj svetlosni izvor float[] pozicija = { -50.f, 50.0f, 100.0f, 1.0f }; Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, pozicija );

Sledeći programski kôd prikazuje postupak kreiranja tačkastog izvora svetlosti:

float[] ambijentalnaKomponenta = { 0.3f, 0.3f, 0.3 f, 1.0f };

Page 99: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 99

float[] difuznaKomponenta = { 0.7f, 0.7f, 0.7f, 1. 0f }; // Pridruži komponente svetlosnom izvoru 0 Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambijentalnaKomponenta); Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, difuznaKo mponenta); // Podesi parametre tackastog svetlosnog izvora Gl.glLightf(Gl.GL_LIGHT0, Gl.GL_SPOT_CUTOFF, 180.0f );

// Ukljuci svetlosni izvor Gl.glEnable(Gl.GL_LIGHT0); // Pozicioniraj svetlosni izvor float[] pozicija = { -50.f, 50.0f, 100.0f, 1.0f }; Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, pozicija );

Listing 6.8.1. prikazuje programski kôd primera primene materijala i osvetljenja (direkciono i ambijentalno) na model aviona, preuzet iz [3]. Avion se može rotirati korišćenjem strelica na tastaturi da bi se bolje video uticaj osvetljenja. Slika 6.8.1 prikazuje rezultat aplikacije.

/************************************************** ********************* * Modul: Program.cs * Autor: Richard S. Wright Jr. * Prilagodio: Srdjan Mihic * Namena: demonstracija OpenGL osvetljenja *************************************************** *********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace Osvetljenje { class Program { // Uglovi rotacije static float xRot = 0.0f; static float yRot = 0.0f; /////////////////////////////////////////////////// ///////////////////// // Naziv: FindFaceNormal // Namena: metoda izracunava normalu za p oligon // Parametri: 3 temena // Povratna vrednost:izracunata normala /////////////////////////////////////////////////// ///////////////////// public static float [] FindFaceNormal( float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)

{

Page 100: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 100

float [] normal = new float [3];

// normala na ravan def. sa tri tacke definisane u CCW smeru normal[0] = (y1 - y2) * (z2 - z3) - (y2 - y3) * (z1 - z2); normal[1] = (x2 - x3) * (z1 - z2) - (x1 - x2) * (z2 - z3);

normal[2] = (x1 - x2) * (y2 - y3) - (x2 - x3) * (y1 - y2);

// normalizacija // duzina vektora normale float len = ( float )( Math .Sqrt((normal[0] * normal[0]) + (normal[1] * normal[1]) + (normal[2] * normal[2]))) ;

// izbegava se deljenje sa nulom if (len == 0.0f) len = 1.0f;

// normalizacija komponenata normal[0] /= len; normal[1] /= len; normal[2] /= len;

return normal; }

/////////////////////////////////////////////////// ////////////////// // Naziv: ProcessSpecialKeyPress // Namena: metoda procesira strelice // Parametri: key, x, y /////////////////////////////////////////////////// /////////////////// static void ProcessSpecialKeyPress( int key, int x, int y) { switch (key) { case Glut .GLUT_KEY_UP: xRot-= 5.0f; break ; case Glut .GLUT_KEY_DOWN: xRot += 5.0f; break ; case Glut .GLUT_KEY_LEFT: yRot -= 5.0f; break ; case Glut .GLUT_KEY_RIGHT: yRot += 5.0f; break ; }; Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); // Save matrix state and do the rotation Gl .glPushMatrix(); Gl .glTranslatef(0.0f, 0.0f, -150.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glBegin( Gl .GL_TRIANGLES); Gl .glNormal3fv(FindFaceNormal(15.0f, 0.0f, 30.0f, 0.0f, 15.0f, 30.0f, 0.0f, 0.0f, 60.0 f)); Gl .glVertex3f(15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, 60.0f);

Page 101: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 101

Gl .glNormal3fv(FindFaceNormal(0.0f, 0.0f, 60.0f, 0.0f , 15.0f, 30.0f, -15.0f, 0.0f, 30.0f)); Gl .glVertex3f(0.0f, 0.0f, 60.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); // Body of the Plane Gl .glNormal3fv(FindFaceNormal(-15.0f, 0.0f, 30.0f, 0.0f, 15.0f, 30.0f, 0.0f, 0.0f, -56. 0f)); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glNormal3fv(FindFaceNormal(0.0f, 0.0f, -56.0f, 0.0f, 15.0f, 30.0f, 15.0f, 0.0f, 30. 0f)); Gl .glVertex3f(0.0f, 0.0f, -56.0f); Gl .glVertex3f(0.0f, 15.0f, 30.0f); Gl .glVertex3f(15.0f, 0.0f, 30.0f); // nekad je lakse direktno specifikovati normalu Gl .glNormal3f(0.0f, -1.0f, 0.0f); Gl .glVertex3f(15.0f, 0.0f, 30.0f); Gl .glVertex3f(-15.0f, 0.0f, 30.0f); Gl .glVertex3f(0.0f, 0.0f, -56.0f); // Left wing // Large triangle for bottom of wing Gl .glNormal3fv(FindFaceNormal(0.0f, 2.0f, 27.0f, -60.0f, 2.0f, -8.0f, 60.0f, 2.0f, -8 .0f)); Gl .glVertex3f(0.0f, 2.0f, 27.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glNormal3fv(FindFaceNormal(60.0f, 2.0f, -8.0f, 0.0f, 7.0f, -8.0f, 0.0f, 2.0f, 27.0f )); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(0.0f, 2.0f, 27.0f); Gl .glNormal3fv(FindFaceNormal(60.0f, 2.0f, -8.0f, - 60.0f, 2.0f, -8.0f, 0.0f, 7.0f, -8.0 f)); Gl .glVertex3f(60.0f, 2.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glNormal3fv(FindFaceNormal(0.0f, 2.0f, 27.0f, 0.0f , 7.0f, -8.0f, -60.0f, 2.0f, -8.0f)); Gl .glVertex3f(0.0f, 2.0f, 27.0f); Gl .glVertex3f(0.0f, 7.0f, -8.0f); Gl .glVertex3f(-60.0f, 2.0f, -8.0f); // Tail section // Bottom of back fin Gl .glNormal3f(0.0f, -1.0f, 0.0f); Gl .glVertex3f(-30.0f, -0.50f, -57.0f); Gl .glVertex3f(30.0f, -0.50f, -57.0f); Gl .glVertex3f(0.0f, -0.50f, -40.0f); Gl .glNormal3fv(FindFaceNormal(0.0f, -0.5f, -40.0f, 30.0f, -0.5f, -57.0f, 0.0f, 4.0f, -5 7.0f)); Gl .glVertex3f(0.0f, -0.5f, -40.0f); Gl .glVertex3f(30.0f, -0.5f, -57.0f);

Page 102: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 102

Gl .glVertex3f(0.0f, 4.0f, -57.0f); Gl .glNormal3fv(FindFaceNormal(0.0f, 4.0f, -57.0f, -30.0f, -0.5f, -57.0f, 0.0f, -0.5f, -40.0f)); Gl .glVertex3f(0.0f, 4.0f, -57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, -0.5f, -40.0f); Gl .glNormal3fv(FindFaceNormal(30.0f, -0.5f, -57.0f, -30.0f, -0.5f, -57.0f, 0.0f, 4.0f, - 57.0f)); Gl .glVertex3f(30.0f, -0.5f, -57.0f); Gl .glVertex3f(-30.0f, -0.5f, -57.0f); Gl .glVertex3f(0.0f, 4.0f, -57.0f); Gl .glNormal3fv(FindFaceNormal(0.0f, 0.5f, -40.0f, 3.0f, 0.5f, -57.0f, 0.0f, 25.0f, -65 .0f)); Gl .glVertex3f(0.0f, 0.5f, -40.0f); Gl .glVertex3f(3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glNormal3fv(FindFaceNormal(0.0f, 25.0f, -65.0f, -3.0f, 0.5f, -57.0f, 0.0f, 0.5f, -40 .0f)); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 0.5f, -40.0f); Gl .glNormal3fv(FindFaceNormal(3.0f, 0.5f, -57.0f, -3.0f, 0.5f, -57.0f, 0.0f, 25.0f, -6 5.0f)); Gl .glVertex3f(3.0f, 0.5f, -57.0f); Gl .glVertex3f(-3.0f, 0.5f, -57.0f); Gl .glVertex3f(0.0f, 25.0f, -65.0f); Gl .glEnd(); Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: ChangeSize // Namena: obradjuje promenu dimenzija pr ozora /////////////////////////////////////////////////// ///////////////////// static void ChangeSize( int width, int height) { float [] lightPos = { -50.0f, 50.0f, -50.0f, 1.0f }; if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); Glu .gluPerspective(45.0f, ( float )width / ( float )height, 1.0f, 225.0f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); // Pozicioniranje svetlosnog izvora! Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_POSITION, lightPos); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi inicijalizacije pre pocetka GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() {

Page 103: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 103

// Vrednosti svetlosnih komponenti float [] ambientLight = { 0.3f, 0.3f, 0.3f, 1.0f }; float [] diffuseLight = { 0.7f, 0.7f, 0.7f, 1.0f }; float [] specular = { 1.0f, 1.0f, 1.0f, 1.0f }; float [] specref = { 1.0f, 1.0f, 1.0f, 1.0f }; Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glEnable( Gl .GL_CULL_FACE); Gl .glFrontFace( Gl .GL_CCW); // Ukjuci proracun osvetljenja Gl .glEnable( Gl .GL_LIGHTING); Gl .glLightModelfv( Gl .GL_LIGHT_MODEL_AMBIENT, ambientLight); // Specifikuj i ukljuci svetlosni izvor 0 Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_DIFFUSE, ambientLight); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_SPECULAR, specular); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_DIFFUSE, diffuseLight); Gl .glEnable( Gl .GL_LIGHT0); // Ukljuci color tracking Gl .glEnable( Gl .GL_COLOR_MATERIAL); // Podesi na koje parametre materijala se odnose po zivi glColor f. Gl .glColorMaterial( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE); // Definisemo belu spekularnu komponentu materijala sa jakim odsjajem Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_SPECULAR, specref); Gl .glMateriali( Gl .GL_FRONT, Gl .GL_SHININESS, 128); Gl .glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // Ukljuci automatsku normalizaciju nad normalama Gl .glEnable( Gl .GL_NORMALIZE); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB | Glut .GLUT_DEPTH); Glut .glutInitWindowSize(800, 600); Glut .glutCreateWindow( "Primena osvetljenja" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); Glut .glutSpecialFunc(ProcessSpecialKeyPress); SetupRenderingContext(); Glut .glutMainLoop(); }

} }

Listing 6.8.1 Primer rada sa osvetljenjem na primeru aviona

U stvarnosti objekti koji su osvetljeni „bacaju” senku. OpenGL model osvetljenja ne podržava automatsko generisanje senki, tako da autor mora sam

Page 104: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 104

generisati i prikazati senku. Proračun i prikaz senki je van okvira ovog teksta. O senkama čitaoci se mogu više informisati u [3].

Listing 6.8.2. prikazuje programski kôd primera korišćenja reflektorskog osvetljenja, preuzet iz [3]. Svetlosni izvor se može pomerati korišćenjem strelica na tastaturi da bi se bolje video uticaj osvetljenja. Slika 6.8.2 prikazuje rezultat aplikacije.

/************************************************** ********************* * Modul: Program.cs * Autor: Richard S. Wright Jr. * Prilagodio: Srdjan Mihic * Namena: demonstracija svetlosnih izvora *************************************************** *********************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace Izvori { class Program { // Uglovi rotacije static float xRot = 0.0f; static float yRot = 0.0f; // Vrednosti svetlosnih komponenti static float [] dirPos = { 0.0f, 0.0f, 75.0f, 0.0f }; static float [] specular = { 1.0f, 1.0f, 1.0f, 1.0f}; static float [] specref = { 1.0f, 1.0f, 1.0f, 1.0f }; static float [] ambientLight = { 0.5f, 0.5f, 0.5f, 1.0f}; static float [] spotDir = { 0.0f, 0.0f, -1.0f }; static float [] spotPos = { 0.0f, 0.0f, 75.0f, 1.0f }; // Stepeni kvaliteta iscrtavanja enum MenuItem { MODE_FLAT = 0, MODE_SMOOTH, MODE_VERYLOW, MODE_MEDIUM, MODE_VERYHIGH, POINT_SOURCE, SPOT_SOURCE, DIRECT_SOURCE }; static MenuItem shadeMode = MenuItem .MODE_FLAT; static MenuItem tessellation = MenuItem .MODE_VERYLOW; static MenuItem lightSource = MenuItem .DIRECT_SOURCE; /////////////////////////////////////////////////// ///////////////// // Naziv: ProcessMenu // Namena: rad sa menijem // Parametri: identifikator izabrane stavke / /////////////////////////////////////////////////// //////////////// static void ProcessMenu( int value) {

Slika 6.8.1 Rezultat primera iz listinga 6.8.1

Page 105: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 105

switch (value) { case 0: shadeMode = MenuItem .MODE_FLAT; break ; case 1: shadeMode = MenuItem .MODE_SMOOTH; break ; case 2: tessellation = MenuItem .MODE_VERYLOW; break ; case 3: tessellation = MenuItem .MODE_MEDIUM; break ; case 4: tessellation = MenuItem .MODE_VERYHIGH; break ; case 5: lightSource = MenuItem .POINT_SOURCE; break ; case 6: lightSource = MenuItem .SPOT_SOURCE; break ; case 7: lightSource = MenuItem .DIRECT_SOURCE; break ; } Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////// // Naziv: ProcessSpecialKeyPress // Namena: metoda procesira strelice // Parametri: key, x, y /////////////////////////////////////////////////// ///////////////// static void ProcessSpecialKeyPress( int key, int x, int y) { switch (key) { case Glut .GLUT_KEY_UP: xRot-= 5.0f; break ; case Glut .GLUT_KEY_DOWN: xRot += 5.0f; break ; case Glut .GLUT_KEY_LEFT: yRot -= 5.0f; break ; case Glut .GLUT_KEY_RIGHT: yRot += 5.0f; break ; };

Page 106: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 106

Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// ///////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////// ///////////////////////// static void RenderScene() { if (shadeMode == MenuItem .MODE_FLAT) Gl .glShadeModel( Gl .GL_FLAT); else // shadeMode = MODE_SMOOTH; Gl .glShadeModel( Gl .GL_SMOOTH); Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glPushMatrix(); // Rotiraj koord. sistem – simulacija kretanja svetlosnog izvora Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Specifikuj novu poziciju i smer svetlosnog izvor a switch (lightSource) { case MenuItem .SPOT_SOURCE: Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_POSITION, spotPos); // smer -z osa, cut off na 50 stepeni Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_SPOT_DIRECTION, spotDir); Gl .glLightf( Gl .GL_LIGHT0, Gl .GL_SPOT_CUTOFF, 25.0f); break ; case MenuItem .POINT_SOURCE: Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_POSITION, spotPos); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_SPOT_DIRECTION, spotDir); Gl .glLightf( Gl .GL_LIGHT0, Gl .GL_SPOT_CUTOFF, 180.0f); break ; case MenuItem .DIRECT_SOURCE: Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_POSITION, dirPos); break ; }; // Nacrtaj crvenu kupu (vizuelni indikator svetlosn og izvora) Gl .glColor3ub(255,0,0); // Pomeri se u tacku gde je svetlo pozicionirano i nacrtaj kupu Gl .glTranslatef(spotPos[0], spotPos[1], spotPos[2]); Glut .glutSolidCone(4.0f,6.0f,15,15); // Nacrtaj malu sferu (sijalica) // Sacuvaj stanje osvetljenja Gl .glPushAttrib( Gl .GL_LIGHTING_BIT); // Iskljuci osvetljenje da bi boja sijalice uvek bi la zuta Gl .glDisable( Gl .GL_LIGHTING); Gl .glColor3ub(255,255,0); Glut .glutSolidSphere(3.0f, 15, 15); // Restauriraj stanje osvetljenja Gl .glPopAttrib(); Gl .glPopMatrix(); // Nacrtaj sferu nad kojom ce se manifestovati efek at osvetljenja Gl .glColor3ub(0, 0, 255);

Page 107: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 107

switch (tessellation) { case MenuItem .MODE_VERYLOW: Glut .glutSolidSphere(30.0f, 7, 7); break ; case MenuItem .MODE_MEDIUM: Glut .glutSolidSphere(30.0f, 15, 15); break ; case MenuItem .MODE_VERYHIGH: Glut .glutSolidSphere(30.0f, 50, 50); break ; }; Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////// // Naziv: ChangeSize // Namena: izmena projekcije prilikom pro mene dimenzija // Parametri: nova sirina i visina /////////////////////////////////////////////////// ///////////////// static void ChangeSize( int width, int height) { if (height == 0) height = 1; Gl .glViewport(0, 0, width, height); Gl .glMatrixMode( Gl .GL_PROJECTION); Gl .glLoadIdentity(); Glu .gluPerspective(35.0f, ( float )width / ( float )height, 1.0f, 500.0f); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); Gl .glTranslatef(0.0f, 0.0f, -250.0f); } /////////////////////////////////////////////////// //////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre // pocetka GLUT petlje /////////////////////////////////////////// //////////////////////// static void SetupRenderingContext() { Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glEnable( Gl .GL_CULL_FACE); Gl .glFrontFace( Gl .GL_CCW); // Ukljuci proracun osvetljenja Gl .glEnable( Gl .GL_LIGHTING); // Podesi parametre svetlosnog izvora 0 i ukljuci g a // Postavi ambijentalno osvetljenje Gl .glLightModelfv( Gl .GL_LIGHT_MODEL_AMBIENT, ambientLight); // Svetlosni izvor 0 podesavanja Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_DIFFUSE, ambientLight); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_SPECULAR, specular); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_POSITION, spotPos); // Podesi parametre specificne za reflektorski svet losni izvor // Cut off na 50 stepeni

Page 108: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 108

Gl .glLightf( Gl .GL_LIGHT0, Gl .GL_SPOT_CUTOFF, 50.0f); // Ukljuci svetlosni izvor 0 Gl .glEnable( Gl .GL_LIGHT0); // Ukljuci i podesi color tracking Gl .glEnable( Gl .GL_COLOR_MATERIAL); Gl .glColorMaterial( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE); Gl .glMaterialfv( Gl .GL_FRONT, Gl .GL_SPECULAR, specref); Gl .glMateriali( Gl .GL_FRONT, Gl .GL_SHININESS, 128); // Crna pozadina Gl .glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } /////////////////////////////////////////////////// ///////////////// // Naziv: Main // Namena: Main metoda /////////////////////////////////////////// ///////////////////////// static void Main( string [] args) { Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGB | Glut .GLUT_DEPTH); Glut .glutInitWindowSize(800, 600); Glut .glutCreateWindow( "Spot osvetljenje" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); Glut .glutSpecialFunc(ProcessSpecialKeyPress); Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "Flat Shading" , ( int ) MenuItem .MODE_FLAT); Glut .glutAddMenuEntry( "Smooth Shading" , ( int ) MenuItem .MODE_SMOOTH); Glut .glutAddMenuEntry( "VL Tess" , ( int ) MenuItem .MODE_VERYLOW); Glut .glutAddMenuEntry( "MD Tess" , ( int ) MenuItem .MODE_MEDIUM); Glut .glutAddMenuEntry( "VH Tess" , ( int ) MenuItem .MODE_VERYHIGH); Glut .glutAddMenuEntry( "Point source" , ( int ) MenuItem .POINT_SOURCE); Glut .glutAddMenuEntry( "Spot source" , ( int ) MenuItem .SPOT_SOURCE); Glut .glutAddMenuEntry( "Direct source" , ( int ) MenuItem .DIRECT_SOURCE); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); SetupRenderingContext(); Glut .glutMainLoop(); } } }

Listing 6.8.2 Primer kreiranja svetlosnih izvora

OpenGL podržava definisanje efekta magle. Proračun efekta magle se uključuje pozivom metode glEnable sa argumentom Gl.GL_FOG. Familija metoda glFog određuje parametre magle.

public static void glFogi(int pname, int param ) public static void glFogf(int pname, float param ) public static void glFogfv(int pname,float[] param )

Page 109: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 109

gde su: pname – parametar koji definiše koja se osobina magle podešava. Neke

od mogućih vrednosti su: � Gl.GL_FOG_MODE – params je blending faktor

(jednačina po kojoj se računa magla) koji može biti: Gl.GL_LINEAR, Gl.GL_EXP, and Gl.GL_EXP2.

� Gl.GL_FOG_DENSITY – params je gustina magle, vrednost mora biti nenegativ-na; inicijalno iznosi 1.

� Gl.GL_FOG_START – params je distanca od koje se počinje primenjivati magla; inicijalno iznosi 0.

� Gl.GL_FOG_END – params je distanca nakon koje svi objekti su u magli; inicijalno iznosi 1.

� Gl.GL_FOG_COLOR – params definiše boju magle; inicijalno je (0, 0, 0, 0) – crna boja.

param – semantiku određuje parametar pname.

Listing 6.8.3 prikazuje isečak programskog kôda primera primene efekta magle. Slika 6.8.3 prikazuje rezultat ovog primera. Primer predstavlja proširenje primera upravljanja kamerom (videti poglavlje 6.6.4).

Slika 6.8.2 Rezultat primera iz listinga 6.8.2

Page 110: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 110

.

.

. /////////////////////////////////////////// /////////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////// /////////////////////// static void RenderScene() { // obrisi prozor sa trenutno aktivnom bojom za bris anje ekrana Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); // podesi kameru if (deltaMove != 0) camera.Move(deltaMove); if (deltaStrafe != 0) camera.Strafe(deltaStrafe); camera.Update(); camera.Look(); // Pozicioniraj svetlosni izvor pre transformacija Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_POSITION, g_lightPosition); // nacrtaj podlogu Gl .glColor3f(0.60f, 0.40f, 0.10f); DrawGround(); // nacrtaj neke objekte kao orijentire u prostoru DrawMarkers(); Glut .glutSwapBuffers(); } /////////////////////////////////////////// ///////////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre // pocetka GLUT petlje /////////////////////////////////////////// ///////////////////////// static void SetupRenderingContext() { Gl .glClearColor(0.0f, 0.0f, 0.0f, 1.0f); camera.Position(0.0f, 1.5f, 6.0f, // eye 0.0f, 1.5f, 0.0f, // forward 0.0f, 1.0f, 0.0f); // up // Siva pozadina Gl .glClearColor(g_grayLight[0], g_grayLight[1], g_gra yLight[2], g_grayLight[3]); // Kreiranje efekta magle Gl .glEnable( Gl .GL_FOG); // ukljuci efekat magle // boja magle = boja pozadine Gl .glFogfv( Gl .GL_FOG_COLOR, g_grayLight); // magla pocinje na udaljenosti od 5 jedi nica Gl .glFogf( Gl .GL_FOG_START, 5.0f);

Page 111: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 111

// magla prestaje nakon 30 jedinica – sve je uronjeno u maglu Gl .glFogf( Gl .GL_FOG_END, 30.0f); // jednacina za proracun efekta magle Gl .glFogi( Gl .GL_FOG_MODE, Gl .GL_LINEAR); // sakrivaj nalicje poligona Gl .glCullFace( Gl .GL_BACK); Gl .glFrontFace( Gl .GL_CCW); Gl .glEnable( Gl .GL_CULL_FACE); Gl .glEnable( Gl .GL_DEPTH_TEST); // kreiraj i podesi svetlosne izvore Gl .glLightModelfv( Gl .GL_LIGHT_MODEL_AMBIENT, g_blackLight); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_AMBIENT, g_grayLight); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_DIFFUSE, g_whiteLight); Gl .glLightfv( Gl .GL_LIGHT0, Gl .GL_SPECULAR, g_whiteLight); Gl .glEnable( Gl .GL_LIGHTING); Gl .glEnable( Gl .GL_LIGHT0); // Ukljuci i podesi color tracking Gl .glEnable( Gl .GL_COLOR_MATERIAL); Gl .glColorMaterial( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE); Gl .glMateriali( Gl .GL_FRONT, Gl .GL_SHININESS, 128); }

.

.

.

Listing 6.8.3 Primer kreiranja efekta magle

OpenGL omogućava simuliranje različitih svetlosnih efekata korišćenjem blending tehnike. Više o ovoj tehnici se može naći u [3]. Dodatno, OpenGL podržava i dithering, primenu logičkih operacija prilikom kombinovanja boja, kao i color masking. Više detalja se može naći u [3].

Slika 6.8.3 Rezultat primera iz listinga 6.8.3

Page 112: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 112

6.9 Teksture Pridruživanje teksture objektima doprinosi realizmu scene. U ovom poglavlju biće prezentovane metode za učitavanje tekstura i njihovo mapiranje. Jedinica teksture se naziva teksel .

OpenGL podržava rad sa 1D, 2D i 3D teksturama, koje se učitavaju pomoću metoda glTexImage1D , glTexImage2D i glTexImage3D .

public static void glTexImage1D(int target , int level , int internalformat ,

int width , int border , int format , int type , IntPtr data )

public static void glTexImage2D(int target , int level , int internalformat ,

int width , int height , int border , int format , int type , IntPtr data )

public static void glTexImage3D(int target , int level , int internalformat ,

int width , int height , int depth , int border , int format , int type , IntPtr data )

gde su: target – odgovarajuća vrednost shodno dimenzionalnosti teksture:

Gl.GL_TEXTURE_1D, Gl.GL_TEXTURE_2D i Gl.GL_TEXTURE_3D,

level – mipmaping level (ako se ne koristi stavlja se 0), internalFormat – format teksela, width, height i depth – dimenzije teksture, border – širina okvira. Dozvoljene vrednosti su: 0 i 1, format , type i data – format, tip piksela i pikseli pikselmape koja se

koristi kao tekstura.

Teksture se mogu kreirati na osnovu sadržaja kolor bafera (iscrtanog dela kadra) pomoću glCopyTexImage1D i glCopyTexImage2D metoda.

public static void glCopyTexImage1D(int target , int level , int internalFormat , int x , int y , int width , int border )

Page 113: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 113

public static void glCopyTexImage2D(int target , int level , int internalFormat , int x , int y , int width , int height , int border )

gde su: target – odgovarajuća vrednost shodno dimenzionalnosti teksture:

Gl. GL_TEXTURE_1D i Gl. GL_TEXTURE_2D, level – mipmaping level (ako se ne koristi stavlja se 0), internalFormat – format teksela, x i y – koordinate donje-levog temena regiona koji se kopira iz kolor

bafera, width, height – dimenzije teksture, border – širina okvira.Dozvoljene vrednosti su: 0 i 1.

Često se teksture menjaju u toku izvršavanja, učitavaju nove i uklanjaju stare iz memorije. Gore navedene operacije za učitavanje teksture su zahtevne po pitanju resursa. S toga postoje metode glTexSubImage1D , glTexSubImage2D i glTexSubImage3D koje omogućavaju zamenu sadržaja teksture.

public static void glTexSubImage1D(int target , int level , int xOffset , int width , int format , int type , IntPtr data ) public static void glTexSubImage2D(int target , int level , int xOffset , int yOffset , int width , int height , int format , int type , IntPtr data ) public static void glTexSubImage3D(int target , int level , int xOffset , int yOffset , int zOffset , int width , int height , int depth , int format , int type , IntPtr data )

gde su: target – odgovarajuća vrednost shodno dimenzionalnosti teksture:

Gl. GL_TEXTURE_1D, Gl. GL_TEXTURE_2D i Gl. GL_TEXTURE_3D,

level – mipmaping level (ako se ne koristi stavlja se 0), xOffset , zOffset i yOffset – pozicija u staroj teksturi od koje se

vrši zamena, width, height i depth – dimenzije teksture, format, type i data – su format, tip piksela i pikseli pikselmape

koja se koristi kao tekstura.

Page 114: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 114

Moguće je zameniti teksturu delom iscrtanog kadra u kolor baferu sa metodama glCopyTexSubImage1D i glCopyTexSubImage2D .

Za mapiranje teksture na objekat (tj. teksela na temena objekta) koriste se koordinate teksture. Slično X3D standardu (videti poglavlje 4.7), koordinate teksture se izražavaju u (s,t,r) komponentama koje uzimaju vrednost iz opsega [0,1]. 1D teksture imaju samo s komponentu, 2D komponente s i t, a 3D teksture imaju s,t i r komponente. U režim mapiranja dvodimenzionalne teksture se ulazi pozivom metode glEnable sa argumentom Gl.GL_TEXTURE_2D. Analogno se ulazi u režime mapiranja za teksture drugih dimenzionalnosti.

Koordinate 1D, 2D i 3D teksture se specifikuju pomoću metoda glTexCoord1f , glTexCoord2f i glTexCoord3f .

public static void glTexCoord1f(float s )

public static void glTexCoord2f(float s , float t )

public static void glTexCoord3f(float s , float t , float r )

gde su: s,t,r – koordinate teksture (širina, visina, dubina).

Za objekte relativno složene geometrije ručno zadavanje koordinata teksture je veoma teško i podložno greškama. OpenGL standard nudi mogućnost automatskog generisanja koordinata teksture. Automatsko generisanje koordinata tekstura se uključuje preko promenljivih stanja: Gl.GL_TEXTURE_GEN_S, Gl.GL_TEXTURE_GEN_T i Gl.GL_TEXTURE_GEN_R. Za dvodimenzionalne teksture se koriste vrednosti: Gl.GL_TEXTURE_GEN_S i Gl.GL_TEX-TURE_GEN_T. Po uključivanju sve pozivi glTexCoord* metoda se ignorišu i OpenGL automatski generiše koordinate teksture.

OpenGL implementaciji se mora zadati na koji način da generiše koordinate teksture. Ovo se postiže pozivom familije metoda glTexGen* .

public static void glTexGenf(int coord , int pname, float param )

public static void glTexGenfv(int coord , int pname, float[] param )

public static void glTexGenfv(int coord , int pname, IntPtr param )

gde su: coord – specifikuje koju koordinatu zadajemo. Dozvoljene vrednosti su:

Gl.GL_S, Gl.GL_T, i Gl.GL_R, pname – vrednost određuje značenje param parametra. Moguće

vrednosti su: Gl.GL_OBJECT_PLANE i Gl.GL_EYE_PLANE, i Gl.GL_TEXTURE_GEN_MODE,

Page 115: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 115

param – način generisanja koordinata teksture. Dozvoljene vrednosti su: Gl.GL_OBJECT_LINEAR, Gl.GL_EYE_LINEAR, i Gl.GL_SPHE-RE_MAP.

OpenGL podržava tri načina automatskog generisanja koordinata tekstura: linearno koje je izraženo u koordinatama objekta (GL_OBJECT_LINEAR), linearno koje je izraženo u koordinatama sa aspekta posmatrača (GL_EYE_LINEAR), i sferično (GL_SPHERE_MAP). Prva dva koriste ravan, a poslednja sferu. Sferično generisanje koordinata teksture daje realistične rezultate iako u praksi se češće koristi mapiranje na kocku. Više detalja o ovom mapiranju se može naći u [3].

Transformacije nad koordinatama teksture se realizuju korišćenjem Texture matrice. Ova matrica se bira pozivom metode glMatrixMode sa argumentom Gl. GL_TEXTURE.

OpenGL omogućava definisanje načina na koji se tekseli stapaju (texel bending) sa materijalom. U tu svrhu se koristi glTextEnv familija metoda.

public static void glTexEnvi(int target , int pname, int param )

public static void glTexEnvf(int target , int pname, float param )

public static void glTexEnviv(int target ,int pname, int[] param )

public static void glTexEnvfv(int target ,int pname, float[] param )

gde su: target – parametar mora biti Gl.GL_TEXTURE_ENV. pname – najčešća vrednost je Gl.GL_TEXTURE_ENV_MODE, tada

params može biti: � Gl.GL_MODULATE – množi teksel sa bojom

materijala, � Gl.GL_DECAL – blending na osnovu alpha

komponente, � Gl.GL_BLEND – blending teksela sa bojom materijala, � Gl.GL_REPLACE – teksel zamenjuje boju materijala.

params – semantiku određuje parametar pname.

Zbog načina na koji se vrši blending teksture, kao rezultat može doći do gubljenja odsjaja materijala (specular highlight). Ako se želi sačuvati odsjaj mora se koristiti secondary specular color tehnika, dostupna od verzije 1.4. U režim rada sa ovom tehnikom se ulazi sledećim programskim kodom:

Gl.glLightModeli(Gl.GL_LIGHT_MODEL_COLOR_CONTROL,

Page 116: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 116

Gl.GL_SEPARATE_SPECULAR_COLOR);

Za izlazak iz režima se koristi sledeći programski kôd:

Gl.glLightModeli(Gl.GL_LIGHT_MODEL_COLOR_CONTROL, Gl.GL_COLOR_SINGLE);

Pored režimskog rada moguće je i ručno podešavati boju odsjaja. Mapiranje teksela na objekat često podrazumeva skaliranje teksela. OpenGL

omogućava specifikovanje filtara za skaliranje tekstura. Filtri se definišu za smanjenje (minimization) i uvećavanje (magnification) teksture. Neki od filtera su: najbliži sused (nearest neighbour), slika 6.9.1a, i linearno filtriranje (linear filtering), slika 6.9.1b. Najbliži sused određuje vrednost nedostajućeg teksela na osnovu njegovog najbližeg suseda, dok linearno filtriranje određuje vrednost nedostajućeg teksela na osnovu srednje vrednosti okolnih teksela. Najbliži sused daje vizeulno lošiji rezultat u poređenju sa linearnim filtriranjem, ali zato je značajno brži od linearnog filtriranja.

OpenGL zahteva da se definiše kako se rukuje koordinatama teksture koje su van opsega ([0,1]) (texture wrapping). Jedna od mogućnosti je ponavljanje teksture u pravcu u kome su koordinate teksture izvan opsega.

a) najbliži sused b) linearno filtriranje

Slika 6.9.1 Tipovi filtriranja teksture, preuzeto iz [3] Familija metoda glTextParameter omogućava gore navedenu funkcionalnost.

public static void glTexParameterf(int target , int pname, float param ) public static void glTexParameteri(int target , int pname, int param )

public static void glTexParameterfv(int target , int pname, float[] params ) public static void glTexParameterfv(int target ,

Page 117: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 117

int pname, IntPtr params ) public static void glTexParameteriv(int target ,

int pname, int[] params ) public static void glTexParameteriv(int target ,

int pname, IntPtr params ) gde su:

target – parametar mora biti: Gl.GL_TEXTURE_1D, Gl.GL_TEXTURE_2D ili Gl.GL_TEXTURE_3D.

pname – može biti: � Gl.GL_TEXTURE_MIN_FILTER – filtriranje teksture

koje se primenjuje u slučaju da se tekstura mora smanjiti da bi bila pridružena objektu,

� Gl.GL_TEXTURE_MAG_FILTER – filtriranje teksture koje se primenjuje u slučaju da se tekstura mora povećati da bi bila pridružena objektu,

� Gl.GL_TEXTURE_WRAP_S – definiše da li će se tekstura ponavljati po s-osi, kao i kojim tekselima će biti realizovano ponavljanje,

� Gl.GL_TEXTURE_WRAP_T – definiše da li će se tekstura ponavljati po t-osi, kao i kojim tekselima će biti realizovano ponavljanje,

� Gl.GL_TEXTURE_BORDER_COLOR – definiše boju okvira teksture. Podrazumevana vrednost je crna boja,

� Gl.GL_TEXTURE_PRIORITY – definiše prioritet teksture.

params – semantiku određuje parametar pname.

Listing 6.9.1 i slika 6.9.2 prikazuju primer pridruživanja teksture objektu – piramidi. Primer je preuzet iz [3].

.

.

. /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { float [] top = { 0.0f, .80f, 0.0f }; // Top 0 float [] backLeft = { -0.5f, 0.0f, -.50f }; // Back left 1 float [] backRight = { 0.5f, 0.0f, -0.50f }; // Back right 2 float [] frontRight = { 0.5f, 0.0f, 0.5f }; // Front right 3 float [] frontLeft = { -0.5f, 0.0f, 0.5f }; // Front left 4 Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT);

Page 118: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 118

Gl .glPushMatrix(); // Pomeri objekat unazad i primeni rotacije Gl .glTranslatef(0.0f, -0.25f, -4.0f); Gl .glRotatef(xRot, 1.0f, 0.0f, 0.0f); Gl .glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Nacrtaj piramidu // uvek je dobro da se definisu materijali s obziro m da postoji // mogucnost da se ne kreira i pridruzi tekstura ob jektu Gl .glColor3f(1.0f, 0.0f, 0.0f); Gl .glBegin( Gl .GL_TRIANGLES); // Osnova piramide Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3fv(backRight); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3fv(frontLeft); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3fv(backLeft); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3fv(backRight); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3fv(frontRight); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3fv(frontLeft); // Prednja stranica Gl .glTexCoord2f(0.5f, 1.0f); Gl .glVertex3fv(top); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3fv(frontLeft); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3fv(frontRight); // Leva stranica Gl .glTexCoord2f(0.5f, 1.0f); Gl .glVertex3fv(top); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3fv(backLeft); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3fv(frontLeft); // Zadnja stranica Gl .glTexCoord2f(0.5f, 1.0f); Gl .glVertex3fv(top); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3fv(backRight); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3fv(backLeft); // Desna stranica Gl .glTexCoord2f(0.5f, 1.0f); Gl .glVertex3fv(top); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3fv(frontRight); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3fv(backRight);

Page 119: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 119

Gl .glEnd(); Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi inicijalizacije pre pocetka GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glFrontFace( Gl .GL_CCW); Gl .glEnable( Gl .GL_CULL_FACE); // Ukljuci color tracking Gl .glEnable( Gl .GL_COLOR_MATERIAL); // Podesi da se materijali definisu samo za prednje poligone Gl .glColorMaterial( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE); // Bela pozadina Gl .glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Ucitaj sliku Bitmap image = new Bitmap ( "..//..//stone.jpg" ); // rotiramo sliku zbog koordinantog sistema opengl- a image.RotateFlip( RotateFlipType .RotateNoneFlipY); Rectangle rect = new Rectangle (0, 0, image.Width, image.Height); // RGBA format (dozvoljena providnost slike tj. alf a kanal) BitmapData imageData = image.LockBits(rect, System.Drawing.Imaging. ImageLockMode .ReadOnly, System.Drawing.Imaging. PixelFormat .Format32bppArgb); // Kreiraj teksturu sa RGBA Gl .glTexImage2D( Gl .GL_TEXTURE_2D, 0, ( int ) Gl .GL_RGBA8, imageData.Width, imageData.Height, 0, Gl .GL_BGRA, Gl .GL_UNSIGNED_BYTE, imageData.Scan0); // Podesi parametre teksture Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_LINEAR); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MAG_FILTER, Gl .GL_LINEAR); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_WRAP_S, Gl .GL_CLAMP); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_WRAP_T, Gl .GL_CLAMP); // Podesi nacin blending teksture Gl .glTexEnvi( Gl .GL_TEXTURE_ENV, Gl .GL_TEXTURE_ENV_MODE, Gl .GL_MODULATE); // Predji u rezim rada sa 2D teksturama Gl .glEnable( Gl .GL_TEXTURE_2D);

Page 120: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 120

// Posto je kreirana tekstura slika nam vise ne tre ba image.UnlockBits(imageData); image.Dispose(); }

.

.

.

Listing 6.9.1 Primer rada sa teksturama - pridruživanje teksture piramidi

Veliki problem predstavlja činjenica što je tekstura fiksnih dimenzija i kao takva teško da se može mapirati na objekat bez potrebe za skaliranjem. Skaliranje skoro uvek daje neželjene artefakte. tzv. scintillation artefacts. Ovi artefakti se najbolje uočavaju kod objekata u pokretu. Takođe, skaliranje predstavlja zahtevnu operaciju sa aspekta zauzeća resursa. Kao rešenje za gore navedene probleme koristi se mipmapping tehnika pridruživanja teksture objektima. Ova tehnika poboljšava kako performanse iscrtavanja tako i vizuelni kvalitet iscrtanih objekata. Mipmapping koristi umesto jedne teksture, čitav niz tekstura (mipmapping levels) iste slike, ali različitog kvaliteta i dimenzija. OpenGL tada koristi najpogodniju teksturu. Mipmapping tekstura se sastoji od niza slika, gde je svaka slika dva puta manjih dimenzija od prethodne, slika 6.9.3.

. . . Slika 6.9.3 Mipmapping tekstura

Za kreiranje mipmapping tekstura koriste se metode: gluBuild1DMipmaps , gluBuild2DMipmaps i gluBuild3DMipmaps .

public static int gluBuild1DMipmaps(int target , int internalFormat , int width , int format , int type , IntPtr data )

Slika 6.9.2 Rezultat primera iz

listinga 6.9.1

Page 121: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 121

public static int gluBuild2DMipmaps(int target , int internalFormat , int width , int height , int format , int type , IntPtr data )

public static int gluBuild3DMipmaps(int target , int internalFormat , int width , int height , int depth , int format , int type , IntPtr data )

gde su: target – odgovarajuća vrednost shodno dimenzionalnosti teksture:

Gl.GL_TEXTURE_1D, Gl.GL_TEXTURE_2D i Gl.GL_TEXTURE_3D,

internalFormat – format teksela, width , height i depth – dimenzije teksture, format , type i data – su format, tip piksela i pikseli pikselmape

koja se koristi kao tekstura.

S obzirom na čestu upotrebu velikog broja tekstura postoji glGenTextures metoda koja kreira N tekstura odjednom. Ovako kreirana tekstura (se naziva Texture Object u OpenGL terminologiji) se pridružuje objektu pozivom metode glBindTexture . Teksture se uništavaju pozivom metode glDeleteTextures .

public static void glGenTextures(int n, int[] textures ) public static void glGenTextures(int n, IntPtr textures )

gde su: n – broj tekstura koje treba da se generišu, textures – niz u kom se smeštaju identifikatori alociranih tekstura.

public static void glBindTexture(int target , int texture )

gde su:

Page 122: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 122

target – Gl.GL_TEXTURE_1D, Gl.GL_TEXTURE_2D i Gl.GL_TEXTURE_3D, texture – identifikator alocirane teksture koja želi koristiti.

public static void glDeleteTextures(int n, int[] textures )

public static void glDeleteTextures(int n, IntPtr textures )

gde su: n – broj tekstura koje treba da se unište, textures – niz identifikatora tekstura.

Listing 6.9.2 i slika 6.9.4 prikazuju primer korišćenja gore navedenih metoda. Primer pokazuje primenu mipmapping tekstura, kao i primenu različitih filtara nad teksturama. Primer je preuzet iz [3].

.

.

. // stavke menija enum MenuItem { NEAREST = 0, LINEAR, N_MIPMAP_N, N_MIPMAP_L, L_MIPMAP_N, L_MIPMAP_L }; // Identifikatori tekstura i putanje do adekvatnih slika struct TextureObjects { public const int TEXTURE_BRICK = 0; public const int TEXTURE_FLOOR = 1; public const int TEXTURE_CEILING = 2; public const int TEXTURE_COUNT = 3; } static int [] textures = new int [ TextureObjects .TEXTURE_COUNT]; static string [] textureFiles = { "..//..//brick.jpg" , "..//..//floor.jpg" , "..//..//ceiling.jpg" };

Slika 6.9.4 Rezultat primera iz listinga 6.9.2

Page 123: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 123

/////////////////////////////////////////////////// ///////////////// // Naziv: ProcessMenu // Namena: rad sa menijem // Parametri: identifikator odabrane stavke /////////////////////////////////////////////////// ///////////////// static void ProcessMenu( int value) { foreach ( int textureId in textures) { Gl .glBindTexture( Gl .GL_TEXTURE_2D, textureId); switch (( MenuItem )value) { case MenuItem .NEAREST: Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_NEAREST); break ; case MenuItem .LINEAR: Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_LINEAR); break ; case MenuItem .N_MIPMAP_N: Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_NEAREST_MIPMAP_NEAREST); break ; case MenuItem .N_MIPMAP_L: Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_NEAREST_MIPMAP_LINEAR); break ; case MenuItem .L_MIPMAP_N: Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_LINEAR_MIPMAP_NEAREST); break ; case MenuItem .L_MIPMAP_L: Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_LINEAR_MIPMAP_LINEAR); break ; } } Glut .glutPostRedisplay(); } /////////////////////////////////////////////////// //////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////// //////////////////////// static void RenderScene() { Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glPushMatrix(); // Pomeraj objekat po z-osi Gl .glTranslatef(0.0f, 0.0f, zPos); for ( float z = 60.0f; z >= 0.0f; z -= 10.0f) { // Pod tunela

Page 124: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 124

Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .TEXTURE_FLOOR]); Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(-10.0f, -10.0f, z); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(-10.0f, -10.0f, z - 10.0f); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(10.0f, -10.0f, z - 10.0f); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(10.0f, -10.0f, z); Gl .glEnd(); // Plafon tunela Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .TEXTURE_CEILING]); Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(-10.0f, 10.0f, z); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(10.0f, 10.0f, z); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(10.0f, 10.0f, z - 10.0f); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(-10.0f, 10.0f, z - 10.0f); Gl .glEnd(); // Levi zid tunela Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .TEXTURE_BRICK]); Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(-10.0f, -10.0f, z); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(-10.0f, 10.0f, z); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(-10.0f, 10.0f, z - 10.0f); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(-10.0f, -10.0f, z - 10.0f); Gl .glEnd(); // Desni zid tunela Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(10.0f, -10.0f, z); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(10.0f, -10.0f, z - 10.0f); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(10.0f, 10.0f, z - 10.0f); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(10.0f, 10.0f, z); Gl .glEnd(); } Gl .glPopMatrix(); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// ///////////////// // Naziv: SetupRenderingContext /////////////////////////////////////////// /////////////////////////

Page 125: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 125

static void SetupRenderingContext() { // Crna pozadina Gl .glClearColor(0.0f, 0.0f, 0.0f,1.0f); // Ukljuci depthtest i back face culling i podesi d a je front = CW Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glEnable( Gl .GL_CULL_FACE); Gl .glFrontFace( Gl .GL_CW); // Teksture se primenjuju sa parametrom decal Gl .glEnable( Gl .GL_TEXTURE_2D); Gl .glTexEnvi( Gl .GL_TEXTURE_ENV, Gl .GL_TEXTURE_ENV_MODE, Gl .GL_DECAL); // Ucitaj slike i kreiraj teksture Gl .glGenTextures( TextureObjects .TEXTURE_COUNT, textures); for ( int i = 0; i < TextureObjects .TEXTURE_COUNT; ++i) { // Pridruzi teksturu odgovarajucem identifikatoru Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[i]); // Ucitaj sliku i podesi parametre teksture Bitmap image = new Bitmap (textureFiles[i]); // rotiramo sliku zbog koordinantog sistema opengl- a image.RotateFlip( RotateFlipType .RotateNoneFlipY); Rectangle rect = new Rectangle (0, 0, image.Width, image.Height); // RGBA format (dozvoljena providnost slike tj. alf a kanal) BitmapData imageData = image.LockBits(rect, System.Drawing.Imaging. ImageLockMode .ReadOnly, System.Drawing.Imaging. PixelFormat .Format32bppArgb); Glu .gluBuild2DMipmaps( Gl .GL_TEXTURE_2D, ( int ) Gl .GL_RGBA8, image.Width, image.Height, Gl .GL_BGRA, Gl .GL_UNSIGNED_BYTE, imageData.Scan0); Gl .glTexParameteri(( int ) Gl .GL_TEXTURE_2D, ( int ) Gl .GL_TEXTURE_MIN_FILTER, ( int ) Gl .GL_LINEAR); Gl .glTexParameteri(( int ) Gl .GL_TEXTURE_2D, ( int ) Gl .GL_TEXTURE_MAG_FILTER, ( int ) Gl .GL_LINEAR); image.UnlockBits(imageData); image.Dispose(); } } /////////////////////////////////////////////////// //////////////// // Naziv: Shutdown // Namena: oslobadjanje alociranih tekstu ra /////////////////////////////////////////// //////////////////////// static void Shutdown() { Gl .glDeleteTextures( TextureObjects .TEXTURE_COUNT, textures); } /////////////////////////////////////////////////// ///////////////// // Naziv: Main // Namena: Main metoda /////////////////////////////////////////// ///////////////////////// static void Main( string [] args) {

Page 126: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 126

Glut .glutInit(); Glut .glutInitDisplayMode( Glut .GLUT_DOUBLE | Glut .GLUT_RGBA | Glut .GLUT_DEPTH); Glut .glutInitWindowSize(800, 600); Glut .glutCreateWindow( "Demonstracija rada sa mipmapping teksturama" ); Glut .glutDisplayFunc(RenderScene); Glut .glutReshapeFunc(ChangeSize); Glut .glutSpecialFunc(ProcessSpecialKeyPress); // Meni Glut .glutCreateMenu(ProcessMenu); Glut .glutAddMenuEntry( "GL_NEAREST", ( int ) MenuItem .NEAREST); Glut .glutAddMenuEntry( "GL_LINEAR" , ( int ) MenuItem .LINEAR); Glut .glutAddMenuEntry( "GL_NEAREST_MIPMAP_NEAREST", ( int ) MenuItem .N_MIPMAP_N); Glut .glutAddMenuEntry( "GL_NEAREST_MIPMAP_LINEAR", ( int ) MenuItem .N_MIPMAP_L); Glut .glutAddMenuEntry( "GL_LINEAR_MIPMAP_NEAREST", ( int ) MenuItem .L_MIPMAP_N); Glut .glutAddMenuEntry( "GL_LINEAR_MIPMAP_LINEAR" , ( int ) MenuItem .L_MIPMAP_L); Glut .glutAttachMenu( Glut .GLUT_RIGHT_BUTTON); SetupRenderingContext(); Glut .glutMainLoop(); Shutdown(); }

Listing 6.9.2 Primer korišćenja mipmapping tekstura

Uobičajno je da se teksture koriste za simulaciju realnog okruženja (pozadine scene). Listing 6.9.3 i slika 6.9.5 prikazuju primer definisanja pozadine scene – korišćenjem kvadra čijim stranicama su pridružene teksture pozadine.

.

.

. // id tekstura struct TextureObjects { public const int BACK_ID = 0; public const int FRONT_ID = 1; public const int BOTTOM_ID = 2; public const int TOP_ID = 3; public const int LEFT_ID = 4; public const int RIGHT_ID = 5; public const int TEXTURE_COUNT = 6; } static int [] textures = new int [ TextureObjects .TEXTURE_COUNT]; /////////////////////////////////////////////////// //////////////// // Naziv: CreateTexture // Namena: kreira mipmapping teksturu // Parametri: niz id tekstura, naziv fajla i id teksture /////////////////////////////////////////////////// ///////////////// static void CreateTexture( int [] textureArray, string fileName, int textureID) {

Page 127: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 127

Bitmap image = new Bitmap (fileName); image.RotateFlip( RotateFlipType .RotateNoneFlipY); System.Drawing.Imaging. BitmapData bitmapdata; Rectangle rect = new Rectangle (0, 0, image.Width, image.Height); bitmapdata = image.LockBits(rect, System.Drawing.Imaging. ImageLockMode .ReadOnly, System.Drawing.Imaging. PixelFormat .Format32bppArgb); textureArray[textureID] = new int (); Gl .glGenTextures(1, out textureArray[textureID]); Gl .glBindTexture( Gl .GL_TEXTURE_2D, textureArray[textureID]); Glu .gluBuild2DMipmaps( Gl .GL_TEXTURE_2D, Gl .GL_RGBA8, image.Width, image.Height, Gl .GL_BGRA, Gl .GL_UNSIGNED_BYTE, bitmapdata.Scan0); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MAG_FILTER, Gl .GL_LINEAR); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_LINEAR_MIPMAP_LINEAR); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_WRAP_S, Gl .GL_CLAMP_TO_EDGE); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_WRAP_T, Gl .GL_CLAMP_TO_EDGE); image.UnlockBits(bitmapdata); image.Dispose(); } /////////////////////////////////////////////////// ///////////////// // Naziv: DrawEnviroment // Namena: crta se kocka kojoj su pridruz ene teksture // Parametri: x,y,z pozicija kocke, width, h eight i length /////////////////////////////////////////////////// ///////////////// static void DrawEnviroment( float x, float y, float z, float width, float height, float length) { // BACK teksturu pridruzi zadnjoj stranici kocke Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .BACK_ID]); // kocka je centrirana oko (x,y,z) tacke x = x - width / 2; y = y - height / 2; z = z - length / 2; // BACK stranica Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(x + width, y, z); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(x + width, y + height, z); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(x, y + height, z); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(x, y, z); Gl .glEnd(); // FRONT teksturu pridruzi prednjoj stranici kocke Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .FRONT_ID]); // FRONT stranica Gl .glBegin( Gl .GL_QUADS);

Page 128: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 128

Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(x, y, z + length); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(x, y + height, z + length); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(x + width, y + hei ght, z + length); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(x + width, y, z + length); Gl .glEnd(); // BOTTOM teksturu pridruzi donjoj stranici kocke Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .BOTTOM_ID]); // BOTTOM stranica Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(x, y, z); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(x, y, z + length); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(x + width, y, z + length); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(x + width, y, z); Gl .glEnd(); // TOP teksturu pridruzi gornjoj stranici Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .TOP_ID]); // TOP stranica Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(x + width, y + height, z); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(x + width, y + hei ght, z + length); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(x, y + height, z + length); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(x, y + height, z); Gl .glEnd(); // LEFT teksturu pridruzi levoj stranici Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .LEFT_ID]); // LEFT stranica Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(x, y + height, z); Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(x, y + height, z + length); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(x, y, z + length); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(x, y, z); Gl .glEnd(); // RIGHT teksturu pridruzi desnoj stranici Gl .glBindTexture( Gl .GL_TEXTURE_2D, textures[ TextureObjects .RIGHT_ID]); // RIGHT stranica Gl .glBegin( Gl .GL_QUADS); Gl .glTexCoord2f(0.0f, 0.0f); Gl .glVertex3f(x + width, y, z); Gl .glTexCoord2f(1.0f, 0.0f); Gl .glVertex3f(x + width, y, z + length); Gl .glTexCoord2f(1.0f, 1.0f); Gl .glVertex3f(x + width, y + hei ght, z + length);

Page 129: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 129

Gl .glTexCoord2f(0.0f, 1.0f); Gl .glVertex3f(x + width, y + height, z); Gl .glEnd(); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi inicijalizacije pre pocetka GLUT petlje /////////////////////////////////////////////////// /////////////////////

static void SetupRenderingContext() { Gl .glClearColor(0.0f, 0.0f, 0.0f, 1.0f); camera.Position(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);

Gl .glEnable( Gl .GL_TEXTURE_2D); Gl .glEnable( Gl .GL_DEPTH_TEST);

CreateTexture(textures, "..//..//back.jpg" , TextureObjects .BACK_ID); CreateTexture(textures, "..//..//front.jpg" , TextureObjects .FRONT_ID); CreateTexture(textures, "..//..//bottom.jpg" , TextureObjects .BOTTOM_ID); CreateTexture(textures, "..//..//top.jpg" , TextureObjects .TOP_ID); CreateTexture(textures, "..//..//left.jpg" , TextureObjects .LEFT_ID); CreateTexture(textures, "..//..//right.jpg" , TextureObjects .RIGHT_ID);

}

.

.

.

Listing 6.9.3 Primer definisanja pozadine scene

Slika 6.9.5 Rezultat primera iz listinga 6.9.3

Page 130: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 130

OpenGL omogućava i ispis teksta kojem je pridružena tekstura. Listing 6.9.4 i slika 6.9.6 prikazuju primer korišćenja tekstura prilikom ispisa teksta.

.

.

. // rotacija teksta static float xRotation, yRotation; // display list koji sadrzi karakter fonta static int fontDL = 0; // tekstura za font static int fontTexture = 0; // bafer za smestanje karaktera – windows specifica n static Gdi . GLYPHMETRICSFLOAT[] gmf = new Gdi . GLYPHMETRICSFLOAT[256]; /////////////////////////////////////////////////// /////////////////// // Naziv: rgCreateFont // Namena: kreiranje fonta kao display l iste // Parametri: DL id, naziv fonta, velicina karak. i stil ispisa // Povratna vrednost: uspesnost kreiranja fonta /////////////////////////////////////////////////// /////////////////// static bool rgCreateFont( ref int id, string name, short height, bool bold, bool italic, bool underline, bool strikeout) { id = Gl .glGenLists(256); // generisemo mesta za 256 karaktera // kreiranje Windows fonta IntPtr font = Gdi .CreateFont(-height, // velicina karaktera 0, / / sirina fonta, nula da automatski je odredi 0, 0, // uglovi - zakosenost fonta (bold) ? Gdi .FW_BOLD : 0, / / bold italic, // italic underline, // underline strikeout, // strikeout Gdi .DEFAULT_CHARSET, // character set identifier Gdi .OUT_TT_PRECIS, // Output Precision Gdi .CLIP_DEFAULT_PRECIS, // Clipping Precision Gdi .ANTIALIASED_QUALITY, // Output Quality Gdi .FF_DONTCARE | Gdi .DEFAULT_PITCH, // Family And Pitch name); // selektuj kreirani font kao aktivni Gdi .SelectObject( Wgl.wglGetCurrentDC(), font); bool success = Wgl.wglUseFontOutlinesW( Wgl.wglGetCurrentDC(), 0, // pocetni karakter 255, // broj DL koji se kreiraju id, // identifikator DLa 0.0f, // koliko se razlikuju od originalnog fonta 0.1f, // debljina fonta (po Z osi) Wgl.WGL_FONT_POLYGONS, // koristi poligone gmf); // bafer u koji se smestaju podaci Gdi .DeleteObject(font); return success; }

Page 131: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 131

/////////////////////////////////////////////////// /////////////////// // Naziv: DeleteFont // Namena: brisanje fonta kao display li ste // Parametri: DL identifikator // Povratna vrednost: /////////////////////////////////////////////////// /////////////////// static void rgDeleteFont( int id) { Gl .glDeleteLists(id, 256); // obrisi svih 256 karaktera } /////////////////////////////////////////////////// /////////////////// // Naziv: CalculateTexturedTextHeight // Namena: izracunavanje visine teksta z a ispis // Parametri: gmf bafer i tekst // Povratna vrednost: duzina /////////////////////////////////////////////////// /////////////////// static float CalculateTexturedTextHeight( Gdi . GLYPHMETRICSFLOAT[] gmf, string text) { float height = 0; foreach ( char i in text) height += gmf[i].gmfCellIncY; // povecaj visinu za visinu karaktera return height; } /////////////////////////////////////////////////// /////////////////// // Naziv: CalculateTexturedTextWidth // Namena: izracunavanje duzine teksta z a ispis // Parametri: gmf bafer i tekst // Povratna vrednost: duzina /////////////////////////////////////////////////// /////////////////// static float CalculateTexturedTextWidth( Gdi . GLYPHMETRICSFLOAT[] gmf, string text) { float width = 0; foreach ( char i in text) width += gmf[i].gmfCellIncX; // povecaj sirinu za sirinu karaktera return width; } /////////////////////////////////////////////////// /////////////////// // Naziv: RenderTexturedText // Namena: ipis teksturiranog teksta // Parametri: DL identifikator, tekst za is pis // Povratna vrednost: /////////////////////////////////////////////////// /////////////////// static void RenderTexturedText( int id, string text) { if (text.Length != 0) { Gl .glPushAttrib( Gl .GL_LIST_BIT); // sacuvamo stanje DL steka Gl .glListBase(id); // pozicioniraj se na pocetak DL Gl .glCallLists(text.Length, Gl .GL_UNSIGNED_SHORT, // STRING JE UNICODE, pa mora 2 bajta! text); // ispis DL teksta Gl .glPopAttrib(); // sacuvamo stanje DL steka

Page 132: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 132

} } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { int miliseconds = Glut .glutGet( Glut .GLUT_ELAPSED_TIME); string message = string .Format( "Proteklo vreme - {0:00}:{1:00}" , (miliseconds/60000)%60, (mil iseconds/1000)%60); float messageWidth = CalculateTexturedTextWidth(gmf, mes sage); Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); Gl .glTranslatef(0.0f, 0.0f, -10.0f); // pomeri 10 jedinica u dubinu Gl .glRotatef(xRotation, 1.0f, 0.0f, 0.0f); // rotiraj po x osi Gl .glRotatef(yRotation, 0.0f, 1.0f, 0.0f); // rotiraj po y osi Gl .glTranslatef(-0.5f*messageWidth, 0.0f, 0.0f); // centriraj tekst RenderTexturedText(fontDL, message); Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// /////////////////// // Naziv: Shutdown // Namena: oslobadja alocirani font /////////////////////////////////////////////////// /////////////////// static void Shutdown() { rgDeleteFont(fontDL); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { Gl .glCullFace( Gl .GL_BACK); Gl .glEnable( Gl .GL_CULL_FACE); Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glShadeModel( Gl .GL_SMOOTH); Gl .glEnable( Gl .GL_LIGHT0); Gl .glEnable( Gl .GL_LIGHTING); Gl .glHint( Gl .GL_PERSPECTIVE_CORRECTION_HINT, Gl .GL_NICEST); // Tekst crne boje na beloj pozadini Gl .glClearColor(1.0f, 1.0f, 1.0f, 1.0f ); Gl .glColor3f(0.0f, 0.0f, 0.0f); // Ucitaj teksturu Bitmap image = new Bitmap ( "..//..//stone.jpg" ); image.RotateFlip( RotateFlipType .RotateNoneFlipY); Rectangle rect = new Rectangle (0, 0, image.Width, image.Height); BitmapData imageData = image.LockBits(rect, System.Drawing.Imaging. ImageLockMode .ReadOnly, System.Drawing.Imaging. PixelFormat .Format32bppArgb);

Page 133: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 133

Gl .glGenTextures(1, out fontTexture); Gl .glBindTexture( Gl .GL_TEXTURE_2D, fontTexture); Gl .glTexImage2D( Gl .GL_TEXTURE_2D, 0, ( int ) Gl .GL_RGBA8, image.Width, image.Height, 0, Gl .GL_BGRA, Gl .GL_UNSIGNED_BYTE, imageData.Scan0); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_LINEAR); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MAG_FILTER, Gl .GL_LINEAR); // Generisi teksture koordinate automatski Gl .glTexGeni( Gl .GL_S, Gl .GL_TEXTURE_GEN_MODE, Gl .GL_OBJECT_LINEAR); Gl .glTexGeni( Gl .GL_T, Gl .GL_TEXTURE_GEN_MODE, Gl .GL_OBJECT_LINEAR); Gl .glEnable( Gl .GL_TEXTURE_GEN_S); Gl .glEnable( Gl .GL_TEXTURE_GEN_T); image.UnlockBits(imageData); image.Dispose(); if (rgCreateFont( ref fontDL, "Verdana" , 12, true , false , false , false ) == true ) { Gl .glEnable( Gl .GL_TEXTURE_2D); Gl .glBindTexture( Gl .GL_TEXTURE_2D, fontTexture); } else Environment .Exit(1); }

.

.

.

Listing 6.9.4 Isečak programskog kôda primera pridruživanja teksture tekstu

U gore navedenom primeru tekst se ispisuje korišćenjem metode RenderTexturedText . Metode rgCreateFont i rgDeleteFont , kreiraju, odnosno brišu teksturirani font. Metoda rgCreateFont kreira svaki karakter kao display list-u, koriščenjem metoda koje su specifične za Windows platformu: CreateFont , wglGet-CurrentDC i wglUseFontOutlines . Ovaj primer demonstrira i automatsko generisanje koordinata tekstura korišćenjem promenljivih stanja: Gl.GL_TEXTURE_-GEN_S i Gl.GL_TEXTURE_GEN_T.

Tekst se može ispisati korišćenjem tekstura (svako slovo je tekstura ili deo teksture) što omogućava da korisnikovoj mašini ne mora biti podržan font koji se koristi za ispis teksta, čime se mogu zaobići ograničenja koje postavlja GLUT ispis teksta. Listing 6.9.5 i slika 6.9.7 prikazuju primer ispisa teksta korišćenjem tekstura.

Slika 6.9.6 Rezultat primera iz listinga 6.9.4

Page 134: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 134

.

.

. // display list koji sadrzi karakter fonta static int fontDL = 0; // tekstura za font static int fontTexture = 0; static int characterCount = 256; /////////////////////////////////////////////////// /////////////////// // Naziv: rgCreateTextureAsFont // Namena: kreiranje "fonta" na osnovu t eksture // Parametri: DL identifikator i teksture f onta, dimenzije // teksture, broj karaktera, broj redova karaktera // Povratna vrednost: uspesnost kreiranja fonta /////////////////////////////////////////////////// /////////////////// static bool rgCreateTextureAsFont( ref int fontId, int textureId, int textureWidth, int textureHeight, int characterCount, int rowCount) { float xPosition, yPosition; // pozicija karaktera u teksturi int columnCount = characterCount/rowCount; int characterWidth = textureWidth/rowCount; int characterHeight = textureHeight/columnCount; fontId = Gl .glGenLists(characterCount); // kreiraj za svaki karak. DL Gl .glBindTexture( Gl .GL_TEXTURE_2D, textureId); // selektuj font tekst. for ( int i = 0; i < characterCount; ++i) { // pozicija karatera xPosition = ( float )(i%rowCount)/characterWidth; // X pozicija yPosition = ( float )(i/columnCount)/characterHeight; // Y pozicija Gl .glNewList(fontId + i, Gl .GL_COMPILE); // nova DL za karakter Gl .glBegin( Gl .GL_QUADS); // koristimo quad na koji mapiramo teksturu karakte ra // donje-levo teme Gl .glTexCoord2f(xPosition, 1.0f - yPosition - 1.0f/( float )characterHeight); Gl .glVertex2i(0, 0); // gornje-levo teme Gl .glTexCoord2f(xPosition, 1.0f - yPosition - 0.001f) ; Gl .glVertex2i(0, characterHeight); // gornje-desno teme Gl .glTexCoord2f(xPosition + 1.0f / ( float )characterWidth, 1.0f - yPosition - 0.00 1f); Gl .glVertex2i(characterWidth, characterHeight); // donje-desno teme Gl .glTexCoord2f(xPosition + 1.0f/( float )characterWidth, 1.0f - yPosition - 1.0f /( float )characterHeight); Gl .glVertex2i(characterWidth, 0); Gl .glEnd(); Gl .glTranslatef(( float )characterWidth, 0, 0); Gl .glEndList(); // posle svake DL proveramo da li je doslo do gresk e if ( Gl .glGetError() != Gl .GL_NO_ERROR)

Page 135: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 135

return false ; } return ( Gl .glGetError() == Gl .GL_NO_ERROR);//vrati uspesnost operacije } /////////////////////////////////////////////////// /////////////////// // Naziv: rgDeleteTextureAsFont // Namena: brisanje fonta kao display li ste // Parametri: DL identifikator i broj karak tera /////////////////////////////////////////////////// /////////////////// static void rgDeleteTextureAsFont( int idDL, int charCount) { Gl .glDeleteLists(idDL, charCount); // obrisi svih 256 karaktera } /////////////////////////////////////////////////// /////////////////// // Naziv: RenderTextUsingTextures // Namena: ispis teksta koriscenjem teks tura // Parametri: DL identifikator, tekst za is pis /////////////////////////////////////////////////// /////////////////// static void RenderTextUsingTextures( int id, string text) { if (text.Length != 0) { Gl .glPushAttrib( Gl .GL_TEXTURE_BIT); // sacuvamo stanje DL steka Gl .glEnable( Gl .GL_TEXTURE_2D); // ukljuci mapiranje tekstura Gl .glListBase(id - 32); // postavi se na pocetak DL byte [] textbytes = new byte [text.Length]; for ( int i = 0; i < text.Length; ++i) textbytes[i] = ( byte )text[i]; Gl .glCallLists(text.Length, Gl .GL_UNSIGNED_BYTE, // STRING JE UNICODE, pa mora 2 bajta textbytes); // ispis DL teksta Gl .glPopAttrib(); // vrati stanje DL steka } } /////////////////////////////////////////////////// ///////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// ///////////////////// static void RenderScene() { int miliseconds = Glut .glutGet( Glut .GLUT_ELAPSED_TIME); string message = string .Format( "Proteklo vreme - {0:00}:{1:00}" , (miliseconds/60000)%60, (mil iseconds/1000)%60); Gl .glClear( Gl .GL_COLOR_BUFFER_BIT | Gl .GL_DEPTH_BUFFER_BIT); Gl .glMatrixMode( Gl .GL_MODELVIEW); Gl .glLoadIdentity(); // crvena boja slova Gl .glColor3f(1.0f, 0.0f, 0.0f); // pozicioniraj se u centar (vrednosti su odredjene na osnovu // poznavanja sirine karaktera i dimenzija ek rana) Gl .glTranslatef(144.0f, 240.0f, 0.0f); // skaliraj slova da visina bude dva puta veca od s irine Gl .glScalef(1.0f, 2.0f, 1.0f);

Page 136: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 136

// ispisi tekst RenderTextUsingTextures(fontDL, message); // Buffer swap Glut .glutSwapBuffers(); } /////////////////////////////////////////////////// /////////////////// // Naziv: Shutdown // Namena: metoda oslobadja resurse /////////////////////////////////////////////////// /////////////////// static void Shutdown() { rgDeleteTextureAsFont(fontDL, 256); Gl .glDeleteTextures(1, ref fontTexture); } /////////////////////////////////////////////////// ///////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijali zacije pre pocetka // GLUT petlje /////////////////////////////////////////////////// ///////////////////// static void SetupRenderingContext() { Gl .glEnable( Gl .GL_CULL_FACE); Gl .glFrontFace( Gl .GL_CW); Gl .glEnable( Gl .GL_DEPTH_TEST); Gl .glShadeModel( Gl .GL_SMOOTH); Gl .glEnable( Gl .GL_COLOR_MATERIAL); Gl .glColorMaterial( Gl .GL_FRONT, Gl .GL_AMBIENT_AND_DIFFUSE); Gl .glClearColor(0.0f, 0.0f, 0.0f, 1.0f ); // Ucitaj teksturu Gl .glEnable( Gl .GL_TEXTURE_2D); Gl .glGenTextures(1, out fontTexture); Gl .glBindTexture( Gl .GL_TEXTURE_2D, fontTexture); // Ucitaj sliku i podesi parametre teksture Bitmap image = new Bitmap ( "..//..//font.jpg" ); image.RotateFlip( RotateFlipType .RotateNoneFlipY); Rectangle rect = new Rectangle (0, 0, image.Width, image.Height); BitmapData imageData = image.LockBits(rect, System.Drawing.Imaging. ImageLockMode .ReadOnly, System.Drawing.Imaging. PixelFormat .Format32bppArgb); Glu .gluBuild2DMipmaps( Gl .GL_TEXTURE_2D, ( int ) Gl .GL_RGBA8, image.Width, image.Height, Gl .GL_BGRA, Gl .GL_UNSIGNED_BYTE, imageData.Scan0); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MIN_FILTER, Gl .GL_LINEAR_MIPMAP_LINEAR); Gl .glTexParameteri( Gl .GL_TEXTURE_2D, Gl .GL_TEXTURE_MAG_FILTER, Gl .GL_LINEAR); if (rgCreateTextureAsFont( ref fontDL, fontTexture, image.Width, image.Height, chara cterCount, 16) == false ) { image.UnlockBits(imageData); image.Dispose( ); Environment .Exit(1); } image.UnlockBits(imageData); image.Dispose(); }

Page 137: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 137

.

.

.

Listing 6.9.5 Isečak programskog kôda korišćenja tekstura za ispis teksta

U gore navedenom primeru tekst se ispisuje korišćenjem metode RenderText-UsingTextures . Metode rgCreateTexture-AsFont i rgDeleteTextureAsFont , kreiraju, odnosno brišu „font“ realizovan korišćenjem tekstura. Metoda rgCreateTextureAsFont kreira svaki karakter kao display list-u, koja predstavlja jedan pravougonik kome je pridružen deo teksture - karakter, slika 6.9.8.

OpenGL, do verzije 2.0, postavlja ograničenja na dimenzije teksture. Dimenzije teksture moraju biti stepen dvojke. Ako je potrebno koristiti teksture proizvoljnih dimenzija tada se koristiti ekstenzija Gl.GL_ARB_-texture_rectangle . Ove teksture se mogu kreirati korišćenjem glTexImage2D, glSubTexImage2D, glCopyTexImage2D i glCopySubTexImage2D gde je target: Gl.GL_TEXTURE_RECTANGLE_ARB . One ne podržavaju mipmapping, kao ni definisanje okvira. Od wrapping modova podržani su: Gl.GL_CLAMP, Gl.GL_CLAMP_TO_EDGE, i Gl.GL_CLAMP_TO_BORDER. S obzirom da je funkcionalnost realizovana kao ekstenzija, do verzije 2.0, mora se ispitati da li hardver podržava datu funkcionalnost. Sledeći programski kôd demonstrira ispitivanje ove funkcionalnosti:

if (Glut.glutExtensionSupported( "GL_ARB_texture_rectangle") == 0) { // ekstenzija podrzana, kreiraj teksturu Gl.glTexImage2D(Gl.GL_TEXTURE_RECTANGLE_ARB, 0, c omponents, width, height, 0, format, type, d ata); }

OpenGL specifikacija verzija 2.0 je ukinula ograničenje na dimenzije teksture, tako da se ekstenzija koristi samo na hardveru koji ne podržava 2.0 specifikaciju.

Slika 6.9.7 Rezultat primera iz listinga 6.9.5

Slika 6.9.8 Tekstura fonta

Page 138: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 138

6.10 Animacija Animacija se može realizovati na dva načina: korišćenjem glutIdleFunc i/ili korišćenjem glutTimerFunc metoda.

Metoda glutIdleFunc omogućava registrovanje callback metode koja se izvršava u pozadini između dva iscrtavanja na ekran (frekvencija iscrtavanja je određena frekvencijom osvežavanja monitora). Obično se u ovu metodu postavlja programski kôd koji menja parametre iscrtavanja – generiše se novi frejm animacije.

public static void glutIdleFunc(IdleCallback func )

public delegate void Glut.IdleCallback(); gde je:

func – metoda koja se poziva u idle stanju.

Metoda glutTimerFunc omogućava definisanje callback metode koja se izvršava nakon proteklog vremena definisanog parametrom msecs. Da bi se postigao efekat tajmera tj. periodičnosti, potrebno je rekurzivno pozivati func metodu. Primenom tajmera postiže se animacija koja je nezavisna od frekvencije osvežavanja monitora.

public static void glutTimerFunc(int msecs , TimerCallback func , int val )

public delegate void Glut.TimerCallback(int val )

gde su: msecs – period kada se poziva metoda func, func – metoda koja će biti pozvana nakon isteklih msecs milisekundi, val – vrednost koja se prosleđuje funkciji (obično se koristi kao

identifikator koji omogućava da se ignoriše tajmer).

Listinzi 6.10.2 i 6.10.3, preuzeti iz [3], prikazuju isti primer (videti listing 6.5.1) u dve verzije: u kojoj se koristi tajmer i u kojoj se koristi glutIdleFunc metoda. Razlika između ova dva primera se vidi u izvršavanju. Drugi primer se izvršava mnogo brže, s obzirom da prvi ima tajmer od 250ms (4Hz), a drugi 60Mhz (na mašini na kojoj je testiran – frekvencija osvežavanja ekrana!).

.

.

. /////////////////////////////////////////////// /////////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////////////// /////////////////// static void RenderScene() { Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEP TH_BUFFER_BIT); Gl.glMatrixMode(Gl.GL_MODELVIEW);

Page 139: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 139

Gl.glPushMatrix(); // Pomeri se po z-osi da bi se videla scena Gl.glTranslatef(0.0f, 0.0f, -300.0f); // Nacrtaj Sunce Gl.glDisable(Gl.GL_LIGHTING); Gl.glColor3ub(255, 255, 0); Glut.glutSolidSphere(15.0f, 30, 17); Gl.glEnable(Gl.GL_LIGHTING); // Pozicioniraj (pomeri) svetlosni izvor nakom iscr tavanja Sunca Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, lightPos); // Zarotiraj koordinatni sistem za ugao revolucije Zemlje Gl.glRotatef(earthRotation, 0.0f, 1.0f, 0.0 f); // Nacrtaj Zemlju Gl.glColor3ub(0, 0, 255); Gl.glTranslatef(105.0f, 0.0f, 0.0f); Glut.glutSolidSphere(15.0f, 30, 17); // Zarotiraj koordinatni sistem za ugao revolucije Meseca Gl.glColor3ub(200, 200, 200); Gl.glRotatef(moonRotation, 0.0f, 1.0f, 0.0f ); Gl.glTranslatef(30.0f, 0.0f, 0.0f); Glut.glutSolidSphere(6.0f, 30, 17); Gl.glPopMatrix(); Glut.glutSwapBuffers(); } /////////////////////////////////////////////////// /////////////////// // Naziv: ProcessIdleState // Namena: izracunava vrednosti uglova ro tacije za sl. frejm /////////////////////////////////////////////////// /////////////////// static void ProcessIdleState () { moonRotation += 15.0f; if (moonRotation > 360.0f) moonRotation = 0.0f; earthRotation += 5.0f; if (earthRotation > 360.0f) earthRotation = 0.0f; Glut.glutPostRedisplay(); } /////////////////////////////////////////////////// /////////////////// // Naziv: Main // Namena: Main metoda /////////////////////////////////////////////////// /////////////////// static void Main( string [] args) { Glut.glutInit(); Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | G lut.GLUT_RGB | Glut.GLUT_DEPTH); Glut.glutInitWindowSize(800, 600); Glut.glutCreateWindow( "Animacija koriscenjem glutIdleFunc funkcije" ); Glut.glutDisplayFunc(RenderScene); Glut.glutReshapeFunc(ChangeSize); Glut.glutIdleFunc(ProcessIdleState); SetupRenderingContext();

Page 140: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 140

Glut.glutMainLoop(); } }

Listing 6.10.2 Primer simulacije revolucije Zemlje i Meseca oko Sunca korišćenjem glutIdleFunc metode

. . .

/////////////////////////////////////////// ///////////////////////// // Naziv: Timer // Namena: animacija sa konstantnim frejm rejtom // Parametri: vrednost koja ima proizvoljnu semantiku /////////////////////////////////////////////////// ///////////////// static void Timer( int value) { Glut.glutPostRedisplay(); // rekurzivni poziv - periodicnost Glut.glutTimerFunc(100, Timer, value); } /////////////////////////////////////////////////// ///////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu /////////////////////////////////////////// ///////////////////// static void RenderScene() { Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL _DEPTH_BUFFER_BIT); Gl.glMatrixMode(Gl.GL_MODELVIEW); Gl.glPushMatrix(); // Pomeri se po z-osi da bi se videla scena Gl.glTranslatef(0.0f, 0.0f, -300.0f); // Nacrtaj Sunce Gl.glDisable(Gl.GL_LIGHTING); Gl.glColor3ub(255, 255, 0); Glut.glutSolidSphere(15.0f, 30, 17); Gl.glEnable(Gl.GL_LIGHTING); // Pozicioniraj (pomeri) svetlosni izvor nakom iscr tavanja Sunca Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITI ON, lightPos); // Zarotiraj koordinatni sistem za ugao revolucije Zemlje Gl.glRotatef(earthRotation, 0.0f, 1.0f, 0.0f); // Nacrtaj Zemlju Gl.glColor3ub(0, 0, 255); Gl.glTranslatef(105.0f, 0.0f, 0.0f); Glut.glutSolidSphere(15.0f, 30, 17); // Zarotiraj koordinatni sistem za ugao revolucije Meseca Gl.glColor3ub(200, 200, 200); Gl.glRotatef(moonRotation, 0.0f, 1.0f, 0.0f); Gl.glTranslatef(30.0f, 0.0f, 0.0f); // Nacrtaj Mesec Glut.glutSolidSphere(6.0f, 30, 17); Gl.glPopMatrix(); earthRotation += 5.0f;

Page 141: Op Engl

VI Open Graphics Library (OpenGL) C#

S. Mihić, D. Dragan, V.Petrović, D.Ivetić – RAČUNARSKA GRAFIKA VEŽBE 141

if (earthRotation > 360.0f) earthRotation = 0.0f; moonRotation += 15.0f; if (moonRotation > 360.0f) moonRotation = 0.0f; Glut.glutSwapBuffers(); } /////////////////////////////////////////// ////////////////////// // Naziv: Main //////////////////////////////////////////// ///////////////////// static void Main( string [] args) { Glut.glutInit(); Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut .GLUT_RGB | Glut.GLUT_DEPTH); Glut.glutInitWindowSize(800, 600); Glut.glutCreateWindow( "Animacija koriscenjem glutTimerFunc funkcije" ); Glut.glutDisplayFunc(RenderScene); Glut.glutTimerFunc(250, Timer, 1); Glut.glutReshapeFunc(ChangeSize); SetupRenderingContext(); Glut.glutMainLoop(); } }

Listing 6.10.3 Primer simulacije revolucije Zemlje i Meseca oko Sunca korišćenjem glutTimerFunc metode

Dva načina realizacije animacije u OpenGL-u nisu međusobno isključivi, već se mogu kombinovati. Prilikom korišćenja tajmera mora se voditi računa o broju tajmera, zbog ograničenosti resursa.

U okviru ovog teksta prezentovan je osnovni deo OpenGL standarda. Za podrobnije upoznavanje sa OpenGL standardom čitaocu se preporučuje [3].

LITERATURA 1. GLUT specification, http://www.opengl.org/resources/libraries/glut/glut-

3.spec.pdf 2. OpenGL specification, http://www.opengl.org/documentation/specs/ 3. Wright R. Jr., Lipchak B., Haemel N., „OpenGL Super Bible“, 4th Ed.,

Addison Wesley, 2007.