Zadanie 1. Ściana Zadanie W pliku walls.cpp znajduje się funkcja void draw_back_wall(). Należy uzupełnić ją, ustawiając odpowiednio parametry teksturowania tak, aby na ścianę, która w pierwotnej wersji jest jednolicie szara, zostały nałożone dwie tekstury: tekstura cegieł oraz tekstura plakatu w sposób jak na zrzucie ekranu poniżej: Przed Po 1. Potrzebne zmienne w dołączonym do zadania kodzie źródłowym Uzupełnić należy definicję funkcji void draw_back_wall() w pliku walls.cpp. W pliku tym włączany jest nagłówek textures.h, w którym zadeklarowane są obiekty dwóch interesujących tekstur: Textures::tex_bricks Textures::tex_poster W momencie wywołania draw_back_wall oba te obiekty będą miały: przypisane odpowiednie obrazki załadowane z plików, wygenerowane poziomy mipmap, ustawione filtrowanie trzyliniowe, ustawiony tryb zawijania obrazka na obcinanie do krawędzi format RGBA z kanałem alfa równym wszędzie 1 (odpowiedni kod wywoływany jest w funkcji init w pliku textures.cpp) W pliku textures.cpp zadeklarowana jest jeszcze jedna przydatna zmienna rzeczywista: Textures::lod_bias Jest to zmienna rzeczywista. Jej wartość zmieniana jest przy pomocy ruchu myszki w pionie z wciśniętym środkowym przyciskiem i obcinana do przedziału [-5,5]. Wykorzystamy ją jako parametr podczas ustawienia przesunięcia poziomu mipmap względem standardowo wybieranego na podstawie wielkości obrazka na ekranie.
2. Włączenie multiteksturowania z użyciem dwóch tekstur. Multiteksturowanie to funkcjonalność pozwalająca w jednym przebiegu rysowania siatki trójkątów, pocieniować ich powierzchnię na podstawie funkcji kolorów uzyskanych zarówno z oświetlenia jak i pobranych w określony sposób z kilku kolejno wykorzystywanych tekstur. W multiteksturowaniu można wyróżnić kolejne etapy teksturowania. Z każdym etapem teksturowania związane są: - obiekt tekstury, - współrzędne tekstury dla każdego wierzchołka siatki trójkątów (lub sposób ich generowania na podstawie jego położenia lub normalnej z nim związanej), - sposób połączenia koloru tekstury z kolorem uzyskanym z poprzedniego etapu teksturowania - stan włączenia/wyłączenia teksturowania Współrzędne tekstury w danym wierzchołku siatki definiowane są niezależnie dla każdego etapu teksturowania. Dodatkowo dla każdego etapu teksturowania można określić macierz przekształcenia podanych współrzędnych tekstury. Od momentu wywołania funkcji glactivetexture(gl_texture0); (analogicznie dla kolejnych stałych GL_TEXTURE1,...) tylko tego etapu teksturowania będą dotyczyć ustawienia: włączenia/wyłączenia teksturowania (np. glenable(gl_texture_2d); ), generowania współrzędnych tekstury (np. gltexgeni(gl_s, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glenable(gl_texture_gen_s);), wyboru używanego obiektu tekstury (np. glbindtexture(gl_texture_2d, texture_object);) macierzy przekształcenia współrzędnych tekstury (np. glmatrixmode(gl_texture); glrotatef(90.0f,0,0,1);) Należy dwukrotnie ustawić aktywny etap teksturowania (glactivetexture), włączyć dla niego teksturowanie (glenable) i wybrać używany obiekt tekstury (glbindtexture). Należy zamienić wywołania gltexcoord2f(...) w definicji kwadratu ściany na pary wywołań glmultitexcoord2f(gl_texture0,...); glmultitexcoord2f(gl_texture1,...); tak, aby zdefiniowane zostały współrzędne tekstury dla wszystkich wierzchołków, dla każdego etapu teksturowania (gltexcoord2f(...) jest równoważne glmultitexcoord2f(gl_texture0,...);).
3. Ustawienie właściwego trybu zawijania obrazka dla obu tekstur. Tryb zawijania związany jest z obiektem tekstury. Przed jego ustawieniem należy się upewnić, że dla aktualnego etapu teksturowania (glactivetexture) związany jest właściwy obiekt tekstury (glbind). Tryb ustala się poprzez wywołanie: gltexparameteri(gl_texture_2d, GL_TEXTURE_WRAP_S, mode);, gdzie zamiast mode powinna pojawić się odpowiednia stała. Najczęściej używane są trzy tryby zawijania obrazka: - powtarzanie obrazka (GL_REPEAT) - obcinanie do krawędzi obrazka (GL_CLAMP_TO_EDGE) - obcinanie do ustalonego koloru brzegu (GL_CLAMP_TO_BORDER) Kolor brzegu można ustalić za pomocą wywołań jak poniżej: vector4 border = vector4(.0f,.0f,.0f,.0f); gltexparameterfv(gl_texture_2d, GL_TEXTURE_BORDER_COLOR,(float*)&border.x); Należy dla tekstury cegieł ustawić tryb zawijania na powtarzanie, a dla tekstury plakatu na obcinanie do koloru brzegu, gdzie kolor brzegu ma składową alfa równą zero.
4. Ustawienie właściwych funkcji mieszania koloru obu tekstur. Sposób połączenia koloru definiowany jest oddzielnie dla składowych RGB koloru i oddzielnie dla kanału alfa. Definicja składa się z: - podania jednej ze stałych określających rodzaj funkcji (dwu- lub trzyargumentowej) np. GL_MODULATE (mnożenie dwóch argumentów), GL_INTERPOLATE (interpolacja liniowa pomiędzy dwoma pierwszymi argumentami na podstawie wartości trzeciego) - podania dla każdego argumentu jego źródła np. GL_PREVIOUS (wynik poprzedniego etapu teksturowania, dla etapu o numerze zero oznacza kolor obiektu po zastosowaniu równań oświetlenia), GL_TEXTURE (kolor pobrany z tekstury związanej z aktualnym etapem teksturowania) Gdy nie korzystamy z multiteksturowania najczęściej sposób liczenia koloru przy użyciu tekstury wybiera się za pomocą jednego z wywołań: gltexenvi(gl_texture_env, GL_TEXTURE_ENV_MODE, GL_REPLACE); gltexenvi(gl_texture_env, GL_TEXTURE_ENV_MODE, GL_MODULATE); Przy korzystaniu z multiteksturowania, aby podać pełną postać funkcji liczenia koloru należy poniższy schemat wywołań powtórzyć dla każdego etapu teksturowania (pomijając ustawienia dla kanału alfa, jeśli nie jest on wykorzystywany na danym etapie): glactivetexture(gl_texture0); gltexenvi(gl_texture_env, GL_TEXTURE_ENV_MODE, GL_COMBINE); gltexenvi(gl_texture_env, GL_COMBINE_RGB, GL_MODULATE); gltexenvi(gl_texture_env, GL_SRC0_RGB, GL_TEXTURE); gltexenvi(gl_texture_env, GL_OPERAND0_RGB, GL_SRC_COLOR); gltexenvi(gl_texture_env, GL_SRC1_RGB, GL_PREVIOUS); gltexenvi(gl_texture_env, GL_OPERAND1_RGB, GL_SRC_COLOR); //Dla GL_INTERPOLATE doszedłby trzeci argument //gltexenvi(gl_texture_env, GL_SRC2_RGB, GL_TEXTURE); //gltexenvi(gl_texture_env, GL_OPERAND2_RGB, GL_SRC_ALPHA); gltexenvi(gl_texture_env, GL_COMBINE_ALPHA, GL_MODULATE); gltexenvi(gl_texture_env, GL_SRC0_ALPHA, GL_TEXTURE); gltexenvi(gl_texture_env, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); gltexenvi(gl_texture_env, GL_SRC1_ALPHA, GL_PREVIOUS); gltexenvi(gl_texture_env, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); W tym zadaniu należy: interpolować kolor pomiędzy kolorem tekstury plakatu, a iloczynem koloru obiektu po oświetleniu i koloru tekstury cegieł, na podstawie wartości kanału alfa wyznaczonego dla tekstury plakatu. Wtedy wszędzie poza prostokątem plakatu na ścianie, gdzie kanał alfa pobrany z tekstury plakatu będzie równy zero, pojawi się wyłącznie tekstura cegieł, a w obrębie prostokąta plakatu wyłącznie tekstura plakatu. Wcześniej zdefiniowany został sposób zawijania tekstury plakatu z obcięciem do koloru brzegu, który ma składową alfa równą zero, natomiast sama tekstura plakatu ma cztery składowe koloru (to jest ważne, bo nie można pobrać kanału alfa dla tekstury w formacie RGB) z czwartą składową alfa równą jeden dla każdego teksela. To zapewnia poprawne wartości kanału alfa dla przeprowadzenia powyższej operacji.
5. Pozycjonowanie tekstury plakatu. Należy wykorzystać macierz przekształcenia tekstury do ustalenia rozmiaru, pozycji i obrotu plakatu na ścianie. 1 1 Plakat powinien mieć wymiary równe x boku ściany. Środek plakatu powinien 4 3 znajdować się w odległości.3 boku ściany od jej lewej krawędzi i.5 boku ściany od jej górnej krawędzi. Plakat powinien być obrócony w prawo o 10 stopni. Należy obliczyć macierz przekształcenia współrzędnych tekstury i ustawić ją dla tekstury plakatu. Odpowiedni blok instrukcji OpenGL powinien mieć postać: glactivetexture(...); // Etap teksturowania, którego dotyczy przekształcenie glmatrixmode(gl_texture); glpushmatrix(); // Zachowanie poprzedniego przekształcenia na stosie glloadidentity(); // tutaj powinien się znaleźć ciąg instrukcji glrotatef(...), gltranslatef(...), glscalef(...) // przekształcenia powinny odpowiadać macierzy M na rysunku powyżej, // pozostawiam ten etap do samodzielnego rozwiązania // rysowanie ściany glpopmatrix(); // Odtworzenie poprzedniego przekształcenia glmatrixmode(gl_modelview);
6. Zmiana standardowo wybieranego poziomu mipmap (rozmycie). Przy korzystaniu z mipmap dla każdego obrazka tekstury tworzone i pamiętane są również kolejne poziomy obrazków, z których każdy następny ma rozmiar dwukrotnie mniejszy od poprzedniego. Poziom mipmap wykorzystywany przy włączonym filtrowaniu trzyliniowym ustalany jest na podstawie wielkości tekseli (punktów tekstury) na ekranie. Można zmienić standardowy sposób wyboru poziomu mipmap, dodając do niego liczbę rzeczywistą, przy czym dodanie jednostki wiąże się mniej więcej z użyciem poziomów mipmap o jeden większych (przy czym zwiększenie poziomu mipmap oznacza użycia obrazka o mniejszej rozdzielczości). Poziomy mipmap mogą i najczęściej są generowane automatycznie. W OpenGL służy do tego instrukcja: gltexparameteri(gl_texture_2d, GL_GENERATE_MIPMAP, GL_TRUE);. Teksel następnego poziomu odpowiada średniej wartości kilku (na przykład czterech) tekseli poprzedniego poziomu. Należy dla każdego etapu teksturowania (glactivetexture(gl_texture0);...glactivetexture(gl_texture1);...) ustawić przesunięcie poziomu mipmap: gltexparameterf(gl_texture_2d, GL_TEXTURE_LOD_BIAS, Textures::lod_bias); Wtedy po uruchomieniu programu, podczas przesuwania myszy z wciśniętym środkowym przyciskiem, będzie można zobaczyć efekt wzmocnionego lub osłabionego filtrowania trzyliniowego: