OpenGL tutorial

background image

0

Tutorial OpenGL i GLUT

Na podstawie ksi ki – OpenGL Ksi ga eksperta - Helion

SPIS TRE CI:

1. Szczegóły interfejsu .............................................................................................. 1

1.1. Typy danych ............................................................................................... 1

1.2. Konwencje nazewnictwa funkcji ............................................................... 2

2. Nasz pierwszy program......................................................................................... 4

3. Rysowanie kształtów w OpenGL.......................................................................... 7

4. Animacja w OpenGL i GLUT............................................................................... 13

4.1. Podwójne buforowanie............................................................................... 15

5. Maszyna stanów .................................................................................................... 15

5.1. Zapisywanie i odtwarzanie stanów ............................................................ 16

6. Rysowanie 3D ....................................................................................................... 17

6.1. Rysowanie punktów ................................................................................... 17

6.2. Ustalanie wielko ci punktów ..................................................................... 19

6.3. Rysowanie linii w trzech wymiarach ......................................................... 22

6.4. Linie łamane i zamkni te............................................................................ 22

6.5. Aproksymacja krzywych liniami prostymi ................................................ 23

6.6. Ustalanie szeroko ci linii ........................................................................... 23

6.7. Rysowanie trójk tów w trzech wymiarach ................................................ 24

6.7.1. Trójk t – mój pierwszy wielok t..................................................... 25

6.7.2. Nawini cie ....................................................................................... 25

6.7.3. Trójk ty sklejane ............................................................................. 26

6.7.4. Wachlarze trójk tów........................................................................ 27

6.8. Budowanie pełnych obiektów .................................................................... 27

6.9. Ustalenie koloru wielok ta......................................................................... 29

7. Tekstury................................................................................................................. 29

7.1. Ładowanie tekstur ...................................................................................... 29

7.2. Odwzorowywanie tekstur na obiekty geometryczne ................................. 32

7.3. Macierze tekstur ......................................................................................... 33

7.4. Prosty przykład dwuwymiarowy................................................................ 33

background image

1

Szczegóły interfejsu

Biblioteka OpenGL została zaprojektowana przez uczonych ludzi posiadaj cych wiele do wiadczenia w projektowaniu

interfejsów programowania grafiki. Zastosowali oni standardowe reguły nazewnictwa funkcji i deklarowania zmiennych.

Powstałe API jest bardzo proste i przejrzyste, a na dodatek pozwala ró nym dostawcom w łatwy sposób rozbudowywa

bibliotek . OpenGL stara si nakłada jak najmniej zasad. Zasadami okre lane

s zało enia, jakie projektanci biblioteki poczynili w zakresie metod wykorzystania API przez u ytkowników.

Przykładami takich zasad mog by zało enia, e dane wierzchołków b d zawsze definiowane jako warto ci

zmiennoprzecinkowe, przed wł czeniem rendcringu mgła b dzie zawsze wł czona albo e wszystkie obiekty na scenie

obj te s tymi samymi parametrami o wietlenia. Takie zało enia mogłyby wyeliminowa wiele z popularnych technik

renderowania powstałych z biegiem czasu.

Typy danych

Aby ułatwi przenoszenie kodu korzystaj cego z OpenGL na inne platformy biblioteka definiuje swoje własne typy

danych. Typy te wynikaj z normalnych typów danych j zyka C, których mo na u ywa zamiennie, je eli zajdzie taka

potrzeba. Trzeba jednak pami ta , e ró ne kompilatory i rodowiska stosuj swoje własne zasady definiuj ce wielko i

uło enie w pami ci typów danych j zyka C. Stosowanie typów danych definiowanych przez OpenGL pozwala

odizolowa nasz kod od tego rodzaju zmian.

W tabeli 2.1 wypisano typy danych biblioteki OpenGL i odpowiadaj ce im typy danych j zyka C w 32-bitowych

rodowiskach Windows (Win32), a tak e przedrostki literałów. W tym tutorialu b dziemy u ywa tych przedrostków w

nazwach wszystkich literałów. Jak b dzie mo na zauwa y pó niej, te same przedrostki stosowane s równie w

nazwach wielu funkcji biblioteki OpenGL.

background image

2

Wszystkie typy danych zaczynaj si od liter GL, co oznacza, e pochodz z biblioteki OpenGL. W wi kszo ci

przypadków za tymi literami znajduje si nazwa odpowiadaj cego im typu danych j zyka C (by te, short, int, float itd.).

Litera u umieszczona przed niektórymi z tych nazw informuje nas, e jest to typ danych bez znaku, na przykład ubyte

oznacza bajt bez znaku (unsigned byte). Do niektórych zastosowa przygotowano bardziej opisowe nazwy, takie jak size

do oznaczania warto ci długo ci lub gł boko ci. Na przykład typ Glsizei stosowany jest do oznaczania parametrów

rozrrtiaru opisywanego liczb całkowit . Oznaczenie clamp jest wskazówk , e warto po\yinna by ci ni ta w

zakresie do 0.0 - 1.0. Zmienne Glboolean u ywane s do przechowywania warto ci logicznych, typ GLenum

przeznaczony jest dla zmiennych wyliczeniowych, a GLbit field dla zmiennych zawieraj cych pola bitowe.

Wska niki i tablice nie otrzymały adnych specjalnych oznacze . Tablice dziesi ciu zmiennych typu GLshort

deklarowana jest po prostu jako:

GLshort shorts[10];

natomiast tablica dziesi ciu wska ników na warto ci GLdoubl e deklarowana jest nast puj co:

GLdouble *doubles[10];

Konwencje nazewnictwa funkcji

Dla wi kszo ci funkcji OpenGL zastosowano konwencje nazewnicze informuj ce nas, z jakiej biblioteki pochodzi dana

funkcja, a cz sto przekazuj ce te informacje o liczbie i typie pobieranych parametrów. Wszystkie funkcje posiadaj

rdze nazwy reprezentuj cy polecenie OpenGL odpowiadaj ce danej funkcji. Na przykład rdzeniem nazwy funkcji

glColor3f" jest polecenie Color. Przedrostek gl oznacza, e funkcja pochodzi z biblioteki gl, a przyrostek 3f mówi, e

funkcja pobiera trzy parametry zmiennoprzecin-kowe. Nazwy wszystkich funkcji OpenGL tworzone s zgodnie z

poni szym formatem:
<przedrostek bibliotcki><rdze polecenia><opcjonalna liczba parametrów> <opcjonalny typ parametrów>

Rysunek 2.4 przedstawia poszczególne elementy nazwy funkcji OpenGL. Przykładowa funkcja z przyrostkiem 3f

pobiera trzy parametry zmiennoprzecinkowe. Inne warianty pobieraj trzy liczby całkowite (glColor3i), trzy liczby

zmiennoprzecinkowe podwójnej precyzji (glColor3d) itd. Konwencja dodawania do nazwy funkcji liczby i typów para-

metrów (tabela 2.1) bardzo ułatwia zapami tanie listy parametrów funkcji bez konieczno ci przegl dania dokumentacji.

Niektóre wersje funkcji gl Color pobieraj te czwarty parametr, oznaczaj cy składow alfa (przezroczysto ).

Wiele kompilatorów C/C++ w systemach Windows zakłada, e ka da podawana jawnie warto

zmiennoprzecinkowajest typu double, chyba e zostanie podany inny typ. Stosuj c literały warto ci

zmiennoprzecinkowych z pomini ciem okre lenia, e s to warto ci typu float, a nie double, otrzymamy od kompilatora

ostrze enie mówi ce o tym, e próbujemy przekaza warto typu double do parametru typu float, co grozi utrat

precyzji liczby. Wraz z rozrastaniem si programów korzystaj cych z OpenGL liczba takich ostrze e szybko ro nie w

setki, co znacznie utrudnia wyszukiwanie rzeczywistych bł dów. Oczywi cie mo na wył czy te ostrze enia za pomoc

odpowiedniej opcji kompilatora, ale zdecydowanie odradzamy ten sposób załatwiania sprawy. Znacznie lepszym roz-

wi zaniem jest tworzenie przejrzystego i przeno nego kodu, dlatego nale y usuwa te ostrze enia poprzez

background image

3

wyczyszczenie kodu (w tym przypadku, poprzez okre lanie typu float przy literałach warto ci zmiennoprzecinkowych),

a nie wył czanie potencjalnie przydatnych ostrze e .

Poza tym, mo na ulec pokusie u ywania wył cznie funkcji pobieraj cych liczby zmien-noprzecinkowe o podwójnej

precyzji i nie zawraca sobie głowy podawaniem typu ka dej wpisywanej jawnie warto ci. Niestety, biblioteka OpenGL

wewn trznie u ywa warto ci typu float, wi c u ywanie warto ci innych ni float powoduje zmniejszenie wydajno ci,

poniewa musz by one cały czas konwertowane na odpowiedni posta , zanim biblioteka b dzie mogła si nimi zaj

(nie wspominaj c nawet o tym, e zmienne typu double zajmuj dwa razy wi cej miejsca ni zmienne typu float). W

programie, w którym „przerzucanych" jest wiele takich liczb, mo e to mie znacz cy wpływ na wydajno !

background image

4

Nasz pierwszy program

W celu lepszego poznania biblioteki GLUT przyjrzyjmy si teraz prawdopodobnie najmniejszemu na wiecie

programowi korzystaj cemu z OpenGL, który napisany został z wykorzystaniem biblioteki GLUT. Na poni szym

listingu przedstawiono program SIMPLE. Przy okazji dowiemy si kilku nowych rzeczy o bibliotece OpenGL!

#include <OpenGL.h>

// Funkcja wywoływana w celu narysowania sceny

void RenderScene(void)

{

// Wyczyszczenie okna aktualnym kolorem czyszcz cym

glClear(GL_COLOR_BUFFER_BIT);

/// Przekazanie polecenia czyszczenia do wykonania

glFlush();

}

// Ustalenie stanu rendrowania

void SetupRC(void)

{

glClearColor(0.0f,0.0f,1.0f,1.0f):

}

// Główny punki wej cia programu

void main(void)

{

glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA):

glutCreateWi ndow("Si mple");

glutDi splayFunct RenderScene):

SetupRC():

glutMainLoo();

}

Program SIMPLE nie robi zbyt wiele. Po uruchomieniu z poziomu wiersza polece (lub rodowiska programistycznego)

tworzy tylko standardowe okno interfejsu GUI z nagłówkiem Simple i pustym niebieskim tłem. Je eli uruchomiony

został z poziomu Visual C++. to po jego zako czeniu w oknie konsoli pojawi si komunikat Press any key. Aby całko-

wicie zamkn program, konieczne b dzie naci ni cie dowolnego klawisza. Ta standardowa funkcja rodowiska

programistycznego Microsoftu u ywana w czasie uruchamiania programów konsolowych ma na celu umo liwienie nam

przejrzenia wszystkich komunikatów jakie mógł wygenerowa program, zanim jego okno zniknie z ekranu. Je eli ten

sam program uruchomimy z poziomu wiersza polece , to nie stwierdzimy takiego zachowania. Je eli klikniemy

dwukrotnie plik w Eksploratorze, to zobaczymy co prawda okno konsoli, ale zniknie ono w momencie zamkni cia

programu.

Ten prosty program korzysta z czterech funkcji biblioteki GLUT (oznaczonych przedrostkiem glut) i trzech

„prawdziwych" funkcji OpenGL (z przedrostkiem gl). Przejrzyjmy teraz program wiersz po wierszu, a pó niej

wprowadzimy do niego kilka dodatkowych funkcji i podniesiemy jako naszego pierwszego przykładu.

Nagłówek

Powy szy kod zawiera tylko jedn instrukcj wł czenia pliku nagłówkowego:

#include <0penGL.h>

Plik ten wł cza w siebie pliki nagłówkowe gl.h i glut.h, w których zapisane s prototypy funkcji u ywanych w programie.

Ciało

Nast pnie przejdziemy do punku wej cia wszystkich programów j zyka C:

void main(void)

Wykonywanie programów w C i C++ działaj cych w trybie konsoli zawsze rozpoczyna si od funkcji mai n.

Do wiadczeni programi ci tworz cy w systemie Windows mog zastanawia si , gdzie podziała si funkcja WinMain.

background image

5

Nie ma jej, poniewa uruchamiana jest aplikacja konsolowa, wi c nie musimy tworzy adnego okna, ani obsługiwa

kolejki komunikatów. Za pomoc Win32 mo liwe jest tworzenie okien graficznych z poziomu aplikacji konsolowej,

podobnie jak mo na tworzy okna konsoli z poziomu aplikacji z interfejsem GUI. Wszystkie szczegóły zapisane s

wewn trz biblioteki GLUT. Trzeba pami ta , e ta biblioteka została zaprojektowana tak, eby ukrywa te wła nie

szczegóły działania platformy.

Tryb wy wietlania — pojedynczy bufor

W przedstawionej tutaj pierwszej linii kodu przekazujemy bibliotece GLUT informacj , jakiego trybu wy wietlania ma

u ywa w czasie tworzenia okna:

glutlnitDisplayMode(GLUT SINGLE | GLUTRGBA);

Podane tu znaczniki nakazuj bibliotece u ywa okna z pojedynczym buforem (GLUT_SINGLE) i trybu kolorów

RGBA (GLUT_RGBA). Okno z pojedynczym buforem oznacza, e wszystkie polecenia rysowania wykonywane s na

wy wietlanym wła nie oknie. Alternatyw jest okno z podwójnym buforowaniem, w którym polecenia rysowania

wykonywane s na nie wy wietlanym buforze, który jest nast pnie szybko przekazywany do widocznego okna. Ta

metoda jest cz sto stosowana do uzyskania efektu animacji, a jej zastosowanie demonstrowane jest w dalszej cz ci tego

