Sie sind auf Seite 1von 141

VI Open Graphics Library (OpenGL) C#

VI Open Graphics Library (OpenGL) C#


OpenGL je standardni programski interfejs aplikacije (API Application Programming Interface) namenjen razvoju aplikacija u oblasti dvodimenzionalne i trodimenzionalne raunarske grafike. OpenGL standard razvijen je i utvren 1992. godine od strane vodeih kompanija, koje ine OpenGL Architecture Review Board, kao efektivni hardversko-nezavisni interfejs, pogodan za realizaciju na razliitim platformama. Za osnovu standarda iskoriena je programska biblioteka IRIS GL, koju je razvila kompanija Silicon Graphics Inc (SGI). Veina proizvoaa hardvera i softvera podrava OpenGL. Implementacije OpenGL standarda postoje za veliki broj platformi. Velika rasprostranjenost OpenGL standarda se bazira na sledeim osobinama: Stabilnost. Dopune i izmene standarda odravaju kompatibilnost sa prethodnim verzijama. Prenosivost. OpenGL aplikacije garantuju istovetan vizuelni rezultat nezavisno od tipa korienog operativnog sistema i hardvera. Lakoa upotrebe. OpenGL poseduje intuitivan i jednostavan interfejs koji omoguava razvoj efektivnih aplikacija uz manji programerski napor. Obino aplikacije koje se oslanjanju na OpenGL sadre manji broj redova programskog kda nego kada se koriste druge grafike biblioteke. Specifinosti korienog hardvera kao i obezbeivanje kompatibilnosti sa razliitom opremom realizovane su na nivou OpenGL implementacije. Verzija standarda koja e biti obraena je OpenGL 2.1 verzija standarda. Vie informacija o OpenGL standardu se moe pronai 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 moe biti softverska ili hardverska, slika 6.1.1. OpenGL dozvoljava softversku emulaciju (softversku implementaciju) funkcionalnosti koju hardver ne implementira. Softverska implementacija koristi raspoloivi grafiki sistem (npr. GDI na Windows plaftormi) za iscrtavanje, dok hardverska koristi OpenGL kompatibilni hardver za iscrtavanje. Obino grafiki hardver daje razliite nivoe ubrzavanja: od hardverske realizacije generisanja linija i poligona do monih grafikih procesora sa podrkom za razliite operacije nad geometrijskim podacima.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C#

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 izvrava. Server se moe nalaziti na tom istom raunaru, na kom se nalazi i klijent ili na drugom raunaru. OpenGL iscrtava grafike objekte u baferu kadra (frame buffer) uzimajui u obzir izabrane reime iscrtavanja. Svaki reim moe se menjati nezavisno od drugih. Definisanje primitiva, izbor reima i druge operacije opisuju se pomou komandi u obliku poziva OpenGL metoda. Grafiki objekti se definiu skupom temena (vertex). Temenu se pridruuju podaci (npr. koordinate, boja i dr.) koji se nazivaju atributima. Uproeni proces prezentacije grafike, slika 6.1.2, se sastoji od sledeih koraka: poziva metoda OpenGL API od strane aplikacije (klijenta), skladitenja zadatih metoda komandi u Command baferu, pranjenja Command bafera (ili programski ili automatski), izvravanja komandi, u redosledu njihovog pojavljivanja, primene transformacije i osvetljenja, rasterizacije pretvaranja 3D scene u 2D projekciju, upis rasterizovane scene u bafer kadra grafike kartice (iscrtavanje). Pravi proces ukljuuje jo neke dodatne korake, ali oni nisu neophodni za razumevanje naina rada OpenGL programske biblioteke. itaocima koje to zanima se preporuuje da pogledaju u literaturi [1].

Slika 6.1.2 Uproeni OpenGL proces prezentacije grafike, preuzeto iz [1]

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C#

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 dinamikoj programskoj biblioteci. Da bi se mogle koristiti OpenGL metode potrebno je u zaglavlju Program.cs fajla dodati sledei programski kd:

using Tao.OpenGl;
Veoma je bitno naglasiti da ceo skup Tao Framework skup biblioteka predstavlja samo C# wrapper odgovarajuih biblioteka implementiranih korienjem nativnog programskog jezika (konkretno za OpenGL u pitanju je C programski jezik).

6.1.2 Sintaksa OpenGL metoda

Nazivi OpenGL metoda su deskriptivni i obino pruaju informacije o klasi u kojoj su implementirane, broju i tipu parametara. Nomenklatura OpenGL metoda je (sa * su oznaeni opcioni elementi):

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


gde su:

tip OpenGL tip podataka koji vraa 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 sledee vrednosti: b, s, i, f, d, ub, us, ui. Vrednosti predstavljaju skraene 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.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C# Primer metode sa oznakama prikazan je na slici 6.1.2.1. Ovakva nomenklatura u znaajnoj meri olakava 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# GL komanda broj i tip parametara klasa tipovi podataka. Veina tipova je ekvivalentna njihovim C verzijama. C Slika 6.1.2.1 Primer OpenGL funkcije pokazivai se opisuju IntPtr tipom podataka. Razlika postoji i kod nizova koji su poseban tip u C#. Sve konstante definisane u klasi Gl poinju prefiksom GL_. Odgovarajue konstante klasa Glu i Glut analogno imaju prefikse GLU_ i GLUT_.

glColor3f()

6.1.4 OpenGL promenljive stanja


OpenGL specifikacija definie OpenGL kao automat stanja. Definisan je veliki broj promenljivih stanja koje se mogu ukljuiti/iskljuiti pozivom metode Gl.glEnable/ Gl.glDisable (npr. Gl.glEnable(Gl.GL_LIGHTING) koja ukljuuje proraun osvetljenja u sceni). Ako je promenljiva stanja ukljuena, ponovni pozivi ukljuenja iste promenljive se ignoriu. Analogno vai i za iskljuivanje 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 naglaeno, 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 simbolika konstanta promenljive stanja koja se ukljuuje/iskljuuje.


Kompletan spisak promenljivih stanja i odgovarajuih konstanti moe se videti u dokumentaciji.

Metoda glIsEnabled se koristi za ispitivanje da li odreena promenljiva stanja ukljuena ili ne.

public static int glIsEnabled(int cap)


gde je:

esto postoji potreba da se stanje sistema sauva/restaurira. OpenGL specifikacija definie FIFO stek stanja sistema, koji omoguava realizaciju gore

cap konstanta promenljive stanja za koju se ispituje stanje.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C# navedenih metoda. Stekom se manipulie korienjem 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 greke


Tokom izvravanja OpenGL metoda mogu nastati greke. OpenGL registruje samo mali podskup moguih greaka. Ovakav pristup se bazira na injenici da bi registrovanje i provera svih moguih greaka opasno ugrozila performansu. OpenGL signalizira greke preko numerikih vrednosti koje se u OpenGL terminologiji nazivaju zastavicama (flags). OpenGL zastavice su prikazane u tabeli 6.1.5.1. Ako doe do greaka sistem nastavlja sa radom, a metode koje su izazvale greku se ignoriu. Jedini izuzetak je zastavica GL_OUT_OF_MEMORY kada je rezultat metode nedefinisan. Naziv
GL_INVALID_ENUM GL_INVALID_VALUE GL_INVALID_OPERATION GL_STACK_OVERFLOW GL_STACK_UNDERFLOW GL_OUT_OF_MEMORY GL_TABLE_TOO_LARGE GL_NO_ERROR

Opis
Enum argument je van opsega. Numeriki argument je van opsega. Trenutno stanje sistema ne dozvoljava izvrenje metode. Izvrenje metode izaziva stack overflow. Izvrenje metode izaziva stack underflow. Za izvrenje OpenGL metode sistema nema dovoljno slobodno memorije. Zadata tabela je suvie velika. Nema greke uspeno izvrena OpenGL metoda.

Za utvrivanje koja zastavica je postavljena koristi se metoda glGetError koja vraa vrednost iz tabele 6.1.4.1. Za dobijanje deskriptivnog tekstualnog opisa greke koristi se metoda gluErrorString.

Tabela 6.1.4.1 Zastavice greaka (error flags)

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


gde je:

errorCode konstanta greke, videti tabelu 6.1.4.1

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C# Ako se desilo vie greaka tada se one mogu dobiti sukcesivnim pozivima metode glGetError sve dok povratna vrednost metode ne bude vrednost: GL_NO_ERROR. S toga je uobiajno da se poziv ove metode nalazi unutar petlje. OpenGL omoguava prezentaciju raunarske grafike nezavisno od konkretnog hardvera, i kao takav se moe posmatrati kao softverski interfejs prema grafikom hardveru. Poto OpenGL vri prezentaciju grafike, on ne sadri 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 kd, jer tada treba nekako apstrahovati platformske specifinosti rukovanja prozorima, ulazno-izlaznim ureajima i dr. S toga su napravljene prenosive biblioteke koje obezbeuju esto koriene metode za meusobno delovanje raunara 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 ukljuuje u sve njegove distribucije i postoje realizacije za razliite platforme. GLUT predstavlja samo minimalni skup metoda za pravljenje OpenGL aplikacija. GLUT je kreirao Mark Kilgard, inenjer SGI, sa ciljem da se omogui programerima da piu u potpunosti prenosive aplikacije. GLUT omoguava rukovanje prozorima, rad sa pop-up menijima, prihvat ulaznih podataka sa tastature, mia i dojstika i dr. Razvoj GLUT programske biblioteke (nije open source) je naputen za Windows platformu. Razvoj je nastavljen kroz open source projekat freeglut. U primerima bie koriena freeglut programska biblioteka, koja se moe 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 okruenje za rad sa freeglut bibliotekom, 3. u zagavlje fajl/ova dodati sledei programski kd:

6.1.6 openGL Utility Toolkit (GLUT)

using Tao.FreeGlut;
S obzirom na portabilnost, GLUT programska biblioteka ne moe u potpunosti realizovati sve specifinosti platforme. GLUT programska biblioteka je izabrana da bi se italac fokusirao na OpenGL programiranje raunarske grafike i pisanje prenosivih aplikacija. U daljem tekstu programski kd i detalji e se odnositi na implementaciju pomou C# programskog jezika na Windows platformi.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C#

