Tutorial OpenGL i GLUT Na podstawie ksiki OpenGL Ksiga eksperta - Helion

Podobne dokumenty
Wprowadzenie do programowania z wykorzystaniem biblioteki OpenGL. Dorota Smorawa

Janusz Ganczarski. OpenGL Pierwszy program

Temat: Transformacje 3D

Sposoby przekazywania parametrów w metodach.

Temat: Wprowadzenie do OpenGL i GLUT

2 Przygotował: mgr inż. Maciej Lasota

Podstawowe obiekty AutoCAD-a

Rysowanie punktów na powierzchni graficznej

1 Wstęp teoretyczny. Temat: Manipulowanie przestrzenią. Grafika komputerowa 3D. Instrukcja laboratoryjna Układ współrzędnych

Przekształcenia geometryczne. Dorota Smorawa

GRAFIKA KOMPUTEROWA 7: Kolory i cieniowanie

Temat: Programowanie zdarzeniowe. Zdarzenia: delegacje, wykorzystywanie zdarze. Elementy Windows Application (WPF Windows Presentation Foundation).

3 Przygotował: mgr inż. Maciej Lasota

Zatem standardowe rysowanie prymitywów wygląda następująco:

Planowanie adresacji IP dla przedsibiorstwa.

Laboratorium 1. Część I. Podstawy biblioteki graficznej OpenGL.

Baltie 3. Podręcznik do nauki programowania dla klas I III gimnazjum. Tadeusz Sołtys, Bohumír Soukup

geometry a w przypadku istnienia notki na marginesie: 1 z 5

Elementarne obiekty geometryczne, bufory. Dorota Smorawa

obsług dowolnego typu formularzy (np. formularzy ankietowych), pobieranie wzorców formularzy z serwera centralnego,

Zastosowanie programu Microsoft Excel do analizy wyników nauczania

Program do konwersji obrazu na cig zero-jedynkowy

Instrukcja obsługi programu DIALux 2.6

Druga aplikacja Prymitywy, alpha blending, obracanie bitmap oraz mały zestaw przydatnych funkcji wyświetlających własnej roboty.

zdefiniowanie kilku grup dyskusyjnych, z których chcemy odbiera informacje, dodawanie, usuwanie lub edycj wczeniej zdefiniowanych grup dyskusyjnych,

Zadania do wykonaj przed przyst!pieniem do pracy:

Rzutowanie DOROTA SMORAWA

Klonowanie MAC adresu oraz TTL

1 Podstawy c++ w pigułce.

Przycisk pracy. Przycisk stopu/kasowanie

Co to jest OpenGL? Oprogramowanie i wykorzystanie stacji roboczych. Wykład 5. OpenGL - Achitektura. OpenGL - zalety. olas@icis.pcz.

Prosty program- cpp. #include <GL/glut.h>