rozdziału. Tak naprawd to trybu podwójnego buforowania b dziemy u ywa we wszystkich pozostałych przykładach

w tym tutorialu. Tryb koloru RGBA oznacza, e musimy osobno podawa intensywno ci wszystkich składowych koloru

— czerwonej (red), zielonej (green) i niebieskiej (blue). Alternatywnym trybem jest, aktualnie bardzo przestarzały, tryb

indeksowany, w którym podawany jest numer koloru we wcze niej zdefiniowanej palecie.

Tworzenie okna OpenGL

Nast pne wywołanie funkcji z biblioteki GLUT tworzy okno na ekranie. Poni sze polecenie tworzy nowe okno i nadaje

mu nagłówek Simple:

glutCreateWindow("Simple");

W jedynym parametrze funkcji glutCreateWindow przekazywany jest tekst nagłówka tworzonego okna.

Wy wietlaj ca funkcja zwrotna

W nast pnym wierszu naszego programu znajduje si wywołanie kolejnej funkcji biblioteki GLUT:

glutDisplayFunc(RenderScene);

W tej linii ustalamy, e zdefiniowana wcze niej funkcja RenderScene b dzie funkcj zwrotn {callback function)

wy wietlaj c obraz na ekranie. Oznacza to, e biblioteka GLUT b dzie wywoływa wskazan tu funkcj za ka dym

razem, gdy okno b dzie wymagało przerysowywania. Takie wywołanie nast pi przy pierwszym wy wietleniu okna, a

tak e przy zmianach jego rozmiaru albo odsłoni ciu. W tym wła nie miejscu umieszczamy wywołania funkcji

renderuj cych biblioteki OpenGL.

Ustalenie kontekstu i start

W nast pnym wierszu znajduje si polecenie niezwi zane ani z bibliotek GLUT, ani z OpenGL, ale jest to rozwi zanie,

którego b dziemy u ywa w całym tutorialu.

SetupRC();

W tej funkcji wykonujemy wszystkie inicjalizacje biblioteki OpenGL, jakie musz by zako czone przed rozpocz ciem

renderowania. Wiele ze stanów biblioteki OpenGL musi by ustalonych tylko raz i nie wymaga pó niejszych

modyfikacji przy renderowaniu ka dej ramki (przygotowywanej do wy wietlenia).

Ostatnie wywołaniem funkcji biblioteki GLUT znajduje si na ko cu programu:

glutMainLoop();

Ta funkcja uruchamia szkielet biblioteki GLUT. Po zdefiniowaniu funkcji zwrotnej obsługuj cej rysowanie na ekranie i

innych funkcji (powiemy o nich w dalszej cz ci) uruchamiany jest mechanizm biblioteki. Powrót z funkcji

glutMainLoop nast puje dopiero przy zako czeniu pracy programu, dlatego wystarczy wywoła j tylko raz. Funkcja ta

przetwarza wszystkie komunikaty systemu operacyjnego, naci ni cia klawiszy i inne, do czasu zako czenia pracy

background image

6

programu.

Wywołania graficzne OpenGL

W funkcji SetupRC znajduje si wywołanie pojedynczej funkcji OpenGL:

glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

funkcja ta ustala kolor stosowany do czyszczenia zawarto ci okna. Prototyp tej funkcji wygl da nast puj co:

void glClearColor(GLclampf red. GLclampf green. GLclampf blue. GLclampf alpha);

W wi kszo ci implementacji biblioteki OpenGL typ GLclapf zdefiniowany jest jako float. W OpenGL pojedynczy kolor

reprezentowany jest jako mieszanka składowych, czerwonej, zielonej i niebieskiej. Warto ka dej z nich musi mie ci

si w zakresie od 0.0 do 1.0. Jest to metoda podobna do specyfikacji stosowanej w systemie Windows, według której

kolory tworzone s za pomoc makra RGB daj cego w wyniku warto COLORREF. Ró nica polega na tym, e w

systemie Windows ka da składowa koloru w strukturze COLORREF mo e przyjmowa warto ci od 0 do 255, co w

wyniku daje 256x256x256, czyli ponad 16 milionów kolorów. W bibliotece OpenGL warto ka dej składowej koloru

mo e przyjmowa dowoln warto zmiennoprzecinkow z zakresu od 0 do i. co oznacza, e teoretycznie mo na

zdefiniowa niesko czon liczb kolorów. W praktyce mo liwo ci odtwarzania kolorów w wi kszo ci urz dze

ograniczone s do 24 bitów, czyli 16 milionów kolorów.

Oczywi cie, zarówno system Windows, jak i biblioteka OpenGL pobieraj warto koloru i przekształcaj j

wewn trznie do najbli szego koloru mo liwego do uzyskania na dost pnym sprz cie wideo.

W tabeli 2.2 wypisali my kilka typowych kolorów i warto ci ich składowych. Mo na z nich korzysta w ka dej funkcji

OpenGL zwi zanej z obsług kolorów.

Ostatni parametr funkcji glClearColor to składowa alfa, która jest stosowana do mieszania kolorów oraz specjalnych

efektów w rodzaju przezroczysto ci. Przezroczysto obiektu jest własno ci pozwalaj c na przenikanie wiatła przez

obiekt. Przypu my, e chcieliby my przygotowa kawałek szkła zabarwionego na czerwono, za którym umieszczone

zostałoby niebieskie ródło wiatła. Niebieskie wiatło wpłyn łoby na wygl d czerwonej barwy szkła — mieszanka

kolorów niebieskiego i czerwonego daje w efekcie kolor purpurowy. Warto składowej alfa mo na zastosowa do

uzyskania półprze roczystego koloru czerwonego, który wygl dałby jak talia szkła, zza której widoczne byłyby inne

obiekty. Taki efekt wi e si nie tylko z wykorzystaniem składowej alfa, ale na razie warto składowej alfa b dziemy

ustala na 1.

background image

7

Czyszczenie bufora kolorów

Do tej pory nakazali my bibliotece OpenGL u ywa koloru niebieskiego jako koloru czyszcz cego. W funkcji

RenderScene musimy teraz wykona wła ciw operacj czyszczenia:

glClear(GL_COLOR_BUFFER_BIT);

Funkcja glClear czy ci zawarto okre lonego bufora lub kombinacji buforów. Bufor jest obszarem w pami ci

przechowuj cym informacj o obrazie. Składowe czerwona, zielona i niebieska, tworz ce rysunek, zazwyczaj opisywane

s terminem bufora koloru (ang. color buffer) lub bufora pikseli (ang. pixel buffer).

W bibliotece OpenGL dost pnych jest kilka rodzajów buforów (koloru, gł bi, szablonowy i akumulacji). Na razie

wystarczy pami ta , e bufor koloru jest miejscem, w którym wewn trznie zapisywany jest wy wietlany obraz, a

czyszczenie tego bufora poleceniem glClear powoduje usuni cie z okna ostatniego obrazu.

Czyszczenie kolejki

W ko cu pojawia si ostatnie polecenie OpenGL:

glFlush();

Powoduje ono, e wszystkie niewykonane go tej pory polecenia OpenGL zostan wykonane. Jak na razie mamy tylko

jedno takie polecenie — glClear.

Biblioteka OpenGL wewn trznie korzysta z potoku renderuj cego sekwencyjnie przetwarzaj cego polecenia. Polecenia i

instrukcje OpenGL najcz ciej umieszczane s w kolejce do czasu, a sterownik OpenGL b dzie mógł przetworzy kilka

polece naraz. Takie działanie podnosi wydajno , poniewa komunikacja ze sprz tem jest z natury powolna. Jed-

nokrotne przesianie do karty graficznej wi kszej ilo ci danych jest znacznie szybsze ni wykonywanie kilku przesyłów,

po jednym dla ka dego polecenia lub instrukcji. W krótkim programie przedstawionym w powy szym listingu, funkcja

glFlush nakazuje bibliotece rozpocz cie przetwarzania dostarczonej do tej pory instrukcji, bez czekania na pojawianie si

kolejnych polece rysowania.

Program SIMPLE z cał pewno ci nie nale y do najciekawszych programów u ywaj cych biblioteki OpenGL, ale

dobrze obrazuje podstawy korzystania z okna za pomoc biblioteki GLUT, a tak e przedstawia sposób okre lania koloru

i czyszczenia zawarto ci okna. Teraz nieco rozbudujemy nasz program, dodaj c do niego kolejne funkcje z bibliotek

GLUT i OpenGL.

Rysowanie kształtów w OpenGL

Program SIMPLE tworzył puste okno z niebieskim tłem. Spróbujmy teraz co w tym oknie narysowa . Dodatkowo

spróbujemy uzyska mo liwo zmiany poło enia i rozmiaru okna, tak eby kod renderuj cy odpowiednio reagował na

te zmiany. Na poni szym listingu podano wszystkie potrzebne modyfikacje programu.

#include <OpenGL.h>

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

// Wywoływana w celu przerysowania sceny

void RenderScene(void)

{

// Wyczyszczenie okna aktualnym kolorem czyszcz cym

glClear(GL_COLOR_BUFFER_BIT);

// Aktualny kolor rysuj cy - czerwony

// R G B

glColor3f(1.0f, 0.0f, 0.0f);

// Narysowanie prostok ta wypełnionego aktualnym kolorem

glRectf(-25.0f, 25.0f, 25.0f, -25.0f);

// Wysłanie polece do wykonania

glFlush();

}

background image

8

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

// Konfiguracja stanu renderowania

void SetupRC(void)

{

// Ustalenie niebieskiego koloru czyszcz cego

glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

}

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

// Wywoływana przez bibliotek GLUT w przypadku zmiany rozmiaru okna

void ChangeSize(int w, int h)