U daljem tekstu bie prezentovan programski kd aplikacije koja prikazuje prozor plave boje koristei se OpenGL i GLUT programskim bibliotekama. U listingu 5.1.7.1 prikazan je programski kd ove aplikacije.
/*********************************************************************** * Modul: Program.cs * Autor: Srdjan Mihic * Namena: kreiranje jednostavnog prozora oslanjajuci 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 za brisanje ekrana Gl.glClear(Gl.GL_COLOR_BUFFER_BIT); // prekopiraj sadrzaj iz zadnjeg bafera u frame bafer Glut.glutSwapBuffers(); } //////////////////////////////////////////////////////////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijalizacije 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"

5.1.7 Primer GLUT aplikacije

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C#


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 sledee faze: inicijalizacija GLUT programske biblioteke, incijalizacija parametara prozora, kreiranje prozora, registrovanje obraivaa dogaaja (callback metode), podeavanja OpenGL konteksta, pokretanje glavne petlje.

Metoda glutInit vri inicijalizaciju GLUT biblioteke, opciono sa proslenim argumentima komandne linije. Poziv ove metode mora prethoditi pozivu bilo koje druge GLUT ili OpenGL metode. U upotrebi je najee verzija metode bez parametara.

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

Inicijalizacija prozora se sastoji od podeavanja odgovarajuih bafera kadra, poetnog pozicije i dimenzija prozora. Metoda glutInitDisplayMode definie parametre kadra: model boja i tip baferovanja. Postoje dva tipa baferovanja single i double. Single tip baferovanja direktno iscrtava u bafer kadra, to najee dovodi do treperenja (flickering). Ovaj tip baferovanja se veoma retko koristi. Najee se koristi double baferovanje kod kojeg se iscrtava u zadnji bafer (offscreen buffer). Nakon zavrenog iscrtavanja sadraj zadnjeg bafera se prekopira u bafer kadra. Ovo se realizuje pomou metode glutSwapBuffers. Postoji nekoliko vrsta bafera. Gore navedeni baferi se nazivaju baferima boje (color buffers). Postoji jo i bafer dubine kadra (depth buffer), koji definie rastojanje objekata od korisnika.

argc nemodifikovani argc argument main metode, argv nemodifikovani argv argument main metode.

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


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C# gde su:

Metoda glutInitWindowSize se koristi za zadavanje poetnih dimenzija prozora. Poetna pozicija prozora na ekranu se moe zadati pomou glutInitWindowPosition metode. Argumenti u pozivima ovih metoda predstavljaju predlog eljenih vrednosti koje ne moraju nuno biti prihvaene.

mode bitwise OR kombinacija konstanti. Neke od esto korienih 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.

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

width irina prozora izraena u pikselima, height - visina prozora izraena u pikselima, x broj piksela od leve ivice ekrana. Podrazumevana vrednost je -1, to
znai da od upravljaa prozora (window manager) zavisi gde e se prozor pojaviti. Izabrana vrednost bi trebalo da bude pozitivan broj ne vei od irine ekrana. broj piksela od gornje ivice ekrana. Podrazumevana vrednost je -1, to znai da od upravljaa prozora (window manager) zavisi gde e se prozor pojaviti. Izabrana vrednost bi trebalo da bude pozitivan broj ne vei od visine ekrana.

Nakon zadavanja parametara prozora potrebno je kreirati prozor pozivom metode glutCreateWindow. Kreiranom prozoru se implicitno pridruuje OpenGL kontekst. Odmah po izvrenju ove metode nad kontekstom se mogu izvravati OpenGL metode. Prozor je skriven sve dok se ne ue u glavnu petlju. Metoda glutCreateWindow vraa identifikator prozora koji je interesantan u sistemima sa vie prozora. GLUT dozvoljava kreiranje i potprozora korienjem metode glutCreateSubWindow.

public static int glutCreateWindow(string name) public static int glutCreateSubWindow(int win, int x, int y,
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C#

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,
GLUT bibliteka omoguava definisanje obraivaa dogaaja preko tzv. metoda sa povratnim pozivom (callback function). Metode sa povrtanim pozivom su realizovane u C# kao delegati (delegates). Kontrola svih dogaaja i pozivanje potrebnih metoda obavlja se unutar glavne (beskonane) petlje. Postoji veliki broj dogaaja na koje se moe reagovati, tako da e biti prezentovani u okviru odgovarajuih poglavlja. Esencijalna metoda je glutDisplayFunc koja registruje metodu za iscrtavanje sadraja prozora. Ta metoda se poziva kad god sadraj prozora treba da se prikae.

height visina potprozora.

public static void glutDisplayFunc( DisplayCallback func) public delegate void Glut.DisplayCallback()
gde je:

func naziv metode za iscrtavanje sadraja prozora.


U primeru iz listinga 6.1.7.1 za prikaz sadraja prozora registrovana je RenderScene metoda. Unutar ove metode se pozivaju metode: glClear i glutSwapBuffers. glClear metoda brie sadraj prozora pritom popunjavajui ga trenutno aktivnom bojom za brisanje prozora (clear color). Nakon toga se pozivom glutSwapBuffers novi sadraj zadnjeg bafera prenosi u bafer kadra.

public static void glClear(int mask)


gde je:

mask bitwise OR kombinacija konstanti raspoloivih bafera. esto

Uobiajno je da se podeavanja OpenGL konteksta enkapsuliraju metodom SetupRenderingContext. U primeru iz listinga 6.1.7.1 se u ovoj metodi podeava boja kojom e biti prebrisan sadraj prozora (boja pozadine). Metoda glClearColor definie boju za brisanje prozora. Podrazumevana boja za brisanje je crna boja. S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

koriene vrednosti su: GL_COLOR_BUFFER_BIT nalae ispunu sadraja kolor bafera bojom definisanom sa glClearColor, GL_DEPTH_BUFFER_BIT nalae ienje bafera dubine.

10

VI Open Graphics Library (OpenGL) C#

public static void glClearColor(float float float float


gde su:

red, green, blue, alpha)

red, green, blue RGB komponente boje [0.0 1.0],


U glavnu (beskonanu) petlju u aplikaciji se ulazi pozivom metode glutMainLoop. Unutar ove petlje se obrauju dogaaji. Petlja se izvrava do izlaska iz aplikacije.

alpha alfa tj. prozirnost.

6.2 Ispis teksta


OpenGL podrava 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 razliitih transformacija, izvlaenje tree dimenzije, primena efekata i dr. Za razliku od prvog, drugi ispis je daleko bri, ali nudi manju mo manipulacije. Izbor tipa ispisa zavisi od konkretnog problema. Postoji mogunost ispisa teksta oslanjajui se na teksture, videti poglavlje 6.9. GLUT omoguava ispis teksta samo predefinisanim fontovima. Ako je potrebno ispisati tekst proizvoljnim fontom tada se moraju koristiti metode specifine za platformu. Za ispis bitmap karaktera tada se koristi wglUseFontBitmaps, a za ispis outline karaktera wglUseFontOutlines. Ove metode zahtevaju poznavanje specifinosti Windows platforme, kao i korienje metoda specifinih za Windows platformu. Metode su implementirane u klasi Wgl u programskoj biblioteci Tao.Platform.Windows. Vie informacija o ovim metodama se moe nai na Internet adresi: http://msdn2.microsoft.com/en-us/library/ms673957.aspx . Alternativno, za OpenGL ispis teksta nezavisan od platforme moe se iskoristiti open source programska biblioteka FTGL, koja se moe preuzeti sa Internet adrese: http://homepages.paradise.net.nz/henryj/code/#FTGL. Freeglut programska biblioteka nudi i metode glutBitmapString i glutStrokeString koje omoguavaju 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 koristei zadati font.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

11

VI Open Graphics Library (OpenGL) C#

public static void glutBitmapCharacter(IntPtr font, int character)


gde su:

Metoda glutBitmapWidth odreuje irinu bitmap karaktera.

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

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 runo 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 veliine ChangeSize, metode za ispis horizontalnog i vertikalnog bitmap teksta, kao i metode za manipulaciju nad projekcijom.

Slika 6.2.2.1 Rezultat aplikacije iz listinga 6.2.2.1


/*********************************************************************** * 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 {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

12

VI Open Graphics Library (OpenGL) C#


// 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 static float static float static float prozora windowWidth = 320.0f; windowHeight = 240.0f; halfWindowWidth = windowWidth/2;

//////////////////////////////////////////////////////////////////////// // Naziv: CalculateBitmapTextWidth // Namena: metoda utvrdjuje sirinu teksta // 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 horizontalno text // pozivajuci glutBitmapCharacter 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 vertikalno 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) {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

13

VI Open Graphics Library (OpenGL) C#


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 brisanje ekrana Gl.glClear(Gl.GL_COLOR_BUFFER_BIT); // ispisi tekst u levo, centriran RenderBitmapTextH(-halfWindowWidth, fontHeight1, 0.0f, font1, "Dobrodosli u"); // ispisi tekst centriran i vertikalno i horizontalno RenderBitmapTextH(CalculateBitmapTextWidth(font2, "OpenGL")/(-2.0f), 0.0f, 0.0f, font2, "OpenGL"); // ispisi vertikalni tekst centriran RenderBitmapTextV(CalculateBitmapTextWidth(font2, "O")/(-2.0f), -0.5f*fontHeight1, 0.0f, fontHeight2, font2, "OpenGL"); Glut.glutSwapBuffers(); // double-buffering } //////////////////////////////////////////////////////////////////////// // Naziv: ChangeSize // Namena: obradjuje promenu dimenzija prozora // 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; // // // if {

// izracunaj odnos sirina/visina

definisemo orto. projekciju tako da odrzava odnos sirine i visine tj. ako je visina >= od sirine tada koristimo sirinu i izracunamo visinu na osnovu pocetnog odnosa visine/sirine,i obratno (width <= height) // definisi ortogonalnu projekciju halfWindowWidth = halfWidth; Gl.glOrtho(-halfWidth, halfWidth, // na osnovu odnosa sirina/visina -halfWidth/aspectRatio, halfWidth/aspectRatio, 1.0, -1.0);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

14

VI Open Graphics Library (OpenGL) C#


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 inicijalizacije 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 tekst" 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 obezbeuje nain da se definie koja metoda treba da bude pozvana kada se promeni veliina prozora, tj. registruje povratni poziv za preraunavanje projekcije. Pored toga, ta metoda se poziva i kod inicijalnog kreiranja prozora. Ako se ne definie 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(


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 15

VI Open Graphics Library (OpenGL) C#

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

Metoda ChangeSize definie kako e se skalirati prozor pri promeni veliine prozora od strane korisnika. U ovoj metodi koriste se metode glMatrixMode i glLoadIdentity koje e biti detaljno objanjene u poglavlju 6.5. Uobiajno je da metoda ChangeSize ima sledeu formu: Provera korektnosti novih dimenzija prozora. Ova provera ukljuuje proveru da li je nova vrednost visine prozora jednaka nuli. Ako jeste tada se ova vrednost svodi na najbliu validnu vrednost jedan piksel. Definisanje mapiranja logikih koordinata u fizike koordinate definisanje viewport-a korienjem metode glViewport. Definisanje projekcije. Projekcijom se definie 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 odgovarajuih OpenGL metoda kojima se definiu. Metoda glViewport definie mapiranje kliping (clipping) prozora u fiziki prozor aplikacije mapiranje logikog koordinatnog sistema u fiziki (slika 6.2.2.1). U primeru 6.2.2.1 kliping prozor se definie da bude sm prozor.

func naziv metode koja e biti pozivana kada prozor promeni veliinu, width i height nove dimenzije prozora.

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


gde su:

x, y donja leva koordinata, najee (0,0), width irina kliping prozora., height visina kliping prozora.

Slika 6.2.2.1 Mapiranje logikih u fizike koordinate prozora, preuzeto iz [3]

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

16

VI Open Graphics Library (OpenGL) C# Metoda glOrtho definie 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 veliini bez obzira gde se nalaze. Najee 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 definie 2D projekciju. Metoda gluOrtho2D predstavlja specijalni sluaj 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:

Pomona metoda CalculateBitmapTextWidth izraunava irinu teksta zadatog preko parametra string, koristei se GLUT funkcijom glutBitmapWidth. Pomone metode RenderBitmapTextH i RenderBitmapTextV ispisuju tekst horizontalno, odnosno vertikalno. Ispisani tekst pokazuje primer ravnanja teksta uz levu ivicu, i centralno (gde je potrebno je izraunati 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.

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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

17

VI Open Graphics Library (OpenGL) C#

6.2.3 Ispis outline teksta


Za ispis outline teksta koriste se metode glutStrokeCharacter i glutStrokeWidth. Metoda glutStrokeCharacter ispisuje outline karakter, a metoda glutStrokeWidth odreuje 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/izraunati irina.
Horizontalan ispis outline teksta se realizuje tako to pomeri koord. sistem na eljenu poziciju korienjem metode glTranslatef. Zatim se pozivom metode glutStrokeCharacter ispisuje karakter. Ova metoda pomera koord. sistem za irinu karaktera. Svaki drugi ispis outline teksta zahteva runo pozicioniranje koord. sistema. Transformacije koord. sistema bie detaljno objanjene 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 slinog teksta (kao u primeru 6.2.2.1), ali korienjem outline fontova. Ovaj primer demonstrira: ispis outline teksta, definisanje debljine linije i projekcije u perspektivi. Metode glPushMatrix i glPopMatrix bie detaljno objanjenje u poglavlju 6.5.

Slika 6.2.4.1 Izlaz listinga 6.2.4.1


/*********************************************************************** * 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;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

18

VI Open Graphics Library (OpenGL) C#


namespace GLUT_outline_tekst { class Program { // promenljive koje sadrze nazive fontova, moguce su 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 static float static float static float prozora windowWidth = 800.0f; windowHeight = 600.0f; halfWindowWidth = windowWidth/2;

//////////////////////////////////////////////////////////////////////// // Naziv: CalculateStrokeTextWidth // Namena: metoda utvrdjuje sirinu teksta // 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 vertikalno 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) {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

19

VI Open Graphics Library (OpenGL) C#


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 brisanje ekrana Gl.glClear(Gl.GL_COLOR_BUFFER_BIT); // ispisi tekst u levo, centriran RenderStrokeTextH(CalculateStrokeTextWidth(font1, "Dobrodosli u")/ (-2.0f), fontHeight1, -2000.0f, font1, "Dobrodosli u"); // ispisi tekst centriran i vertikalno i horizontalno RenderStrokeTextH(CalculateStrokeTextWidth(font2, "OpenGL")/(-2.0f), 0.0f, -2000.0f, font2, "OpenGL"); // ispisi vertikalni tekst centriran RenderStrokeTextV(CalculateStrokeTextWidth(font2, "O")/(-2.0f), -0.5f*fontHeight1, -2000.0f, fontHeight2, font2, "OpenGL"); Glut.glutSwapBuffers(); } //////////////////////////////////////////////////////////////////////// // Naziv: ChangeSize // Namena: obradjuje promenu dimenzija prozora // 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 }

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

20

VI Open Graphics Library (OpenGL) C#


//////////////////////////////////////////////////////////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijalizacije 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 koriena je projekcija u perspektivi, slika 6.2.4.2. U perspektivi objekti koji su dalji od posmatraa se prikazuju manjim i obratno. Ova projekcija omoguava stvaranje realistinog utiska sveta. Metoda gluPerspective definie projekciju u perspektivi.

public static void gluPerspective(double double double double


gde su:

fovy, aspect, zNear, zFar)

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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

21

VI Open Graphics Library (OpenGL) C#

S obzirom da se tekst ispisuje kao vektorska grafika, mogue je definisati debljinu linije korienjem metode glLineWidth, koja je detaljno opisana u poglavlju 6.4.1. Pomona metoda CalculateStrokeTextWidth izraunava irinu teksta zadatog preko parametra string, koristei se GLUT funkcijom glutStrokeWidth. Pomone metode RenderStrokeTextH i RenderStrokeTextV ispisuju tekst horizontalno, odnosno vertikalno na zadatim koordinatama. Ispisani tekst pokazuje primer centriranog teksta (potrebno je izraunati irinu teksta i podeliti sa dva). OpenGL omoguava iscrtavanje sledeih grafikih objekata u prostoru: taaka, linija, trouglova, poligona, punih tela (sfera, kvadra i dr.) i mesh objekata. Ovo poglavlje se sastoji iz etiri sekcije: sekcija o takama i linijama, sekcija o poligonima, sekcije o mesh objektima i sekcije o punim telima. Osnovna jedinica iscrtavanja u OpenGL standardu je taka (vertex). Taka je odreena sa tri koordinate Dekartovog pravouglog koordinatnog sistema (pravilo desne ruke). Taka se definie u OpenGL standardu pozivom neke od metode iz familije metoda glVertex. esto koriene metode iz ove familije su:

Slika 6.2.4.2 Projekcija u perspektivi, preuzeto iz [3]

6.3 OpenGL iscrtavanje objekata

6.3.1 Crtanje taaka i linija

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

x,y,z koordinate take, glVertex2f podrazumeva z = 0, vertex (x,y,z) kao niz.

Da bi se taka, a i bilo koja primitiva, iscrtala na ekranu potrebno je poziv glVertex metode enkapsulirati izmeu para metoda glBegin i glEnd. Ove dve metode definiu tip primitive i enkapsuliraju niz poziva metoda glVertex. Za iscrtavanje taaka mora biti prosleena vrednost Gl.GL_POINTS kao argument glBegin metode. Listing 6.3.1.1 prikazuje programski kod koji iscrtava tri take. S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 22

V Open Graphics Library (OpenGL)

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 kd za crtanje tri take

Podrazumevana vrednost veliine take iznosi jedan piksel (kvadratnog oblika!). Ako se eli promeniti veliina take tada je potrebno pozvati metodu glPointSize.

void glPointSize(float size)


gde je:

Veliina take ne moe biti proizvoljna i zavisi od OpenGL implementacije. Najmanja i najvea podrana veliina take je sadrana u promenljivoj stanja: Gl.GL_POINT_SIZE_RANGE, a korak inkrement u Gl.GL_POINT_SIZE_GRANULITY. Listing 6.3.1.2 prikazuje programski kd za utvrivanje podranih veliina take:

size veliina take.

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,
Listing 6.3.1.2 Programski kd za utvrivanje podranih veliina take

korak);

Na taku ne deluje perspektiva tj. taka je iste veliine bez obzira gde je pozicionirana u prostoru. Crtanje linija se realizuje korienjem 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 take, ukupan broj taaka mora biti paran. Linija se povlai izmeu dva susedna temena (po redosledu navoenja poziva glVertex metode). Listing 6.3.1.3 prikazuje primer crtanja dve linije.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

23

VI Open Graphics Library (OpenGL) C#

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();
GL_LINE_STRIP iscrtava otvorenu poliliniju. Ne postoji ogranienje da broj temena mora biti paran broj, kao kod GL_LINES. Segment polilinije se povlai izmeu dva susedna temena (po redosledu navoenja poziva glVertex metode). Listing 6.3.1.4 prikazuje primer crtanja slova M.

Listing 6.3.1.3 Programski kd za crtanje dve linije

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_LINE_LOOP iscrtava zatvorenu poliliniju. Razlika izmeu 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).

Listing 6.3.1.4 Programski kd za crtanje polilinije u obliku 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

24

V Open Graphics Library (OpenGL) Podrazumevana debljina linije iznosi jedan piksel, a moe se promeniti pozivom metode glLineWidth.

void glLineWidth(float width)


gde je: Slino kao i kod definisanja veliine take, i debljina linije ne moe biti proizvoljna i zavisi od OpenGL implementacije. Najmanja i najvea podrana debljina linije je sadrana u promenljivoj stanja: GL_LINE_WIDTH_RANGE, a korak inkrement u GL_LINE_WIDTH_GRANULARITY. Listing 6.3.1.6 prikazuje programski kd za utvrivanje podranih debljina linije.

width 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,
Listing 6.3.1.6 Programski kd za utvrivanje podranih debljina linije Linija se moe iscrtavati prema ablonu (pattern), kao npr. isprekidana linija. U reim iscrtavanja prema ablonu ulazi se sa: Gl.glEnable (Gl.GL_LINE_STIPPLE). Zatim se poziva metoda glLineStipple, koja je oblika:

korak);

void glLineStipple(int factor, short pattern)


gde su:

factor faktor skaliranja ablona (koliko puta se poveava 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 taku linije takasta linija). ablon se parsira s desna na levo!

Za izlazak iz reima se koristi metoda glDisable sa argumentom GL_LINE_STIPPLE. Listing 6.3.1.7 prikazuje primer crtanja isprekidane linije korienjem ablona.

// sablon: isprekidana linija ushort sablon = 0x5555; // udji u rezim rada sa sablonima
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 25

VI Open Graphics Library (OpenGL) C#

Gl.glEnable(Gl.GL_LINE_STIPPLE); Gl.glLineStipple(1, 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);
Pomou linija se moe nacrtati bilo koje grafiki objekat, ali tako nacrtan objekat ne moe biti ispunjen bojom, niti mu se moe pridruiti tekstura. Za grafiki objekat iscrtan pomou linija se kae se da je wireframe objekat. U ovom poglavlju bie prezentovano crtanje poligona: trouglova, etvorouglova i ntouglova. Crtanje trouglova se realizuje korienjem 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 take, ukupan broj taaka mora biti umnoak broja tri. Trougao odreuju tri susedna temena (po redosledu navoenja poziva glVertex metode). Redosled iscrtavanja linija okvira trougla nije odreen redosledom navoenja temena, ve u smeru suprotnom od smera kretanja kazaljke na satu (counterclockwise, CCW). Listing 6.3.2.1 prikazuje primer crtanja dva odvojena trougla. Listing 6.3.1.7 Primer crtanja isprekidane linije

// def. sablon

6.3.2 Crtanje poligona

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();
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

26

V Open Graphics Library (OpenGL) Listing 6.3.2.1 Programski kd za crtanje dva odvojena trougla
GL_TRIANGLE_STRIP iscrtava niz trouglova koji imaju zajednike ivice. Ova primitiva se najee koristi za iscrtavanje mesh objekata. Svaki trougao, osim prvog, u nizu je odreen 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 pomou 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);


Listing 6.3.2.2 Programski kd za crtanje kvadrata pomou trouglova (strip)

Gl.glEnd();

GL_TRIANGLE_FAN iscrtava niz trouglova koji svi imaju jedno zajedniko teme. Svaki trougao, osim prvog, se definie sa jednim temenom. Listing 6.3.2.3 prikazuje primer crtanja estougla stranica duine deset jedinica (square_root_3 je konstanta koja sadri 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);
Listing 6.3.2.3 Primer crtanja pravilnog estougla pomou trouglova (fan)

Gl.glEnd();

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

27

VI Open Graphics Library (OpenGL) C# Trouglovi uglavnom predstavljaju najbri nain za definisanje/crtanje objekata, jer je njihovo iscrtavanje hardverski ubrzano (hardware acclerated) kod svakog OpenGL kompatibilnog hardvera. Crtanje etvorouglova se realizuje korienjem 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 leati u istoj ravni! GL_QUADS crta niz planarnih etvrouglova. etvorougao je definisan sa etiri temena, tako da ukupan broj taaka mora biti umnoak 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);


Listing 6.3.2.4 Programski kd za crtanje kvadrata pomou GL_QUADS

Gl.glEnd();

GL_QUAD_STRIP crta niz etvorouglova koji imaju zajednike 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 pomou 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 kd za crtanje pravougonika preko GL_QUAD_STRIP Crtanje planaranih poligona se realizuje pozivom glBegin sa argumentom Gl.GL_POLYGON i navoenjem temena unutra glBegin/glEnd sekcije. Iscrtavanje poligona je u CCW smeru. Dozvoljeni su samo konveksni poligoni (zbog razliitih S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

28

V Open Graphics Library (OpenGL) optimizacija koje su mogue samo nad konveksim poligonima). Konkavni poligoni se dobijaju spajanjem vie 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);
Listing 6.3.2.6 Primer crtanja pravilnog estougla pomou GL_POLYGON Ispuna poligona moe 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:

Gl.glEnd();

void glPolygonMode(int face, int mode)


gde su:

face specifikuje da li se odnosi na lice (front-facing polygons) ili nalije mode


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

Ispuna poligona moe biti prema nekom ablonu. U reim 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: Listing 6.3.2.7 prikazuje primer korienja reima ispune poligona ablonom.

bitmap bitmapa koja definie ablon.

// udji u rezim ispune poligona sablonom


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

29

VI Open Graphics Library (OpenGL) C#

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);
Prilikom crtanja objekata pomou primitiva prikaz ivica (Gl.GL_LINE mode) unutar objekata uglavnom nije poeljan. OpenGL nudi metodu glEdgeFlag kojom se moe definisati da li su unutranje ivice vidljive. Listing 6.3.2.7 Primer ispune poligona ablonom

void glEdgeFlag(int flag)


gde je:

flag vrednost iscrtavanja unutranjih linija objekta. Poetna vrednost je

Gl.GL_TRUE. Listing 6.3.2.8 prikazuje programski kd koji demonstrira iscrtavanje gore navedenih grafikih 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, TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN, QUADS, QUAD_STRIP, POLYGON }; // dimenzije prozora static float windowWidth = 300.0f; static float windowHeight = 300.0f; // Globalna promenljiva koja definise koju primitivu nacrtati static MenuItem selectedMenuItem = MenuItem.POINTS;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

30

V Open Graphics Library (OpenGL)


////////////////////////////////////////////////////////////////////// // 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 deblja 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();

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

31

VI Open Graphics Library (OpenGL) C#


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

----

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

32

V Open Graphics Library (OpenGL)


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: 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, // za ostale nista ne radi

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

33

VI Open Graphics Library (OpenGL) C#


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 inicijalizacije 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 grafikih 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 lakeg uoavanja.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

34

V Open Graphics Library (OpenGL) PREPORUKE ZA KORIENJE: koristiti trouglove umesto etvorouglova i poligona, jer: o uvek su planarni, o uvek su konveksni, voditi rauna da kombinovanje primitiva koje se iscrtavaju u suprotnim smerovima znaajno 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 najee koriste trouglovi, iz ve navedenih razloga. Svi poligonalni objekti se mogu nacrtati preko trouglova. Kao jednostavan primer bie 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;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

35

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

36

V Open Graphics Library (OpenGL)


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 obratno 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 obratno 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 wireframe, // 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 rotacije 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 vrednost 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);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

37

VI Open Graphics Library (OpenGL) C#


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 inicijalizacije 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 front poligoni CCW // zato moramo da obrnemo smer iscrtavanja front poligona

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

38

V Open Graphics Library (OpenGL)


Gl.glFrontFace(Gl.GL_CW); }

////////////////////////////////////////////////////////////////////// // Naziv: ProcessSpecialKeyPress // Namena: metoda obradjuje pritisak na specijalne 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: case Glut.GLUT_KEY_LEFT: xRot += 5.0f; break; yRot -= 5.0f; break;

case Glut.GLUT_KEY_RIGHT: yRot += 5.0f; break; }; if if if if (key (key (key (key > < > < 356.0f) -1.0f) 356.0f) -1.0f) xRot xRot yRot yRot = = = = 0.0f; 355.0f; 0.0f; 355.0f;

Glut.glutPostRedisplay(); } ////////////////////////////////////////////////////////////////////// // Naziv: ChangeSize // Namena: metoda obradjuje promenu velicine 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();

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

39

VI Open Graphics Library (OpenGL) C#


// da bi se moglo vrsiti testiranje dubine potrebno je prilikom // inicijalizacije alocirati bafer za testiranje 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 (pomou Gl.GL_TRIANGLE_FAN) i aproksimacije omotaa (takoe Gl.GL_TRIANGLE_FAN). Susedni trouglovi se iscrtavaju razliitim bojama radi lakeg uoavanja. FRONT poligoni (poligoni lica) su oni poligoni koji su na spoljanjosti objekta. BACK poligoni (poligoni nalija) su poligoni unutranjosti. S toga redosled navoenja temena nije proizvoljan! Ako se temena navode u CW redosledu tada ti poligoni su poligoni lica i obratno (redosled navoenja temena primitiva je prikazan na slici 6.4.3.1). Podrazumevana orijentacija iscrtavanja temena za FRONT poligone je CCW, a za BACK je CW. Poto Gl.GL_TRIANGLE_FAN ima orijentaciju CW, neophodno je izmeniti orijentaciju iscrtavanja FRONT poligona. Ovo se postie pozivom metode glFrontFace sa argumentom Gl.GL_CW.

public static void glFrontFace(int mode)


gde je:

mode vrednost orijentacije poligona lica. Mogue su dve vrednosti:


Gl.GL_CW i Gl.GL_CCW. Poetna vrednost je Gl.GL_CCW.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

40

V Open Graphics Library (OpenGL)

a) redosled navoenja temena za primitive GL_TRIANGLES (CCW) i GL_TRIANGLE_FAN (CW)

b) redosled navoenja temena za primitive GL_TRIANGLE_STRIP (CCW)

c) redosled navoenja temena za primitive GL_QUAD (CW) i GL_QUAD_STRIP (CW)

Depth testing omoguava sakrivanje objekata koji su zaklonjeni nekim drugim objektom (sakrivanje po dubini). Ako nije ukljuen, tada je zaklonjen onaj objekat koji je ranije nacrtan (sakrivanje po vremenu iscrtavanja). U primeru se to moe lepo uoiti, ako se kupa rotira oko ose da se vidi i omota i osnova, ako nije ukljuen depth testing osnova e se videti preko omotaa. Back face culling (BFC) (sakrivanje nevidljivih povrina) omoguava znaajnu utedu resursa poto se nevidljive povrine ne iscrtavaju. Utvrivanje koja povrina S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 41

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

VI Open Graphics Library (OpenGL) C# se iscrtava se odreuje na osnovu orijentacije iscrtavanja temena poligona. Ako je BFC ukljuen tada se ne iscrtavaju BACK poligoni.

a) kupa sa testiranjem dubine

b) kupa bez testiranja dubine

c) kupa sa d) kupa sa osnovom sakrivanjem iscrtanom kao nevidljivih povrina iani model

Metoda glutSpecialFunc omoguava definisanje metode koja obrauje ulaz sa tastature i to specijalnih tastera (funkcijski, strelice, home, end, insert, delete, pgup i pgdn). Metoda SpecialKeys definie ugao rotacije kupe na osnovu pritisnutih kurzorskih strelica. U funkciji RenderScene se vri rotaciju kupe na osnovu vrednosti dobijenih iz metode SpecialKeys. Metode glPushMatrix i glRotatef e biti detaljno objanjene u poglavlju 6.5.

Slika 6.3.3.2 Rezultat rada aplikacije iz listinga 6.3.3.1

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. Mogue 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 definie za jedan template objekat i dalje se primenjuje na sve objekte koji se kreiraju nakon tog template objekta. ivotni ciklus (programski kd) tog objekta je sledei: 1. Instanciranje novog quadrics objekta sa:

Glu.GLUquadric object = Glu.gluNewQuadric();


2. Podeavanje parametara iscrtavanja. 3. Iscrtavanje objekata sa parametrima definisanim object promenljivom. 4. Oslobaanje memorije sa: Za podeavanje parametara iscrtavanja na raspolaganju su etiri metode: gluQuadricDrawStyle, gluQuadricOrientation, gluQuadricNormals i gluQuadricTexture. Metoda gluQuadricDrawStyle definie nain iscrtavanja quadric objekta.

Glu.gluDeleteQuadric(object);

public static void gluQuadricDrawStyle( GLUquadric obj, int drawStyle)


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

42

VI Open Graphics Library (OpenGL) C# gde su:

obj objekat na koji se metoda primenjuje, drawStyle nain iscrtavanja moe biti: Gl.GL_FILL, Gl.GL_LINE,
Gl.GL_POINTS i Gl.GLU_SILHOUETTE. O prva dva stila je bilo rei kod metode glPolygonMode. Gl.GL_POINTS iscrtava objekat samo kao niz temena. Gl.GLU_SILHOUETTE slino kao i Gl.GL_LINE, ali se iscrtavaju samo odreene ivice tako da se vidi samo silueta objekta.

Metode gluQuadricNormals i gluQuadricOrientation definiu 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 generiu normale, normals tip normala, moe biti:
Glu.GLU_NONE ne generiu se normale, Glu.GLU_FLAT normale su normalne na povrinu (facet), Glu.GLU_SMOOTH normale su tako postavljene da se dobija glatka povrina objekta.

orientation smer normala, moe biti:

Metoda gluQuadricTexture omoguava automatsko generisanje koordinata teksture. Rad sa teksturama e biti objanjen u poglavlju 6.10.

Glu.GLU_OUTSIDE smer normala je napolje (najee korieno), Glu.GLU_INSIDE normale su usmerene u unutranjost quadric objekta. Koristi se ako eli prikazivati unutranjost objekta, npr. unutranjost kapsule svemirskog broda, koja je modelovana pomou quadric objekta - sfere.

public static void gluQuadricTexture( GLUquadric obj, int textureCoords)


gde su:

obj quadric objekat za koji se generiu koordinate teksture, textureCoords odreuje da li se generiu koordinate teksture.
Moe biti: Glu.GLU_TRUE generiu se koordinate teksture, Glu.GLU_FALSE ne generiu se koordinate teksture.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

43

VI Open Graphics Library (OpenGL) C# Sfera se kreira pomou metode gluSphere. Centar sfere je u koordinatnom poetku 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 definie parametre iscrtavanja sfere, radius radijus sfere, slices i stacks broj segmenata po x odnosno y osi. (sfera se

Valjak se kreira pomou metode gluCylinder. Centar valjka osnove je u koordinatnom poetku i valjak se iscrtava u pozitivnom smeru z ose. Ako je topRadius jednak nuli tada se dobija kupa.

iscrtava aproksimacijom pomou trouglova ili etvorouglova (quad stripes))

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

iscrtava aproksimacijom pomou trouglova ili etvorouglova (quad stripes)) Prsten se kreira pomou metode gluDisk. Centar prstena je u koordinatnom poetku i iscrtava se u XY ravni. Ako je innerRadius jednak nuli tada se dobija krug.

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

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

obj objekat koji definie parametre iscrtavanja, innerRadius unutranji radijus, outerRadius spoljanji radijus, slices i loops broj segmenata po x odnosno y osi. (prsten se

iscrtava aproksimacijom pomou trouglova ili etvorouglova (quad stripes))

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

44

VI Open Graphics Library (OpenGL) C# 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, glutSolidOctahedron i glutWireOctahedron, glutSolidTetrahedron i glutWireTetrahedron, glutSolidIcosahedron i glutWireIcosahedron, glutSolidTeapot i glutWireTeapot. Parametri metoda su slini 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_SPHERE, GLUT_TEAPOT }; // dimenzije prozora static float windowWidth = 300.0f; static float windowHeight = 300.0f; // Globalna promenljiva koja definise koju primitivu 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);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

45

VI Open Graphics Library (OpenGL) C#


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: break; } Glut.glutSwapBuffers(); } // za ostale nista ne radi

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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

46

VI Open Graphics Library (OpenGL) C#


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 inicijalizacije 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

47

VI Open Graphics Library (OpenGL) C#

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 omoguava kreiranje parametarskih krivih. Metode za njihovo kreiranje bie objaenje u sledeem poglavlju.

6.3.5 Crtanje parametarskih krivih i zakrpa


OpenGL podrava 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 jednaina. U optem sluaju veoma je teko pronai algebarsku jednainu za proizvoljnu krivu/zakrpu. Uvidevi ovaj problem Bezier, inenjer u Renou, osmislio je matematiki model koji omoguava reprezentaciju proizvoljnih krivih/zakrpa uz veoma mali skup podataka kojima se te krive/zakrpe opisuju. Bezier-ove krive se opisuju preko svojih kontrolnih taaka. U reim rada sa 2D Bezier-ovim krivama se ulazi ukljuivanjem promenljive stanja Gl.GL_MAP1_VERTEX_3. Zatim je potrebno zadati krivu korienjem familije metoda glMap1*. Za evaluaciju taaka 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 poetna i krajna vrednost, stride razmak izmeu kontrolnih taaka u bajtima, order i points broj i niz kontrolnih taaka.
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 48

VI Open Graphics Library (OpenGL) C# 3D Bezier-ove zakrpe se realizuju na analogan nain korienjem metoda: glMap2*, glMapGrid2* i glEvalMesh2*, kao i promenljive stanja Gl.GL_MAP2_VERTEX_3. GLU programska biblioteka omoguava crtanje NURBS krivih i zakrpa. Rad je slian kao i kod quadrics objekata. Prvo se kreira NURBS (template) objekat pozivom metode gluNewNurbsRenderer. Zatim se radi nad kreiranim NURBS objektom. Po zavretku rada potrebno je unititi objekat pozivom gluDeleteNurbsRenderer. Parametri NURBS objekta se podeavaju pozivom metode gluNurbsProperty. Ova metoda omoguava podeavanje kvaliteta prikaza objekta, kao i reim iscrtavanje (wireframe ili fill). Programski kod koji crta NURBS krive/zakrpe se enkapsulira pozivom metoda glBeginCurve/glBeginSurface i glEndCurve/glEndSurface. NURBS kriva/zakrpa se definie 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[, ] {{ -4.0f, { -6.0f, { 6.0f, { 4.0f, bcCtrlPoints = 0.0f, 0.0f }, 4.0f, 0.0f }, -4.0f, 0.0f }, 0.0f, 0.0f }};

// // // //

pocetna tacka kontrolna tacka kontrolna tacka krajnja tacka

// Podaci za Bezier zakrpu static int bsNumPoints = 3; static float[, ,] bsCtrlPoints = {{{ -4.0f, 0.0f, 4.0f }, { -2.0f, 4.0f, 4.0f }, { 4.0f, 0.0f, 4.0f }}, {{ -4.0f, 0.0f, 0.0f },

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

49

VI Open Graphics Library (OpenGL) C#


{ -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.0f, 1.0f}; // Podaci za NURBS zakrpu static int nsNumPoints = 4; // 4 X 4 static float[,,] nsCtrlPoints = { {{ -6.0f, -6.0f, { -6.0f, -2.0f, { -6.0f, 2.0f, { -6.0f, 6.0f, {{ { { { { { {{ { { { { { {{ { { {

0.0f}, // u = 0, v = 0.0f}, // 0.0f}, // v = 0.0f}}, // v

0 v = 1 2 = 3

// //

-2.0f, -6.0f, 0.0f}, -2.0f, -2.0f, 8.0f}, -2.0f, 2.0f, 8.0f}, -2.0f, -2.0f, 0.0f}, -2.0f, 2.0f, 0.0f}, -2.0f, 6.0f, 0.0f}}, 2.0f, -6.0f, 0.0f }, 2.0f, -2.0f, 8.0f }, 2.0f, 2.0f, 8.0f }, 2.0f, -2.0f, 0.0f }, 2.0f, 2.0f, 0.0f }, 2.0f, 6.0f, 0.0f }}, 6.0f, -6.0f, 0.0f}, 6.0f, -2.0f, 0.0f}, 6.0f, 2.0f, 0.0f}, 6.0f, 6.0f, 0.0f}}};

// u = 1, v = 0 // v = 1 // v = 2 // v = 1 // v = 2 // v = 3 // u = 2, // // // // // v = 0 v v v v v = = = = = 1 2 1 2 3

// //

// u = 3, v = 0 // v = 1 // v = 2 // v = 3

// NURBS zakrpa - cvorovi static float[] nsKnots = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f,1.0f,1.0f,1.0f }; // uglovi rotacije static float xRot = 65.0f; static float yRot = 45.0f; // globalna promenljiva koja definise koju parametarsku krivu iscrtati static MenuItem selectedMenuItem = MenuItem.BEZIER_CURVE;

//////////////////////////////////////////////////////////////////////

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

50

VI Open Graphics Library (OpenGL) C#


// 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 if if if (key (key (key (key > < > < 356.0f) -1.0f) 356.0f) -1.0f) xRot xRot yRot yRot = = = = 0.0f; 355.0f; 0.0f; 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

51

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

52

VI Open Graphics Library (OpenGL) C#


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_OUTLINE_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, 8, nsKnots, 8, nsKnots, 4 * 3, 3,

// NURBS objekat // Broj i niz cvorova po U // Broj i niz cvorova po V // Rastojanj po U. // Rastojanje po V

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

53

VI Open Graphics Library (OpenGL) C#


nsCtrlPoints, 4, 4, Gl.GL_MAP2_VERTEX_3); // Kontrolne tacke // U i V red // 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 promene 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.0f); Gl.glMatrixMode(Gl.GL_MODELVIEW); Gl.glLoadIdentity(); } //////////////////////////////////////////////////////////////////////// // Naziv: SetupRenderingContext // Namena: metoda vrsi potrebne inicijalizacije 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) {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

54

VI Open Graphics Library (OpenGL) C#


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

Veoma esto postoji potreba za iscrtavanjem vie instanci nekog objekta. Enkapsulacija programskog kda u metode ne daje dovoljno dobre rezultate u aplikacijama gde je bitna performansa. Takoe, esto se geometrija nekog objekta ne menja iz frejma u frejm. OpenGL nudi mehanizam pomou kojeg se moe znaajno ubrzati iscrtavanje sloenih objekata Display List (DL)-e. DL mehanizam omoguava 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. Obino DL liste se kreiraju u toku inicijalizacije aplikacije. Definisanje DL listi se realizuje enkapsulacijom programskog kda za iscrtavanje objekata parom glNewList/glEndList komandi. Sledei programski kd prikazuje primer definisanja DL liste.

6.3.6 Crtanje objekata korienjem Display List i Vertex Array mehanizama

Gl.glNewList(list_id, Gl.GL_COMPILE);
.

OpenGL programski kd za isctavanje objekta


.

Svaka DL lista se jednoznano identifikuje preko svog naziva koji se navodi kao prvi argument u pozivu glNewList (u primeru je to list_id). Runa definicija S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

Gl.glEndList();

55

VI Open Graphics Library (OpenGL) C# identifikatora liste nije preporuljiva, jer je podlona greci. OpenGL programska biblioteka nudi metodu glGenLists koja generie jedinstvene identifikatore. Metoda glGenLists generie niz uzastopnih identifikatora. Povratna vrednost iz metode je identifikator prvog objekta.

public static int glGenLists(int range)


gde je: Metoda glDeleteLists oslobaa zauzete identifikatore i alociranu memoriju za njihovo skladitenje.

range broj identifikatora koji se trebaju generisati.

public static void glDeleteLists(int list_id, int range)


gde su:

Iscrtavanje DL liste se realizuje korienjem metoda glCallList i glCallLists. Razlika izmeu metoda je u tome to poslednja omoguava izvravanje vie DL lista jednim pozivom.

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

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, obino GL_UNSIGNED_BYTE, n broj identifikatora niza lists.
Ugnjedavanje poziva iscrtavanja DL listi je dozvoljeno, ali ne i ugnjedavanje poziva kreiranja DL lista! Najvie moe biti 64 nivoa hijerarhije. Listing 6.4.6.1 prikazuje iseak programskog koda primera crtanja 1000 kopija aviona korienjem DL mehanizma. . . .
// identifikator aviona static int planeDL;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

56

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

57

VI Open Graphics Library (OpenGL) C#

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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

58

VI Open Graphics Library (OpenGL) C#


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 Iseak programskog koda za crtanje aviona pomou DL liste


Iako se DL liste prevashodno koriste za opis statine geometrije, programski kd koji se enkapsulira moe biti bilo koji skup OpenGL komandi sa izuzetkom glNewList/glDeleteList. Naime, nije dozvoljena rekurzija u definiciji DL lista. S obzirom da se OpenGL programski kd prekompajlira DL liste nisu pogodne za opis geometrije koja se menja tokom izvravanja. Poto se DL liste smetaju 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 izvravanja i/ili koji imaju veliki broj temena. Ovi mehanizmi koriste nizove temena koji se prosleuju kao jedini parametar. Ovim se znaajno 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 sledee faze: 1. Ukljuenje klijentske promenljive stanja GL_VERTEX_ARRAY pozivom metode glEnableClientState. Ova metoda ukljuuje klijentske promenljive stanja koje su prosleene kao argument. Suprotna akcija se realizuje pozivom glDisableClientState.

public static void glEnableClientState( int cap)


gde je:

cap simbolika konstanta klijentske promenljive stanja koja


se ukljuuje.

2. Signalizacije koji niz temena treba da se iscrta pozivom metode glVertexPointer. Ova metoda signalizira OpenGL gde su smeteni 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,


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 59

VI Open Graphics Library (OpenGL) C#

int stride, IntPtr pointer)


gde su:

size broj koordinata po temenu. Inicijalna vrednost iznosi


etiri,

type

stride razmak izmeu susednih temena izraen u


bajtima. Inicijalna vrednost iznosi nula,

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

pointer niz temena.


3. Iscrtavanja niza temena pozivom metode glDrawArrays. Ova metoda iscrtava grafiku primitivu definisanu parametrom mode sa count temena poevi od temena sa indeksom first.

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


gde su:

mode koju primitivu treba iscrtavati tj. kako tumaiti temena, first indeks poetnog temena, count broj temena koja se iscrtavaju.

4. Iskljuivanje vertex array mehanizma pozivom glDisableClientState sa argumentom GL_VERTEX_ARRAY.

public static void glDisableClientState( int cap)


gde je:

cap simbolika konstanta klijentske promenljive stanja koja


se iskljuuje.

U indeksnoj verziji postoje dva niza temena: niz indeksa i niz jedinstvenih temena. Ovaj pristup esto obezbeuje bolju performansu. Naime, u velikom broju sluaja kod mesh objekata broj temena se ponavlja jer se poligoni nastavljaju jedan na drugi. S toga umesto prosleivanja niza svih temena od kojih se veliki broj ponavlja, prosleuje se niz jedinstvenih (meusobno razliitih) temena i niz indeksa tih temena. Rad sa indeksnom verzijom vertex array mehanizma se razlikuje od obine verzije u fazi tri gde se niz iscrtava pozivom metode glDrawElements.

public static void glDrawElements(int mode,


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

60

VI Open Graphics Library (OpenGL) C#

int
gde su:

count, int type, IntPtr indices)

mode koju primitivu treba iscrtavati tj. kako tumaiti 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,


Listing 6.3.6.2 prikazuje iseak programskog kda primera iscrtavanja 1000 mesh modela aviona korienjem Vertex Array i Indexed Vertex Array mehanizama.

indices niz indeksa.

. . .
// da li crtamo sa ili bez koriscenja indeksne verzije vertex arrays bool g_usingIndexedVertexArrays = false; // indeksirana verzija, niz ima elemenata onoliko koliko 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.0f, 0.0f, 60.0f, 0.0f, 0.5f, -40.0f, 0.0f, -0.5f, -40.0f, 0.0f, 15.0f, 30.0f, 0.0f, 2.0f, 27.0f, 0.0f, 25.0f, -65.0f, 0.0f, 4.0f, -57.0f, 0.0f, 7.0f, -8.0f, 15.0f, 0.0f, 30.0f, -15.0f, 0.0f, 30.0f, 3.0f, 0.5f, -57.0f, -3.0f, 0.5f, -57.0f,

// // // // // // // // // // // // //

0 1 2 3 4 5 6 7 8 9 10 11 12

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

61

VI Open Graphics Library (OpenGL) C#


30.0f, -0.5f, -57.0f, -30.0f, -0.5f, -57.0f, 60.0f, 2.0f, -8.0f, -60.0f, 2.0f, -8.0f}; // // // // 13 14 15 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.0f, 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();

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

62

VI Open Graphics Library (OpenGL) C#


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

Pored VA mehanizma postoji slian mehanizam - Vertex Buffer Object (VBO) koji nudi dodatna podeavanja 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 slinost sa DL listama). Metode za pristup i referenciranje podataka u baferima koriste se iste metode kao i kod VA mehanizma. Ovaj mehanizam omoguava kontrolu nad transferom podataka. Podrane su tri mogunosti: GL_STREAM_DRAW, GL_STATIC_DRAW i GL_DYNAMIC_DRAW. GL_STREAM_DRAW reim radi na isti nain kao VA mehanizam podaci se alju prilikom svakog iscrtavanja (pozivi metoda: glDrawArrays, glDrawElements). Ovaj reim je pogodan za iscrtavanje animiranih objekata u sceni. GL_STATIC_DRAW reim alje podatke grafikom kontroleru i oni se skladite u memoriji grafike kartice. Ovaj reim najvie pogoduje za iscrtavanje nedeformabilnih (statikih) objekata. Za razliku od prethodnih u GL_DYNAMIC_DRAW reimu drajveri grafike kartice odreuju gde i kako e biti podaci uskladiteni. Rad sa VBO mehanizmom se realizuje kroz sledee faze: 1. Ukljuenje klijentske promenljive stanja GL_VERTEX_ARRAY pozivom metode glEnableClientState. 2. Kreiranje bafera metodom: glGenBuffers.

. . . Listing 6.4.6.2 Iseak programskog kda za crtanje aviona korienjem Vertex Array mehanizma

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 smeta niz identifikatora bafera koji se
alociraju. 3. Proglasiti bafer aktivnim pozivom metode glBindBuffer. S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

63

VI Open Graphics Library (OpenGL) C#

public static void glBindBuffer( int target, int buffer) public static void glBindBuffer( int target, uint buffer)
gde su:

target odreuje na koji tip bafera se vezuje. Mogue vrednosti su: GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER i GL_PIXEL_UNPACK_BUFFER. buffer identifikator aktivnog bafera.
i specifikacija inicijalnih podataka sa

4. Inicijalizacija bafera 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 odreuje na koji tip bafera se vezuje. Mogue vrednosti


su: GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER i GL_PIXEL_UNPACK_BUFFER,

size veliina u bajtima objekta u baferu,

data podaci koji e inicijalno biti kopirani, usage specifikuje reim 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 sadraja bafera se realizuje tako to se bafer proglasi aktivnim, a zatim pozivima glVertexPointer i glDrawArrays na slian nain iscrta. Na primer:

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


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

64

VI Open Graphics Library (OpenGL) C#

// 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 glDeleteBuffers. je osloboditi bafer pozivom metode

public static void glDeleteBufffers(int int[] buffers) public static void glDeleteBufffers(int IntPtr buffers) public static void glDeleteBufffers(int ref int buffers) public static void glDeleteBufffers(int uint[] buffers) public static void glDeleteBufffers(int ref uint buffers)
gde su:

n, n, n, n, n,

n broj bafera koji se oslobaaju,

8. Iskljuivanje vertex array mehanizma pozivom glDisableClientState sa argumentom GL_VERTEX_ARRAY.

buffers niz identifikatora bafera koji se oslobaaju.

public static void glDisableClientState( int cap)


gde je:

cap simbolika konstanta klijentske promenljive stanja koja se iskljuuje.

S obzirom da predstavlja kombinaciju najboljih osobina DL i VA mehanizma predstavlja preporuku za korienje. U OpenGL standardu transformacije se realizuju pomou matrica: Viewing, Modeling, Modelview, Projection i Viewport. Redosled primena transformacija je fiksan i identian redosledu navoenja matrica u prethodnoj reenici. S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

6.4 Transformacije objekata

65

VI Open Graphics Library (OpenGL) C# 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). b) pomeranje Viewing matrica definie taku a) pomeranje kamere koord. sistema posmatranja kameru (transformie koordinatni sistem). Modeling matrica Slika 6.4.1 Ekvivalencija transformacija omoguava transformacije nad kamere i koord. sistema, preuzeto iz [3] modelom i njegovim objektima. Modelview matrica integrie transformacije koje vre prethodne dve matrice i olakava transformacije nad scenom. Ovo proizilazi iz injenice da sa aspekta posmatraa je svejedno da li se kamera premestila ili su primenjene transformacije nad objektima ako je rezultujui pogled na scenu identian u oba sluaja, slika 6.4.1. Nakon ovih transformacija primenjuju se transformacije projekcije. Projection matrica definie vidljivi volumen, kao i tip projekcije scene na ekran (ortogonalna ili projekcija u perspektivi). Viewport matrica definie mapiranje 2D projekcije scene u prozor u kojem se prikazuje. Najee se manipulacije vri nad Modelview i Projection matricama. Grafika predstava procesa primena transformacija nad temenom je prikazana na slici 6.4.2.

Izbor matrice nad kojom se vre transformacije se realizuje pomou metode glMatrixMode.

Slika 6.4.2 Redosled primene transformacija nad temenom, preuzeto iz [3]

public static void glMatrixMode(int mode)


gde je:

mode koja matrica se selektuje. Izmeu ostalih mogue su vrednosti:


Gl.GL_MODELVIEW, Gl.GL_PROJECTION kojima se selektuje odgovarajue matrice.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

66

VI Open Graphics Library (OpenGL) C# Translacija se realizuje pomou familije metoda glTranslate, od kojih je najee koriena metoda glTranslatef.

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


gde su: Rotacija se realizuje pomou familije metoda glRotate, od kojih je najee koriena metoda glRotatef.

x, y, z pomeraj po x,y,z osama.

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


gde su:

angle ugao rotacije izraen u stepenima, x, y, z vektor u odnosu na koji se vri rotacija (vektor je definisan sa
Skaliranje se realizuje pomou familije metoda glScale, od kojih je najee koriena metoda glScalef. Uniformno skaliranje se realizuje sa x = y = z. (0,0,0) i (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 logina realizacija se namee sledei programski kd:

// 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 kd zbog kumulativnosti primene transformacija daje rezultat prikazan na slici 6.4.3b.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

67

VI Open Graphics Library (OpenGL) C#

a) eljena pozicija

b) rezultujua pozicija

Slika 6.4.3 Kumulativnost transformacija, preuzeto iz [3] Da bi se izbegao problem kumulativnosti potrebno je imati mogunost resetovanja matrice. U te svrhe se koristi metoda glLoadIdentity. Iako korienje ove metode reava gore pomenute probleme sama metoda je zahtevna. Mnogo bi bilo lake da je mogue nekako sauvati privremeno stanje matrice, primeniti izmene i posle to stanje vrati. OpenGL definie matrini stek (LIFO) za tu namenu i metode glPushMatrix i glPopMatrix. Sve operacije matrinog steka se odnose na trenutno izabranu matricu (korienjem metode glMatrixMode). Sledei programski kd 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);

Listing 6.4.1 i slika 6.4.4 prikazuje iseak programskog kda (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

Slika 6.4.4 Rezultat rada aplikacije iz listinga 6.4.1 u razliitim vremenskim trenucima

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

68

VI Open Graphics Library (OpenGL) C#

fEarthRot ugao u odnosu na Sunce, a onda se Mesec zarotira za fMoonRot ugao u odnosu na Zemlju. Ovo je postignuto upravo korienjem 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(); }

OpenGL nudi niz metoda za matrini raun kojima se direktno moe menjati aktivna matrica (npr. ModelView). Vie o ovim metodama se moe nai u [2, 3].

Listing 6.4.1 Primer primene transformacija Solarni sistem

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

69

VI Open Graphics Library (OpenGL) C#

U ovom poglavlju bie objanjen rad sa kamerom, kao i mogunosti interakcije sa korisnikom koje prua GLUT programska biblioteka.

6.5 Kamera i interakcija

6.5.1 Rad sa kamerom


Za specifikovanje pozicije kamere koristi se Viewing matrica, videti poglavlje 6.5. Pozicioniranje kamere se realizuje korienjem 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 taka posmatranja, centerx, centery, centerz vektor koji opisuje pravac i upx, upy, upz
smer u kome gleda kamera (forward vector), vektor koji odreuje pravac i smer na gore (upward vector).

Pozicija i orijentacija objekta (obino se koristi termin akter), a i kamere, u prostoru se jednoznano opisuje pomou tri atributa: pozicije objekta, vektora koji definie ta je napred (forward vector) i vektora koji definie ta je iznad (upward vector), slika 6.5.1. Na ovaj nain se znaajno olakavaju transformacije nad objektima, npr. ako treba rotirati avion na slici ulevo tada je potrebno izmeniti njegov Slika 6.5.1 Jednoznano odreivanje forward vector. Dodatno, olakane su i pozicije i orijentacije objekta u prostoru 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 odreen na ovaj nain se naziva frame of reference. Interakcija sa korisnikom je omoguena GLUT metodama: glutKeyboardFunc, glutKeyboardUpFunc, glutGetModifiers, glutSpecialFunc, glutSpecialUpFunc, glutMouseFunc, glutMotionFunc, glutPassiveMotionFunc, glutEntryFunc i glutIgnoreKeyRepeat.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

70

VI Open Graphics Library (OpenGL) C#

6.5.2 Interakcija korisnika sa tastaturom


Interakcija korisnika sa tastaturom se realizuje preko metoda: glutKeyboardFunc, glutKeyboardUpFunc, glutSpecialFunc i glutSpecialUpFunc. Metoda glutKeyboardFunc omoguava registrovanje callback metode za obradu pritisnutih ASCII karaktera na tastaturi, dok metoda glutKeyboardUpFunc omoguava registrovanje callback metode za obradu otputanja ASCII karaktera na tastaturi. Ako je potrebno oitati stanje modifikatorskih (Alt-Ctrl-Shift) tastera tada se koristi metoda glutGetModifiers. Ova metoda daje validne rezultate ako se poziva iz obraivaa dogaaja sa tastature i mia.

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 otputa, x,y koordinate mia prilikom pritiskanja/otputanja.
Povratna vrednost od glutGetModifiers je broj jedan ili OR kombinacija sledeih vrednosti: Glut.GLUT_ACTIVE_SHIFT, Glut.GLUT_ACTIVE_CTRL i Glut.GLUT_ACTIVE_ALT. Metoda glutSpecialFunc omoguava registrovanje callback metode za obradu pritiska specijalnih karaktera na tastaturi (funkcijski tasteri, Home, Delete, Insert, End, PgUp, PgDn i kurzorske strelice). Metoda glutSpecialUpFunc omoguava registrovanje callback metode za obradu otputanja 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)
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

71

VI Open Graphics Library (OpenGL) C#

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


gde su:

key specijalni karakter koji je pritisnut/se otputa, mogue 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 mia prilikom pritiskanja/otputanja.

GLUT parsira pritisnut taster sve dok se ne otpusti. Ovakvo ponaanje nije uvek pogodno. Npr. ako je pritisnuto vie tastera odjednom, ovakav mehanizam registruje samo pritisak prvog tastera. S toga, metoda glutIgnoreKeyRepeat omoguava iskljuivanje procesiranja dranja pritisnutog tastera.

public static void glutIgnoreKeyRepeat( int repeatMode)


gde je:

repeatMode nula vrednost ukljuuje ponavljanje, dok vrednost


razliita od nule iskljuuje ponavljanje.

6.5.3 Interakcija korisnika sa miem


Interakcija korisnika sa miem realizuje se preko metoda: glutMouseFunc, glutMotionFunc i glutPassiveMotionFunc. Metoda glutMouseFunc omoguava registrovanje callback metode za obradu pritiska tastera mia. Ako je potrebno reagovati na pomeranje kurzora pomou mia tada se koriste metode glutMotionFunc i glutPassiveMotionFunc. Razlika izmeu ovih metoda je u tome to glutPassiveMotionFunc ne registruje stanje dugmadi mia prilikom pomeranja. Metoda glutEntryFunc omoguava definisanje reakcije na naputanje/ulazak kurzora mia 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(
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

72

VI Open Graphics Library (OpenGL) C#

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 mia. Mogue su sl. vrednosti:


Glut.GLUT_LEFT_BUTTON, Glut.GLUT_MIDDLE_BUTTON ili Glut.GLUT_RIGHT_BUTTON, x,y koordinate mia prilikom pritiskanja/otputanja, state stanje dugmeta mia. Mogue su sl. vrednosti: Glut.GLUT_LEFT ili Glut.GLUT_ENTERED za metodu glutEntryFunc, a za glutMouseFunc: Glut.GLUT_UP ili Glut.GLUT_DOWN.

U dalje tekstu bie prezentovan primer upravljanja kamerom korienjem W,A,S,D tastera i strelica za pomeranje, kao i pomeranjem mia 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 interakciju za pomeranje kamere ************************************************************************/ using System; using System.Collections.Generic; using System.Text; using Tao.OpenGl; using Tao.FreeGlut; namespace Kamera { class Program

6.5.4 Primer upravljanja kamerom pomou tastature i mia

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

73

VI Open Graphics Library (OpenGL) C#


{ // 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 vizuelne markere ////////////////////////////////////////////////////////////////////// static void DrawMarkers() { // iscrtaj neka tela cisto kao orijentire u prostoru 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(); }

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

74

VI Open Graphics Library (OpenGL) C#


////////////////////////////////////////////////////////////////////// // 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 WASD // Parametri: key, x, y ////////////////////////////////////////////////////////////////////// static void ProcessNormalKeyPressRelease(byte key, int x, int y) { switch ((char)key) { case 'a' : case 'd' : deltaStrafe = 0.0f;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

75

VI Open Graphics Library (OpenGL) C#


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 -> namesti 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 - simulacija 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 - simulacija trcanja if (modifierState == Glut.GLUT_ACTIVE_SHIFT) deltaMove = -2*speed; else deltaMove = -speed; break; // pritisak na F4 siri prikaz na ceo ekran, i obratno case Glut.GLUT_KEY_F4: if (g_fullscreen == false) Glut.glutFullScreen();

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

76

VI Open Graphics Library (OpenGL) C#


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 strelice // Parametri: key, x, y ////////////////////////////////////////////////////////////////////// static void ProcessSpecialKeyPressRelease(int key, int x, int y) { switch (key) { // otpusten taster za pomeranje levo-desno -> resetuj pomeraj case Glut.GLUT_KEY_LEFT : case Glut.GLUT_KEY_RIGHT : deltaStrafe = 0.0f; break; // otpusten taster za pomeranje napred-nazad -> resetuj 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 // pomeranje // pomeranje float angleY float angleZ ugao po x osi treba da rotira oko y-ose po y osi treba da rotira oko z-ose = (halfWindowWidth - x) / angleScale; = (halfWindowHeight - y) / angleScale;

// ne dopusta se rotacija veca od 360/-360 stepeni if (lastRotationZ + angleZ < -1.0f || lastRotationZ + angleZ > 1.0f) return;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

77

VI Open Graphics Library (OpenGL) C#

// 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 prozora ////////////////////////////////////////////////////////////////////// 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 ////////////////////////////////////////////////////////////////////////

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

78

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

79

VI Open Graphics Library (OpenGL) C#

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 kd ove klase.
using using using using System; System.Collections.Generic; System.Text; 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(

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

80

VI Open Graphics Library (OpenGL) C#


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 * sinTheta)* viewY; newViewX += ((1 - cosTheta) * x * z + y * sinTheta)* viewZ; newViewY = ((1 - cosTheta) * x * y + z * sinTheta)* viewX; newViewY += (cosTheta + (1 - cosTheta) * y * y)* viewY; newViewY += ((1 - cosTheta) * y * z - x * sinTheta)* viewZ; newViewZ = ((1 - cosTheta) * x * z - y * sinTheta)* viewX; newViewZ += ((1 - cosTheta) * y * z + x * sinTheta)* 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_upVectorY)); float axisY = ((viewZ * m_upVectorX) - (viewX * m_upVectorZ)); float axisZ = ((viewX * m_upVectorY) - (viewY * m_upVectorX)); // 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); }

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

