## Rzutowanie perspektywiczne Zadania **main_3_1** zaczynają się w miejscu, w którym skończyło się zadanie **main_2_1** z poprzednich zajęć. Widać w nim jedynie kwadrat, nie cały prostopadłościan. Wyświetlimy go w rzutowaniu perspektywicznym, dzięki temu otrzymamy iluzję trzech wymiarów. #### Zadanie 1 Macierz perspektywy tworzy funkcja `createPerspectiveMatrix()`, przyjrzyj się definicji tej funkcji. Prześlij macierz perspektywy do shadera. Wynik wygląda nie do końca tak jakbyśmy się spodziewali. Wynika to z tego, że kamera znajduje się wewnątrz prostopadłościanu. Dodaj macierz kamery do macierzy transformacji, dzięki temu będzie można przesuwać kamerę za pomocą klawiszy. Przesuń prostopadłościan tak, żeby można go było zobaczyć od zewnątrz. #### Zadanie 1* Zmodyfikuj macierz perspektywy. W funkcji `createPerspectiveMatrix()` znajduje się zmienna `frustumScale`, która odpowiada ona za kąt widzenia, zmodyfikuj jej wartość i zobacz jaki jest efekt. By obliczyć jej wartość możesz skorzystać ze wzoru $ S = \frac{1}{tan\left( \frac{fov}{2}* \frac{\pi}{2}\right)} $​, gdzie $fov$ oznacza kąt widzenia. #### Zadanie 1** Wciąż jest problem z rozciąganiem się obrazu przy zmianie kształtu okna. Rozwiązaniem jest wstawienie różnej wartości **frustumScale** dla współrzędnych **X** i **Y**. by to naprawić wykorzystaj funkcję `onReshape`, która jest wywoływana przy zmianie wielkości ekranu. Najpierw oblicz w niej proporcje ekranu i przypisz do zmiennej globalnej `screenRatio`. Następnie przemnóż odpowiednią współrzędną przez `screenRatio` w funkcji `createPerspectiveMatrix()`. ## Obsługa Shaderów W tej części zadań będziemy korzystać z innych obiektów, usuń z funkcji `init` inicjalizację prostopadłościanu i jego rysowanie z funkcji `renderScene` oraz zamień shadery na `shaders/shader_3_2.vert` i `shaders/shader_3_2.frag`. #### Zadanie 2 Wczytaj statek i sferę za pomocą do `loadModelToContext` do odpowiednich `Core::RenderContext`. Następnie wyświetl je za pomocą funkcji `Core::DrawContext`. Rozmieść je w różnych miejscach w przestrzeni. ##### Dodaj możliwość zmiany kolorów obiektów: Stwórz zmienną `uniform vec3 objectColor` w pliku `shader_3_2.frag` (jej definicja musi się ona znajdować nad definicją funkcji `main`), wykorzystamy ją do przesłania koloru w formacie RGB do shadera. Zmienna wbudowana `gl_FragColor` jest typu `vec4` w formacie RGBA, współrzędne przyjmują wartości od od 0 do 1. Do części RGB przypisz wartość `objectColor` a do A wartość 1. Możemy teraz ustawić kolor rysowanego obiektu ustawiając wartość zmiennej `objectColor` przed rysowaniem obiektu. Robimy to korzystając z funkcji `glUniform3f( int location, float v0, float v1, float v2 )`, gdzie parametr `location` oznacza adres zmiennej w pamięci karty graficznej, do której chcemy wartości wysłać. Można ten adres uzyskać wywołując funkcje `glGetUniformLocation(program, "nazwa zmiennej")`. #### Zadanie 2* Zmodyfikuj program tak, żeby kolor statku zmieniał się w czasie. #### Zadanie 3 Wyświetl "kolor" wektora normalnego do powierzchni w danym punkcie. > Wektor normalny to wektor prostopadły do powierzchni w danym punkcie, pozwala on na przykład na policzenie odbicia światła. Wektor normalny wierzcholka dostępny jest w *vertex shaderze* (plik z rozszerzeniem **.vert**). Kolor powierzchni (piksela) ustala sie jednak we *fragment shaderze* (**.frag**). Zatem należy przesłać wartość wektora normalnego z *vertex* do *fragment* shadera. Służą do tego specjalne zmienne (interpolatory). Stwórz zmienną typu `out vec3 nazwa` w *vertex shaderze* oraz odpowiadająca mu zmienna `in vec3 nazwa` we *fragment shaderze*. Prześlij przy jej użyciu wartość wektora normalnego. Użyj tej wartości, aby w jakiś sposób przypisać kolor pikselowi. Aby otrzymać ładny efekt, najpierw znormalizuj wektor otrzymany przez *fragment shader*. Następnie przeskaluj wartości (x, y, z) wektora z przedziału [-1, 1] do [0, 1] i przypisz je do kanałów R, G, B zmiennej `gl_FragColor`. #### Zadanie 4 Stwórz funkcje `drawObject`, która ułatwi rysowanie wielu obiektów. Na liście parametrów musza znaleźć się referencja do `Core::RenderContext` oraz macierz modelu (*model matrix*) obiektu. Wyświetl kilka obiektów w różnych pozycjach (i obejrzyj je z każdej strony). "Przyczep" model statku do kamery - uzależnij jego macierz modelu od pozycji i orientacji kamery tak, aby wyglądało jakbyś poruszał(a) się statkiem. ```C++ glm::mat4 shipModelMatrix = glm::translate(cameraPos + cameraDir * 0.5f + glm::vec3(0,-0.25f,0)) * glm::rotate(-cameraAngle + glm::radians(90.0f), glm::vec3(0,1,0)) * glm::scale(glm::vec3(0.25f)); ``` Przeanalizuj tą macierz modelu lub napisz własną. #### Zadanie 5 Stwórz układ planetarny - jedna nieruchoma kule na środku (Słonce) i kilka orbitujących wokół niej planet. Niech przynajmniej jedna planeta ma księżyce.