1. Klasa typu sealed. Przykład 1. sealed class Standard{ class NowyStandard:Standard{ // błd!!!

Poniszy rysunek przedstawia obraz ukoczonej powierzchni wykorzystywanej w wiczeniu.

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

GRAFIKA CZASU RZECZYWISTEGO Wprowadzenie do OpenGL

Część 4 życie programu

Instrukcja obsługi programu Pilot PS 5rc

CYKL ZAJ POZNAJEMY POWER POINT

Oprogramowanie i wykorzystanie stacji roboczych. Wykład 5

Temat: Liniowe uporzdkowane struktury danych: stos, kolejka. Specyfikacja, przykładowe implementacje i zastosowania. Struktura słownika.

INSTRUKCJA OBSŁUGI PROGRAMU C-STATION

1 Podstawy c++ w pigułce.

Lekcja 8 - ANIMACJA. 1 Polecenia. 2 Typy animacji. 3 Pierwsza animacja - Mrugaj ca twarz

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

ISO/ANSI C - funkcje. Funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje. ISO/ANSI C - funkcje

Instrukcja obsługi dodatku InsERT GT Smart Documents

5. Kliknij czarny trójkt umieszczony w prawym dolnym rogu ikony narzdzia Wypełnienie i - z rozsuwanej palety - wybierz pozycj Wypełnienie jednolite.

Ćwiczenie 1 Automatyczna animacja ruchu

Przegldanie stron wymaga odpowiedniej mikroprzegldarki w urzdzeniu mobilnym lub stosownego emulatora.

Programowanie Równoległe wykład, CUDA, przykłady praktyczne 1. Maciej Matyka Instytut Fizyki Teoretycznej

Laboratorium Ergonomii Politechniki Wrocławskiej (

Program Sprzeda wersja 2011 Korekty rabatowe

Dodawanie grafiki i obiektów

Janusz Ganczarski. OpenGL Definiowanie sceny 3D

System midzybankowej informacji gospodarczej Dokumenty Zastrzeone MIG DZ ver Aplikacja WWW ver. 2.1 Instrukcja Obsługi

Reprezentacje danych multimedialnych - grafika. 1. Terminologia 2. Obrazy czarno-białe 3. Obrazy kolorowe 4. Paleta 5.

INSTYTUT TECHNIKI Zakad Elektrotechniki i Informatyki mdymek@univ.rzeszow.pl FLASH

Jak napisać program obliczający pola powierzchni różnych figur płaskich?

OpenGL - charakterystyka

// Potrzebne do memset oraz memcpy, czyli kopiowania bloków

WYKŁAD 10. Wzorce projektowe czynnociowe Command Strategy

Twoja instrukcja użytkownika HP PAVILION DV6-1215SA

Podstawy Processingu. Diana Domańska. Uniwersytet Śląski

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Tworzenie prezentacji w MS PowerPoint

Grafika 3D OpenGL część II

DesignCAD 3D Max 24.0 PL

Grafika komputerowa. Dla DSI II

1. Opis okna podstawowego programu TPrezenter.

Laboratorium grafiki komputerowej i animacji. Ćwiczenie V - Biblioteka OpenGL - oświetlenie sceny

Języki formalne i automaty Ćwiczenia 5

SZYBKI START AUTOCAD 2000

Laboratorium 5: Tablice. Wyszukiwanie binarne

Zajęcia nr 15 JavaScript wprowadzenie do JavaScript

Zmienne, stałe i operatory

Projektowanie algorytmów rekurencyjnych

Systemy multimedialne 2015

W dowolnym momencie można zmienić typ wskaźnika.

I - Microsoft Visual Studio C++

Ćwiczenie 6 Animacja trójwymiarowa

CorelDraw - podstawowe operacje na obiektach graficznych

Sterowanie prac plotera w układach logiki programowalnej

Mozilla Firefox PL. Wykorzystanie certyfikatów niekwalifikowanych w oprogramowaniu Mozilla Firefox PL. wersja 1.1

1. Wprowadzenie do C/C++

Lekcja 9 - LICZBY LOSOWE, ZMIENNE

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

Lekcja 3 Banki i nowe przedmioty

Wstęp do Programowania, laboratorium 02

Proces tworzenia programu:

Komputerowa Ksiga Podatkowa Wersja 11.4 ZAKOCZENIE ROKU

LABORATORIUM INFORMATYKI 0

Przed instalacj naley sprawdzi wersj posiadanych sterowników urzdzenia. Powinna by nie starsza ni:

Programowanie w języku Python. Grażyna Koba

Wprowadzanie i zmiany faktur z zakupu, wydruk rejestru zakupu

Poradnik korzystania z serwisu UNET: Dostp do poczty elektronicznej ze strony WWW

AUTOCAD MIERZENIE I PODZIAŁ

Rasteryzacja (ang. rasterization or scan-conversion) Grafika rastrowa. Rysowanie linii (1) Rysowanie piksela

GLKit. Wykład 10. Programowanie aplikacji mobilnych na urządzenia Apple (IOS i ObjectiveC) #import "Fraction.h" #import <stdio.h>

.! $ Stos jest list z trzema operacjami: dodawanie elementów na wierzch stosu, zdejmowanie elementu z wierzchu stosu, sprawdzanie czy stos jest pusty.

Transkrypt:

Tutorial OpenGL i GLUT Na podstawie ksiki OpenGL Ksiga eksperta - Helion SPIS TRECI: 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 wielkoci punktów... 19 6.3. Rysowanie linii w trzech wymiarach... 22 6.4. Linie łamane i zamknite... 22 6.5. Aproksymacja krzywych liniami prostymi... 23 6.6. Ustalanie szerokoci linii... 23 6.7. Rysowanie trójktów w trzech wymiarach... 24 6.7.1. Trójkt mój pierwszy wielokt... 25 6.7.2. Nawinicie... 25 6.7.3. Trójkty sklejane... 26 6.7.4. Wachlarze trójktów... 27 6.8. Budowanie pełnych obiektów... 27 6.9. Ustalenie koloru wielokta... 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 0

Szczegóły interfejsu Biblioteka OpenGL została zaprojektowana przez uczonych ludzi posiadajcych wiele dowiadczenia 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 okrelane s załoenia, jakie projektanci biblioteki poczynili w zakresie metod wykorzystania API przez uytkowników. Przykładami takich zasad mog by załoenia, e dane wierzchołków bd zawsze definiowane jako wartoci zmiennoprzecinkowe, przed włczeniem rendcringu mgła bdzie zawsze włczona albo e wszystkie obiekty na scenie objte s tymi samymi parametrami owietlenia. Takie załoenia mogłyby wyeliminowa wiele z popularnych technik renderowania powstałych z biegiem czasu. Typy danych Aby ułatwi przenoszenie kodu korzystajcego z OpenGL na inne platformy biblioteka definiuje swoje własne typy danych. Typy te wynikaj z normalnych typów danych jzyka C, których mona uywa zamiennie, jeeli zajdzie taka potrzeba. Trzeba jednak pamita, e róne kompilatory i rodowiska stosuj swoje własne zasady definiujce wielko i ułoenie w pamici typów danych jzyka 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 odpowiadajce im typy danych jzyka C w 32-bitowych rodowiskach Windows (Win32), a take przedrostki literałów. W tym tutorialu bdziemy uywa tych przedrostków w nazwach wszystkich literałów. Jak bdzie mona zauway póniej, te same przedrostki stosowane s równie w nazwach wielu funkcji biblioteki OpenGL. 1

Wszystkie typy danych zaczynaj si od liter GL, co oznacza, e pochodz z biblioteki OpenGL. W wikszoci przypadków za tymi literami znajduje si nazwa odpowiadajcego im typu danych jzyka 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 wartoci długoci lub głbokoci. 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 cinita w zakresie do 0.0-1.0. Zmienne Glboolean uywane s do przechowywania wartoci logicznych, typ GLenum przeznaczony jest dla zmiennych wyliczeniowych, a GLbit field dla zmiennych zawierajcych pola bitowe. Wskaniki i tablice nie otrzymały adnych specjalnych oznacze. Tablice dziesiciu zmiennych typu GLshort deklarowana jest po prostu jako: GLshort shorts[10]; natomiast tablica dziesiciu wskaników na wartoci GLdoubl e deklarowana jest nastpujco: GLdouble *doubles[10]; Konwencje nazewnictwa funkcji Dla wikszoci funkcji OpenGL zastosowano konwencje nazewnicze informujce nas, z jakiej biblioteki pochodzi dana funkcja, a czsto przekazujce te informacje o liczbie i typie pobieranych parametrów. Wszystkie funkcje posiadaj rdze nazwy reprezentujcy polecenie OpenGL odpowiadajce 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 poniszym 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 parametrów (tabela 2.1) bardzo ułatwia zapamitanie listy parametrów funkcji bez koniecznoci przegldania dokumentacji. Niektóre wersje funkcji gl Color pobieraj te czwarty parametr, oznaczajcy składow alfa (przezroczysto). Wiele kompilatorów C/C++ w systemach Windows zakłada, e kada podawana jawnie warto zmiennoprzecinkowajest typu double, chyba e zostanie podany inny typ. Stosujc literały wartoci zmiennoprzecinkowych z pominiciem okrelenia, e s to wartoci typu float, a nie double, otrzymamy od kompilatora ostrzeenie mówice o tym, e próbujemy przekaza warto typu double do parametru typu float, co grozi utrat precyzji liczby. Wraz z rozrastaniem si programów korzystajcych z OpenGL liczba takich ostrzee szybko ronie w setki, co znacznie utrudnia wyszukiwanie rzeczywistych błdów. Oczywicie mona wyłczy te ostrzeenia za pomoc odpowiedniej opcji kompilatora, ale zdecydowanie odradzamy ten sposób załatwiania sprawy. Znacznie lepszym rozwizaniem jest tworzenie przejrzystego i przenonego kodu, dlatego naley usuwa te ostrzeenia poprzez 2

wyczyszczenie kodu (w tym przypadku, poprzez okrelanie typu float przy literałach wartoci zmiennoprzecinkowych), a nie wyłczanie potencjalnie przydatnych ostrzee. Poza tym, mona ulec pokusie uywania wyłcznie funkcji pobierajcych liczby zmien-noprzecinkowe o podwójnej precyzji i nie zawraca sobie głowy podawaniem typu kadej wpisywanej jawnie wartoci. Niestety, biblioteka OpenGL wewntrznie uywa wartoci typu float, wic uywanie wartoci innych ni float powoduje zmniejszenie wydajnoci, poniewa musz by one cały czas konwertowane na odpowiedni posta, zanim biblioteka bdzie mogła si nimi zaj (nie wspominajc nawet o tym, e zmienne typu double zajmuj dwa razy wicej miejsca ni zmienne typu float). W programie, w którym przerzucanych" jest wiele takich liczb, moe to mie znaczcy wpływ na wydajno! 3

Nasz pierwszy program W celu lepszego poznania biblioteki GLUT przyjrzyjmy si teraz prawdopodobnie najmniejszemu na wiecie programowi korzystajcemu z OpenGL, który napisany został z wykorzystaniem biblioteki GLUT. Na poniszym 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 czyszczcym 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 wejcia 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. Jeeli uruchomiony został z poziomu Visual C++. to po jego zakoczeniu w oknie konsoli pojawi si komunikat Press any key. Aby całkowicie zamkn program, konieczne bdzie nacinicie dowolnego klawisza. Ta standardowa funkcja rodowiska programistycznego Microsoftu uywana w czasie uruchamiania programów konsolowych ma na celu umoliwienie nam przejrzenia wszystkich komunikatów jakie mógł wygenerowa program, zanim jego okno zniknie z ekranu. Jeeli ten sam program uruchomimy z poziomu wiersza polece, to nie stwierdzimy takiego zachowania. Jeeli klikniemy dwukrotnie plik w Eksploratorze, to zobaczymy co prawda okno konsoli, ale zniknie ono w momencie zamknicia 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 Powyszy kod zawiera tylko jedn instrukcj włczenia pliku nagłówkowego: #include <0penGL.h> Plik ten włcza w siebie pliki nagłówkowe gl.h i glut.h, w których zapisane s prototypy funkcji uywanych w programie. Ciało Nastpnie przejdziemy do punku wejcia wszystkich programów jzyka C: void main(void) Wykonywanie programów w C i C++ działajcych w trybie konsoli zawsze rozpoczyna si od funkcji mai n. Dowiadczeni programici tworzcy w systemie Windows mog zastanawia si, gdzie podziała si funkcja WinMain. 4

Nie ma jej, poniewa uruchamiana jest aplikacja konsolowa, wic nie musimy tworzy adnego okna, ani obsługiwa kolejki komunikatów. Za pomoc Win32 moliwe jest tworzenie okien graficznych z poziomu aplikacji konsolowej, podobnie jak mona tworzy okna konsoli z poziomu aplikacji z interfejsem GUI. Wszystkie szczegóły zapisane s wewntrz biblioteki GLUT. Trzeba pamita, e ta biblioteka została zaprojektowana tak, eby ukrywa te włanie szczegóły działania platformy. Tryb wywietlania pojedynczy bufor W przedstawionej tutaj pierwszej linii kodu przekazujemy bibliotece GLUT informacj, jakiego trybu wywietlania ma uywa w czasie tworzenia okna: glutlnitdisplaymode(glut SINGLE GLUTRGBA); Podane tu znaczniki nakazuj bibliotece uywa 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 wywietlanym włanie oknie. Alternatyw jest okno z podwójnym buforowaniem, w którym polecenia rysowania wykonywane s na nie wywietlanym buforze, który jest nastpnie szybko przekazywany do widocznego okna. Ta metoda jest czsto stosowana do uzyskania efektu animacji, a jej zastosowanie demonstrowane jest w dalszej czci tego rozdziału. Tak naprawd to trybu podwójnego buforowania bdziemy uywa we wszystkich pozostałych przykładach w tym tutorialu. Tryb koloru RGBA oznacza, e musimy osobno podawa intensywnoci 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 wczeniej zdefiniowanej palecie. Tworzenie okna OpenGL Nastpne wywołanie funkcji z biblioteki GLUT tworzy okno na ekranie. Ponisze polecenie tworzy nowe okno i nadaje mu nagłówek Simple: glutcreatewindow("simple"); W jedynym parametrze funkcji glutcreatewindow przekazywany jest tekst nagłówka tworzonego okna. Wywietlajca funkcja zwrotna W nastpnym wierszu naszego programu znajduje si wywołanie kolejnej funkcji biblioteki GLUT: glutdisplayfunc(renderscene); W tej linii ustalamy, e zdefiniowana wczeniej funkcja RenderScene bdzie funkcj zwrotn callback function) wywietlajc obraz na ekranie. Oznacza to, e biblioteka GLUT bdzie wywoływa wskazan tu funkcj za kadym razem, gdy okno bdzie wymagało przerysowywania. Takie wywołanie nastpi przy pierwszym wywietleniu okna, a take przy zmianach jego rozmiaru albo odsłoniciu. W tym włanie miejscu umieszczamy wywołania funkcji renderujcych biblioteki OpenGL. Ustalenie kontekstu i start W nastpnym wierszu znajduje si polecenie niezwizane ani z bibliotek GLUT, ani z OpenGL, ale jest to rozwizanie, którego bdziemy uywa w całym tutorialu. SetupRC(); W tej funkcji wykonujemy wszystkie inicjalizacje biblioteki OpenGL, jakie musz by zakoczone przed rozpoczciem renderowania. Wiele ze stanów biblioteki OpenGL musi by ustalonych tylko raz i nie wymaga póniejszych modyfikacji przy renderowaniu kadej ramki (przygotowywanej do wywietlenia). Ostatnie wywołaniem funkcji biblioteki GLUT znajduje si na kocu programu: glutmainloop(); Ta funkcja uruchamia szkielet biblioteki GLUT. Po zdefiniowaniu funkcji zwrotnej obsługujcej rysowanie na ekranie i innych funkcji (powiemy o nich w dalszej czci) uruchamiany jest mechanizm biblioteki. Powrót z funkcji glutmainloop nastpuje dopiero przy zakoczeniu pracy programu, dlatego wystarczy wywoła j tylko raz. Funkcja ta przetwarza wszystkie komunikaty systemu operacyjnego, nacinicia klawiszy i inne, do czasu zakoczenia pracy 5

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 zawartoci okna. Prototyp tej funkcji wyglda nastpujco: void glclearcolor(glclampf red. GLclampf green. GLclampf blue. GLclampf alpha); W wikszoci implementacji biblioteki OpenGL typ GLclapf zdefiniowany jest jako float. W OpenGL pojedynczy kolor reprezentowany jest jako mieszanka składowych, czerwonej, zielonej i niebieskiej. Warto kadej z nich musi mieci 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 dajcego w wyniku warto COLORREF. Rónica polega na tym, e w systemie Windows kada składowa koloru w strukturze COLORREF moe przyjmowa wartoci od 0 do 255, co w wyniku daje 256x256x256, czyli ponad 16 milionów kolorów. W bibliotece OpenGL warto kadej składowej koloru moe przyjmowa dowoln warto zmiennoprzecinkowz zakresu od 0 do i. co oznacza, e teoretycznie mona zdefiniowa nieskoczon liczb kolorów. W praktyce moliwoci odtwarzania kolorów w wikszoci urzdze ograniczone s do 24 bitów, czyli 16 milionów kolorów. Oczywicie, zarówno system Windows, jak i biblioteka OpenGL pobieraj warto koloru i przekształcaj j wewntrznie do najbliszego koloru moliwego do uzyskania na dostpnym sprzcie wideo. W tabeli 2.2 wypisalimy kilka typowych kolorów i wartoci ich składowych. Mona z nich korzysta w kadej funkcji OpenGL zwizanej 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 przezroczystoci. Przezroczysto obiektu jest własnoci pozwalajc na przenikanie wiatła przez obiekt. Przypumy, e chcielibymy 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 wygld czerwonej barwy szkła mieszanka kolorów niebieskiego i czerwonego daje w efekcie kolor purpurowy. Warto składowej alfa mona zastosowa do uzyskania półprzeroczystego koloru czerwonego, który wygldałby jak talia szkła, zza której widoczne byłyby inne obiekty. Taki efekt wie si nie tylko z wykorzystaniem składowej alfa, ale na razie warto składowej alfa bdziemy ustala na 1. 6

Czyszczenie bufora kolorów Do tej pory nakazalimy bibliotece OpenGL uywa koloru niebieskiego jako koloru czyszczcego. W funkcji RenderScene musimy teraz wykona właciw operacj czyszczenia: glclear(gl_color_buffer_bit); Funkcja glclear czyci zawarto okrelonego bufora lub kombinacji buforów. Bufor jest obszarem w pamici przechowujcym informacj o obrazie. Składowe czerwona, zielona i niebieska, tworzce rysunek, zazwyczaj opisywane s terminem bufora koloru (ang. color buffer) lub bufora pikseli (ang. pixel buffer). W bibliotece OpenGL dostpnych jest kilka rodzajów buforów (koloru, głbi, szablonowy i akumulacji). Na razie wystarczy pamita, e bufor koloru jest miejscem, w którym wewntrznie zapisywany jest wywietlany obraz, a czyszczenie tego bufora poleceniem glclear powoduje usunicie z okna ostatniego obrazu. Czyszczenie kolejki W kocu 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 wewntrznie korzysta z potoku renderujcego sekwencyjnie przetwarzajcego polecenia. Polecenia i instrukcje OpenGL najczciej umieszczane s w kolejce do czasu, a sterownik OpenGL bdzie mógł przetworzy kilka polece naraz. Takie działanie podnosi wydajno, poniewa komunikacja ze sprztem jest z natury powolna. Jednokrotne przesianie do karty graficznej wikszej iloci danych jest znacznie szybsze ni wykonywanie kilku przesyłów, po jednym dla kadego polecenia lub instrukcji. W krótkim programie przedstawionym w powyszym listingu, funkcja glflush nakazuje bibliotece rozpoczcie przetwarzania dostarczonej do tej pory instrukcji, bez czekania na pojawianie si kolejnych polece rysowania. Program SIMPLE z cał pewnoci nie naley do najciekawszych programów uywajcych biblioteki OpenGL, ale dobrze obrazuje podstawy korzystania z okna za pomoc biblioteki GLUT, a take przedstawia sposób okrelania koloru i czyszczenia zawartoci okna. Teraz nieco rozbudujemy nasz program, dodajc 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 moliwo zmiany połoenia i rozmiaru okna, tak eby kod renderujcy odpowiednio reagował na te zmiany. Na poniszym listingu podano wszystkie potrzebne modyfikacje programu. #include <OpenGL.h> /////////////////////////////////////////////////////////// // Wywoływana w celu przerysowania sceny void RenderScene(void) // Wyczyszczenie okna aktualnym kolorem czyszczcym glclear(gl_color_buffer_bit); // Aktualny kolor rysujcy - czerwony // R G B glcolor3f(1.0f, 0.0f, 0.0f); // Narysowanie prostokta wypełnionego aktualnym kolorem glrectf(-25.0f, 25.0f, 25.0f, -25.0f); // Wysłanie polece do wykonania glflush(); 7

/////////////////////////////////////////////////////////// // Konfiguracja stanu renderowania void SetupRC(void) // Ustalenie niebieskiego koloru czyszczcego 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 wielkoci widoku na równ wielkoci okna glviewport(0, 0, w, h); // Ustalenie układu współrzdnych glmatrixmode(gl_projection); glloadidentity(); // Wyznaczenie przestrzeni ograniczajcej (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 wejcia 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 rysujcego dodalimy nastpujce wiersze: //Aktualny kolor rysujcy - czerwony // RGB glcolor3f(1.0f, 0.0f, 0.0f); // Narysowanie prostokta 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 nastpnie funkcj glrectf rysujemy sam prostokt. Funkcja glcolor3f pozwala na takie same wybranie koloru jak funkcja glclearcolor, cho nie wymaga podania wartoci przezroczystoci alfa. Przyjmowana jest domylna warto 1.0, co oznacza brak przezroczystoci: void glcolor3f(glfloat red. GLfloat green. GLfloat blue): Funkcja glrectf pobiera parametry zmiennoprzecinkowe, co jest sygnalizowane kocow 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ółrzdnych (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 prostokta, a druga para prawy dolny. 8

W jaki sposób OpenGL przekłada te współrzdne na rzeczywiste pozycje w oknie? Wykonywane jest to włanie w funkcji zwrotnej ChangeSize. Funkcja ta zdefiniowana została jako funkcja zwrotna wywoływana za kadym razem, gdy zmienia si rozmiar okna (w momencie rozcignicia, maksymalizacji itp.). Wyznaczenie tej funkcji odbywa si w bardzo podobny sposób jak wyznaczenie wywietlajcej funkcji zwrotnej: glutreshacefunc(changesize): Za kadym razem, gdy zmienia si wielko lub dowolny wymiar okna, konieczne jest ponowne ustalenie układu współrzdnych. Skalowanie do okna W niemal wszystkich rodowiskach okienkowych uytkownik moe w dowolnym momencie zmieni wielko i wymiary okna. Nawet jeeli tworzymy gr cały czas działajc na pełnym ekranie, to i tak okno raz zmienia swoj wielko przy uruchomieniu programu. W takim wypadku okno reaguje ponownym rozrysowaniem swojej zawartoci, przy czym pod uwag brane s nowe wymiary okna. Czasami moe si zdarzy, e dla małych okien konieczne moe by przycicie obrazu, a wikszych oknach wywietlenie obrazu w jego oryginalnym rozmiarze. W naszych przykładach najczciej bdziemy starali si tak przcskalowa rysunek, eby dostosowa go do wymiarów okna, niezalenie od wielkoci rysunku lub okna. W efekcie w małym oknie znajdzie si pełny, cho niewielki rysunek, a w duym oknie rysunek bdzie miał taki sam wygld, cho wikszy rozmiar. Ten efekt bardzo czsto mona zobaczy w programach do rysowania, w których inne działanie ma rozciganie okna, a inne zmiana rozmiaru obrazka. Najczciej rozcignicie okna nie powoduje zmiany rozmiaru obrazka, ale powikszenie obrazu sprawia, e i okno si powiksza. Ustawienie widoku i przestrzeni ograniczajcej Omawialimy ju sposób, w jaki widok i przestrze widoczna wpływaj na zakres współrzdnych i skalowanie rysunków dwu- i trójwymiarowego w dwuwymiarowym oknie na ekranie komputera. Teraz zajmiemy si ustaleniem współrzdnych widoku i przestrzeni ograniczajcej w bibliotece OpenGL. Mimo e nasz rysunek jest dwuwymiarowym płaskim prostoktem, to i tak rysujemy w przestrzeni współrzdnych trójwymiarowych. Funkcja glrectf rysuje prostokt na płaszczynie xy ze współrzdn z równ 0 (z=0). Nasza perspektywa ustawiona jest wzdłu dodatnich wartoci osi z, tak eby widoczny był prostokt narysowany na zerowej współrzdnej z. Przy kadej zmianie rozmiaru okna, widok i przestrze ograniczajca 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ółrzdnych na współrzdne ekranowe pozostaje niezmienne bez wzgldu na zmiany rozmiarów okna. Ze wzgldu na to, e zmiany rozmiaru okna w rónych rodowiska s wykrywane i obsługiwane odmiennie, biblioteka GLUT wprowadza funkcj glutreshapefunc rejestrujc funkcj zwrotn wywoływan przez bibliotek przy kadej zmianie 9

rozmiarów okna. Funkcja przekazywana do glutreshapefunc prototypowana jest w nastpujcy sposób: void ChangeSize(GLsizei w, GLsizei h); Wybralimy dla tej funkcji opisow nazw ChangeSize (zmie rozmiar), której konsekwentnie bdziemy uywa take w kolejnych przykładach. Funkcja ChangeSize otrzymuje w parametrach now szeroko i wysoko okna, gdy tylko zmieni si jego rozmiar. Moemy uy tych informacji do zmodyfikowania odwzorowania potrzebnego nam układu współrzdnych na współrzdne 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 zawartoci funkcji ChangeSize. Na pocztku wywoływana jest w niej funkcja glviewport z podanymi nowymi wartociami szerokoci i wysokoci okna. Funkcja glviewport zdefiniowana jest nastpujco: void glviewport(glint x, Glint y, GLsizei width. GLsizei height): Parametry x i y okrelaj pozycj dolnego lewego rogu widoku wewntrz okna, a parametry width i height definiuj rozmiar tego widoku w pikselach. Najczciej wartoci parametrów x i y ustalane s na 0, ale widoków mona uywa te do renderowania kilku rysunków w rónych obszarach okna. Widok definiuje obszar wewntrz okna podawany we współrzdnych ekranu, którego OpenGL moe uywa do rysowania (zobacz rysunek 2.8). Nastpnie aktualna przestrze ograniczajca odwzorowywana jest w nowym widoku. Jeeli zdefiniujemy widok mniejszy od współrzdnych okna, to renderowany obraz po przeskalowaniu równie bdzie mniejszy, co wida na rysunku 2.8. Definiowanie widocznej przestrzeni ograniczajcej Ostatnim wymaganiem w stosunku do naszej funkcji ChangeSize jest ponowne zdefiniowanie przestrzeni ograniczajcej 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ługoci w kierunku pionowym, do liczby pikseli w jednostce długoci w kierunku poziomym. Współczynnik kształtu obrazu o wartoci 1.0 definiuje obraz kwadratowy, natomiast współczynnik o wartoci 0.5 definiuje obraz, w którym na jeden piksel w jednostce długoci w kierunku pionowym przypadaj dwa piksele w tej samej jednostce długoci w kierunku poziomym. Jeeli zdefiniujemy niekwadratowy widok, w którym odwzorowywana jest kwadratowa przestrze ograniczajca, to otrzymamy obraz zniekształcony. Na przykład widok o wymiarach identycznych z rozmiarami okna, w którym odwzorowywana jest kwadratowa przestrze ograniczajca, moe w wskich, ale wysokich oknach przedstawia wskie i wysokie obrazy, a w oknach niskich i szerokich obrazy niskie i szerokie. W takim przypadku narysowany przez nas kwadrat bdzie faktycznie wygldał jak kwadrat tylko wtedy, gdy rozmiar okna bdzie kwadratem. W naszym przykładzie do przestrzeni ograniczajcej zastosowalimy rzutowanie prostopadle. W bibliotece OpenGL funkcj tworzc takie rzutowanie jest funkcja glortho: void glortho(gldouble left. GLdouble right. GLdouble bottom, GLdouble top, GLdouble near, GLdouble far); W trójwymiarowej przestrzeni kartezjaskiej wartoci left i right okrelaj minimaln i maksymaln współrzdn na osi x, a wartoci bottom i top na osi y. Wartoci near i far dotycz osi z, przy czym najczciej wartoci ujemne rosn 10

wraz z oddalaniem si od widza (rysunek 2.9). Wiele bibliotek graficznych i rysunkowych w poleceniach ryso-wania uywa współrzdnych okna (pikseli). Nowym uytkownikom biblioteki OpenGL bardzo trudno si przyzwyczai do korzystania ze współrzdnych zmiennoprzecinkowych (sprawiajcych wraenie z niczym niezwizanych), 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ółrzdnych glmatrixmode(gl_projection); glloadldentity(); Macierz rzutowania jest miejscem, w którym rzeczywicie definiujemy nasz przestrze widoczn. Pojedyncze wywołanie funkcji glloadidentit.y jest konieczne, poniewa funkcja glortho tak naprawd nie tworzy przestrzeni ograniczajcej, ale modyfikuje istniejc przestrze. Mnoy ona macierz opisujc aktualn przestrze ograniczajc przez macierz opisujc przestrze ograniczajc podan w parametrach. Na razie wystarczy zapamita, e funkcja glloadidentity słuy do ponownego ustawienia (resetu) układu współrzdnych, zanim wykonane zostanjakiekolwiek manipulacje na macierzach. Bez ponownego ustawienia ukfadu współrzdnych przed kadym wywołaniem funkcji glortho kade kolejne wywołanie powodowałoby coraz wiksze zniekształcenia planowanej przestrzeni ograniczajcej, co w efekcie mogłoby nawet doprowadzi do zniknicia kwadratu z ekranu. Ostatnie dwa przedstawione tutaj wiersze kodu informuj bibliotek OpenGL, e wszystkie przyszłe przekształcenia bd dotyczyły naszych modeli, czyli tego, co narysujemy: glmatrixmode(gl_modelview); glloadldentity(); Musimy jednak ju teraz poda informacje o sposobie konfigurowania tych operacji ich wartociami domylnymi. Jeeli tego nie zrobimy i pozwolimy na eksperymentowanie, to wywietlany przez program obraz moe by daleki od naszych oczekiwa. Aby kwadrat był kwadratem Poniszy kod zajmuje si utrzymaniem kwadratowoci" naszego kwadratu: // Wyznaczenie przestrzeni ograniczajcej (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 ograniczajca (widoczny układ współrzdnych) modyfikowana jest w ten sposób, e lewa strona zawsze ma warto x=-100, a prawa strona rozciga si do wartoci 100, chyba e szeroko okna jest wiksza od jego wysokoci. Na podobnej zasadzie dół przestrzeni ograniczajcej zawsze ma warto y=-100, a góra rozciga si do 11

wartoci 100, chyba e wysoko okna jest wiksza od jego szerokoci. W takim przypadku, górna współrzdna równie skalowana jest współczynnikiem kształtu ekranu. W ten sposób, niezalenie od kształtu okna, utrzymywany jest kwadratowy region o wymiarach 200x200, którego rodek ma współrzdne (0.0). Rysunek 2.10 przedstawia zasad działania tego mechanizmu. 12

Animacja w OpenGL i GLUT Jak na razie omawialimy podstawy uytkowania biblioteki GLUT w zakresie tworzenia okien i korzystania z rysujcych polece OpenGL. Bardzo czsto bdziemy chcieli przesun nasz scen albo j obróci, tworzc w ten sposób efekt animacji. Wemiemy teraz poprzedni przykład z rysowanym kwadratem i sprawimy, e bdzie si on odbijał od ram okna. Moemy przygotowa ptl, w której bdziemy zmienia współrzdne obiektu przed wywołaniem funkcji RenderScene. Spowoduje to, e kwadrat bdzie sprawiał wraenie ruchu wewntrz okna. Biblioteka GLUT pozwala na zarejestrowanie specjalnej funkcji zwrotnej ułatwiajcej wykonywanie prostych sekwencji animacji. Umoliwia to funkcja gluttimerfunc, pobierajca 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 kadym wywołaniem funkcji func. W parametrze vdlue mona do tej funkcji przekazywa zdefiniowane przez uytkownika wartoci. Funkcja wywoływana co okrelony czas prototypowana jest w nastpujco: void TimerFunction(int value); Przeciwnie ni w mechanizmach czasowych systemu Windows, funkcja ta wywoływana jest tylko raz. Aby uzyska efekt cigłej animacji w samej funkcji czasowej, musimy ponownie ustawi mechanizm czasowy. W programie GLRect zmienimy teraz zapisane na stałe wartoci pozycji naszego prostokta, zastpujc je zmiennymi, a nastpnie bdziemy cały czas modyfikowa te zmienne w wywoływanej cyklicznie funkcji czasowej. W ten sposób prostokt zacznie porusza si wewntrz okna. Przyjrzyjmy si przykładowi tego rodzaju animacji. Na poniszym listingu znajduje si zmodyfikowany program z listingu poprzedniego, do którego dodano funkcj animacji kwadratu odbijajcego si od ram okna. Musimy cały czas kontrolowa pozycj i wielko kwadratu, jak równie wszystkie zmiany wielkoci okna. #include <OpenGL.h> // Pocztkowy rozmiar i pozycja prostokta 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 zmieniajcych si rozmiarów okna GLfloat windowwidth; GLfloat windowheight; /////////////////////////////////////////////////////////// // Wywoływana w celu przerysowania sceny void RenderScene(void) // Wyczyszczenie okna aktualnym kolorem czyszczcym glclear(gl_color_buffer_bit); // Aktualny kolor rysujcy - czerwony // R G B glcolor3f(1.0f, 0.0f, 0.0f); // Narysowanie prostokta 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, jeeli osignito lew lub praw krawd if(x1 > windowwidth-rsize x1 < -windowwidth) xstep = -xstep; // Odwrócenie kierunku, jeeli osignito doln lub górn krawd if(y1 > windowheight y1 < -windowheight + rsize) ystep = -ystep; 13

// Wykonanie przesunicia kwadratu x1 += xstep; y1 += ystep; // Kontrola obramowania. Wykonywana jest na wypadek, gdyby okno // zmniejszyło swoj wielko w czasie, gdy kwadrat odbijał si od // krawdzi, co mogłoby spowodowa, e znalazł by si poza // przestrzeni ograniczajc. 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ółrzdnymi glutpostredisplay(); gluttimerfunc(33,timerfunction, 1); /////////////////////////////////////////////////////////// // Konfigurowanie stanu renderowania void SetupRC(void) // Ustalenie niebieskiego koloru czyszczcego glclearcolor(0.0f, 0.0f, 1.0f, 1.0f); /////////////////////////////////////////////////////////// // Wywoływana przez bibliotek GLUT przy kadej zmianie wielkoci okna void ChangeSize(GLsizei w, GLsizei h) GLfloat aspectratio; // Zabezpieczenie przed dzieleniem przez zero if(h == 0) h = 1; // Ustalenie wielkoci widoku zgodnego z rozmiarami okna glviewport(0, 0, w, h); // Ustalenie układu współrzdnych glmatrixmode(gl_projection); glloadidentity(); // Ustanowienie przestrzeni ograniczajcej (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 wejcia programu void main(void) glutinitdisplaymode(glut_double GLUT_RGB); glutcreatewindow("bounce"); glutdisplayfunc(renderscene); glutreshapefunc(changesize); gluttimerfunc(33, TimerFunction, 1); SetupRC(); glutmainloop(); 14

Podwójne buforowanie Jedn z najwaniejszych funkcji kadego pakietu graficznego jest obsługa podwójnego buforowania. Funkcja ta pozwala na wykonywanie kodu rysujcego na buforze niewidocznym na ekranie. Nastpnie poleceniem podmiany narysowany w ten sposób obraz umieszczany jest natychmiast na ekranie. Mechanizm podwójnego buforowania ma słuy dwóm celom. Po pierwsze, rysowanie pewnych bardziej skomplikowanych rysunków moe zaj do duo czasu, co moe powodowa, e na ekranie widoczne bd kolejne kroki tworzenia obrazu. Za pomoc podwójnego buforowania obraz moe by najpierw przygotowany, a dopiero póniej wywietlony na ekranie. W efekcie uytkownik nigdy nie bdzie miał okazji zobaczy czciowo utworzonego rysunku. Drugim zastosowaniem podwójnego buforowania jest animacja. Kada ramka rysowana jest w niewywietlanym buforze, a nastpnie szybko umieszczana na ekranie poprzez zamian buforów widocznego i niewidocznego. Biblioteka GLUT pozwala na uywanie okien z podwójnym buforowaniem. Prosz na powyszym listingu zauway nastpujcy wiersz: glutinitdisplaymode(glut_double GLUT_RGB); Zmienilimy stał GLUT_SINGLE na GLUT_DOUBLE. Ta zmiana powoduje, e wszystkie polecenia działaj na buforze niewidocznym. Nastpnie, zmienilimy te kocó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 odbijajcego si od krawdzi okna. Funkcja glutswapbuffers powoduje wyczyszczenie bufora polece, nawet jeeli działalibymy w trybie pojedynczego buforowania. Aby zobaczy, jak ta sama animacja wyglda bdzie w trybie buforowania pojedynczego, wystarczy w programie zmieni stał GLUT_DOUBLE na GLUT_SINGLE. Jak mona zauway, kwadrat cały czas zacina si i migocze w trybie pojedynczego buforowania efektu animacji nie mona nazwa zadowalajcym. Biblioteka GLUT stanowi wzgldnie prost podstaw dla tworzenia złoonych programów przykładowych, a nawet rozbudowanych aplikacji komercyjnych (zakładajc, e nie potrzeba nam funkcji systemu operacyjnego i interfejsu GUI). Zadaniem tego tutorialu nie jest jednak opisywanie biblioteki GLUT w całej jej wielkoci. Bdziemy 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łoone. W kolejnych rozdziałach opisywa bdziemy róne funkcje biblioteki OpenGL. Wiele rónych efektów moe wpływa na sposób rysowania kadego wycinka geometrii. Czy pada na niego wiatło? Jakie s właciwoci tego wiatła? Jakie s właciwoci materiału? Jak tekstur naley zastosowa? Czy w ogóle stosowa jakkolwiek tekstur? List takich pyta mona by jeszcze długo rozbudowywa. T kolekcj zmiennych nazywamy stanem potoku. Maszyna stanów jest abstrakcyjnym modelem kolekcji zmiennych stanu, z których kada moe przyjmowa róne wartoci, by włczana lub wyłczana itd. Okrelanie wszystkich zmiennych stanu, za kadym razem gdy chcemy co narysowa, nie jest praktyczne, dlatego biblioteka OpenGL wprowadza model stanów (lub maszyn stanów) zapamitujcy wartoci wszystkich zmiennych stanu. Gdy jakiej zmiennej nadawana jest warto, to pozostaje ona niezmieniona do czasu, a zmieni jjaka inna funkcja. Wiele zmiennych stanów jest po prostu włczana i wyłczana. Na przykład owietlenie mona włcza i wyłcza. Obiekty rysowane bez włczonego owietlenia s rysowane bez wykonywania jakichkolwiek oblicze owietlenia wpływajcego na zcsiaw kolorów zastosowany w obiekcie. Ten sam obiekt rysowany po włczeniu owietlenia rysowany jest z zastosowaniem oblicze owietlenia. Aby włczy ten rodzaj zmiennych stanu, naley uy nastpujcej funkcji OpenGL: void glenable(glenum capability); 15

T sam zmienn mona póniej wyłczy za pomoc nastpujcej funkcji: void gldisable(glenum capability); W przypadku owietlenia, ponisz instrukcj mona włczy odpowiedni stan: glenable(gl_lighting); Wyłczanie tego stanu odbywa si poprzez wywołanie poniszej instrukcji: gldisable(gl_lighting); Jeeli chcielibymy sprawdzi, czy jaka zmienna stanu jest włczona, to biblioteka OpenGL udostpnia 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 bdziemy opisywa, moe przyjmowa wartoci zapamitywane do czasu ich zmiany. Moemy te w dowolnym momencie sprawdzi, jakie wartoci przechowywane s w tych zmiennych. Dostpny jest w tym celu zestaw funkcji pozwalajcych na sprawdzenie wartoci logicznych, całkowitych, zmiennoprzecinkowych pojedynczej oraz podwójnej precyzji. Prototypy tych czterech funkcji wygldaj nastpujco: void glgetbooleanv(glenum pname. GLboolean *params); void glgetdoublev(glenum pname, GLdouble *params); void glgetfloatv(glenum pname, GLfloat *params); void glgetintegerv(glenum pname. GLint *params); Kada z funkcji moe zwróci pojedyncz warto lub cał tablic wartoci, które zapisywane s pod podanym adresem. Wikszo z tych funkcji z pewnoci nie bdzie od razu zrozumiała, ale wraz z dowiadczeniem ronie równie zrozumienie. Zapisywanie i odtwarzanie stanów Biblioteka OpenGL posiada równie bardzo wygodny mechanizm zapisywania i odtwarzania całych zakresów wartoci stanu. Stos jest wygodn struktur danych pozwalajc na odkładanie wartoci (push) i póniejsze zdjcie ich ze stosu (pop). Elementy s zdejmowane ze stosu w kolejnoci odwrotnej do kolejnoci kładzenia ich na stosie. Tak struktur nazywa si UFO (ang. Last In First Out ostatni przyszedł, pierwszy wyjdzie). Mona j prosto opisa w nastpujcy sposób: mówic: Prosz, zachowaj to dla mnie", zapisujemy dane na stos, a póniej, mówic: Oddaj mi to, co włanie zapisałem", zdejmujemy dane ze stosu. Idea stosu odgrywa znaczc rol w manipulacjach macierzami. Poniszym poleceniem moemy zapisa na stos atrybutów zarówno pojedyncz warto stanu, jak i cały ich zbiór: void glpushattrib(glbitfield mask); Odpowiednio, te same wartoci mog by odczytane za pomoc tego polecenia: void glpopattrib(glbitfield mask): Prosz zauway, 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 jzyku C reprezentowanej przez operator ), dziki czemu w jednym wywołaniu funkcji mona zapisa kilka wartoci zmiennych stanu. Na przykład moemy zapisa stan owietlenia i teksturowania, wywołujc nastpujce polecenie: glpushattrib(gl_texture_bit GL_LIGHTING_BIT); 16

Rysowanie 3D Rysowanie punktów Zaczniemy od pierwszych i najprostszych obiektów podstawowych punktów. Przyjrzyjmy si poniszemu kodowi: glbegin(gl_points); glvertex3f(0.0f. O.0f. O.Of): glvertex3f(50.0f, 50.Of, 50. 0f); g lend (): //Obiektami podstawowymi bdpunkty //Definiujemy punkt //Definiujemy kolejny punkt // 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 wan rzecz, o której trzeba pamita, stosujc funkcje glbegin i glend midzy ich wywołaniami moemy podawa cał list obiektów podstawowych pod warunkiem, e s one tego samego typu. W ten sposób jedn sekwencj funkcji glbegin i glend moemy doda do sceny dowoln liczb obiektów podstawowych. Poniszy segment kodu dla odmiany bdzie wykonywał si znacznie wolniej ni podany wczeniej: gl Begm(GL_POINTS); glvertex3f(0.0f, 0.0f, 0.0f); glend(); g1begin(gl_points): glvertex3f(50 0f, 50.0f, 50.0f); glend() ; // Definiujemy punkt do rysowania // Definiujemy kolejny punkt Nasz pierwszy przykład Kod z poniszego listingu rysuje w rodowisku trójwymiarowym kilka punktów. Program stosuje proste obliczenia trygonometryczne do wyznaczenia pozycji serii punktów tworzcych co w rodzaju korkocigu wokół osi z. Kod pochodzi z programu POINTS, który mona pobra wraz z tym tutorialem. Naley zauway, e w funkcji SetupRC ustalamy aktualny kolor rysujcy na zielony. #include <math.h> // Definiujemy stał o wartoci 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 przechowujce współrzdne i kty // Wyczyszczenie okna aktualnym kolorem czyszczcym 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); 17

// Okrelenie punktu i przesunicie współrzdnej Z glvertex3f(x, y, z); z += 0.5f; // Zakoczenie 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 ); // Bdziemy 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; // Odwieenie zawartoci 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 ograniczajcej (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); 18

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 wany jest jedynie kod pomidzy wywołaniami funkcji glbegin i glend. Powyszy kod wylicza współrzdne x i y na podstawie kta trzykrotnie rosncego od wartoci 0 do 360. W programie przedstawiamy te wartoci w radianach, a nie w stopniach; kto nie zna trygonometrii, musi uwierzy na słowo. Przy rysowaniu kadego punktu warto współrzdnej z powikszana jest o niewielk warto. Po uruchomieniu programu zobaczymy na ekranie koło składajce si z samych punktów. Wynika to z tego, e pocztkowo bdziemy patrze wzdłu osi z. Aby zobaczy cał spiral, naley naciskajc klawisze strzałek, obróci rysunek wokół osi x i y. Ustalanie wielkoci punktu W czasie rysowania pojedynczego punktu domyln wielkoci tego punktu jest jeden piksel. Mona to zmieni, stosujc funkcj glpointsize: void glpointsize(glfloat size): Funkcja glpointsize pobiera jeden parametr okrelajcy przyblion wielko rysowanego punktu podan w pikselach. Niestety, nie mona poda dowolnego rozmiaru punktu, dlatego naley si upewni, czy podawany rozmiar bdzie prawidłowo obsłuony. Mona uy poniszego kodu w celu sprawdzenia zakresu dostpnych rozmiarów punktów i najmniejszych odstpów midzy nimi. GLfloat sizes[2]; GLfloat step; // Do zapisania dopuszczalnego zakresu wielkoci //Zapamituje obsługiwany przyrost rozmiaru // Pobranie dopuszczalnych rozmiarów punktów glgetfloatv(gl_point_size_range, s izes); glgetfloatv(gl_point_size_granularity, &step); W tablicy sizes znajd si dwa elementy okrelajce najmniejsz i najwiksz warto przyjmowan przez funkcj gl PointSi ze. Dodatkowo zmienna step przechowywa bdzie rozmiar dopuszczalnego kroku pomidzy 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 wielkoci 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 bdzie rozmiar najbliszy podanemu. W przeciwiestwie 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 powikszaj si wraz z przyblianiem si. Poza tym punkty zawsze maj kształt kwadratu, nawet jeeli za pomoc funkcji gl PointSi ze powikszymy ich rozmiar. Na ekranie zobaczymy tylko coraz wiksze kwadraty! Aby uzyska punkty okrgłe, musimy rysowa je z włczonym efektem antyaliasingu. Przyjrzyjmy si przykładowi wykorzystujcemu te nowe funkcje. Kod z poniszego listingu tworzy tak sam spiral co kod z pierwszego przykładu, ale tym razem punkty s stopniowo powikszane od najmniejszej moliwej wartoci, do najwikszej. Przykład pochodzi z programu POINTSZ który mona pobra wraz z tym tutorialem. // Definiujemy stał o wartoci 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 przechowujce współrzdne i kty GLfloat sizes[2]; // Do zapisania dopuszczalnego zakresu wielkoci GLfloat step; // Zapamituje obsługiwany przyrost rozmiaru GLfloat cursize; // Zapamituje aktualny rozmiar 19

// Wyczyszczenie okna aktualnym kolorem czyszczcym 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 pocztkowego rozmiaru punktu cursize = sizes[0]; // Ustalenie pocztkowej współrzdnej 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 wartoci 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(); // Powikszenie współrzdnej 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 ); // Bdziemy 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; // Odwieenie zawartoci okna glutpostredisplay(); 20

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 ograniczajcej (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 powyszym przykładzie zademonstrowanych zostało kilka wanych rzeczy. Przede wszystkim trzeba zauway, e funkcja glpointsize musi by wywoływana poza zakresem objtym funkcjami glbegin i glend. Nie wszystkie funkcje OpenGL mog by wywoływane pomidzy wywołaniami tych dwóch funkcji. Mimo e funkcja gl PointSize wpływa na wszystkie narysowane póniej punkty, to samo rysowanie nie moe rozpocz si przed wywołaniem funkcji glbegin(gl_points). Jeeli podamy w parametrze funkcji glpointsize rozmiar punktu wikszy ni warto zwrócona do zmiennej size, to zauwaymy, e biblioteka stosowa bdzie najwikszy dostpny rozmiar punktu, ale nie bdzie ich bardziej powiksza. Jest to zasada wspólna dla wszystkich funkcji OpenGL przyjmujcych parametry z pewnego zakresu wartoci. Wszystkie wartoci spoza dopuszczalnego zakresu modyfikowane s w taki sposób, aby si w tym zakresie zmieciły. Wartoci zbyt małe powikszane s do najmniejszej dopuszczalnej wartoci, a wartoci zbyt due zmniejszane do najwikszej dopuszczalnej. Ja mona zauway w przykładowym programie POINTSZ, punkty o wikszych rozmiarach rysowane s po prostu jako wiksze kwadraty. Jest to domylne zachowanie biblioteki, cho w wielu aplikacjach takie działanie jest raczej niepodane. Poza tym mona si zastanawia, dlaczego moliwe jest definiowanie punktów o wielkoci mniejszej ni jeden. Jeeli punkt o wielkoci 1.0 oznacza jeden piksel, to jak mona przedstawia piksel o wielkoci, powiedzmy, 2.5? Odpowied na to pytanie brzmi: parametr pobierany przez funkcj gl PointSize nie oznacza dokładnego rozmiaru punktu w pikselach, ale przyblion rednic koła zawierajcego wszystkie piksele uyte do narysowania punktu. Poprzez włczenie wygładzania punktów (ang. point smoothing) mona zmusi bibliotek OpenGL do rysowania ładniej wygldajcych 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 wygładzenia schodkowatych krawdzi i zaokrglania rogów. 21