81

VI Open Graphics Library (OpenGL) C#


// 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 float viewY = m_viewY float viewZ = m_viewZ float axisX = ((viewY float axisY = ((viewZ float axisZ = ((viewX

* * *

m_positionX; m_positionY; m_positionZ; m_upVectorZ) - (viewZ * m_upVectorY)); m_upVectorX) - (viewX * m_upVectorZ)); m_upVectorY) - (viewY * m_upVectorX));

// 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

82

VI Open Graphics Library (OpenGL) C# Pored ovih metoda GLUT definie i metode za rad sa spejsbolom, dojstikom i tabletom.

6.6 Boja i senenje objekata


OpenGL koristi RGB model boja za specifikovanje boje. Svaka od komponenti se opisuje jednim bajtom koji definie intenzitet te komponente. Koristi se i RGBA model boja, koji predstavlja RGB model proiren Alpha komponentom koja definie prozirnost (transparency). U OpenGL standardu boja se definie pomou familije metoda glColor. Najee se koriste sledee 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 bie iscrtani u boji koju je taj poziv specifikovao. Boja se uvek odnosi na taku teme objekta. Tako da ako su dva temena nekog objekta obojena razliitim 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 senenja. OpenGL podrava dva tipa senenja: flat i smooth. Ako u sceni ne postoji osvetljenje flat tip senenja (homogeno (Lambert) senenje) e liniju izmeu dva temena obojiti bojom drugog temena, dok smooth senenje (Gouraud senenje) e obojiti liniju prelivom boja temena. Slino se realizuje senenje poligona, sa razlikom da u definisanju senenja uestvuje vie temena. Pravila za homogeno senenje se mogu nai u [2]. Slike 6.6.1 i 6.6.2 prikazuju tipove senenja primenjene na poligon, odnosno liniju.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

