Instrukcja laboratoryjna 10 Grafika komputerowa 3D Temat: Prymitywy Przygotował: dr inż. Grzegorz Łukawski, mgr inż. Maciej Lasota, mgr inż. Tomasz Michno 1 Wstęp teoretyczny Prymitywy proste figury geometryczne, z których możliwe jest tworzenie bardziej zaawansowanych obiektów. W OpenGL należą do nich: punkt, linie, linie łamane, linie łamane zamknięte, trójkąty, pasek z trójkątów i wachlarz z trójkątów, czworokąt, połączone czworokąty i wielokąt o dowolnej liczbie wierchołków. 1.1 Podstawy rysowania prymitywów Podstawowymi funkcjami wykorzystywanymi podczas rysowania prymitywów są: glbegin(typ_prymitywu), glend() oraz funkcje z rodziny glvertex (najczęściej wykorzystywane to glvertex2f oraz glvertex3f). Funkcja glbegin(typ_prymitywu) służy do poinformowania biblioteki o rozpoczęciu rysowania prymitywu podanego w parametrze. Następnie należy podać kolejne wierzchołki figury, np. za pomocą glvertex3f(x, y, z). Po podaniu wszystkich wierzchołków figury, należy zakończyć rysowanie za pomocą glend(). Zatem standardowe rysowanie prymitywów wygląda następująco: glbegin(typ_prymitywu); podanie wierzchołków Nie można zagnieżdzać w sobie funkcji glbegin i glend, tzn. użycie np. poniższej konstrukcji jest niepoprawne: glbegin(typ_prymitywu1); podanie wierzchołków figury 1 glbegin(typ_prymitywu2); ŹLE!!! podanie wierzchołków figury 2 1/8
1.1.1 Punkty Rysowanie punktów jest najprostszym przykładem rysowania prymitywu, ponieważ jest to najmniejsza, a zarazem najprostsza figura. W celu jej narysowania w funkcji glbegin używa się typu GL_POINTS. Przykład 1: glbegin(gl_points); glvertex3f(5.0f, 5.0f, 5.0f); Przykład 2: float pozycja[] = {5.0f, 5.0f, 5.0f}; glbegin(gl_points); glvertex3fv(pozycja); Możliwe jest również narysowanie większej liczby punktów w jednym bloku glbegin glend: Przykład 3: glbegin(gl_points); glvertex3f(5.0f, 5.0f, 5.0f); glvertex3f(15.0f, 5.0f, 5.0f); glvertex3f(25.0f, 25.0f, 5.0f); Możliwe jest również ustawienie rozmiaru punktu na ekranie za pomocą poniższej funkcji: void glpointsize(glfloat rozmiar) Przyjmuje ona tylko jeden parametr, którym jest nowy rozmiar punktu. Dodatkowo zmiana jest wprowadzona na stałe, tzn. każdy punkt rysowany po wywołaniu tej funkcji będzie miał podany rozmiar, aż do ponownego wywołania glpointsize z innym rozmiarem. Kolor każdego z punktów (również wierzchołków figur) można ustawić za pomocą funkcji 2/8
glcolor3f(glfloat r, glfloat g, glfloat b). Parametry r, g oraz b przyjmują wartości od 0 do 1 (1 odpowiednik 255 z allegro). Istnieje również funkcja glcolor4f(glfloat r, glfloat g, glfloat b, glfloat a), której dodatkowy parametr określa współczynnik alfa. 1.1.2 Linie (odcinki), łamane, łamane zamknięte Linie w bibliotece OpenGL, są odpowiednikami odcinków w matematyce - składają się z dwóch punktów oraz łączącej je linii. Rysuje się je z użyciem typu GL_LINES. Do obowiązków programisty należy jedynie podanie dwóch punktów (np. za pomocą glvertex3f), natomiast resztą zajmuje się już biblioteka. Przykład 4: glbegin(gl_points); glvertex3f(-200, 200, 0); glvertex3f(-150, 220, 0); Podobnie jak dla punktów, możliwe jest narysowanie większej liczby linii w jednym bloku glbegin...glend. Należy wtedy podawać kolejno po dwa wierzchołki na odcinek. Przykład 5: glbegin(gl_lines); glvertex3f(-200, 200, 0); // pierwszy punkt - pierwsza linia glvertex3f(-150, 220, 0); // drugi punkt - pierwsza linia glvertex3f(-100, 200, 0); // trzeci punkt - druga linia glvertex3f(-50, 220, 0); // czwarty punkt - druga linia 3/8
Łamane tworzone są w sposób bardzo zbliżony do linii. W funkcji glbegin należy użyć typu GL_LINE_STRIP, a następnie podać kolejne punkty łamanej (punkty początkowy, końcowy i wszelkie zagięcia ): Przykład 6: glbegin(gl_line_strip); glvertex3f(-200, 150, 0); // pierwszy punkt glvertex3f(-150, 170, 0); // drugi punkt glvertex3f(-100, 150, 0); // trzeci punkt glvertex3f(-50, 170, 0); // czwarty punkt Łamana zamknięta jest identyczna w obsłudze ze zwykłą łamaną, z drobną różnicą ostatni punkt jest łączony z pierwszym, dzięki czemu uzyskujemy wielokąt. Typ jaki należy użyć to GL_LOOP. Przykład 7: glbegin(gl_line_loop); glvertex3f(-200, 80, 0); // pierwszy punkt glvertex3f(-150, 100, 0); // drugi punkt glvertex3f(-100, 80, 0); // trzeci punkt glvertex3f(-50, 100, 0); // czwarty punkt Możliwe jest również ustawienie grubości linii, za pomocą funkcji: void gllinewidth(glfloat rozmiar); Jako jedyny parametr przyjmuje ona nowy rozmiar i podobnie jak glpointsize() ustawia rozmiar linii na stałe, aż do ponownego wywołania. 4/8
1.1.3 Trójkąty Trójkąty są najczęściej wykorzystywanymi prymitywami (jest to standard w grafice 3D), ponieważ z ich pomocą można łatwo budować bardziej skomplikowane obiekty (np. teapot, sferę itp.). Trójkąty są również pierwszymi z omawianych prymitywów, które są wypełnione. W celu narysowania trójkąta należy użyć typu GL_TRIANGLES oraz podać 3 wierzchołki: Przykład 8: glbegin(gl_triangles); glvertex3f(0, 200, 0); // pierwszy punkt glcolor3f(0.0, 1.0, 1.0); glvertex3f(50, 220, 0); // drugi punkt glcolor3f(1.0, 1.0, 1.0); glvertex3f(100, 200, 0); // trzeci punkt Podobnie jak wcześniej możliwe jest narysowanie większej liczby trójkątów w jednym bloku glbegin...glend: Przykład 9: glbegin(gl_triangles); glvertex3f(0, 200, 0); // pierwszy punkt glcolor3f(0.0, 1.0, 1.0); glvertex3f(50, 220, 0); // drugi punkt glcolor3f(1.0, 1.0, 1.0); glvertex3f(100, 200, 0); // trzeci punkt glcolor3f(1, 1, 0); glvertex3f(120, 220, 0); // czwarty punkt glcolor3f(1, 0, 1); glvertex3f(170, 240, 0); // piąty punkt glcolor3f(0.5, 0.5, 0.5); glvertex3f(220, 220, 0); // szósty punkt 5/8
1.1.4 Pozostałe prymitywy Nazwa Pasek trójkątów Wachlarz trójkątów Czworokąt Połączone czworokąty Wielokąt o dowolnej liczbie wierzchołków Typ GL_TRIANGLE_STRIP GL_TRIANGLE_FAN GL_QUADS GL_QUAD_STRIP GL_POLYGON 1.1.5 Kierunek rysowania Podczas podawania wierzchołków bardzo ważne jest zachowywanie zawsze tego samego kierunku: zgodnego lub przeciwnego do wskazówek zegara. Jest to o tyle ważne, że OpenGL w ten sposób rozpoznaje, czy ściana ma być przednia (zewnętrzna, widoczna), czy tylna (wewnętrzna, niewidoczna). Do określenia, który z kierunków będzie oznaczał ścianę przednią, a który tylną służy funkcja glfrontface. Przyjmuje ona jeden parametr określający kierunek rysowania, zgodny z ruchem wskazówek zegara GL_CW, lub kierunek przeciwny do ruchu wskazówek zegara GL_CCW. 1.2 Czyszczenie bufora kolorów oraz głębi W OpenGL wyróżniamy cztery rodzaje buforów: bufor koloru, głębi, szablonu (wzorca) i akumulacyjny. Najczęściej stosowane są dwa pierwsze czyli bufor kolorów odpowiedzialny za prawidłowe wyświetlanie kolorów oraz bufor głębi odpowiedzialny za poprawne renderowanie obiektów w przestrzeni 3D. Za czyszczenie buforów odpowiedzialna jest funkcja: void glclear(glbitfield mask) Parametrem tej funkcji są stałe określające rodzaj bufora (GL_COLOR_BUFFER_BIT, 6/8
GL_DEPTH_BUFFER_BIT, GL_ACCUM_BUFFER_BIT, GL_STENCIL_BUFFER_BIT), który chcemy wyczyścić. Bufory można łączyć za pomocą operacji OR (operator ). Dodatkowo do czyszczenie bufora kolorów na wybrany kolor służy funkcja: void glclearcolor(glfloat R, GLfloat G, GLfloat B, GLfloat A) Przyjmuje ona cztery parametry określające kolor w formacie RGBA na jaki ma zostać wyczyszczony bufor. 1.3 Antialiasing Antialiasing umożliwia wygładzenie ostrych krawędzi punktów lub linii. W OpenGL włączenie antialiasingu polega na aktywowaniu opcji GL_POINT_SMOOTH dla punktów lub GL_LINE_SMOOTH dla linii. Aktywowane odpowiednich funkcji dokonywane jest za pomocą funkcji: void glenable(glenum mode) Wyłączenie opcji odbywa się przez wywołanie funkcji: void gldisable(glenum mode) Przykład 10: glenable(gl_point_smooth); 1.4 Cieniowanie W przypadku kolorowania wielokątów, kolory określane są dla wierzchołków, a nie dla wielokątów. O tym, czy wielokąt będzie posiadał jednolity kolor (kolor określony dla ostatniego wierzchołka), czy ten kolor będzie się zmieniał płynnie od wierzchołka do wierzchołka, decyduje model cieniowania. Aby ustawić odpowiedni model cieniowania wykorzystywana jest funkcja: void glshademodel(glenum mode) Funkcja przyjmuje jeden z dwóch parametrów GL_FLAT określający model cieniowania jednolitego (płaskiego) oraz GL_SMOOTH model cieniowania płynnego przejścia. Cieniowanie jest bardzo ważnym elementem wizualizacji. Wykorzystywane jest m. in. przy obliczeniach związanych ze światłem. 7/8
2 Zadania 1. Wykorzystując przykładowy program przetestuj działanie pozostałych prymitywów z instrukcji. 2. Stwórz animację padającego śniegu z wykorzystaniem GL_POINTS, zmiany rozmiaru punktów oraz włączonego antialiasingu dla punktów. Wskazówka: możesz utworzyć tablicę, w której będą przechowywane pozycje wszystkich płatków śniegu (początkowo mające wartość losową). Następnie przy każdym odmalowaniu ekranu współrzędna y każdego płatka jest zmniejszana (gdy osiągnie dolną krawędź ekranu, należy nadać jej początkową wartość). W celu zwiększenia realizmu można dodać drobne losowe zmiany położenia w pionie i poziomie. 3. Narysuj wypełnioną piramidę (za pomocą trójkątów), której każdy wierzchołek będzie posiadał inny kolor. Przetestuj również różne modele cieniowania. 4. Do zadania 3 dodaj możliwość wyświetlania piramidy jako druciak (użyj linii). Dodaj również czyszczenie ekranu na losowy kolor. 8/8