{

GLfloat aspectRatio;

// Zabezpieczenie przed dzieleniem przez zero

if(h == 0)

h = 1;

// Ustawienie wielko ci widoku na równ wielko ci okna

glViewport(0, 0, w, h);

// Ustalenie układu współrz dnych

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

// Wyznaczenie przestrzeni ograniczaj cej (lewy, prawy, dolny, górny, bliski, odległy)

aspectRatio = (GLfloat)w / (GLfloat)h;

if (w <= h)

glOrtho (-100.0, 100.0, -100 / aspectRatio, 100.0 / aspectRatio, 1.0, -1.0);

else

glOrtho (-100.0 * aspectRatio, 100.0 * aspectRatio, -100.0, 100.0, 1.0, -1.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

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

// Główny punkt wej cia programu

int main(int argc, char* argv[])

{

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

glutInitWindowSize(800, 600);

glutCreateWindow("GLRect");

glutDisplayFunc(RenderScene);

glutReshapeFunc(ChangeSize);

SetupRC();

glutMainLoop();

return 0;

}

Poprzednio nasz program wykonywał wył cznie operacj czyszczenia ekranu. Teraz do kodu rysuj cego dodali my

nast puj ce wiersze:

//Aktualny kolor rysuj cy - czerwony

//

RGB

glColor3f(1.0f, 0.0f, 0.0f);

// Narysowanie prostok ta wypełnionego aktualnym kolorem glRectf(-25.0f, 25.0f, 25.0f, -25.0f);

W tych wierszach, wywołaniem funkcji glColor3f ustalamy kolor przyszłych operacji rysowania (linii i wypełnie ), a

nast pnie funkcj glRectf rysujemy sam prostok t.

Funkcja glColor3f pozwala na takie same wybranie koloru jak funkcja glClearColor, cho nie wymaga podania warto ci

przezroczysto ci alfa. Przyjmowana jest domy lna warto 1.0, co oznacza brak przezroczysto ci:

void glColor3f(GLfloat red. GLfloat green . GLfloat blue):

Funkcja glRectf pobiera parametry zmiennoprzecinkowe, co jest sygnalizowane ko cow liter

r

. W nazwie funkcji nie jest

podawana liczba parametrów, poniewa wszystkie warianty polecenia glRect pobieraj cztery parametry. Podane tu cztery

parametry funkcji g i Rectf definiuj dwie pary współrz dnych—(x1, y1) i ( x 2 , y2):

void glRectf(GLfloat x l . GLfloat yl. GLfloat x2. GLfloat y2);

Pierwsza para definiuje lewy górny róg prostok ta, a druga para — prawy dolny.

background image

9

W jaki sposób OpenGL przekłada te współrz dne na rzeczywiste pozycje w oknie? Wykonywane jest to wła nie w funkcji

zwrotnej ChangeSize. Funkcja ta zdefiniowana została jako funkcja zwrotna wywoływana za ka dym razem, gdy zmienia

si rozmiar okna (w momencie rozci gni cia, maksymalizacji itp.). Wyznaczenie tej funkcji odbywa si w bardzo podobny

sposób jak wyznaczenie wy wietlaj cej funkcji zwrotnej:

glutReshaceFunc(ChangeSize):

Za ka dym razem, gdy zmienia si wielko lub dowolny wymiar okna, konieczne jest ponowne ustalenie układu

współrz dnych.

Skalowanie do okna

W niemal wszystkich rodowiskach okienkowych u ytkownik mo e w dowolnym momencie zmieni wielko i wymiary

okna. Nawet je eli tworzymy gr cały czas działaj c na pełnym ekranie, to i tak okno raz zmienia swoj wielko — przy

uruchomieniu programu. W takim wypadku okno reaguje ponownym rozrysowaniem swojej zawarto ci, przy czym pod

uwag brane s nowe wymiary okna. Czasami mo e si zdarzy , e dla małych okien konieczne mo e by przyci cie obrazu,

a wi kszych oknach — wy wietlenie obrazu w jego oryginalnym rozmiarze. W naszych przykładach najcz ciej b dziemy

starali si tak przcskalowa rysunek, eby dostosowa go do wymiarów okna, niezale nie od wielko ci rysunku lub okna. W

efekcie w małym oknie znajdzie si pełny, cho niewielki rysunek, a w du ym oknie rysunek b dzie miał taki sam wygl d,

cho wi kszy rozmiar. Ten efekt bardzo cz sto mo na zobaczy w programach do rysowania, w których inne działanie ma

rozci ganie okna, a inne zmiana rozmiaru obrazka. Najcz ciej rozci gni cie okna nie powoduje zmiany rozmiaru obrazka,

ale powi kszenie obrazu sprawia, e i okno si powi ksza.

Ustawienie widoku i przestrzeni ograniczaj cej

Omawiali my ju sposób, w jaki widok i przestrze widoczna wpływaj na zakres współrz dnych i skalowanie rysunków

dwu- i trójwymiarowego w dwuwymiarowym oknie na ekranie komputera. Teraz zajmiemy si ustaleniem współrz dnych

widoku i przestrzeni ograniczaj cej w bibliotece OpenGL.

Mimo e nasz rysunek jest dwuwymiarowym płaskim prostok tem, to i tak rysujemy w przestrzeni współrz dnych

trójwymiarowych. Funkcja glRectf rysuje prostok t na płaszczy nie xy ze współrz dn z równ 0 (z=0). Nasza

perspektywa ustawiona jest wzdłu dodatnich warto ci osi z, tak eby widoczny był prostok t narysowany na zerowej

współrz dnej z.

Przy ka dej zmianie rozmiaru okna, widok i przestrze ograniczaj ca musz by zdefiniowane na nowo, tak aby dostosowa je

do nowych rozmiarów okna. W przeciwnym razie uzyskamy efekt podobny do przedstawionego na rysunku 2.7, w którym

odwzorowanie układu współrz dnych na współrz dne ekranowe pozostaje niezmienne bez wzgl du na zmiany rozmiarów

okna.

Ze wzgl du na to, e zmiany rozmiaru okna w ró nych rodowiska s wykrywane i obsługiwane odmiennie, biblioteka GLUT

wprowadza funkcj glutReshapeFunc rejestruj c funkcj zwrotn wywoływan przez bibliotek przy ka dej zmianie

background image

10

rozmiarów okna. Funkcja przekazywana do glutReshapeFunc prototypowana jest w nast puj cy sposób:

void ChangeSize(GLsizei w, GLsizei h);

Wybrali my dla tej funkcji opisow nazw ChangeSize (zmie rozmiar), której konsekwentnie b dziemy u ywa tak e w

kolejnych przykładach.

Funkcja ChangeSize otrzymuje w parametrach now szeroko i wysoko okna, gdy tylko zmieni si jego rozmiar. Mo emy

u y tych informacji do zmodyfikowania odwzorowania potrzebnego nam układu współrz dnych na współrz dne

rzeczywistego ekranu. Operacj t wykonamy za pomoc dwóch funkcji: glViewport i glOrtho.

Definiowanie widoku

Aby zrozumie metod uzyskiwania definicji widoku, musimy dokładniej przyjrze si zawarto ci funkcji ChangeSize.

Na pocz tku wywoływana jest w niej funkcja glViewport z podanymi nowymi warto ciami szeroko ci i wysoko ci okna.

Funkcja glViewport zdefiniowana jest nast puj co:

void glViewport(GLint x, Glint y, GLsizei width. GLsizei height):

Parametry x i y okre laj pozycj dolnego lewego rogu widoku wewn trz okna, a parametry width i height definiuj

rozmiar tego widoku w pikselach. Najcz ciej warto ci parametrów x i y ustalane s na 0, ale widoków mo na u ywa te

do renderowania kilku rysunków w ró nych obszarach okna. Widok definiuje obszar wewn trz okna podawany we

współrz dnych ekranu, którego OpenGL mo e u ywa do rysowania (zobacz rysunek 2.8). Nast pnie aktualna przestrze

ograniczaj ca odwzorowywana jest w nowym widoku. Je eli zdefiniujemy widok mniejszy od współrz dnych okna, to

renderowany obraz po przeskalowaniu równie b dzie mniejszy, co wida na rysunku 2.8.

Definiowanie widocznej przestrzeni ograniczaj cej

Ostatnim wymaganiem w stosunku do naszej funkcji ChangeSize jest ponowne zdefiniowanie przestrzeni ograniczaj cej

w taki sposób, aby współczynnik kształtu obrazu (aspect ratio) pozostał niezmieniony. Współczynnik kształtu obrazu to

stosunek liczby pikseli w jednostce długo ci w kierunku pionowym, do liczby pikseli w jednostce długo ci w kierunku

poziomym. Współczynnik kształtu obrazu o warto ci 1.0 definiuje obraz kwadratowy, natomiast współczynnik o warto ci

0.5 definiuje obraz, w którym na jeden piksel w jednostce długo ci w kierunku pionowym przypadaj dwa piksele w tej

samej jednostce długo ci w kierunku poziomym.

Je eli zdefiniujemy niekwadratowy widok, w którym odwzorowywana jest kwadratowa przestrze ograniczaj ca, to

otrzymamy obraz zniekształcony. Na przykład widok o wymiarach identycznych z rozmiarami okna, w którym

odwzorowywana jest kwadratowa przestrze ograniczaj ca, mo e w w skich, ale wysokich oknach przedstawia w skie i

wysokie obrazy, a w oknach niskich i szerokich — obrazy niskie i szerokie. W takim przypadku narysowany przez nas

kwadrat b dzie faktycznie wygl dał jak kwadrat tylko wtedy, gdy rozmiar okna b dzie kwadratem.

W naszym przykładzie do przestrzeni ograniczaj cej zastosowali my rzutowanie prostopadle. W bibliotece OpenGL

funkcj tworz c takie rzutowanie jest funkcja glOrtho:

void glOrtho(GLdouble left. GLdouble right. GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);

W trójwymiarowej przestrzeni kartezja skiej warto ci left i right okre laj minimaln i maksymaln współrz dn na osi

x, a warto ci bottom i top — na osi y. Warto ci near i far dotycz osi z, przy czym najcz ciej warto ci ujemne rosn

background image

11

wraz z oddalaniem si od widza (rysunek 2.9). Wiele bibliotek graficznych i rysunkowych w poleceniach ryso-wania

u ywa współrz dnych okna (pikseli). Nowym u ytkownikom biblioteki OpenGL bardzo trudno si przyzwyczai do

korzystania ze współrz dnych zmiennoprzecinkowych (sprawiaj cych wra enie z niczym niezwi zanych), jednak po

napisaniu kilku programów takie działanie staje si drug natur programisty.


Prosz zwróci uwag na dwie funkcje umieszczone tu przed wywołaniem funkcji glOrtho:

// Ustalenie układu współrz dnych

glMatrixMode(GL_PROJECTION); glLoadldentity();

Macierz rzutowania jest miejscem, w którym rzeczywi cie definiujemy nasz przestrze widoczn . Pojedyncze

wywołanie funkcji glLoadIdentit.y jest konieczne, poniewa funkcja glOrtho tak naprawd nie tworzy przestrzeni

ograniczaj cej, ale modyfikuje istniej c przestrze . Mno y ona macierz opisuj c aktualn przestrze ograniczaj c

przez macierz opisuj c przestrze ograniczaj c podan w parametrach. Na razie wystarczy zapami ta , e funkcja

glLoadIdentity słu y do ponownego ustawienia (resetu) układu współrz dnych, zanim wykonane zostan jakiekolwiek

manipulacje na macierzach. Bez ponownego ustawienia ukfadu współrz dnych przed ka dym wywołaniem funkcji

glOrtho ka de kolejne wywołanie powodowałoby coraz wi ksze zniekształcenia planowanej przestrzeni ograniczaj cej,

co w efekcie mogłoby nawet doprowadzi do znikni cia kwadratu z ekranu.

Ostatnie dwa przedstawione tutaj wiersze kodu informuj bibliotek OpenGL, e wszystkie przyszłe przekształcenia b d

dotyczyły naszych modeli, czyli tego, co narysujemy:

glMatrixMode(GL_MODELVIEW);

glLoadldentity();

Musimy jednak ju teraz poda informacje o sposobie konfigurowania tych operacji ich warto ciami domy lnymi. Je eli

tego nie zrobimy i pozwolimy na eksperymentowanie, to wy wietlany przez program obraz mo e by daleki od naszych

oczekiwa .

Aby kwadrat był kwadratem

Poni szy kod zajmuje si utrzymaniem „kwadratowo ci" naszego kwadratu:

// Wyznaczenie przestrzeni ograniczaj cej (lewy, prawy, dolny, górny, bliski, odległy)

aspectRatio = (GLfloat)w / (GLfloat)h:
if (w <= h)

glOrtho (-100.0, 100.0, -100 / aspectRatio, 100.0 / aspectRatio, 1.0, -1.0);

else

glOrtho (-100.0 * aspectRatio, 100.0 * aspectRatio, -100.0, 100.0, 1.0, -1.0):

Nasza przestrze ograniczaj ca (widoczny układ współrz dnych) modyfikowana jest w ten sposób, e lewa strona

zawsze ma warto x=-100, a prawa strona rozci ga si do warto ci 100, chyba e szeroko okna jest wi ksza od jego

wysoko ci. Na podobnej zasadzie dół przestrzeni ograniczaj cej zawsze ma warto y=-100, a góra rozci ga si do

background image

12

warto ci 100, chyba e wysoko okna jest wi ksza od jego szeroko ci. W takim przypadku, górna współrz dna równie

skalowana jest współczynnikiem kształtu ekranu. W ten sposób, niezale nie od kształtu okna, utrzymywany jest

kwadratowy region o wymiarach 200x200, którego rodek ma współrz dne (0.0). Rysunek 2.10 przedstawia zasad

działania tego mechanizmu.

background image

13

Animacja w OpenGL i GLUT

Jak na razie omawiali my podstawy u ytkowania biblioteki GLUT w zakresie tworzenia okien i korzystania z rysuj cych

polece OpenGL. Bardzo cz sto b dziemy chcieli przesun nasz scen albo j obróci , tworz c w ten sposób efekt

animacji. We miemy teraz poprzedni przykład z rysowanym kwadratem i sprawimy, e b dzie si on odbijał od ram

okna. Mo emy przygotowa p tl , w której b dziemy zmienia współrz dne obiektu przed wywołaniem funkcji

RenderScene. Spowoduje to, e kwadrat b dzie sprawiał wra enie ruchu wewn trz okna.

Biblioteka GLUT pozwala na zarejestrowanie specjalnej funkcji zwrotnej ułatwiaj cej wykonywanie prostych sekwencji

animacji. Umo liwia to funkcja glutTimerFunc, pobieraj ca nazw funkcji zwrotnej i interwał, z jakim ta funkcja ma

by wywoływana:

void glutTimerfunc(unsigned int msecs, void (*func)(int value). int value);

Funkcja ta nakazuje bibliotece GLUT odczekiwa msecs milisekund przed ka dym wywołaniem funkcji func. W

parametrze vdlue mo na do tej funkcji przekazywa zdefiniowane przez u ytkownika warto ci. Funkcja wywoływana co

okre lony czas prototypowana jest w nast puj co:

void TimerFunction(int value);

Przeciwnie ni w mechanizmach czasowych systemu Windows, funkcja ta wywoływana jest tylko raz. Aby uzyska efekt

ci głej animacji w samej funkcji czasowej, musimy ponownie ustawi mechanizm czasowy.

W programie GLRect zmienimy teraz zapisane na stałe warto ci pozycji naszego prostok ta, zast puj c je zmiennymi, a

nast pnie b dziemy cały czas modyfikowa te zmienne w wywoływanej cyklicznie funkcji czasowej. W ten sposób

prostok t zacznie porusza si wewn trz okna. Przyjrzyjmy si przykładowi tego rodzaju animacji. Na poni szym

listingu znajduje si zmodyfikowany program z listingu poprzedniego, do którego dodano funkcj animacji kwadratu

odbijaj cego si od ram okna. Musimy cały czas kontrolowa pozycj i wielko kwadratu, jak równie wszystkie

zmiany wielko ci okna.

#include <OpenGL.h>

// Pocz tkowy rozmiar i pozycja prostok ta

GLfloat x = 0.0f;

GLfloat y = 0.0f;

GLfloat rsize = 25;

// Rozmiar kroku (liczba pikseli) w osi x i y

GLfloat xstep = 1.0f;

GLfloat ystep = 1.0f;

// Dane zmieniaj cych si rozmiarów okna

GLfloat windowWidth;

GLfloat windowHeight;

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

// Wywoływana w celu przerysowania sceny

void RenderScene(void)

{

// Wyczyszczenie okna aktualnym kolorem czyszcz cym

glClear(GL_COLOR_BUFFER_BIT);

// Aktualny kolor rysuj cy - czerwony

// R G B

glColor3f(1.0f, 0.0f, 0.0f);

// Narysowanie prostok ta wypełnionego aktualnym kolorem

glRectf(-25.0f, 25.0f, 25.0f, -25.0f);

// Wysłanie polece do wykonania

glFlush();

}

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

// Wywoływana przez bibliotek GLUT w czasie, gdy okno nie

// jest przesuwane ani nie jest zmieniana jego wielko

void TimerFunction(int value)

{

// Odwrócenie kierunku, je eli osi gni to lew lub praw kraw d

if(x1 > windowWidth-rsize || x1 < -windowWidth)

xstep = -xstep;

// Odwrócenie kierunku, je eli osi gni to doln lub górn kraw d

if(y1 > windowHeight || y1 < -windowHeight + rsize)

ystep = -ystep;

background image

14

// Wykonanie przesuni cia kwadratu

x1 += xstep;

y1 += ystep;

// Kontrola obramowania. Wykonywana jest na wypadek, gdyby okno

// zmniejszyło swoj wielko w czasie, gdy kwadrat odbijał si od

// kraw dzi, co mogłoby spowodowa , e znalazł by si poza

// przestrzeni ograniczaj c .

if(x1 > (windowWidth-rsize + xstep))

x1 = windowWidth-rsize-1;

else if(x1 < -(windowWidth + xstep))

x1 = -windowWidth -1;

if(y1 > (windowHeight + ystep))

y1 = windowHeight-1;

else if(y1 < -(windowHeight - rsize + ystep))

y1 = -windowHeight + rsize - 1;

// Ponowne rysowanie sceny z nowymi współrz dnymi

glutPostRedisplay();

glutTimerFunc(33,TimerFunction, 1);

}

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

// Konfigurowanie stanu renderowania

void SetupRC(void)

{

// Ustalenie niebieskiego koloru czyszcz cego

glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

}

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

// Wywoływana przez bibliotek GLUT przy ka dej zmianie wielko ci okna

void ChangeSize(GLsizei w, GLsizei h)

{

GLfloat aspectRatio;

// Zabezpieczenie przed dzieleniem przez zero

if(h == 0)

h = 1;

// Ustalenie wielko ci widoku zgodnego z rozmiarami okna

glViewport(0, 0, w, h);

// Ustalenie układu współrz dnych

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

// Ustanowienie przestrzeni ograniczaj cej (lewo, prawo, dół, góra, blisko, daleko)

aspectRatio = (GLfloat)w / (GLfloat)h;

if (w <= h)

{

windowWidth = 100;

windowHeight = 100 / aspectRatio;

glOrtho (-100.0, 100.0, -windowHeight, windowHeight, 1.0, -1.0);

}

else

{

windowWidth = 100 * aspectRatio;

windowHeight = 100;

glOrtho (-windowWidth, windowWidth, -100.0, 100.0, 1.0, -1.0);

}

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

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

// Główny punkt wej cia programu

void main(void)

{

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

glutCreateWindow("Bounce");

glutDisplayFunc(RenderScene);

glutReshapeFunc(ChangeSize);

glutTimerFunc(33, TimerFunction, 1);

SetupRC();

glutMainLoop();

}

background image

15

Podwójne buforowanie

Jedn z najwa niejszych funkcji ka dego pakietu graficznego jest obsługa podwójnego buforowania. Funkcja ta pozwala

na wykonywanie kodu rysuj cego na buforze niewidocznym na ekranie. Nast pnie poleceniem podmiany narysowany w

ten sposób obraz umieszczany jest natychmiast na ekranie.

Mechanizm podwójnego buforowania ma słu y dwóm celom. Po pierwsze, rysowanie pewnych bardziej

skomplikowanych rysunków mo e zaj do du o czasu, co mo e powodowa , e na ekranie widoczne b d kolejne

kroki tworzenia obrazu. Za pomoc podwójnego buforowania obraz mo e by najpierw przygotowany, a dopiero pó niej

wy wietlony na ekranie. W efekcie u ytkownik nigdy nie b dzie miał okazji zobaczy cz ciowo utworzonego rysunku.

Drugim zastosowaniem podwójnego buforowania jest animacja. Ka da ramka rysowana jest w niewy wietlanym buforze,

a nast pnie szybko umieszczana na ekranie poprzez zamian buforów — widocznego i niewidocznego. Biblioteka GLUT

pozwala na u ywanie okien z podwójnym buforowaniem. Prosz na powy szym listingu zauwa y nast puj cy wiersz:

glutInitDIsplayMode(GLUT_DOUBLE | GLUT_RGB);

Zmienili my stał GLUT_SINGLE na GLUT_DOUBLE. Ta zmiana powoduje, e wszystkie polecenia działaj na buforze
niewidocznym.

Nast pnie, zmienili my te ko cówk funkcji RenderScene:

// Wysłanie polece do wykonania i zamiana buforów

glutSwapBuffers();

Terazju nie wywołujemy funkcji glFlush. Nie jest ona ju potrzebna, poniewa zamiana buforów powoduje niejawne

wykonania operacji czyszczenia bufora polece .

Wprowadzone zmiany tworz w oknie płynn animacj kwadratu odbijaj cego si od kraw dzi okna. Funkcja

glutSwapBuffers powoduje wyczyszczenie bufora polece , nawet je eli działaliby my w trybie pojedynczego buforo-

wania. Aby zobaczy , jak ta sama animacja wygl da b dzie w trybie buforowania pojedynczego, wystarczy w

programie zmieni stał GLUT_DOUBLE na GLUT_SINGLE. Jak mo na zauwa y , kwadrat cały czas zacina si i

migocze — w trybie pojedynczego buforowania efektu animacji nie mo na nazwa zadowalaj cym.

Biblioteka GLUT stanowi wzgl dnie prost podstaw dla tworzenia zło onych programów przykładowych, a nawet

rozbudowanych aplikacji komercyjnych (zakładaj c, e nie potrzeba nam funkcji systemu operacyjnego i interfejsu

GUI). Zadaniem tego tutorialu nie jest jednak opisywanie biblioteki GLUT w całej jej wielko ci. B dziemy ogranicza

si do opisywania jedynie niewielkich wycinków tej biblioteki, koniecznych do zademonstrowania ró nych funkcji

biblioteki OpenGL.

Maszyna stanów OpenGL

Rysowanie grafik trójwymiarowych to zadanie bardzo zło one. W kolejnych rozdziałach opisywa b dziemy ró ne

funkcje biblioteki OpenGL. Wiele ró nych efektów mo e wpływa na sposób rysowania ka dego wycinka geometrii.

Czy pada na niego wiatło? Jakie s wła ciwo ci tego wiatła? Jakie s wła ciwo ci materiału? Jak tekstur nale y

zastosowa ? Czy w ogóle stosowa jak kolwiek tekstur ? List takich pyta mo na by jeszcze długo rozbudowywa .

T kolekcj zmiennych nazywamy stanem potoku. Maszyna stanów jest abstrakcyjnym modelem kolekcji zmiennych

stanu, z których ka da mo e przyjmowa ró ne warto ci, by wł czana lub wył czana itd. Okre lanie wszystkich

zmiennych stanu, za ka dym razem gdy chcemy co narysowa , nie jest praktyczne, dlatego biblioteka OpenGL

wprowadza model stanów (lub maszyn stanów) zapami tuj cy warto ci wszystkich zmiennych stanu. Gdy jakiej

zmiennej nadawana jest warto , to pozostaje ona niezmieniona do czasu, a zmieni j jaka inna funkcja. Wiele

zmiennych stanów jest po prostu wł czana i wył czana. Na przykład o wietlenie mo na wł cza i wył cza . Obiekty

rysowane bez wł czonego o wietlenia s rysowane bez wykonywania jakichkolwiek oblicze o wietlenia wpływaj cego

na zcsiaw kolorów zastosowany w obiekcie. Ten sam obiekt rysowany po wł czeniu o wietlenia rysowany jest z

zastosowaniem oblicze o wietlenia.

Aby wł czy ten rodzaj zmiennych stanu, nale y u y nast puj cej funkcji OpenGL:

void glEnable(GLenum capability);

background image

16

T sam zmienn mo na pó niej wył czy za pomoc nast puj cej funkcji:

void glDisable(Glenum capability);

W przypadku o wietlenia, poni sz instrukcj mo na wł czy odpowiedni stan:

glEnable(GL_LIGHTING);

Wył czanie tego stanu odbywa si poprzez wywołanie poni szej instrukcji:

glDisable(GL_LIGHTING);

Je eli chcieliby my sprawdzi , czy jaka zmienna stanu jest wł czona, to biblioteka OpenGL udost pnia nam do tego celu

odpowiedni funkcj :

GLboolean glIsEnabled(GLenum capability);

Jednak nic wszystkie zmienne mog by tylko wł czane i wył czane. Wiele innych funkcji OpenGL, które dopiero b dziemy

opisywa , mo e przyjmowa warto ci zapami tywane do czasu ich zmiany. Mo emy te w dowolnym momencie

sprawdzi , jakie warto ci przechowywane s w tych zmiennych. Dost pny jest w tym celu zestaw funkcji pozwalaj cych na

sprawdzenie warto ci logicznych, całkowitych, zmiennoprzecinkowych pojedynczej oraz podwójnej precyzji. Prototypy tych

czterech funkcji wygl daj nast puj co:

void glGetBooleanv(GLenum pname. GLboolean *params);

void glGetDoublev(GLenum pname, GLdouble *params);

void glGetFloatv(GLenum pname, GLfloat *params);

void glGetIntegerv(GLenum pname. GLint *params);

Ka da z funkcji mo e zwróci pojedyncz warto lub cał tablic warto ci, które zapisywane s pod podanym adresem.
Wi kszo z tych funkcji z pewno ci nie b dzie od razu zrozumiała, ale wraz z do wiadczeniem ro nie równie zrozumienie.

Zapisywanie i odtwarzanie stanów

Biblioteka OpenGL posiada równie bardzo wygodny mechanizm zapisywania i odtwarzania całych zakresów warto ci

stanu. Stos jest wygodn struktur danych pozwalaj c na odkładanie warto ci (push) i pó niejsze zdj cie ich ze stosu (pop).

Elementy s zdejmowane ze stosu w kolejno ci odwrotnej do kolejno ci kładzenia ich na stosie. Tak struktur nazywa si

UFO (ang. Last In First Out — ostatni przyszedł, pierwszy wyjdzie). Mo na j prosto opisa w nast puj cy sposób: mówi c:

„Prosz , zachowaj to dla mnie", zapisujemy dane na stos, a pó niej, mówi c: „Oddaj mi to, co wła nie zapisałem", zdej-

mujemy dane ze stosu. Idea stosu odgrywa znacz c rol w manipulacjach macierzami.

Poni szym poleceniem mo emy zapisa na stos atrybutów zarówno pojedyncz warto stanu, jak i cały ich zbiór:

void glPushAttrib(GLbitfield mask);

Odpowiednio, te same warto ci mog by odczytane za pomoc tego polecenia:

void glPopAttrib(GLbitfield mask):

Prosz zauwa y , e parametrem tych funkcji jest warto typu bitfield (pole bitowe). Oznacza to, e musimy stosowa
mask bitow , która pozwala na wykonywanie bitowej operacji sumy logicznej (OR — w j zyku C reprezentowanej przez
operator |), dzi ki czemu w jednym wywołaniu funkcji mo na zapisa kilka warto ci zmiennych stanu. Na przykład mo emy
zapisa stan o wietlenia i teksturowania, wywołuj c nast puj ce polecenie:

glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT);

background image

17

Rysowanie 3D

Rysowanie punktów

Zaczniemy od pierwszych i najprostszych obiektów podstawowych — punktów. Przyjrzyjmy si poni szemu kodowi:

glBegin(GL_POINTS);

//Obiektami podstawowymi b d punkty

glVertex3f(0.0f. O.0f. O.Of):

//Definiujemy punkt

glVertex3f(50.0f, 50.Of, 50. 0f);

//Definiujemy kolejny punkt

g lEnd ():

// Koniec rysowania punktów

Parametr funkcji glBegin — GL_POINTS — nakazuje bibliotece OpenGL interpretowa wszystkie podawane

wierzchołki jako punkty do rysowania. W przykładzie zdefiniowano dwa wierzchołki, które przekładaj si na dwa

punkty rysowane na ekranie.

Ten przykład uwydatnia bardzo wa n rzecz, o której trzeba pami ta , stosuj c funkcje glBegin i glEnd — mi dzy ich

wywołaniami mo emy podawa cał list obiektów podstawowych pod warunkiem, e s one tego samego typu. W ten

sposób jedn sekwencj funkcji glBegin i glEnd mo emy doda do sceny dowoln liczb obiektów podstawowych.

Poni szy segment kodu dla odmiany b dzie wykonywał si znacznie wolniej ni podany wcze niej:

gl Begm(GL_POINTS);

// Definiujemy punkt do rysowania

glVertex3f(0.0f, 0.0f, 0.0f);

glEnd();

g1Begin(GL_POINTS):

// Definiujemy kolejny punkt

glVertex3f(50 0f, 50.0f, 50.0f);

glEnd() ;

Nasz pierwszy przykład

Kod z poni szego listingu rysuje w rodowisku trójwymiarowym kilka punktów. Program stosuje proste
obliczenia trygonometryczne do wyznaczenia pozycji serii punktów tworz cych co w rodzaju korkoci gu
wokół osi z. Kod pochodzi z programu POINTS, który mo na pobra wraz z tym tutorialem. Nale y zauwa y ,

e w funkcji SetupRC ustalamy aktualny kolor rysuj cy na zielony.

#include <math.h>

// Definiujemy stał o warto ci liczby PI

#define GL_PI 3.1415f

// Wielko obrotów

static GLfloat xRot = 0.0f;

static GLfloat yRot = 0.0f;

// Wywoływana w celu przerysowania sceny

void RenderScene(void)

{

GLfloat x,y,z,angle; // Zmienne przechowuj ce współrz dne i k ty

// Wyczyszczenie okna aktualnym kolorem czyszcz cym

glClear(GL_COLOR_BUFFER_BIT);

// Zapisanie stanu macierzy i wykonanie obrotu

glPushMatrix();

glRotatef(xRot, 1.0f, 0.0f, 0.0f);

glRotatef(yRot, 0.0f, 1.0f, 0.0f);

// Wywoła tylko raz, przed rysowaniem wszystkich punktów

glBegin(GL_POINTS);

z = -50.0f;

for(angle = 0.0f; angle <= (2.0f*GL_PI)*3.0f; angle += 0.1f)

{

x = 50.0f*sin(angle);

y = 50.0f*cos(angle);

background image

18

// Okre lenie punktu i przesuni cie współrz dnej Z

glVertex3f(x, y, z);

z += 0.5f;

}

// Zako czenie rysowania punktów

glEnd();

// Odtworzenie macierzy przekształce

glPopMatrix();

// Wykonanie polece rysowania

glutSwapBuffers();

}

// Ta funkcja wykonuje wszystkie konieczne inicjalizacje kontekstu renderowania

void SetupRC()

{

// Czarne tło

glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

// B dziemy rysowa kolorem zielonym

glColor3f(0.0f, 1.0f, 0.0f);

}

void SpecialKeys(int key, int x, int y)

{

if(key == GLUT_KEY_UP)

xRot-= 5.0f;

if(key == GLUT_KEY_DOWN)

xRot += 5.0f;

if(key == GLUT_KEY_LEFT)

yRot -= 5.0f;

if(key == GLUT_KEY_RIGHT)

yRot += 5.0f;

if(key > 356.0f)

xRot = 0.0f;

if(key < -1.0f)

xRot = 355.0f;

if(key > 356.0f)

yRot = 0.0f;

if(key < -1.0f)

yRot = 355.0f;

// Od wie enie zawarto ci okna

glutPostRedisplay();

}

void ChangeSize(int w, int h)

{

GLfloat nRange = 100.0f;

// Zabezpieczenie przed dzieleniem przez zero

if(h == 0)

h = 1;

// Ustalenie wymiarów widoku na zgodnych z wymiarami okna

glViewport(0, 0, w, h);

// Ponowne ustawienie stosu macierzy rzutowania

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

// Utworzenie przestrzeni ograniczaj cej (lewo, prawo, dół, góra, blisko, daleko)

if (w <= h)

glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);

else

glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

// Ponowne ustawienie stosu macierzy rzutowania

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

int main(int argc, char* argv[])

{

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

background image

19

glutCreateWindow("Points Example");

glutReshapeFunc(ChangeSize);

glutSpecialFunc(SpecialKeys);

glutDisplayFunc(RenderScene);

SetupRC();

glutMainLoop();

return 0;

}

W tym i pozostałych przykładach z tego rozdziału dla naszych celów wa ny jest jedynie kod pomi dzy

wywołaniami funkcji glBegin i glEnd. Powy szy kod wylicza współrz dne x i y na podstawie k ta trzykrotnie

rosn cego od warto ci 0° do 360°. W programie przedstawiamy te warto ci w radianach, a nie w stopniach; kto nie

zna trygonometrii, musi uwierzy na słowo. Przy rysowaniu ka dego punktu warto współrz dnej z powi kszana jest

o niewielk warto . Po uruchomieniu programu zobaczymy na ekranie koło składaj ce si z samych punktów.

Wynika to z tego, e pocz tkowo b dziemy patrze wzdłu osi z. Aby zobaczy cał spiral , nale y naciskaj c

klawisze strzałek, obróci rysunek wokół osi x i y.

Ustalanie wielko ci punktu

W czasie rysowania pojedynczego punktu domy ln wielko ci tego punktu jest jeden piksel. Mo na to zmieni , stosuj c

funkcj glPointSize:

void glPointSize(GLfloat size):

Funkcja glPointSize pobiera jeden parametr okre laj cy przybli on wielko rysowanego punktu podan w

pikselach. Niestety, nie mo na poda dowolnego rozmiaru punktu, dlatego nale y si upewni , czy podawany

rozmiar b dzie prawidłowo obsłu ony. Mo na u y poni szego kodu w celu sprawdzenia zakresu dost pnych

rozmiarów punktów i najmniejszych odst pów mi dzy nimi.

GLfloat sizes[2];

// Do zapisania dopuszczalnego zakresu wielko ci

GLfloat step;

//Zapami tuje obsługiwany przyrost rozmiaru

// Pobranie dopuszczalnych rozmiarów punktów

glGetFloatv(GL_POINT_SIZE_RANGE, s i z e s ) ;

glGetFloatv(GL_POINT_SIZE_GRANULARITY, &step);

W tablicy sizes znajd si dwa elementy okre laj ce najmniejsz i najwi ksz warto przyjmowan przez funkcj gl PointSi

ze. Dodatkowo zmienna step przechowywa b dzie rozmiar dopuszczalnego kroku pomi dzy kolejnymi rozmiarami punktu.

Specyfikacja biblioteki OpenGL wymaga tylko, eby obsługiwany był jeden rozmiar punku — 1.0. Na przykład

implementacja biblioteki przygotowana przez Microsoft pozwala na stosowanie punktów o wielko ci od 0.5 do 10.0 z

minimalnym krokiem 0.125. Podanie rozmiaru spoza dopuszczalnego zakresu nie jest traktowane jako bł d, po prostu

stosowany b dzie rozmiar najbli szy podanemu.

W przeciwie stwie do obiektów geometrycznych punkty nie podlegaj wpływowi perspektywy. Oznacza to, e nie staj si

one mniejsze wraz z oddalaniem si od widza i nie powi kszaj si wraz z przybli aniem si . Poza tym punkty zawsze maj

kształt kwadratu, nawet je eli za pomoc funkcji gl PointSi ze powi kszymy ich rozmiar. Na ekranie zobaczymy tylko coraz

wi ksze kwadraty! Aby uzyska punkty okr głe, musimy rysowa je z wł czonym efektem antyaliasingu. Przyjrzyjmy si

przykładowi wykorzystuj cemu te nowe funkcje. Kod z poni szego listingu tworzy tak sam spiral co kod z pierwszego

przykładu, ale tym razem punkty s stopniowo powi kszane od najmniejszej mo liwej warto ci, do najwi kszej. Przykład

pochodzi z programu POINTSZ który mo na pobra wraz z tym tutorialem.

// Definiujemy stał o warto ci liczby PI

#define GL_PI 3.1415f

// Wielko obrotów

static GLfloat xRot = 0.0f;

static GLfloat yRot = 0.0f;

// Wywoływana w celu przerysowania sceny

void RenderScene(void)

{

GLfloat x,y,z,angle;

// Zmienne przechowuj ce współrz dne i k ty

GLfloat sizes[2];

// Do zapisania dopuszczalnego zakresu wielko ci

GLfloat step;

// Zapami tuje obsługiwany przyrost rozmiaru

GLfloat curSize;

// Zapami tuje aktualny rozmiar

background image

20

// Wyczyszczenie okna aktualnym kolorem czyszcz cym

glClear(GL_COLOR_BUFFER_BIT);

// Zapisanie stanu macierzy i wykonanie obrotu

glPushMatrix();

glRotatef(xRot, 1.0f, 0.0f, 0.0f);

glRotatef(yRot, 0.0f, 1.0f, 0.0f);

// Pobranie dopuszczalnych rozmiarów punktów

glGetFloatv(GL_POINT_SIZE_RANGE,sizes);

glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);

// Ustalenie pocz tkowego rozmiaru punktu

curSize = sizes[0];

// Ustalenie pocz tkowej współrz dnej z

z = -50.0f;

// Obracamy si w kółko trzy razy

for(angle = 0.0f; angle <= (2.0f*3.1415f)*3.0f; angle += 0.1f)

{

// Wyliczenie warto ci x i y na kole

x = 50.0f*sin(angle);

y = 50.0f*cos(angle);

// Zdefiniowanie rozmiaru punktu przed utworzeniem obiektu podstawowego

glPointSize(curSize);

// Rysowanie punktu

glBegin(GL_POINTS);

glVertex3f(x, y, z);

glEnd();

// Powi kszenie współrz dnej z i rozmiaru punktu

z += 0.5f;

curSize += step;

}

// Odtworzenie macierzy przekształce

glPopMatrix();

// Wykonanie polece rysowania

glutSwapBuffers();

}

// Ta funkcja wykonuje wszystkie konieczne inicjalizacje kontekstu renderowania

void SetupRC()

{

// Czarne tło

glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

// B dziemy rysowa kolorem zielonym

glColor3f(0.0f, 1.0f, 0.0f);

}

void SpecialKeys(int key, int x, int y)

{

if(key == GLUT_KEY_UP)

xRot-= 5.0f;

if(key == GLUT_KEY_DOWN)

xRot += 5.0f;

if(key == GLUT_KEY_LEFT)

yRot -= 5.0f;

if(key == GLUT_KEY_RIGHT)

yRot += 5.0f;

if(key > 356.0f)

xRot = 0.0f;

if(key < -1.0f)

xRot = 355.0f;

if(key > 356.0f)

yRot = 0.0f;

if(key < -1.0f)

yRot = 355.0f;

// Od wie enie zawarto ci okna

glutPostRedisplay();

}

background image

21

void ChangeSize(int w, int h)

{

GLfloat nRange = 100.0f;

// Zabezpieczenie przed dzieleniem przez zero

if(h == 0)

h = 1;

// Ustalenie wymiarów widoku na zgodnych z wymiarami okna

glViewport(0, 0, w, h);

// Ponowne ustawienie stosu macierzy rzutowania

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

// Utworzenie przestrzeni ograniczaj cej (lewo, prawo, dół, góra, blisko, daleko)

if (w <= h)

glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);

else

glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

// Ponowne ustawienie stosu macierzy rzutowania

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

int main(int argc, char* argv[])

{

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

glutCreateWindow("Points Size Example");

glutReshapeFunc(ChangeSize);

glutSpecialFunc(SpecialKeys);

glutDisplayFunc(RenderScene);

SetupRC();

glutMainLoop();

return 0;

}

W powy szym przykładzie zademonstrowanych zostało kilka wa nych rzeczy. Przede wszystkim trzeba zauwa y , e funkcja

glPointSize musi by wywoływana poza zakresem obj tym funkcjami glBegin i glEnd. Nie wszystkie funkcje OpenGL mog

by wywoływane pomi dzy wywołaniami tych dwóch funkcji. Mimo e funkcja gl PointSize wpływa na wszystkie narysowane

pó niej punkty, to samo rysowanie nie mo e rozpocz si przed wywołaniem funkcji glBegin(GL_POINTS).

Je eli podamy w parametrze funkcji glPointSize rozmiar punktu wi kszy ni warto zwrócona do zmiennej size, to

zauwa ymy, e biblioteka stosowa b dzie najwi kszy dost pny rozmiar punktu, ale nie b dzie ich bardziej powi ksza .

Jest to zasada wspólna dla wszystkich funkcji OpenGL przyjmuj cych parametry z pewnego zakresu warto ci. Wszystkie

warto ci spoza dopuszczalnego zakresu modyfikowane s w taki sposób, aby si w tym zakresie zmie ciły. Warto ci zbyt

małe powi kszane s do najmniejszej dopuszczalnej warto ci, a warto ci zbyt du e zmniejszane do najwi kszej

dopuszczalnej.

Ja mo na zauwa y w przykładowym programie POINTSZ, punkty o wi kszych rozmiarach rysowane s po prostu jako

wi ksze kwadraty. Jest to domy lne zachowanie biblioteki, cho w wielu aplikacjach takie działanie jest raczej niepo dane.

Poza tym mo na si zastanawia , dlaczego mo liwe jest definiowanie punktów o wielko ci mniejszej ni jeden. Je eli punkt o

wielko ci 1.0 oznacza jeden piksel, to jak mo na przedstawia piksel o wielko ci, powiedzmy, 2.5?

Odpowied na to pytanie brzmi: parametr pobierany przez funkcj gl PointSize nie oznacza dokładnego rozmiaru punktu

w pikselach, ale przybli on rednic koła zawieraj cego wszystkie piksele u yte do narysowania punktu. Poprzez wł czenie

wygładzania punktów (ang. point smoothing) mo na zmusi bibliotek OpenGL do rysowania ładniej wygl daj cych

punktów (czyli niewielkich, wypełnionych kół). Funkcja wygładzania punktów razem z funkcj wygładzania linii (ang.

line smoothing) nale do rodziny technik o wspólnej nazwie antyaliasingu. Antyaliasing to techniki stosowane w celu wy-

gładzenia schodkowatych kraw dzi i zaokr glania rogów.

background image

22

Rysowanie linii w trzech wymiarach

Obiekt podstawowy GL_POINTS, jakiego u ywali my do tej pory, miał bardzo proste działanie — dla ka dego zdefiniowanego
wierzchołka rysowany jest jeden punkt. Nast pnym logicznym krokiem byłoby zdefiniowanie dwóch wierzchołków i
narysowanie pomi dzy nimi linii. Dokładnie tak funkcj spełnia obiekt podstawowy GL_LINES. Poni szy wycinek kodu rysuje
linie od punktu ( 0 , 0, 0) do punktu (50, 50, 50):

glBegin(GL_LINES);

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

glVertex3f(50.0f, 50.0f, 50.0 f ) ;

glEnd();

Teraz jeden obiekt podstawowy definiowany jest dwoma wierzchołkami. Mi dzy ka dymi dwoma podanymi wierzchołkami

rysowana jest jedna linia. Je eli zdefiniujemy nieparzyst liczb wierzchołków, to ostatni z nich zostanie po prostu

zignorowany. Na poni szym listingu przedstawiony został nieco bardziej rozbudowany wycinek kodu rysuj cy linie roz-

chodz ce si promieni cie z punktu centralnego. Kod ten pochodzi z przykładowego programu LINES który mo na pobra

wraz z tym tutorialem. Ka dy z punktów definiowanych w tym przykładzie ma swój odpowiednik znajduj cy si po drugiej

stronie koła.

// Wywoła tylko raz, przed rysowaniem wszystkich punktów

glBegin(GL_LINES);

z = 0.0f;

for(angle = 0.0f; angle <= GL_PI; angle += (GL_PI / 20.0f))

{

// Górna połowa koła

x = 50.0f*sin(angle);

y = 50.0f*cos(angle);

glVertex3f(x, y, z);

// Dolna połowa koła

x = 50.0f*sin(angle+GL_PI);

y = 50.0f*cos(angle+GL_PI);

glVertex3f(x, y, z);

}

// Zako czenie rysowania punktów

glEnd();

Linie łamane i zamkni te

Kolejne dwa obiekty podstawowe biblioteki OpenGL opieraj si na obiektach GL_LINES, pozwalaj c zadeklarowa list

wierzchołków, na podstawie których rysowana jest linia.

Podaj c rodzaj obiektu GL_LINE_STRIP linie rysowane s od jednego wierzchołka do nast pnego, tworz c w ten sposób ci gł lini
łaman . Poni szy kod rysuje na płaszczy nie xy dwie linie wyznaczone przez trzy wierzchołki, co zostało przedstawione na rysunku
3.7.

glBegin(GL_LINE_STRIP);

glVertex3f(0.0f, O.Of, O.Of);

//V0

g!Vertex3f(50.0f. 50.Of. O.Of);

//Vl

glVertex3f(50.0f. 100.Of. O.Of);

//V2

glEnd();

background image

23

Ostatnim liniowym obiektem podstawowym jest GL_LINE_LOOP. Zachowuje si on dokładnie tak jak GL_LINE_STRIP, jednak

ko cowa linia rysowana jest pomi dzy ostatnim a pierwszym podanym wierzchołkiem. W ten sposób mo na bardzo łatwo

rysowa figury zamkni te. Na rysunku 3.8 przedstawiono obiekt GL_LINE_LOOP narysowany w oparciu o te same wierzchołki

co obiekt GL_LINF_STRIP z rysunku 3.7.

Aproksymacja krzywych liniami prostymi

Przykładowy program POINTS pokazał nam, jak mo na za pomoc rysowania punktów utworzy co w rodzaju spirali.

Kusz c mo e wydawa si propozycja zag szczenia punktów (poprzez zmniejszenie warto ci inkre-mcntacji k ta), aby w

ten sposób uzyska spiraln krzyw , a nie zbiór punktów przybli aj cych ten kształt. Jest to co prawda działanie całkowicie

prawidłowe, ale w przypadku bardziej skomplikowanych krzywych, składaj cych si z tysi cy punktów, mo e działa

bardzo wolno.

Lepszym sposobem aproksymacji krzywej jest stosowanie obiektów GL_LINE_STRIP i zabawa w „poł cz punkty". Wraz z

zag szczaniem punktów tworzona jest dokładniejsza krzywa, w której nie musimy definiowa wszystkich jej punktów. Jak

wida , aproksymacja krzywej wygl da bardzo dobrze. Jak b dzie mo na si przekona , ta technika jest wszechobecna w

programach wykorzystuj cych bibliotek OpenGL.

// Wywoła tylko raz, przed rysowaniem wszystkich punktów

glBegin(GL_LINE_STRIP);

z = -50.0f;

for(angle = 0.0f; angle <= (2.0f*3.1415f)*3.0f; angle += 0.1f)

{

x = 50.0f*sin(angle);

y = 50.0f*cos(angle);

// Okre lenie punktu i przesuni cie współrz dnej Z

glVertex3f(x, y, z);

z += 0.5f;

}

Zako czenie rysowania punktów

glEnd();

Ustalanie szeroko ci linii

Tak jak mo liwe jest ustalenie rozmiaru rysowanych punktów, w podobny sposób da si te okre la szeroko rysowanych linii za
pomoc funkcji glLineWidth:

void glLineWidth(GLfloat width);

Funkcja gl LineWidth pobiera jeden parametr okre laj cy przybli on szeroko rysowanej linii podan w pikselach.

Niestety, podobnie jak było w przypadku punktów, nie mo na poda dowolnej szeroko ci linii, dlatego nale y si

upewni , czy podawana szeroko b dzie obsłu ona prawidłowo. Mo na u y poni szego kodu w celu sprawdzenia

zakresu dost pnych szeroko ci linii i najmniejszych odst pów mi dzy nimi.

GLfloat sizes[2];

//Zapami tuje dopuszczalny zakres szeroko ci

GLfloat step;

//Zapami tuje obsługiwany przyrost szeroko ci

background image

24

// Pobranie dopuszczalnych szeroko ci linii i wielko ci kroku

glGetFloatv(GL_LINE_WIDTH_RANGE, sizes);
glGetFloatv(GL_LINE_WIDTH_GRANULARITY, &step);

W tablicy sizes znajd si dwa elementy okre laj ce najmniejsz i najwi ksz warto przyjmowan przez funkcj gl

LineWidth. Dodatkowo, zmienna step przechowywa b dzie wielko dopuszczalnego kroku pomi dzy kolejnymi

szeroko ciami linii. Specyfikacja biblioteki OpenGL wymaga tylko, eby obsługiwana była jedna szeroko linii — 1.0.

Na przykład implementacja biblioteki przygotowana przez Microsoft pozwala na stosowanie linii o szeroko ci od 0.5 do

10.0 z minimalnym krokiem 0.125.

Poni szy listing przedstawia kod dobrego przykładu wykorzystania funkcji glLineWidth. Pochodzi on z programu

LINESW i rysuje w oknie dziesi linii o ró nych szeroko ciach. Rysowanie zaczynane jest w dolnej cz ci okna, od

warto ci -90 w osi y, a nast pnie warto ci współrz dnej y s powi kszane o 20 przy rysowaniu ka dej kolejnej linii. Dla

ka dej kolejnej rysowanej linii jej szeroko powi kszana jest o 1.

Prosz zauwa y , e tym razem do podawania współrz dnych linii u ywali my funkcji glVertex2f, a nie glVertex3f. Jak

ju wspomniano wcze niej, pozwala to na osi gni cie wi kszej wygody, poniewa i tak rysujemy na płaszczy nie xy,

gdzie warto współrz dnej z jest zawsze równa 0. Aby si przekona , e rzeczywi cie nadal rysujemy w trzech

wymiarach, wystarczy nacisn klawisze ze strzałkami i obróci rysunek w dowolnym kierunku. Zobaczymy wtedy, e

wszystkie narysowane linie le na tej samej płaszczy nie.

// Wywoływana w celu przerysowania sceny

void RenderScene(void)

{

GLfloat y;

// Przechowuje warto współrz dnej Y

GLfloat fSizes[2];

// Dane zakresu szeroko ci linii

GLfloat fCurrSize;

// Zapisanie aktualnej szeroko ci

...

...

...

// Pobranie informacji o dopuszczalnych szeroko ciach linii

// i zapisanie najmniejszej mo liwej warto ci

glGetFloatv(GL_LINE_WIDTH_RANGE,fSizes);

fCurrSize = fSizes[0];

// Współrz dn y zwi kszamy o 20 jednostek

// przy ka dym obiegu p tli

for(y = -90.0f; y < 90.0f; y += 20.0f)

{

// Ustalenie szeroko ci linii

glLineWidth(fCurrSize);

// Rysowanie linii

glBegin(GL_LINES);

glVertex2f(-80.0f, y);

glVertex2f(80.0f, y);

glEnd();

// Zwi kszenie szeroko ci linii

fCurrSize += 1.0f;

}

...

...

}

Rysowanie trójk tów w trzech wymiarach

Wiemy ju , jak mo na rysowa punkty i linie, a nawet jak za pomoc obiektu podstawowego GL_LINE_LOOP budowa

zamkni te wielok ty. Ju za pomoc tych obiektów podstawowych mo na w prosty sposób budowa dowolne kształty w trzech

wymiarach. Mo na, na przykład, narysowa sze kwadratów, układaj c je tak, aby razem tworzyły sze cian.

Niestety, jak mo na było zauwa y , wszystkie kształty tworzone w ten sposób nie s wypełniane adnym kolorem, a poza tym

rysowane s tylko linie. I rzeczywi cie, narysowany takimi metodami sze cian b dzie tylko szkieletem sze cianu, bez

wypełnienia. Aby uzyska pełne powierzchnie, potrzebne nam jest co wi cej ni tylko punkty i linie. Do takich celów

musimy zastosowa wielok ty. Wielok t (polygon) jest kształtem zamkni tym, który mo e (cho nie musi) by

wypełniany aktualnie wybranym kolorem. Takie wła ciwo ci nadaj mu status bazowego elementu wszystkich

wypełnianych kompozycji tworzonych w OpenGL.

background image

25

Trójk t — mój pierwszy wielok t

Najprostszym z mo liwych wielok tów jest posiadaj cy tylko trzy boki trójk t. Obiekt podstawowy GL_TRIANGLES

umo liwia rysowanie trójk tów poprzez poł czenie trzech zadeklarowanych wierzchołków. Poni szy kod rysuje dwa

trójk ty, z których ka dy korzysta z trzech podanych wierzchołków, co pokazano na rysunku 3.14.

glBegin(GL_TRANGLES);

glVertex2r(0.0f. 0.0f);

//V0

glVertex2f(25.0f. 25.0f);

//V1

glVertex2f(50.0f. 0.0f):

//V2

glVertex2f(-50.0f, 0.0f);

//V3

glVcrtex2f(-75.0f,

50.0f):

//V4

glVertex2f(-25.0F, 0.0f);

//V5

glEnd();

Nawini cie

Na rysunku 3.14 przedstawiona została bardzo wa na cecha ka dego wielok tnego obiektu podstawowego. Prosz

zwróci uwag na strzałki na liniach ł cz cych poszczególne wierzchołki. Podczas rysowania pierwszego trójk ta linie

rysowane s od wierzchołka V0 do V1, potem do V2 i na ko cu znów do V0, dzi ki czemu trójk t zostaje zamkni ty.

Ta cie ka odpowiada kolejno ci definiowania wierzchołków, a z naszego punktu widzenia, s one uło one zgodnie z ruchem

wskazówek zegara. Drugi z trójk tów ma dokładnie tak sam charakterystyk kierunkow .

Kombinacja kolejno ci i kierunku w którym definiowane s wierzchołki nazywana jest nawini ciem (ang. winding). O

trójk tach z rysunku 3.14 mówi si , e posiadaj nawini cie zgodne z ruchem wskazówek zegara, poniewa układaj si

dokładnie w tym kierunku. Je eli w trójk cie znajduj cym si po lewej stronie zamienimy miejscami wierzchołki V4 i V5,

to powstały w ten sposób trójk t b dzie miał nawini cie przeciwne do ruchu wskazówek zegara. Rysunek 3.15 przedstawia te

dwa trójk ty o przeciwnych nawini ciach.

Domy lnie biblioteka OpenGL uznaje wielok ty o nawini ciu przeciwnym do kierunku ruchu wskazówek zegara za uło one

przodem. Oznacza to, e trójk t znajduj cy si na rysunku 3.15 po lewej stronie b dzie ustawiony przodem do widza,

natomiast trójk t z prawej strony b dzie ustawiony tyłem do widza.

Dlaczego jest to tak wa ne? Jak wkrótce zobaczymy, bardzo cz sto b dziemy chcieli nada inne charakterystyki przedniej

i tylnej stronie wielok ta. Tyln stron mo emy całkowicie ukry albo nada jej inny kolor i wła ciwo ci odblaskowe. Bardzo

background image

26

wa ne jest, eby nawini cie wszystkich wielok tów na scenie było zawsze takie samo, tak aby przednie strony wielok tów znaj-

dowały si na zewn trznych powierzchniach tworzonych obiektów. W kolejnym podrozdziale (dotycz cym pełnych obiektów)

zobrazujemy t zasad , za pomoc kilku bardziej zło onych modeli.

Je eli konieczne b dzie odwrócenie tego domy lnego zachowania biblioteki OpenGL, mo na to zrobi , wywołuj c

poni sz funkcj :

lgFront(GL_CW);

Parametr GL_CW nakazuje bibliotece OpenGL, eby traktowała wielok ty o nawini ciu zgodnym z ruchem wskazówek

zegara jako ukierunkowane do przodu. Aby powróci do normalnego traktowania wielok tów o nawini ciu przeciwnym

do ruchu wskazówek zegara, nale y wywoła t funkcj z parametrem GL_CCW.

Trójk ty sklejane

Tworz c wiele powierzchni i kształtów, b dziemy musieli narysowa kilka poł czonych ze sob trójk tów. Mo na

oszcz dzi przy tym wiele czasu, rysuj c ci g sklejonych ze sob trójk tów za pomoc obiektu podstawowego

GL_TRIANGLE_STRIP. Rysunek 3.16 przedstawia post p rysowania trzech sklejonych trójk tów okre lanych przez

definicje pi ciu wierzchołków ponumerowanych od V0 do V4. Jak wida , kolejne wierzchołki nie musz by przetwarzane w

tej samej kolejno ci, w jakiej s definiowane. Wynika to z konieczno ci zachowania przeciwnego do ruchu wskazówek zegara

nawini cia ka dego trójk ta. Kolejnym trójk tom wierzchołki przydzielane s nast puj co: V0, V1, V2, potem V2, V1, V3, V2,

V3, V4 itd.

Od teraz w opisach pozostałych obiektów podstawowych nie b dziemy podawa ju wycinków kodów demonstruj cych

tworzenie wierzchołków po wywołaniu funkcji glBegm. Do tej pory wszyscy powinni ju zrozumie , o co chodzi. Pó niej,

gdy b dziemy mieli ju gotowy program przykładowy, przypomnimy sobie te wszystkie przykłady.

U ywanie trójk tów sklejanych wi e si z dwoma zaletami w porównaniu do definiowania ka dego trójk ta z osobna. Po

pierwsze, po zdefiniowaniu trzech wierzchołków pierwszego trójk ta ka dy kolejny trójk t tworzymy, definiuj c tylko jeden

wierzchołek. W ten sposób oszcz dzamy wiele miejsca przeznaczonego na przechowywanie danych. Szczególnie gdy nasz

obiekt składa si z wielu trójk tów. Drug zalet jest poprawa wydajno ci oblicze matematycznych i oszcz dno ci przy

przesyłaniu danych. Mniej wierzchołków oznacza szybsze przesłanie danych z pami ci komputera do karty graficznej, a

tak e mniej przekształce wierzchołków.

background image

27

Wachlarze trójk tów

Oprócz mo liwo ci tworzenia trójk tów sklejanych mo emy te tworzy grupy trójk tów tworz cych wachlarz wokół

pewnego rodkowego punktu, czyli obiekt podstawowy GL_TRIANGLE_FAN. Rysunek 3.17 przedstawia taki wachlarz

składaj cy si z trzech trójk tów definiowanych przez cztery wierzchołki. Pierwszy wierzchołek (V

0

) wyznacza rodek

tego wachlarza. Pierwsze trzy zdefiniowane wierzchołki u ywane s do narysowania pierwszego trójk ta, jednak ka dy

kolejny wierzchołek w poł czeniu z wierzchołkiem centralnym i poprzednio zdefiniowanym (V

n

- 1) definiuje nowy

trójk t.

Budowanie pełnych obiektów

Tworzenie z trójk tów (lub innych wielok tów) pełnych, zamkni tych obiektów to zadanie wymagaj ce czego wi cej ni tylko

poł czenia ze sob serii wierzchołków zdefiniowanych w trzech wymiarach. Przyjrzyjmy si przykładowemu programowi

TRIANGLE, w którym do zbudowania w przestrzeni widocznej sto ka wykorzystano dwa wachlarze trójk tów. Pierwszy

wachlarz tworzy kształt sto ka, przy czym pierwszy wierzchołek wyznacza czubek sto ka, a pozostałe wierzchołki tworz

koło wokół osi z. Drugi wachlarz definiuje koło całkowicie le ce na płaszczy nie xy.

Patrz c na sto ek wzdłu osi z, zobaczymy tylko koło utworzone z wachlarza trójk tów. Poszczególne trójk ty uwypuklane

s poprzez stosowanie zamiennie kolorów czerwonego i zielonego.

Kod funkcji SetupRC i RenderScene przedstawiony został na listingu poni ej. Znajduje si w nim kilka nieopisywanych do tej pory

zmiennych i stałych, które s w nim krótko obja niane. Program jest demonstracj kilku aspektów budowania obiektów

trójwymiarowych. Klik-ni cie w oknie prawym klawiszem myszy wywołuje menu kontekstowe obsługuj ce ró ne efekty. Jest

ono wykorzystywane do wł czania i wył czania pewnych efektów rysowania w trzech wymiarach, umo liwiaj c nam

zapoznanie si z niektórymi charakterystykami tworzenia obiektów trójwymiarowych.

// Funkcja wykonuje wszystkie konieczne inicjalizacje kontekstu renderowania

void SetupRC()

{

// Czarne tło

glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

// Kolor rysuj cy - zielony

glColor3f(0.0f, 1.0f, 0.0f);

// Model cieniowania kolorów - płaski

glShadeModel(GL_FLAT);

// Wielok ty o nawini ciu zgodnym z ruchem wskazówek zegara traktowane s

// jako skierowane do przodu. Takie ustawienie jest konieczne, poniewa

// korzystamy z wachlarzy trójk tów.

glFrontFace(GL_CW);

}

// Wywoływana w celu przerysowania sceny

void RenderScene(void)

{

GLfloat x,y,angle; // Przechowuj warto ci współrz dnych i k ta

int iPivot = 1;

// Do oznaczania zamiennych kolorów

// Wyczyszczenie okna i bufora gł bi

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Wł czenie lub wył czenie mechanizmu eliminowania ukrytych powierzchni

background image

28

if(iCull)

glEnable(GL_CULL_FACE);

else

glDisable(GL_CULL_FACE);

// Wł czenie lub wył czenie mechanizmu sprawdzania gł bi

if(iDepth)

glEnable(GL_DEPTH_TEST);

else

glDisable(GL_DEPTH_TEST);

// Je eli ten znacznik b dzie ustawiony, to wielok ty zwrócone

// tyłem do widza b d rysowane tylko w postaci szkieletu

if(iOutline)

glPolygonMode(GL_BACK,GL_LINE);

else

glPolygonMode(GL_BACK,GL_FILL);

// Zapisanie stanu macierzy i wykonanie obrotu

glPushMatrix();

glRotatef(xRot, 1.0f, 0.0f, 0.0f);

glRotatef(yRot, 0.0f, 1.0f, 0.0f);

// Rozpocz cie rysowania wachlarza trójk tów

glBegin(GL_TRIANGLE_FAN);

// Czubek sto ka jest wspólnym wierzchołkiem wszystkich trójk tów z wachlarza

// wysuni tym do góry w osi z. W ten sposób zamiast koła powstanie sto ek.

glVertex3f(0.0f, 0.0f, 75.0f);

// Wykonujemy obrót w około i oznaczamy w równych odst pach wierzchołki

// tworz ce wachlarz trójk tów.

for(angle = 0.0f; angle < (2.0f*GL_PI); angle += (GL_PI/8.0f))

{

// Wyliczenie współrz dnych x i y kolejnego wierzchołka

x = 50.0f*sin(angle);

y = 50.0f*cos(angle);

// Wybieranie koloru - zielony lub czerwony

if((iPivot %2) == 0)

glColor3f(0.0f, 1.0f, 0.0f);

else

glColor3f(1.0f, 0.0f, 0.0f);

// Inkrementacja zmiennej okre laj cej rodzaj koloru

iPivot++;

// Definiowanie kolejnego wierzchołka w wachlarzu trójk tów

glVertex2f(x, y);

}

// Zako czenie rysowania trójk tów sto ka

glEnd();

// Rozpocz cie rysowania kolejnego wachlarza trójk tów

// zakrywaj cego podstaw sto ka

glBegin(GL_TRIANGLE_FAN);

// rodek wachlarza znajduje si na pocz tku układu współrz dnych

glVertex2f(0.0f, 0.0f);

for(angle = 0.0f; angle < (2.0f*GL_PI); angle += (GL_PI/8.0f))

{

// Wyliczenie współrz dnych x i y kolejnego wierzchołka

x = 50.0f*sin(angle);

y = 50.0f*cos(angle);

// Wybieranie koloru - zielony lub czerwony

if((iPivot %2) == 0)

glColor3f(0.0f, 1.0f, 0.0f);

else

glColor3f(1.0f, 0.0f, 0.0f);

// Inkrementacja zmiennej okre laj cej rodzaj koloru

iPivot++;

// Definiowanie kolejnego wierzchołka w wachlarzu trójk tów

glVertex2f(x, y);

}

// Zako czenie rysowania trójk tów podstawy sto ka

glEnd();

// Odtworzenie macierzy przekształce

background image

29

glPopMatrix();

// Wysłanie polece do wykonania

glutSwapBuffers();

}

Ustalanie koloru wielok ta

Do tej pory kolor ustalali my tylko raz i rysowali my tylko pojedynczy kształt. Teraz jednak, przy rysowaniu wielu

wielok tów, zrobiło si naprawd interesuj co. Stosujemy teraz ró ne kolory, aby mo liwe było ogl danie efektów naszej

pracy. Tak naprawd to kolory przydziela si poszczególnym wierzchołkom, a nie całym wielok tom. Model cieniowania

okre la, czy wielok t b dzie pokryty jednolitym kolorem (kolor pobierany jest z ostatniego wierzchołka tworz cego

wielok t) czy mo e pokryty płynnym przej ciem pomi dzy kolorami poszczególnych wierzchołków.

W linii:

glShadeModel(GL_FLAT);

okre lamy, e biblioteka OpenGL b dzie wypełniała wielok ty jednolitym kolorem, pobranym z ostatnio zdefiniowanego

wierzchołka tego wielok ta. W ten sposób mo emy po prostu zmienia aktualny kolor na zielony lub czerwony tu przed

zdefiniowaniem kolejnego wierzchołka wachlarza trójk tów. Z drugiej strony linia:

glShadeModel(GL_SMOOTH);

nakazałaby bibliotece miesza ze sob kolory definiowane w aktualnym wielok cie przez wszystkie jego wierzchołki.

Tekstury


Ładowanie tekstur

Pierwszym krokiem w procedurze nakładania tekstur na obiekty geometryczne jest załadowanie tekstury do pami ci. Po

załadowaniu tekstura staje si cz ci aktualnego stanu tekstur (ang. texture state) — wi cej na ten temat w dalszej cz ci

rozdziału. Do ładowania tekstur z bufora w pami ci (gdzie znalazły si po wczytaniu z pliku) najcz ciej stosowane s trzy

funkcje:

void glTexImage1D(GLenum target, GLint level, GLenum internalFormat,

GLsizei width, GLint border,

GLenum format, GLenum type. void *data);

void glTexImage2D(GLenum target, GLint level, GLenum internalFormat,

GLsizei width, GLsizei height, GLint border,

GLenum format, GLenum type. void *data);

void glTexImage3D(GLenum target, GLint level, GLenum internalFormat,

GLsizei width, GLsizei height, GLsizei depth, GLint border,

GLenum format, GLenum type. void *data);

Te trzy przydługie funkcje przekazuj bibliotece OpenGL wszystkie konieczne informacje o sposobach interpretowania informacji o
danych tekstury wskazywanej przez parametr data.

Pierwsza rzecz, jaka rzuca si w oczy, to fakt, e wszystkie trzy funkcje s tylko wariantami podstawowej funkcji g1TexImage.
Biblioteka OpenGL obsługuje tekstury jedno-, dwu- i trójwymiarowe, a te trzy funkcje umo liwiaj załadowanie ka dego z tych
rodzajów tekstur i ustawienie wczytanej tekstury jako aktualnej. Trzeba by wiadomym tego, e po wywołaniu jednej z tych funkcji,
biblioteka OpenGL kopiuje dane tekstury wskazywane parametrem data.

W parametrze target wszystkich trzech funkcji nale y podawa warto ci GL_TEXTURE_1D, GL_TEXTURE_2D lub

GL_TEXTURE_3D odpowiednio dla rodzaju funkcji. Podaj c warto ci GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D

lub GL_PROXY_TEXTURE_3D, mo na te definiowa tekstury zast pcze (proxy). Funkcja glGetTexParameter pozwoli nam wtedy

sprawdzi wyniki prób utworzenia takiej zast pczej tekstury.

Parametr level okre la poziom ładowanej mipmapy. Je eli nie u ywamy mipmap b dziemy stosowa tutaj warto 0.

Nast pnie musimy poda warto parametru internalFormat opisuj cego dane tekstury. W ten sposób informujemy

bibliotek OpenGL, ile składowych kolorów ma opisywa ka dy teksel, podajemy równie rozmiar poszczególnych

składowych i ewentualn informacj o kompresji tekstury. W tabeli 8.1 podajemy najcz ciej stosowane warto ci tego

background image

30

parametru.

Parametry width, height i depth okre laj wymiary ładowanej tekstury. Trzeba zaznaczy , e te wymiary musz by

całkowitymi pot gami liczby 2 (1, 2, 4, 8, 16, 32, 64 itd.). Nie istnieje wymóg, eby tekstury były kwadratowe (wszystkie

wymiary musiałyby mie identyczn wielko ), jednak załadowanie tekstury o wielko ci nie b d cej pot g liczby 2 spowoduje

natychmiastowe wył czenie mechanizmu teksturowania.

Parametr border umo liwia okre lenie szeroko ci obramowania tekstury. Umo liwia to powi kszenie szeroko ci,

wysoko ci i gł boko ci tekstury o dodatkowe piksele wstawiane na jej brzegach. Graj one bardzo wa n rol w opisanym

nieco dalej mechanizmie filtrowania tekstur, jednak na razie b dziemy temu parametrowi nadawa warto 0.

Ostatnie trzy parametry — format, type i data — maj takie samo znaczenie jak w funkcji g!0rawPixels u ywanej do

ładowania danych obrazów do bufora kolorów. Dla wygody prawidłowe warto ci stałych dla parametrów format i type

podajemy ponownie w tabelach 8.2 i 8.3.

Je eli nie zostanie wł czony odpowiedni stan tekstur, to załadowane tekstury nie zostan nało one na obiekty geometryczne.

Wł czanie i wył czanie teksturowania dla poszczególnych stanów wykonujemy, wywołuj c funkcje giEnabie i glDisable

z parametrami GL_TEXTURE_1D, GL_TEXTURE_2D lub GL_TEXTURE_3D. Dla jednej jednostki teksturuj cej mo e by wł czony

tylko jeden spo ród tych trzech stanów teksturowania. Poza tym dobr praktyk jest wył czanie nieu ywanych stanów

teksturowania. Na przykład, aby przeł czy si pomi dzy teksturowaniem jednowymiarowym na teksturowanie

dwuwymiarowe, nale y wywoła poni sze funkcje:

glDisable(GL_TEXTURE_1D);

glEnable(GL TEXTURE_2D);

background image

31

background image

32

Odwzorowywanie tekstur na obiekty geometryczne

Załadowanie tekstury i wł czenie mechanizmu teksturowania powoduje, e tekstura nakładana jest na ka dy obiekt

podstawowy. Musimy jednak przekaza bibliotece informacje o tym, jak ten proces ma by wykonywany. Wykonywane

jest to poprzez przypisanie ka demu wierzchołkowi współrz dnych tekstury. Poszczególne teksele wewn trz tekstury

nie s adresowane jak komórki pami ci (tak jak jest to w piksmapach), ale za pomoc bardziej abstrakcyjnych

współrz dnych tekstury. Współrz dne tekstury najcz ciej definiowane s jako warto ci zmiennoprzecinkowe

ograniczone do zakresu od 0.0 do 1.0. Współrz dne tekstury oznaczane s literami s, r, t i q (odpowiadaj ce

współrz dnym wierzchołków x, y, z i w) opisuj cymi jedno, dwu i trójwymiarowe tekstury, a tak e współrz dn ich

skalowania.

Na rysunku 8.2 przedstawiono jedno-, dwu- i trójwymiarow tekstur oraz sposób, w jaki współrz dne opisuj teksele.

Nie istniej tekstury czterowymiarowe, nasuwa si wi c pytanie, co ma oznacza współrz dna c/? Jest ona

odpowiednikiem geometrycznej współrz dnej w, czyli współczynnikiem skalowania stosowanym wobec pozostałych

współrz dnych tekstury. Oznacza to, e wszystkie współrz dne opisuj ce tekstury maj rzeczywiste warto ci s/g, t/g i r/q.

Domy lnie współrz dnej a nadawana jest warto 1.0.

Współrz dne tekstury wyznaczane s za pomoc funkcj i glTexCoord. Podobnie jak funkcje definiuj ce współrz dne

wierzchołków, wektorów normalnych lub warto ci kolorów ta funkcja równie dost pna jest w wielu podobnych wersjach.

Poni sze trzy wersje funkcji b d u ywane w przykładowych programach:

void glTexCoord1f(GLfloat s ) ;

void glT exCoord2f(GLfloat s. Glfloat t ) ;

v o i d g l T e xC o o r d 3 f ( G L f l o a t s . G l f l o a t t , G l f l o a t r ) ;

Za pomoc tych funkcji mo na przypisa ka demu wierzchołkowi współrz dne tekstury. Nast pnie, w czasie nakładania

tekstury na obiekt geometryczny, biblioteka OpenGL rozci ga lub ciska tekstur tak, eby dopasowa j do odpowiednich

współrz dnych. Rozci ganie i ciskanie tekstury odbywa si poprzez aktualny/////- tekstury, który równie b dziemy

pokrótce opisywa . Na rysunku 8.3 przedstawiono przykładowe odwzorowanie dwuwymiarowej tekstury na obiekt

GL_QUAD. Prosz zauwa y , e rogi tekstury powi zane s z rogami czworok ta. Współrz dne tekstury musz by

definiowane przed wierzchołkiem, podobnie jak inne wła ciwo ci wierzchołków (materiały, wektory normalne itd.)!

Niestety, takie doskonałe dopasowanie tekstury do obiektu geometrycznego wyst puje niezwykle rzadko. W celu lepszego

wyja nienia znaczenia współrz dnych tekstury na rysunku 8.4 przedstawiamy kolejny przykład ich zastosowania. Na tym

rysunku widoczna jest równie kwadratowa tekstura, ale nakładana jest ona na inny obiekt geometryczny — trójk t.

Współrz dne tekstury nało one na tekstur odpowiadaj miejscom na teksturze przypisanym poszczególnym

wierzchołkom trójk ta.

background image

33

Macierze tekstur

Współrz dne tekstury mog by równie przekształcane za pomoc macierzy tekstur. Stos macierzy tekstur działa

tak samo jak stosy innych rodzajów opisywanych wcze niej macierzy (model-widok, rzutowania i kolorów). Podaj c

funkcji glMatnxMode parametr GL TEXTURE, powodujemy, e wszystkie kolejne wywołania funkcji operuj cych na ma-

cierzach b d działały na macierzach tekstur:

glMatrixMode(GL_TEXTURE);

Stos macierzy tekstur mo e mie zaledwie dwa poziomy gł boko ci, z których mog korzysta funkcje glPushMatrix i

glPopMatrix. Współrz dne tekstur mog by te przesuwane skalowane, a nawet obracane.

Prosty przykład dwuwymiarowy

Załadowanie tekstury i przypisanie jej współrz dnych to podstawowe operacje wykonywane w czasie odwzorowywana

tekstur. Musimy si jednak zaj jeszcze kilkoma innymi sprawami, takimi jak zawijanie współrz dnych, filtry tekstur i

rodowisko tekstur. Co znacz te poj cia i jak nale y z nich korzysta ? Zwolnijmy mo e na chwil i przyjrzyjmy si

przykładowi wykorzystuj cemu tekstur dwuwymiarow . W poni szym kodzie wykorzystywane s funkcje, które zostały ju

opisane, ale równie kilka zupełnie nowych. Cały ten przykład ma nam słu y jako podstawa do opisywania pozostałych

problemów zwi zanych z odwzorowywaniem tekstur.

Poni szy listing zawiera cało kodu przykładowego programu PYRAMID. Program rysuje prost , cztero cienn piramid

zbudowan z trójk tów. Na ka dy z boków, jak równie na podstaw , nakładana jest tekstura z obrazem kamienia.

Podobnie jak w poprzednich przykładach mo emy obraca piramid , naciskaj c klawisze ze strzałkami.

background image

34

#include "../../Common/OpenGLSB.h"

// Biblioteki systemowe i OpenGL

#include "../../Common/GLTools.h" // Biblioteka GLTools

// Wielko ci obrotów

static GLfloat xRot = 0.0f;

static GLfloat yRot = 0.0f;

// Zmiana przestrzeni widocznej i okna.

// Wywoływana w momencie zmiany rozmiaru okna

void ChangeSize(int w, int h)

{

GLfloat fAspect;

// Zabezpieczenie przed dzieleniem przez zero

if(h == 0)

h = 1;

// Zrównanie wielko ci widoku i okna

glViewport(0, 0, w, h);

fAspect = (GLfloat)w/(GLfloat)h;

// Ustalenie układu współrz dnych

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

// Utworzenie rzutowania perspektywicznego

gluPerspective(35.0f, fAspect, 1.0, 40.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

// Ta funkcja wykonuje wszystkie konieczne inicjalizacje kontekstu renderowania.

// Tutaj, konfiguruje i inicjalizuje o wietlenie sceny

void SetupRC()

{

GLubyte *pBytes;

GLint iWidth, iHeight, iComponents;

GLenum eFormat;

// Warto ci i współrz dne wiatła

GLfloat whiteLight[] = { 0.05f, 0.05f, 0.05f, 1.0f };

GLfloat sourceLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };

GLfloat lightPos[] = { -10.f, 5.0f, 5.0f, 1.0f };

glEnable(GL_DEPTH_TEST); // Usuwanie ukrytych powierzchni

glEnable(GL_CULL_FACE); // Nie b dziemy prowadzi oblicze wn trza samolotu

glFrontFace(GL_CCW); // Wielok ty z nawini ciem przeciwnym do ruchu wskazówek zegara

// Wł czenie o wietlenia

glEnable(GL_LIGHTING);

// Konfiguracja i wł czenie wiatła numer 0

glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLight);

glLightfv(GL_LIGHT0,GL_AMBIENT,sourceLight);

glLightfv(GL_LIGHT0,GL_DIFFUSE,sourceLight);

glLightfv(GL_LIGHT0,GL_POSITION,lightPos);

glEnable(GL_LIGHT0);

// Wł czenie ledzenia kolorów

glEnable(GL_COLOR_MATERIAL);

// Wła ciwo ci o wietlenia otoczenia i rozproszenia

// b d ledzi warto ci podawane funkcji glColor

glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

// Czarne tło

glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

// Ładowanie tekstury

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

pBytes = gltLoadTGA("Stone.tga", &iWidth, &iHeight, &iComponents, &eFormat);

glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);

free(pBytes);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

background image

35

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

glEnable(GL_TEXTURE_2D);

}