83

VI Open Graphics Library (OpenGL) C#

a) smooth tip senenja

b) flat tip senenja

Slika 6.6.1 Tipovi senenja na primeru trougla

a) smooth tip senenja

b) flat tip senenja

Slika 6.6.2 Tipovi senenja na primeru linije Model senenja se definie pomou metode glShadeModel, koja ima oblik:

public static void glShadeModel(int mode)


gde je:

mode tip senenja objekta. Dozvoljene vrednosti su: Gl.GL_SMOOTH i


Gl.GL_FLAT. Podrazumevana vrednost je Gl.GL_SMOOTH.

Listing 6.6.1 prikazuje programski kd aplikacije koja demonstrira tipove senenja 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};

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

84

VI Open Graphics Library (OpenGL) C#


////////////////////////////////////////////////////////////////////// // 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

85

VI Open Graphics Library (OpenGL) C#


{ 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 inicijalizacije 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 senenja na primeru senenja 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. S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

86

VI Open Graphics Library (OpenGL) C# Difuzno svetlo osvetljava objekte iz nekog konkretnog pravca. Svetlosni zraci se prelamaju i rasipaju na povrini objekta. Ova komponenta svetla kreira senke. Primer ovog osvetljenja je stona lampa. Spekularno svetlo (specular highlight), slino kao i difuzno svetlo, dolazi iz nekog pravca, ali refleksija je pod mnogo otrijim uglom i nema rasipanja. Ova svetlost kreira veoma jako osvetljene povrine na objektu odsjaj. Pored ovih osnovnih komponenti moe se definisati i emisiona komponenta. Ona predstavlja boju koju materijal isijava. Materijal se definie pomou familije metoda glMaterial, od kojih se najee 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. Poetna vrednost je Gl.GL_FRONT_AND_BACK, pname koja komponenta se podeava sa param parametrom. Mogue 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. Poetna vrednost je Gl.GL_AMBIENT_AND_DIFFUSE, params parametar ija semantika zavisi od pname, uglavnom je boja.

Ovakav nain navoenja materijala za svaki objekat nije uvek pogodan. OpenGL nudi alternativni nain definisanja materijala color tracking. Color tracking podrazumeva definisanje materijala preko poziva glColor metode. U color tracking reim 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 najee koristi ovakav nain 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. Poetna vrednost je Gl.GL_FRONT_AND_BACK,

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

87

VI Open Graphics Library (OpenGL) C#

mode koja komponenta se podeava sa param parametrom. Mogue


vrednosti su: Gl.GL_AMBIENT, Gl.GL_DIFFUSE, Gl.GL_SPECULAR, Gl.GL_AMBIENT_AND_DIFFUSE, i Gl.GL_EMISSION. Poetna vrednost je Gl.GL_AMBIENT_AND_DIFFUSE. Listinzi 6.7.1, 6.7.2 i slika 6.7.1 prikazuju primer aviona kome su pridrueni materijali, u prvom sluaju korienjem color tracking tehnike odnosno korienjem glMaterial familije metoda u drugom sluaju. Programski kd 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);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

