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 = $​, 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.

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.