Laboratorium 2 OpenGl (2)

Transkrypt

Laboratorium 2 OpenGl (2)
Laboratorium 2
OpenGl (2)
Celem ćwiczenia jest zaznajomienie się ze sposobami interpretacji przestrzeni 2D oraz 3D przez środowisko biblioteki
graficznej OpenGL. Dodatkowo zostanie pokazany sposób na interakcje z programem poprzez klawiaturę. Pokazany zostanie
również prosty sposób animacji.
Przestrzeń obiektu (inaczej przestrzeń modelu) – jest to układ współrzędnych obiektu, w którym ten obiekt jest definiowany.
Przykładowo: dla sfery jej przestrzenią obiektu może być układ współrzędnych, którego środek jest środkiem sfery; dla walca
środek układu może leżeć w środku podstawy, a kierunek osi z jest zgodny z kierunkiem osi symetrii tego walca. Położenie
wierzchołków w przestrzeni obiektów jest określone jako wektor [x, y, z].
Współrzędne homogeniczne – to czteroelementowy wektor postaci [x, y, z, w], w którym pierwsze 3 składniki określają
położenie w przestrzeni 3D, a czwarty to dodatkowy parametr w. Jeśli wektor położenia zostaje wyrażony za pomocą wektora
3-elementowego to zakłada się, że w = 1. Matematyczne znaczenie parametru w jest takie, że jest to wartość, przez którą
należy podzielić x, y i z by uzyskać położenie w postaci tradycyjnej. Tak, więc jest to pewien współczynnik skali.
Przestrzeń świata – przestrzeń konkretnego obiektu nie ma związku z innymi obiektami posiadającymi własne przestrzenie.
Przestrzeń świata definiuje pewien bezwzględny punkt odniesienia dla wszystkich obiektów sceny. Jeśli przyjmiemy, że
przestrzenią świata jest sala laboratoryjna, to obiekty w niej występujące (komputery, stoły, krzesła) mają różne położenie i
ukierunkowanie.
Przekształcenie modelu – opisuje sposób, w jaki obiekt w przestrzeni modelu jest transformowany do przestrzeni świata. Na
przykład, musimy obrócić, przeskalować i przesunąć stolik by znalazł się on w odpowiednim miejscu w laboratorium.
Wszystkie te przekształcenia można zapisać matematycznie jako macierze 4x4 i składać je w jedną macierz transformacji, co
jest istotne dla wydajności programu. Mnożąc położenie punktu w postaci homogenicznej (w = 1) w przestrzeni modelu
przez macierz 4x4 reprezentującą przekształcenie modelu w przestrzeń świata, otrzymamy to samo położenie opisane w
przestrzeni świata.
Przestrzeń oka (inaczej przestrzeń widoku) – to przestrzeń obserwatora, czyli układ współrzędnych obserwatora względem,
którego opisujemy położenie obserwowanych obiektów w scenie. W standardzie OpenGL przyjęło się, że domyślnie
obserwator („oko”) znajduje się w początku swojego układu współrzędnych, a kierunek patrzenia na scenę jest zgodny z
kierunkiem osi z i biegnie wzdłuż jej ujemnych wartości.
Przekształcenie widoku – konwertuje położenie w przestrzeni świata na położenie w przestrzeni obserwatora. To
przekształcenie da się zestawić w postaci macierzy 4x4 i nazywane jest macierzą model-widok. Jest to macierz, która łączy w
sobie przekształcenie modelu i przekształcenie widoku.
Przestrzeń przycięcia – kiedy położenia znajdują się już w przestrzeni oka, kolejnym krokiem jest określenie, które z nich
znajduje się w widocznym obszarze. Zatem kolejnym układem po przestrzeni oka jest przestrzeń przycięcia. Wyjaśnienie tej
techniki można prześledzić obserwując działanie funkcji np. glOrtho().
Przekształcenie, które konwertuje współrzędne przestrzeni oka do przestrzeni przycięcia jest nazywane przekształceniem
rzutowania. To przekształcenie definiuje obszar przestrzeni oka, w którym znajdują się widoczne obiekty. W OpenGL
wszystko co ma być widoczne musi się znajdować w sześcianie, którego każdy punkt spełnia nierówności: -w ≤ x ≤ w, -w ≤ y
≤ w, -w ≤ z ≤ w. Przekształcenie to podobnie jak wcześniej wymienione da się zestawić w postaci tzw. macierzy rzutowania o
rozmiarach 4x4.
Znormalizowane współrzędne przycięcia – współrzędne przycięcia maja postać homogeniczną [x, y, z, w], lecz koniecznym
jest aby uzyskać położenie w przestrzeni dwu-wymiarowej (x,y) wraz zadaną wartością głębi. Uzyskuje się to dzieląc
składowe wektora x, y, z przez składnik w. W ten sposób otrzymane współrzędne noszą nazwę znormalizowanych
współrzędnych urządzenia. Na ostatnim etapie następuje transformacja znormalizowanych współrzędnych urządzenia na
współrzędne okna, które mierzone są w pikselach.
Animacja w OpenGL może być realizowana w prosty sposób. Wystarczy aby przed wywołaniem funkcji renderującej scenę
wywołać funkcję, która będzie wyliczała np. aktualne położenie obiektu na podstawie zapamiętanego wcześniej położenia.
Zmiana tego parametru może być dokonywana w wybranych chwilach czasowych. Zrealizować to można za pomocą funkcji
glutTimerFunc z biblioteki GLUT. Jako pierwszy argument tej funkcji podaje się liczbę milisekund, po upływie których
funkcja wywołuje funkcję, której nazwa została podana jako drugi argument. Prototyp funkcji wywołującej jest następujący:
void TimerFunction(int value);
GLUT czeka zadaną liczbę milisekund poczym odpala wykonanie funkcji TimerFunction(). Jednakże, jest to jednorazowe
wywołanie, więc aby zachować ciągłość należy w funkcji TimerFunction() zresetować licznik wywołaniem:
glutTimerFunc(30, TimerFunction, 1); /*1*/
1. Skompiluj i uruchom załączony program.
2. Zmodyfikuj funkcję DrawSceneAxes dodając na jej końcu ustawianie koloru rysowania na szary (wszystkie
składowe koloru przyjmują wartość 0.5f), oraz funkcję z biblioteki GLUT rysującą dzbanek na herbatę:
glutWireTeapot(4.0);
3. Skompiluj i uruchom program. Dzbanek jest rysowany jako niepełna siatka - co należy poprawić w kodzie by
siatka była rysowana w całości (może coś jest nie tak z rzutowaniem)? Dokonaj stosownych poprawek i
sprawdź rezultaty.
4. Po uruchomieniu na ekranie widzimy obrazek, gdzie dzbanek widoczny jest w pozycji, w której nie da się
stwierdzić czy jest to obiekt trójwymiarowy czy tylko płaska siatka. Żeby pokazać trójwymiarową strukturę
tego obiektu musimy go obrócić nieznacznie. W tym celu, w linii poprzedzającej rysowanie dzbanka dodaj
wywołanie: glRotatef(-20.0f, 1.0f, 0.3f, 0.0f);Zobacz efekt.
5. Korzystając z operacji obrotu, przesunięcia (glTranslatef) oraz skalowania (glScalef), spróbuj przemieścić,
obrócić i przeskalować dzbanek. Czy efekt będzie ten sam jeśli zamienimy kolejność operacji?
6. Powróć do kodu z pkt. 4. Zmodyfikuj kod tak aby dzbanek obracał się wokół osi x i y. W tym celu zadeklaruj
dwie zmienne globalne przechowujące bieżący kąt obrotu względem podanych osi, np.:
/* Kąty obrotu wokół osi X i Y */
GLfloat x_angle;
GLfloat y_angle;
7. Obrotu dokonuj za pomocą funkcji:
glRotatef(x_angle, 1.0f, 0.0f, 0.0f);
glRotatef(y_angle, 0.0f, 1.0f, 0.0f);
8. Zdefiniuj własną procedurę TimerFunction(), w której będzie następowała odpowiednia inkrementacja tych
zmiennych o wartość v_angle z pkt. 10. Przed wyjściem z tej funkcji umieść resetowanie licznika milisekund
(/*1*/). Funkcje zakończ wywołaniem funkcji odświeżającej okno: glutPostRedisplay(). W funkcji main, w
linii za rejestracją funkcji zwrotnych umieść resetowanie licznika (/*1*/).
9. W funkcji main dodaj linię:
glutKeyboardFunc(KeyboardFunc);
10. Skopiuj i wklej poniży kod. Następnie dokonaj stosownych modyfikacji tak aby wciśnięcie klawisza ‘w’ lub ‘r’
powodowało przyspieszenie lub spowolnienie (poprzez obrót w przeciwnym kierunku) obracania się dzbanka.
Pamiętaj o deklaracji zmiennej globalnej GLfloat v_angle;
/* Funkcja obsługująca klawiaturę
*/
void KeyboardFunc(unsigned char key, int x, int y)
{
switch(key)
{
case 27: // Wciśnięcie klawisza ESC spowoduje wyjście z programu
exit(0);
case 'w': // Wciśnięcie klawisza w spowoduje inkrementację zmiennej
v_angle += 0.05f;
break;
case 'r': // Wciśnięcie klawisza r spowoduje dekrementację zmiennej
v_angle -= 0.05f;
break;
}
glutPostRedisplay();
}