88

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

89

VI Open Graphics Library (OpenGL) C#


// 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 prilikom 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

90

VI Open Graphics Library (OpenGL) C#


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 pozivi 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 korienja 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;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

91

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

92

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

93

VI Open Graphics Library (OpenGL) C#


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 prilikom 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 / height, -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() {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

94

VI Open Graphics Library (OpenGL) C#


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 korienja glMaterialfv metode za definisanje materijala


}

Slika 6.7.1 Rezultat aplikacije iz listinga 6.7.1

Osvetljenje je esencijalno u postizanju realizma modelovane scene. Takoe, svojstva materijala dolaze do izraaja tek kada je u sceni prisutno osvetljenje. U OpenGL standardu se proraun osvetljenja ukljuuje pozivom metode glEnable sa argumentom Gl.GL_LIGHTING. Analogno se iskljuuje proraun osvetljenja.
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 95

6.8 Osvetljenje

VI Open Graphics Library (OpenGL) C# U proraunu osvetljenja nekog objekat OpenGL ne koristi napredne algoritme kao to je npr. ray-tracing. OpenGL koristi Phong-ov iluminacioni model. Za proraun osvetljenosti nekog poligona potrebno je poznavati njegov vektor normale. Vektor normale se definie za svako teme objekta i mora biti normalizovan. Mogue je definisati samo jedan vektor normale za poligon vektor normale na ravan u kojoj poligon lei (OpenGL dozvoljava samo planarne poligone!). U OpenGL standardu vektor normale se zadaje pomou familije metoda glNormal, od kojih se najee koristi:

