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 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 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 right okre laj  minimaln  i maksymaln  współrz dn  na osi 

x, a warto ci bottom top — na osi y. Warto ci near 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 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 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 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).  

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