GRK/cw 3/zadania_3.md

73 lines
5.0 KiB
Markdown
Raw Normal View History

2022-01-12 16:07:16 +01:00
## 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.