public static void glNormal3f(float nx, float ny, float nz)


gde su: Odreivanje vektora normale u optem sluaju nije trivijalan zadatak. Za odreivanje vektora normale na nivou poligona koristie se pomona metoda FindFaceNormal:

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

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 izraunati vektor normale, x1,y1,z1,x2,y2,z2,x3,y3,z3 tri temena koje odreuju
ravan poligona.

Transformacije sabijanja/rastezanja modela se primenjuju i na njegove vektore normala, tako da je potrebno izvriti normalizaciju nad vektorima normala objekta nakon primene transformacija. OpenGL omoguava automatsku normalizaciju pomou promenljive stanja Gl.GL_NORMALIZE. Meutim, primena automatske normalizacije smanjuje brzinu prorauna osvetljenja zbog raunske sloenosti. 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 vie vrednosti, najee se koristi


Gl.GL_LIGHT_MODEL_AMBIENT.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

96

VI Open Graphics Library (OpenGL) C#

params semantiku odreuje parametar pname, za gore navedenu


vrednost params je boja ambijentalnog osvetljenja scene. U sceni moe postojati najvie jedan globalni ambijentalni svetlosni izvor. Sledei programski kd 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 definie 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 simboliko ime oblika:


Gl.GL_LIGHT<x> gde je: <x> broj Gl.GL_MAX_LIGHTS i <x> 0. pname model osvetljenja, mogue 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 odreuje parametar pname, npr. za vrednost params jednako Gl.GL_AMBIENT je boja ambijentalne komponente svetlosnog izvora scene.