// Reakcje na klawisze strzałek

void SpecialKeys(int key, int x, int y)

{

if(key == GLUT_KEY_UP)

xRot-= 5.0f;

if(key == GLUT_KEY_DOWN)

xRot += 5.0f;

if(key == GLUT_KEY_LEFT)

yRot -= 5.0f;

if(key == GLUT_KEY_RIGHT)

yRot += 5.0f;

xRot = (GLfloat)((const int)xRot % 360);

yRot = (GLfloat)((const int)yRot % 360);

// Od wie enie zawarto ci okna

glutPostRedisplay();

}

// Wywoływana w celu przerysowania sceny

void RenderScene(void)

{

GLTVector3 vNormal;

GLTVector3 vCorners[5] = { { 0.0f, .80f, 0.0f }, // Góra 0

{ -0.5f, 0.0f, -.50f }, // Lewy tył 1

{ 0.5f, 0.0f, -0.50f }, // Prawy tył 2

{ 0.5f, 0.0f, 0.5f }, // Prawy przód 3

{ -0.5f, 0.0f, 0.5f }}; // Lewy przód 4

// Czyszczenie okna aktualnym kolorem czyszcz cym

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Zapisanie stanu macierzy i wykonanie obrotów

glPushMatrix();

// Cofni cie obiektów

glTranslatef(0.0f, -0.25f, -4.0f);

glRotatef(xRot, 1.0f, 0.0f, 0.0f);

glRotatef(yRot, 0.0f, 1.0f, 0.0f);

// Rysowanie piramidy

glColor3f(1.0f, 1.0f, 1.0f);

glBegin(GL_TRIANGLES);

// Podstawa piramidy - dwa trójk ty

glNormal3f(0.0f, -1.0f, 0.0f);

glTexCoord2f(1.0f, 1.0f);

glVertex3fv(vCorners[2]);

glTexCoord2f(0.0f, 0.0f);

glVertex3fv(vCorners[4]);

glTexCoord2f(0.0f, 1.0f);

glVertex3fv(vCorners[1]);

glTexCoord2f(1.0f, 1.0f);

glVertex3fv(vCorners[2]);

glTexCoord2f(1.0f, 0.0f);

glVertex3fv(vCorners[3]);

glTexCoord2f(0.0f, 0.0f);

glVertex3fv(vCorners[4]);

// Przednia strona

gltGetNormalVector(vCorners[0], vCorners[4], vCorners[3], vNormal);

glNormal3fv(vNormal);

glTexCoord2f(0.5f, 1.0f);

glVertex3fv(vCorners[0]);

glTexCoord2f(0.0f, 0.0f);

glVertex3fv(vCorners[4]);

glTexCoord2f(1.0f, 0.0f);

glVertex3fv(vCorners[3]);

// Lewa strona

gltGetNormalVector(vCorners[0], vCorners[1], vCorners[4], vNormal);

glNormal3fv(vNormal);

glTexCoord2f(0.5f, 1.0f);

glVertex3fv(vCorners[0]);

glTexCoord2f(0.0f, 0.0f);

background image

36

glVertex3fv(vCorners[1]);

glTexCoord2f(1.0f, 0.0f);

glVertex3fv(vCorners[4]);

// Tylna strona

gltGetNormalVector(vCorners[0], vCorners[2], vCorners[1], vNormal);

glNormal3fv(vNormal);

glTexCoord2f(0.5f, 1.0f);

glVertex3fv(vCorners[0]);

glTexCoord2f(0.0f, 0.0f);

glVertex3fv(vCorners[2]);

glTexCoord2f(1.0f, 0.0f);

glVertex3fv(vCorners[1]);

// Prawa strona

gltGetNormalVector(vCorners[0], vCorners[3], vCorners[2], vNormal);

glNormal3fv(vNormal);

glTexCoord2f(0.5f, 1.0f);

glVertex3fv(vCorners[0]);

glTexCoord2f(0.0f, 0.0f);

glVertex3fv(vCorners[3]);

glTexCoord2f(1.0f, 0.0f);

glVertex3fv(vCorners[2]);

glEnd();

// Odtworzenie stanu macierzy

glPopMatrix();

// Zamiana buforów

glutSwapBuffers();

}

