GRAFIKA CZASU RZECZYWISTEGO Wprowadzenie do OpenGL Grafika komputerowa i wizualizacja, Bioinformatyka S1, II Rok
OpenGL Open Graphics Library Jest to API pozwalające na renderowanie grafiki w czasie rzeczywistym, zorientowane na wykorzystanie akceleracji sprzętowej OpenGL nie jest biblioteką Jest to specyfikacja interfejsu programowania (API) Bibliotekami są implementacje OpenGL na konkretne platformy, dostarczane przez producentów sprzętu, systemów operacyjnych itp. Jednym z głównych celów OpenGL jest wieloplatformowość Konkurencją jest Microsoft Direct3D z DirectX 2
OpenGL OpenGL opisuje zbiór funkcji i numerycznych stałych, pozwalających na renderowanie grafiki Nie obejmuje procedur obsługi wejścia, czy integracji z systemem operacyjnym w celu utworzenia kontekstu Istnieją multiplatformowe biblioteki dedykowane dla OpenGL, które rozwiązują te problemy: np. GLUT (freeglut), GLFW Założeniem jest, że implementacja OpenGL opiera się głównie na procedurach sprzętowych Operacje wykonywane bezpośrednio przez kartę graficzną, a nie software'owe rozwiązania oparte o CPU Wiele z oferowanych możliwości, jeśli nie są zaimplementowane w procedurach sprzętowych, może być emulowanych na CPU 3
OpenGL Historia 1992 OpenGL 1.0 wydany przez Sillicon Graphics (SGI) 1997-2003 rozszerzenia OpenGL 1.x 2004 OpenGL 2.0, zorientowany na programowalny potok renderowania (shadery, GLSL) 2006 OpenGL rozwijany jest przez non-profitową organizację Khronos Group 2008 OpenGL 3.0, znaczne ograniczenie API, usunięcie archaicznych podejść 2010 OpenGL 4.0, odpowiednik DirectX 11 (np. teselacja) 2012 OpenGL 4.3, aktualna wersja OpenGL ES Podzbiór standardu OpenGL, przeznaczony do implementacji na urządzeniach mobilnych OpenGL ES 3.0 wersja najbardziej aktualna (2012), kopmpatybilna z OpenGL 4.3 4
OpenGL Uproszczony schemat wykorzystania OpenGL w programowaniu grafiki czasu rzeczywistego Program Nasz program OpenGL Implementacja OpenGL dla danej platformy Sterownik, OS Sprzęt System operacyjny Karta graficzna 5
OpenGL Architektura wykorzystania OpenGL jako warstwy pośredniej pomiędzy aplikacją, a kartą graficzną opiera się o model klient-serwer Specyfikacja OpenGL wcale nie wymaga, aby obie strony znajdowały się w jednej, fizycznej maszynie! Serwer Klient (implementacja OpenGL) (program) Zlecenia renderowania Opis sceny Używa pamięci głównej Logika programu Użycie wynikowego obrazu Konteksty Renderowanie Komunikacja ze sterownikiem Dostęp do GPU i pamięci graficznej 6
OpenGL Działanie OpenGL należy rozumieć jako maszynę stanu Stanem nazywamy aktualne, chwilowe wartości wszystkich parametrów systemu Jeśli zmienimy wartość jakiegoś parametru, pozostaje ona zmieniona do czasu kolejnej zmiany Przykład: Jeśli zaczniemy w jednej klatce rysować czerwony prostokąt, wszystkie następne obiekty będą czerwone jeśli nie dokonamy zmiany koloru. Nawet w następnej klatce! 7
OpenGL Układ współrzędnych w OpenGL Trzeba zapamiętać albo mieć pod ręką! +y +x +z Jednostki są zupełnie arbitralne, można przyjąć np. że jedna jednostka to 1 metr (albo 13 cm, albo 2 ft, albo...) 8
GLUT GL Utility Toolkit Freeglut jest open-source'owym klonem, z którego będziemy korzystać (w pełni kompatybilny z GLUT) Dostarcza m.in.: Biblioteka narzędziowa do OpenGL Międzyplatformową obsługę urządzeń wejścia (mysz, klawiatura) Łatwe tworzenie okien z kontekstem OpenGL Procedury rysowania prostych brył (sześcian, kula itd.) Implementację pętli głównej (mainloop/gameloop) Wykorzystuje ideę callbacków, czyli funkcji obsługujących zdarzenia W ten sposób programista ma możliwość reakcji na zdarzenia Przypisanie callbacka odbywa się poprzez wywołanie specjalnej funkcji ustawiającej, z wskaźnikiem do funkcji obsługującej zdarzenie jako parametr 9
Przykładowy program int main(int argc, char * argv[]) { glutinit(&argc, argv); glutinitwindowsize(640, 360); glutinitdisplaymode(glut_rgba GLUT_DOUBLE GLUT_DEPTH); glutcreatewindow("opengl/glut Example"); glutdisplayfunc(onrender); glutmainloop(); return 0; } void OnRender() { glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT); glulookat(0.0f, 0.0f, -6.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); glcolor3f(1.0f, 0.0f, 0.0f); glutsolidcube(1.0f); glutswapbuffers(); glflush(); glutpostredisplay(); } 10
Programowanie z użyciem OpenGL Nazwy funkcji OpenGL: glnazwafunkcjiparam(...) param jeśli dana funkcja może przyjmować różne rodzaje parametrów, w ten sposób określany jest rodzaj tych parametrów oraz ich liczba, np.: f float, d double, i int, b bool itd. v vector (tablica) glnazwafunkcjiext(...), glnazwafunkcjiarb(...) Funkcjonalności pochodzące z rozszerzeń niebędących częścią standardu. Niektóre z nich w późniejszych wersjach OpenGL przestają posiadać sufiksy EXT i ARB. glvertex3f(float x, float y, float z) glvertex3fv(float *xyz) glvertex2f(float x, float y) glvertex3d(double x, double y, double z) glvertex2i(int x, int y)... Do obsługi rozszerzeń warto użyć biblioteki GLEW Nazwy funkcji GLU oraz GLUT: glunazwafunkcji(...), glutnazwafunkcji(...) 11
Częścią stanu OpenGL są dwie podstawowe macierze transformacji: Macierz Modelu-Widoku (GL_MODELVIEW) Łączy w sobie przekształcenia związane zarówno z przejściem ze współrzędnych modelu do współrzędnych świata, jak i ze współrzędnych świata do współrzędnych kamery Macierz Projekcji (GL_PROJECTION) Czyli uwzględnia zarówno przekształcenie konkretnego obiektu na scenie, jak i położenie i obrót kamery Uwzględnia rodzaj projekcji (perspektywiczna/prostokątna), kąt widzenia, płaszczyzny przycinania, proporcje. Tylko jedna z tych macierzy jest w danym momencie edytowalna Wyboru aktualnie edytowanej macierzy dokonuje się za pomocą funkcji glmatrixmode(matrix) matrix GL_MODELVIEW lub GL_PROJECTION 12
Umiejscowienie macierzy transformacji w potoku przetwarzania geometrii Współrzędne modelu Macierz modelu Współrzędne świata GL_MODELVIEW Macierz widoku Współrzędne kamery Macierz projekcji Współrzędne projekcji Kanoniczna bryła widzenia Normalizacja, przycinanie itp. GL_PROJECTION Zazwyczaj poza bezpośrednią kontrolą Mapowanie na ekran Współrzędne ekranu 13
Aktualnie wybraną do edycji macierz transformacji modyfikujemy za pomocą funkcji: glloadidentity() glloadmatrixf(float *v) Mnoży zawartość macierzy przez macierz odpowiadającą translacji o wektor [x; y; z] glrotatef(float angle, float x, float y, float z) Mnoży zawartość macierzy przez macierz odpowiadającą rotacji o angle stopni wokół wektora [x; y; z] Warto stosować z wersorami, np. [0; 1; 0] glscalef(float xs, float ys, float zs) Mnoży zawartość macierzy przez macierz v gltranslatef(float x, float y, float z) Zastępuje zawartość wartościami 16-elementowej tablicy glmultmatrixf(float *v) Zastępuje zawartość macierzą jednostkową Mnoży zawartość macierzy przez macierz odpowiadającą skalowaniu ze skalami [xs; ys; zs] 14
Przykłady Zakładamy, że hipotetyczna funkcja DrawBlackSquare() rysuje czarny kwadrat będący częścią płaszczyzny XY i rozciągający się w zakresie -1..1: +y 1 1 +x +z Na razie nie wnikamy, jak tego dokonuje Scenę obserwujemy z punktu [0; 0; 5], patrząc w kierunku [0; 0; -1], wektor pionu [0; 1; 0] Projekcja perspektywiczna 15
Przykłady DrawBlackSquare(); 16
Przykłady gltranslatef(2.0f, 0.0f, 0.0f); DrawBlackSquare(); 17
Przykłady gltranslatef(2.0f, 0.0f, 0.0f); gltranslatef(0.0f, 1.0f, 0.0f); DrawBlackSquare(); 18
Przykłady glrotatef(45.0f, 0.0f, 0.0f, 1.0f); DrawBlackSquare(); 19
Przykłady gltranslatef(2.0f, 0.0f, 0.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); DrawBlackSquare(); 20
Przykłady glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(2.0f, 0.0f, 0.0f); DrawBlackSquare(); 21
Przykłady glrotatef(45.0f, 0.0f, 1.0f, 0.0f); DrawBlackSquare(); 22
Przykłady glscalef(1.0f, 2.0f, 1.0f); DrawBlackSquare(); 23
Przykłady glscalef(1.0f, 2.0f, 1.0f); DrawBlackSquare(); DrawRedSquare(); Stan macierzy pozostaje zmieniony! 24
Przykłady glscalef(1.0f, 2.0f, 1.0f); DrawBlackSquare(); DrawRedSquare(); 25
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M stos 26
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M stos 27
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M stos 28
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M stos 29
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M0 stos 30
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M0 stos 31
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M1 M0 stos 32
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M1 M0 stos 33
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M1 M0 stos 34
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M1 M0 stos 35
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M0 stos 36
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M M0 stos 37
Zapamiętywanie stanu macierzy na stosie glpushmatrix() powoduje, że aktualny stan macierzy zostaje zapamiętany na stosie glpopmatrix() zdejmuje ze stosu ostatnio zapamiętany stan i przywraca go Możliwe jest wielokrotne zagnieżdżanie Podgląd rezultatu: Przy czym należy pamiętać, że zawsze przywracamy ostatni stan DrawGreenSquare(); gltranslatef(2.0f, 0.0f, -1.0f); glrotatef(45.0f, 0.0f, 0.0f, 1.0f); gltranslatef(0.0f, 1.0f, 0.0f); glscalef(1.5f, 1.5f, 1.0f); DrawBlackSquare(); DrawRedSquare(); DrawBlueSquare(); aktualna macierz: M stos 38
Definicja geometrii Najprostszą metodą definicji i renderowania geometrii jest tzw. immediate mode Definicja własności wszystkich wierzchołków w każdej klatce Podejście którego współcześnie się już nie stosuje Jest nieefektywne W każdej klatce duża ilość danych przekazywana do karty graficznej Współcześnie używa się buforów w pamięci karty graficznej Jest najłatwiejsze w zrozumieniu Prymityw glbegin(gl_quads); glvertex3f(-1.0f, -1.0f, 0.0f); glvertex3f(1.0f, -1.0f, 0.0f); glvertex3f(1.0f, 1.0f, 0.0f); glvertex3f(-1.0f, 1.0f, 0.0f); glend(); 39
Definicja geometrii Prymitywy oferowane przez OpenGL: Źródło obrazu: http://www.opengl.org 40
Kolor w OpenGL Częścią stanu OpenGL jest także kolor wierzchołków Kolory określa się za pomocą komponentów RGB(A) Wartości są znormalizowane (0.0-1.0) Czwarty kanał A może określać przezroczystość Przykłady: (1.0, 0.0, 0.0) (0.0, 1.0, 0.0) (0.0, 0.0, 1.0) (0.0, 0.0, 0.0) (1.0, 1.0, 1.0) (0.5, 0.5, 0.5) (1.0, 0.5, 0.5) (0.0, 0.6, 1.0) Używa się do tego celu funkcji: glcolor3f(float r, float g, float b) lub analogicznych (4f, 3fv, 4fv,...) 41
Kolor w OpenGL Przykłady: glcolor3f(1.0f, 0.0f, 0.0f); glbegin(gl_quads); glvertex3f(-1.0f, -1.0f, 0.0f); glvertex3f(1.0f, -1.0f, 0.0f); glvertex3f(1.0f, 1.0f, 0.0f); glvertex3f(-1.0f, 1.0f, 0.0f); glend(); glbegin(gl_quads); glcolor3f(0.0f, 0.0f, 0.0f); glvertex3f(-1.0f, -1.0f, 0.0f); glcolor3f(1.0f, 0.0f, 0.0f); glvertex3f(1.0f, -1.0f, 0.0f); glcolor3f(0.0f, 1.0f, 0.0f); glvertex3f(1.0f, 1.0f, 0.0f); glcolor3f(0.0f, 0.0f, 1.0f); glvertex3f(-1.0f, 1.0f, 0.0f); glend(); 42
Kolor w OpenGL Bardziej zaawansowane kolorowanie geometrii może wykorzystywać techniki takie, jak: Oświetlenie (tzw. cieniowanie, ang. shading) Teksturowanie (ang. texture mapping) Źródła obrazów: http://pythonstuff.org http://marketplace.secondlife.com 43
Proste bryły w GLUT Sześcian glutsolidcube(size), glutwirecube(size) size długość krawędzi Aby uzyskać nieforemny prostopadłościan, należy poddać sześcian skalowaniu, np.: glutwirecube(1.0f); glscalef(4.0f, 2.0f, 0.5f); glutwirecube(1.0f); Należy pamiętać, że w ten sposób zmieniamy stan macierzy transformacji! Następne bryły też będą przeskalowane. 44
Proste bryły w GLUT Kula glutsolidsphere(size, slices, stacks), glutwiresphere(size, slices, stacks) size długość promienia slices, stacks liczby podziałów glutwiresphere(1.0f, 10, 10); glutwiresphere(1.0f, 30, 10); glutwiresphere(1.0f, 30, 30); glutwiresphere(1.0f, 10, 30); glutwiresphere(1.0f, 6, 6); 45
Proste bryły w GLUT Stożek glutsolidcone(base, height, slices, stacks), glutwirecone(base, height, slices, stacks) base długość promienia podstawy height - wysokość slices, stacks liczby podziałów, analogicznie do kuli glutwirecone(1.0f, 2.0f, 16, 16); 46
GRAFIKA CZASU RZECZYWISTEGO Wprowadzenie do OpenGL Grafika komputerowa i wizualizacja, Bioinformatyka S1, II Rok