Nakon specifikovanja svetlosnog izvora potrebno ga je ukljuiti pozivom metode glEnable sa argumentom Gl.GL_LIGHT<x>, gde je <x> broj svetlosnog izvora. OpenGL specifikacija definie minimalno osam svetlosnih izvora koje implementacija mora podravati. Maksimum svetlosnih izvora koje implementacija podrava je sadran u konstanti Gl.GL_MAX_LIGHTS koja mora biti vea ili jednaka od osam. Na Windows platformi mogue je maksimalno definisati osam svetlosnih izvora. Ako je potrebno na sceni imati vie svetlosnih izvora, tada se svetlosni izvori moraju reciklirati ili se mora simulirati efekti osvetljenja. Svetlosni izvor se pozicionira u sceni pomou metode glLightfv sa pname jednako Gl.GL_POSITION i kao params se navede pozicija svetlosnog izvora. Pozicija svetlosnog izvora je opisana kao ureena etvorka (x,y,z,w) gde su x,y i z koordinate svetlosnog izvora, a parametar w definie da li je u pitanju reflektorski S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

97

VI Open Graphics Library (OpenGL) C# 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. Sledei programski kd definie 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 definiu korienjem Gl.GL_SPOT_DIRECTION, Gl.GL_SPOT_CUTOFF i Gl.GL_SPOT_EXPONENT vrednosti za definisanje smera, cut-off ugla i koeficijenta opadanja intenziteta o o o o svetlosti. Cut-off ugao je u opsegu [0 , 90 ] ili 180 . Vrednost 180 za ugao je specijalna i oznaava uniformno rasipanje svetlosti takasti svetlosni izvor. Koeficijent opadanja intenziteta svetlosti, u opsegu [0, 128], definie koliko e svetlosni snop biti fokusiran (videti poglavlje 4.8). Podrazumevane vrednosti su: za o smer (0,0,-1) tj. u smeru z-ose; za ugao 180 i za koeficijent opadanja intenziteta vrednost 0. Sledei programski kd prikazuje postupak kreiranja reflektorskog svetlosnog izvora, njegovo pozicioniranje i ukljuivanje:

float[] float[] float[]

ambijentalnaKomponenta = { 0.3f, 0.3f, 0.3f, 1.0f }; difuznaKomponenta = { 0.7f, 0.7f, 0.7f, 1.0f }; smer = { 0.0f, 0.0f, -1.0f };

// Pridrui komponente svetlosnom izvoru 0 Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambijentalnaKomponenta); Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, difuznaKomponenta); // Podesi parametre reflektorkskog izvora Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPOT_DIRECTION, smer); 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);

Sledei programski kd prikazuje postupak kreiranja takastog izvora svetlosti:

float[]

ambijentalnaKomponenta = { 0.3f, 0.3f, 0.3f, 1.0f };

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

98

VI Open Graphics Library (OpenGL) C#

float[]

difuznaKomponenta = { 0.7f, 0.7f, 0.7f, 1.0f };

// Pridrui komponente svetlosnom izvoru 0 Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambijentalnaKomponenta); Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, difuznaKomponenta); // 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 kd primera primene materijala i osvetljenja (direkciono i ambijentalno) na model aviona, preuzet iz [3]. Avion se moe rotirati korienjem 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 poligon // 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) {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

99

VI Open Graphics Library (OpenGL) C#


float[] normal = new float[3]; // normala na ravan def. sa normal[0] = (y1 - y2) * (z2 normal[1] = (x2 - x3) * (z1 normal[2] = (x1 - x2) * (y2 tri tacke definisane u CCW smeru - z3) - (y2 - y3) * (z1 - z2); - z2) - (x1 - x2) * (z2 - z3); - 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.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);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

100

VI Open Graphics Library (OpenGL) C#


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.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.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, -57.0f)); Gl.glVertex3f(0.0f, -0.5f, -40.0f); Gl.glVertex3f(30.0f, -0.5f, -57.0f);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

101

VI Open Graphics Library (OpenGL) C#


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, -65.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 prozora //////////////////////////////////////////////////////////////////////// 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() {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

102

VI Open Graphics Library (OpenGL) C#


// 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 pozivi 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 podrava automatsko generisanje senki, tako da autor mora sam

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

103

VI Open Graphics Library (OpenGL) C# generisati i prikazati senku. Proraun i prikaz senki je van okvira ovog teksta. O senkama itaoci se mogu vie informisati u [3]. Listing 6.8.2. prikazuje programski kd primera korienja reflektorskog osvetljenja, preuzet iz [3]. Svetlosni izvor se moe pomerati korienjem strelica na tastaturi da bi se bolje video uticaj osvetljenja. Slika 6.8.2 prikazuje rezultat aplikacije.

Slika 6.8.1 Rezultat primera iz listinga 6.8.1