int main(int argc, char *argv[])

{

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize(800, 600);

glutCreateWindow("Textured Pyramid");

glutReshapeFunc(ChangeSize);

glutSpecialFunc(SpecialKeys);

glutDisplayFunc(RenderScene);

SetupRC();

glutMainLoop();

return 0;

}

W funkcji SetupRC wykonywane s niezb dne inicjalizacje programu, w tym równie załadowanie tekstury za pomoc

funkcji gltLoadTGA, która to jest doł czona do tego tutoriala i umo liwia ona szybkie załadowanie tekstury z pliku .tga.

Nast pnie tekstura przekazywana jest do funkcji glTexImage2D:

// Ładowanie tekstury

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

pBytes = gltLoadTGA("Stone.tga", &iWidth, &iHeight, &iComponents, &eFormat);

glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);

free(pBytes);

Oczywi cie musi te zosta wł czony mechanism odwzorowywania tekstur:

GlEnable(GL_TEXTURE_2D);

Funkcja RenderScene rysuje piramid jako zbiór pokrytych teksturami trójk tów. W poni szym wycinku kodu tworzona

jest jedna powierzchnia, dla której wyliczany jest wektor normalny (na podstawie wierzchołków), a tak e współrz dne

tekstury:

// Przednia strona

gltGetNormalVector(vCorners[0], vCorners[4], vCorners[3], vNormal);

glNormal3fv(vNormal);

glTexCoord2f(0.5f, 1.0f);

glVertex3fv(vCorners[0]);

glTexCoord2f(0.0f, 0.0f);

glVertex3fv(vCorners[4]);

glTexCoord2f(1.0f, 0.0f);

glVertex3fv(vCorners[3]);


Wyszukiwarka

Podobne podstrony:
Grafika komputerowa i OpenGL
bugzilla tutorial[1]
freeRadius AD tutorial
Alignmaster tutorial by PAV1007 Nieznany
free sap tutorial on goods reciept
ms excel tutorial 2013
Joomla Template Tutorial
ALGORYTM, Tutoriale, Programowanie
Zadania z OpenGL do wykonania
8051 Tutorial uart
opengl nurbs
B tutorial
Labview Tutorial
Obraz partycji (ghost2003) Tutorial
[LAB5]Tutorial do kartkówki
M2H Networking Tutorial Original
opengl test zaslaniania
ABAQUS Tutorial belka z utwierdzeniem id 50029 (2)

więcej podobnych podstron