73 lines
5.0 KiB
Markdown
73 lines
5.0 KiB
Markdown
## 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.
|
||
|