/*********************************************************************** * 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) {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

104

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

105

VI Open Graphics Library (OpenGL) C#


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 izvora 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 svetlosnog 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 bila 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 efekat osvetljenja Gl.glColor3ub(0, 0, 255);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

106

VI Open Graphics Library (OpenGL) C#


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 promene 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 inicijalizacije 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 ga // 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 svetlosni izvor // Cut off na 50 stepeni

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

107

VI Open Graphics Library (OpenGL) C#


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 podrava definisanje efekta magle. Proraun efekta magle se ukljuuje pozivom metode glEnable sa argumentom Gl.GL_FOG. Familija metoda glFog odreuje 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)
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

108

VI Open Graphics Library (OpenGL) C# gde su:

pname parametar koji definie koja se osobina magle podeava. Neke

Listing 6.8.3 prikazuje iseak programskog kda primera primene efekta magle. Slika 6.8.3 prikazuje rezultat ovog primera. Primer predstavlja proirenje primera upravljanja kamerom (videti poglavlje 6.6.4).

od moguih vrednosti su: Gl.GL_FOG_MODE params je blending faktor (jednaina po kojoj se rauna magla) koji moe biti: Gl.GL_LINEAR, Gl.GL_EXP, and Gl.GL_EXP2. Gl.GL_FOG_DENSITY params je gustina magle, vrednost mora biti nenegativna; inicijalno iznosi 1. Gl.GL_FOG_START params je distanca od koje se poinje 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 definie boju magle; inicijalno je (0, 0, 0, 0) crna boja. param semantiku odreuje parametar pname.

Slika 6.8.2 Rezultat primera iz listinga 6.8.2

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

109

VI Open Graphics Library (OpenGL) C#

. . .
////////////////////////////////////////////////////////////////// // Naziv: RenderScene // Namena: metoda iscrtava OpenGL scenu ////////////////////////////////////////////////////////////////// static void RenderScene() { // obrisi prozor sa trenutno aktivnom bojom za brisanje 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 inicijalizacije 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_grayLight[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 jedinica Gl.glFogf(Gl.GL_FOG_START, 5.0f);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

110

VI Open Graphics Library (OpenGL) C#


// 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 omoguava simuliranje razliitih svetlosnih efekata korienjem blending tehnike. Vie o ovoj tehnici se moe nai u [3]. Dodatno, OpenGL podrava i dithering, primenu logikih operacija prilikom kombinovanja boja, kao i color masking. Vie detalja se moe nai u [3].

Slika 6.8.3 Rezultat primera iz listinga 6.8.3


S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 111

VI Open Graphics Library (OpenGL) C#

Pridruivanje teksture objektima doprinosi realizmu scene. U ovom poglavlju bie prezentovane metode za uitavanje tekstura i njihovo mapiranje. Jedinica teksture se naziva teksel. OpenGL podrava rad sa 1D, 2D i 3D teksturama, koje se uitavaju pomou metoda glTexImage1D, glTexImage2D i glTexImage3D.

6.9 Teksture

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 odgovarajua 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 sadraja kolor bafera (iscrtanog dela kadra) pomou glCopyTexImage1D i glCopyTexImage2D metoda.

public static void glCopyTexImage1D(int target, int level, int internalFormat, int x, int y, int width, int border)
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

112

VI Open Graphics Library (OpenGL) C#

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

target odgovarajua 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,

esto se teksture menjaju u toku izvravanja, uitavaju nove i uklanjaju stare iz memorije. Gore navedene operacije za uitavanje teksture su zahtevne po pitanju resursa. S toga postoje metode glTexSubImage1D, glTexSubImage2D i glTexSubImage3D koje omoguavaju zamenu sadraja teksture.

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

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 odgovarajua 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
vri zamena,

width, height i depth dimenzije teksture, format, type i data su format, tip piksela i pikseli pikselmape
koja se koristi kao tekstura.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

113

VI Open Graphics Library (OpenGL) C# Mogue 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. Slino X3D standardu (videti poglavlje 4.7), koordinate teksture se izraavaju 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 reim mapiranja dvodimenzionalne teksture se ulazi pozivom metode glEnable sa argumentom Gl.GL_TEXTURE_2D. Analogno se ulazi u reime mapiranja za teksture drugih dimenzionalnosti. Koordinate 1D, 2D i 3D teksture se specifikuju pomou 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: Za objekte relativno sloene geometrije runo zadavanje koordinata teksture je veoma teko i podlono grekama. OpenGL standard nudi mogunost automatskog generisanja koordinata teksture. Automatsko generisanje koordinata tekstura se ukljuuje 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_TEXTURE_GEN_T. Po ukljuivanju sve pozivi glTexCoord* metoda se ignoriu i OpenGL automatski generie koordinate teksture. OpenGL implementaciji se mora zadati na koji nain da generie koordinate teksture. Ovo se postie pozivom familije metoda glTexGen*.

s,t,r koordinate teksture (irina, visina, dubina).

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: pname vrednost odreuje znaenje param
parametra. Mogue vrednosti su: Gl.GL_OBJECT_PLANE i Gl.GL_EYE_PLANE, i Gl.GL_TEXTURE_GEN_MODE, 114
Gl.GL_S, Gl.GL_T, i Gl.GL_R,

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

VI Open Graphics Library (OpenGL) C#

param nain generisanja koordinata teksture. Dozvoljene vrednosti su:


Gl.GL_OBJECT_LINEAR, Gl.GL_EYE_LINEAR, i Gl.GL_SPHERE_MAP. OpenGL podrava tri naina automatskog generisanja koordinata tekstura: linearno koje je izraeno u koordinatama objekta (GL_OBJECT_LINEAR), linearno koje je izraeno u koordinatama sa aspekta posmatraa (GL_EYE_LINEAR), i sferino (GL_SPHERE_MAP). Prva dva koriste ravan, a poslednja sferu. Sferino generisanje koordinata teksture daje realistine rezultate iako u praksi se ee koristi mapiranje na kocku. Vie detalja o ovom mapiranju se moe nai u [3]. Transformacije nad koordinatama teksture se realizuju korienjem Texture matrice. Ova matrica se bira pozivom metode glMatrixMode sa argumentom Gl.GL_TEXTURE. OpenGL omoguava definisanje naina 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 najea vrednost je Gl.GL_TEXTURE_ENV_MODE, tada
params moe biti: Gl.GL_MODULATE mnoi 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 odreuje parametar pname.

Zbog naina na koji se vri blending teksture, kao rezultat moe doi do gubljenja odsjaja materijala (specular highlight). Ako se eli sauvati odsjaj mora se koristiti secondary specular color tehnika, dostupna od verzije 1.4. U reim rada sa ovom tehnikom se ulazi sledeim programskim kodom:

Gl.glLightModeli(Gl.GL_LIGHT_MODEL_COLOR_CONTROL,
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

115

VI Open Graphics Library (OpenGL) C#

Za izlazak iz reima se koristi sledei programski kd:

Gl.GL_SEPARATE_SPECULAR_COLOR);

Pored reimskog rada mogue je i runo podeavati boju odsjaja. Mapiranje teksela na objekat esto podrazumeva skaliranje teksela. OpenGL omoguava specifikovanje filtara za skaliranje tekstura. Filtri se definiu za smanjenje (minimization) i uveavanje (magnification) teksture. Neki od filtera su: najblii sused (nearest neighbour), slika 6.9.1a, i linearno filtriranje (linear filtering), slika 6.9.1b. Najblii sused odreuje vrednost nedostajueg teksela na osnovu njegovog najblieg suseda, dok linearno filtriranje odreuje vrednost nedostajueg teksela na osnovu srednje vrednosti okolnih teksela. Najblii sused daje vizeulno loiji rezultat u poreenju sa linearnim filtriranjem, ali zato je znaajno bri od linearnog filtriranja. OpenGL zahteva da se definie kako se rukuje koordinatama teksture koje su van opsega ([0,1]) (texture wrapping). Jedna od mogunosti je ponavljanje teksture u pravcu u kome su koordinate teksture izvan opsega.

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

a) najblii sused

b) linearno filtriranje

Slika 6.9.1 Tipovi filtriranja teksture, preuzeto iz [3] Familija metoda glTextParameter omoguava 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,
S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE 116

VI Open Graphics Library (OpenGL) C#

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: parametar mora biti: Gl.GL_TEXTURE_1D, Gl.GL_TEXTURE_2D ili Gl.GL_TEXTURE_3D. pname moe biti: Gl.GL_TEXTURE_MIN_FILTER filtriranje teksture koje se primenjuje u sluaju da se tekstura mora smanjiti da bi bila pridruena objektu, Gl.GL_TEXTURE_MAG_FILTER filtriranje teksture koje se primenjuje u sluaju da se tekstura mora poveati da bi bila pridruena objektu, Gl.GL_TEXTURE_WRAP_S definie da li e se tekstura ponavljati po s-osi, kao i kojim tekselima e biti realizovano ponavljanje, Gl.GL_TEXTURE_WRAP_T definie da li e se tekstura ponavljati po t-osi, kao i kojim tekselima e biti realizovano ponavljanje, Gl.GL_TEXTURE_BORDER_COLOR definie boju okvira teksture. Podrazumevana vrednost je crna boja, Gl.GL_TEXTURE_PRIORITY definie prioritet teksture. params semantiku odreuje parametar pname. Listing 6.9.1 i slika 6.9.2 prikazuju primer pridruivanja 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);

target

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

117

VI Open Graphics Library (OpenGL) C#


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 obzirom da postoji // mogucnost da se ne kreira i pridruzi tekstura objektu 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);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

118

VI Open Graphics Library (OpenGL) C#


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. alfa 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_LINEAR); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_LINEAR); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_CLAMP); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_CLAMP);

Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_TEXTURE_WRAP_S, Gl.GL_TEXTURE_WRAP_T,

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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

119

VI Open Graphics Library (OpenGL) C#


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

Listing 6.9.1 Primer rada sa teksturama - pridruivanje teksture piramidi Veliki problem predstavlja injenica to je tekstura fiksnih dimenzija i kao takva teko da se moe mapirati na objekat bez potrebe za skaliranjem. Skaliranje skoro uvek daje neeljene artefakte. tzv. scintillation artefacts. Ovi artefakti se najbolje uoavaju kod objekata u pokretu. Takoe, skaliranje predstavlja zahtevnu operaciju sa aspekta zauzea resursa. Kao reenje za gore navedene probleme koristi se mipmapping tehnika pridruivanja teksture objektima. Ova tehnika poboljava kako Slika 6.9.2 Rezultat primera iz performanse iscrtavanja tako i vizuelni kvalitet listinga 6.9.1 iscrtanih objekata. Mipmapping koristi umesto jedne teksture, itav niz tekstura (mipmapping levels) iste slike, ali razliitog 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)

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

120

VI Open Graphics Library (OpenGL) C#

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 odgovarajua vrednost shodno dimenzionalnosti teksture:


Gl.GL_TEXTURE_1D, Gl.GL_TEXTURE_2D 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. i

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 pridruuje objektu pozivom metode glBindTexture. Teksture se unitavaju 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 generiu, textures niz u kom se smetaju identifikatori alociranih tekstura. public static void glBindTexture(int target, int texture)
gde su: S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

121

VI Open Graphics Library (OpenGL) C#

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 unite, textures niz identifikatora tekstura.

Slika 6.9.4 Rezultat primera iz listinga 6.9.2 Listing 6.9.2 i slika 6.9.4 prikazuju primer korienja gore navedenih metoda. Primer pokazuje primenu mipmapping tekstura, kao i primenu razliitih 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 struct TextureObjects { public const int TEXTURE_BRICK = public const int TEXTURE_FLOOR = public const int TEXTURE_CEILING = public const int TEXTURE_COUNT = } do adekvatnih slika

0; 1; 2; 3;

static int[] textures = new int[TextureObjects.TEXTURE_COUNT]; static string[] textureFiles = { "..//..//brick.jpg", "..//..//floor.jpg", "..//..//ceiling.jpg" };

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

122

VI Open Graphics Library (OpenGL) C#


//////////////////////////////////////////////////////////////////// // 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

123

VI Open Graphics Library (OpenGL) C#


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 ////////////////////////////////////////////////////////////////////

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

124

VI Open Graphics Library (OpenGL) C#


static void SetupRenderingContext() { // Crna pozadina Gl.glClearColor(0.0f, 0.0f, 0.0f,1.0f); // Ukljuci depthtest i back face culling i podesi da 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. alfa 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 tekstura /////////////////////////////////////////////////////////////////// static void Shutdown() { Gl.glDeleteTextures(TextureObjects.TEXTURE_COUNT, textures); } //////////////////////////////////////////////////////////////////// // Naziv: Main // Namena: Main metoda //////////////////////////////////////////////////////////////////// static void Main(string[] args) {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

125

VI Open Graphics Library (OpenGL) C#


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 korienja mipmapping tekstura

Uobiajno je da se teksture koriste za simulaciju realnog okruenja (pozadine scene). Listing 6.9.3 i slika 6.9.5 prikazuju primer definisanja pozadine scene korienjem kvadra ijim stranicama su pridruene 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) {

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

126

VI Open Graphics Library (OpenGL) C#


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_LINEAR); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_LINEAR_MIPMAP_LINEAR); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_CLAMP_TO_EDGE); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_CLAMP_TO_EDGE); image.UnlockBits(bitmapdata); image.Dispose(); } //////////////////////////////////////////////////////////////////// // Naziv: DrawEnviroment // Namena: crta se kocka kojoj su pridruzene teksture // Parametri: x,y,z pozicija kocke, width, height 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); Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_TEXTURE_WRAP_S, Gl.GL_TEXTURE_WRAP_T,

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

127

VI Open Graphics Library (OpenGL) C#


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 + height, 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 + height, 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 + height, z + length);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

128

VI Open Graphics Library (OpenGL) C#


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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

129

VI Open Graphics Library (OpenGL) C# OpenGL omoguava i ispis teksta kojem je pridruena tekstura. Listing 6.9.4 i slika 6.9.6 prikazuju primer korienja 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 specifican static Gdi.GLYPHMETRICSFLOAT[] gmf = new Gdi.GLYPHMETRICSFLOAT[256]; ////////////////////////////////////////////////////////////////////// // Naziv: rgCreateFont // Namena: kreiranje fonta kao display liste // 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; }

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

130

VI Open Graphics Library (OpenGL) C#


////////////////////////////////////////////////////////////////////// // Naziv: DeleteFont // Namena: brisanje fonta kao display liste // Parametri: DL identifikator // Povratna vrednost: ////////////////////////////////////////////////////////////////////// static void rgDeleteFont(int id) { Gl.glDeleteLists(id, 256); // obrisi svih 256 karaktera } ////////////////////////////////////////////////////////////////////// // Naziv: CalculateTexturedTextHeight // Namena: izracunavanje visine teksta za 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 za 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 ispis // 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

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

131

VI Open Graphics Library (OpenGL) C#


} } //////////////////////////////////////////////////////////////////////// // 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, (miliseconds/1000)%60); float messageWidth = CalculateTexturedTextWidth(gmf, message); 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 inicijalizacije 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);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

132

VI Open Graphics Library (OpenGL) C#


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 Iseak programskog kda primera pridruivanja teksture tekstu U gore navedenom primeru tekst se ispisuje metode RenderTexturedText. korienjem Metode rgCreateFont i rgDeleteFont, kreiraju, odnosno briu teksturirani font. Metoda rgCreateFont kreira svaki karakter kao display list-u, korienjem metoda koje su specifine za Windows platformu: CreateFont, wglGetCurrentDC i wglUseFontOutlines. Ovaj primer demonstrira i automatsko generisanje koordinata tekstura korienjem promenljivih stanja: Slika 6.9.6 Rezultat primera iz listinga 6.9.4 Gl.GL_TEXTURE_-GEN_S i Gl.GL_TEXTURE_GEN_T. Tekst se moe ispisati korienjem tekstura (svako slovo je tekstura ili deo teksture) to omoguava da korisnikovoj maini ne mora biti podran font koji se koristi za ispis teksta, ime se mogu zaobii ogranienja koje postavlja GLUT ispis teksta. Listing 6.9.5 i slika 6.9.7 prikazuju primer ispisa teksta korienjem tekstura.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

133

VI Open Graphics Library (OpenGL) C#

. . .
// 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 teksture // Parametri: DL identifikator i teksture fonta, 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 karaktera // 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.001f); 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 greske if (Gl.glGetError() != Gl.GL_NO_ERROR)

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

134

VI Open Graphics Library (OpenGL) C#


return false; } return (Gl.glGetError() == Gl.GL_NO_ERROR);//vrati uspesnost operacije } ////////////////////////////////////////////////////////////////////// // Naziv: rgDeleteTextureAsFont // Namena: brisanje fonta kao display liste // Parametri: DL identifikator i broj karaktera ////////////////////////////////////////////////////////////////////// static void rgDeleteTextureAsFont(int idDL, int charCount) { Gl.glDeleteLists(idDL, charCount); // obrisi svih 256 karaktera } ////////////////////////////////////////////////////////////////////// // Naziv: RenderTextUsingTextures // Namena: ispis teksta koriscenjem tekstura // Parametri: DL identifikator, tekst za ispis ////////////////////////////////////////////////////////////////////// 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, (miliseconds/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 ekrana) Gl.glTranslatef(144.0f, 240.0f, 0.0f); // skaliraj slova da visina bude dva puta veca od sirine Gl.glScalef(1.0f, 2.0f, 1.0f);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

135

VI Open Graphics Library (OpenGL) C#


// 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 inicijalizacije 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, characterCount, 16) == false) { image.UnlockBits(imageData); image.Dispose(); Environment.Exit(1); } image.UnlockBits(imageData); image.Dispose(); }

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

136

VI Open Graphics Library (OpenGL) C#


. . .

Listing 6.9.5 Iseak programskog kda korienja tekstura za ispis teksta U gore navedenom primeru tekst se ispisuje korienjem metode RenderTextUsingTextures. Metode rgCreateTextureAsFont i rgDeleteTextureAsFont, kreiraju, odnosno briu font realizovan korienjem tekstura. Metoda rgCreateTextureAsFont kreira svaki karakter kao display list-u, koja predstavlja jedan pravougonik kome je pridruen deo teksture - karakter, slika 6.9.8. OpenGL, do verzije 2.0, postavlja Slika 6.9.7 Rezultat primera iz ogranienja na dimenzije teksture. Dimenzije listinga 6.9.5 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 korienjem glTexImage2D, glSubTexImage2D, glCopyTexImage2D i glCopySubTexImage2D gde je target: Gl.GL_TEXTURE_RECTANGLE_ARB. One ne podravaju mipmapping, kao ni definisanje okvira. Od wrapping modova podrani su: Gl.GL_CLAMP, Gl.GL_CLAMP_TO_EDGE, i Gl.GL_CLAMP_TO_BORDER. S obzirom da je funkcionalnost realizovana kao ekstenzija, do Slika 6.9.8 Tekstura fonta verzije 2.0, mora se ispitati da li hardver podrava datu funkcionalnost. Sledei programski kd demonstrira ispitivanje ove funkcionalnosti:

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

OpenGL specifikacija verzija 2.0 je ukinula ogranienje na dimenzije teksture, tako da se ekstenzija koristi samo na hardveru koji ne podrava 2.0 specifikaciju.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

137

VI Open Graphics Library (OpenGL) C#

Animacija se moe realizovati na dva naina: korienjem glutIdleFunc i/ili korienjem glutTimerFunc metoda. Metoda glutIdleFunc omoguava registrovanje callback metode koja se izvrava u pozadini izmeu dva iscrtavanja na ekran (frekvencija iscrtavanja je odreena frekvencijom osveavanja monitora). Obino se u ovu metodu postavlja programski kd koji menja parametre iscrtavanja generie se novi frejm animacije.

6.10 Animacija

public static void glutIdleFunc(IdleCallback func) public delegate void Glut.IdleCallback();


gde je:

func metoda koja se poziva u idle stanju.


Metoda glutTimerFunc omoguava definisanje callback metode koja se izvrava nakon proteklog vremena definisanog parametrom msecs. Da bi se postigao efekat tajmera tj. periodinosti, potrebno je rekurzivno pozivati func metodu. Primenom tajmera postie se animacija koja je nezavisna od frekvencije osveavanja 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 prosleuje funkciji (obino se koristi kao
identifikator koji omoguava da se ignorie 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 izmeu ova dva primera se vidi u izvravanju. Drugi primer se izvrava mnogo bre, s obzirom da prvi ima tajmer od 250ms (4Hz), a drugi 60Mhz (na maini na kojoj je testiran frekvencija osveavanja ekrana!).
. . . ////////////////////////////////////////////////////////////////////// // 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);

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

138

VI Open Graphics Library (OpenGL) C#


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 iscrtavanja 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.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); Glut.glutSolidSphere(6.0f, 30, 17); Gl.glPopMatrix(); Glut.glutSwapBuffers(); } ////////////////////////////////////////////////////////////////////// // Naziv: ProcessIdleState // Namena: izracunava vrednosti uglova rotacije 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 | Glut.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();

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

139

VI Open Graphics Library (OpenGL) C#


Glut.glutMainLoop(); } }

Listing 6.10.2 Primer simulacije revolucije Zemlje i Meseca oko Sunca korienjem glutIdleFunc metode
. . . //////////////////////////////////////////////////////////////////// // Naziv: Timer // Namena: animacija sa konstantnim frejmrejtom // 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 iscrtavanja 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.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;

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

140

VI Open Graphics Library (OpenGL) C#


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 korienjem glutTimerFunc metode Dva naina realizacije animacije u OpenGL-u nisu meusobno iskljuivi, ve se mogu kombinovati. Prilikom korienja tajmera mora se voditi rauna o broju tajmera, zbog ogranienosti resursa. U okviru ovog teksta prezentovan je osnovni deo OpenGL standarda. Za podrobnije upoznavanje sa OpenGL standardom itaocu se preporuuje [3].

LITERATURA
1. GLUT specification, http://www.opengl.org/resources/libraries/glut/glut3.spec.pdf 2. OpenGL specification, http://www.opengl.org/documentation/specs/ th 3. Wright R. Jr., Lipchak B., Haemel N., OpenGL Super Bible, 4 Ed., Addison Wesley, 2007.

S. Mihi, D. Dragan, V.Petrovi, D.Iveti RAUNARSKA GRAFIKA VEBE

141

Das könnte Ihnen auch gefallen