diff --git a/grk/cw 6/Zadania 7.html b/grk/cw 6/Zadania 7.html new file mode 100644 index 0000000..afd349c --- /dev/null +++ b/grk/cw 6/Zadania 7.html @@ -0,0 +1,196 @@ + + + + + + + Zadania 7 + + + + + + +

Normal Mapping

+

W tej części będziemy dalej modyfikować shadery shader_5_tex poprzez implementację normal mappingu.

+

Obliczenia dla map normalnych należy wykonywać w przestrzeni stycznych. Przestrzeń styczna jest wyliczana dla każdego punktu w obiekcie. Jej celem jest takie przekształcenie przestrzeni, żeby wektor normalny był wektorem jednostkowym (0,1,0).

+

Do wyliczenia przestrzeni stycznej potrzebujemy dla każdego wierzchołka oprócz wektora normalnego wektor styczny i bistyczny (tangent i bitangent). Są one wyliczane przez bibliotekę Assimp.

+

Wykonaj kopię shaderów shader_5_tex.vert shader_5_tex.frag

+

Przenieś obliczenia światła do przestrzeni stycznej.

+
    +
  1. Oblicz macierz TBN.

    +

    Macierz TBN to macierz 3x3 wyznaczana przez wektory tangent, bitangent i normal, służy do przenoszenia wektorów z przestrzeni świata do przestrzeni stycznej.

    +
      +
    1. W vertex shaderze przekrztałć wektory vertexNormal, vertexTangent i vertexBitangent do przestrzeni świata (przemnóż macierz modelu przez te wektory, tak jak to robiliśmy wcześniej z wektorem normalnym, z uwzględnieniem zmiennej w=0) i zapisz wyniki odpowiednio w zmiennych normal, tangent i bitangent. +
        +
      1. Stwórz macierz 3x3 TBN jako transpose(mat3(tangent, bitangent, normal)). Macierz transponujemy, aby szybko uzyskać jej odwrotność (możemy tak zrobić przy założeniu, ze jest ortogonalna).
      2. +
    2. +
  2. +
+
    +
  1. Przenieś wektor światła i wektor widoku do przestrzeni stycznych +
      +
    1. Musimy przekształcić wektor światła (L) i wektor widoku (V) do przestrzeni stycznych. Zrobimy to w vertex shaderze. W tym celu przenieś potrzebne dane dotyczące światła i kamery (uniformy lightPos i cameraPos) z fragment shadera do vertex shadera.

    2. +
    3. Oblicz wektor viewDir jako znormalizowana różnice cameraPos i worldPos (tu jeszcze działamy w przestrzeni świata). Analogicznie oblicz lightDir jako różnicę lightPos i worldPos

    4. +
    5. Przekształć wektory viewDir i lightDir do przestrzeni stycznej mnożąc je przez macierz TBN. Wynik zapisz w zmiennych viewDirTS i lightDirTS odpowiednio.

    6. +
    7. Przekaż viewDirTS i lightDirTS do fragment shadera. (zadeklaruj je jako zmienne out)

      +
      +

      (Sufiks TS oznacza tangent space. Ważne jest, aby oznaczać (np. dopisując coś do nazwy zmiennej) w jakiej przestrzeni znajdują się używane wektory, tak aby poprawnie wykonywać obliczenia. Trzeba zawsze zwracać uwagę na to, w jakiej przestrzeni działamy.)

      +
    8. +
  2. +
  3. Przekształć fragment shader, by obsługiwał tangent space +
      +
    1. Nie potrzebujemy już we fragment shaderze informacji na temat pozycji fragmentu i wektora normalnego geometrii, skasuj wiec zmienne przekazujące te wektory pomiędzy shaderami.
    2. +
    3. wektora lightDir powinniśmy użyć wektora lightDirTS (należy go dodatkowo znormalizować), a jako wektor widoku V powinniśmy użyć wektora viewDirTS (również należy go znormalizować). Jako wektora N użyj na razie wektora vec3(0,0,1).
    4. +
  4. +
+

Efekt finalny powinien wyglądać tak samo, jak przed jakąkolwiek zmianą. Następnym krokiem będzie wykorzystanie map normalnych.

+

Wykorzystaj normalmapy

+
    +
  1. Chcemy wczytywać normalne z tekstury, w tym celu dodaj we fragment shaderze dodatkowy sampler do czytania map normalnych, nazwij go normalSampler. Pobierz z niego wektor normalny analogicznie, jak czytamy kolor zwykłej tekstury z samplera textureSampler i zapisz go w zmiennej N. +
      +
    1. Ponieważ w teksturze wartości są w przedziale \([0,1]\), musimy jeszcze przekształcić je do przedziału \([-1,1]\). W tym celu przemnóż wektor N przez 2 i odejmij 1. Na koniec warto jeszcze znormalizować wektor normalny, aby uniknąć błędów związanych z precyzja lub kompresja tekstury.
    2. +
    3. Wczytaj pliki zawierające mapy normalnych w kodzie C++ W tym celu załaduj przy użyciu funkcji Core::LoadTexture mapy normalnych dla wszystkich modeli. Maja one taką samą nazwę jak zwykle tekstury, tyle że z suffiksem "_normals".
    4. +
    5. Zmodyfikuj na koniec funkcje drawObjectTexture. Dodaj do niej nowy argument GLuint normalmapId, który będzie służył do przekazywania id tekstury zawierającej mapę normalnych. Przy użyciu funkcji Core::SetActiveTexture załaduj normalmapId jako normalSampler i ustaw jednostkę teksturowania nr 1. Argument odpowiadający za normalne w miejscach wywołania funkcji drawObjectTexture.
    6. +
  2. +
+

Zadanie

+

Ustaw mapy normalne do statku planety i księżyca (lub przynajmniej 3 obiektów, jeżeli rysujesz swoją scenę). Wykorzystaj multitexturing na statku, musisz w takim wypadku mieszać zarówno tekstury koloru i normalanych.

+

SkyBox

+

Cubemapy są specjalnym rodzajem tekstur. Zawieją one 6 tekstur, każda z niej odpowiada za inną ścianę sześcianu. Nie służy ona do teksturowania zwykłego sześcianu, pozwala ona bowiem próbkować po wektorze kierunku. To znaczy, możemy o tym myśleć jak o kostce, w której środku się znaleźliśmy, co obrazuje poniższy rysunek. W przeciwieństwie do zwykłych tekstur samplujemy ją nie za pomocą dwuwymiarowych współrzędnych UV, ale za pomocą wektora trójwymiarowego, który odpowiada kierunkowi promienia. Jednym z zastosowań Cubemapy jest wyświetlanie skyboxa, czyli dalekiego tła dla sceny. Może to być na przykład rozgwieżdżone niebo z górami na horyzoncie albo obraz dalekiej galaktyki.

+

Ładowanie cubemapy

+

Cubemapę generujemy podobnie jak inne tekstury, ale przy bindowaniu należy podać GL_TEXTURE_CUBE_MAP.

+
glGenTextures(1, &textureID);
+glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
+

Skoro składa się ona z 6 tekstur, to należy każdą z nich załadować za pomocą void glTexImage2D( GLenum target, ...) taget wskazuje którą z tekstur ładujemy. Możliwe wartości rozpisane są w tabeli poniżej |Layer number|Texture target | Orientation| |—-|——————–:|———–:| |0|GL_TEXTURE_CUBE_MAP_POSITIVE_X | Right | |1|GL_TEXTURE_CUBE_MAP_NEGATIVE_X|Left| |2|GL_TEXTURE_CUBE_MAP_POSITIVE_Y|Top| |3|GL_TEXTURE_CUBE_MAP_NEGATIVE_Y|Bottom| |4|GL_TEXTURE_CUBE_MAP_POSITIVE_Z|Back| |5|GL_TEXTURE_CUBE_MAP_NEGATIVE_Z|Front|

+

Możemy je ładować w pętli biorąc za kolejne targety GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, ale należy pamiętać o powyższej kolejności. Poniższy kod ładuje do wszystkich 6 ścian tę samą teksturę, która znajduje się pod filepath.

+

+int w, h;
+for(unsigned int i = 0; i < 6; i++)
+{
+    unsigned char* image = SOIL_load_image(filepath, &w, &h, 0, SOIL_LOAD_RGBA);
+    glTexImage2D(
+        GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 
+        0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image
+    );
+}
+

Na koniec pozostaje ustawić parametry opisujące zachowanie tekstury:

+
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);  
+

Zadanie*

+

Napisz funkcję, która będzie ładować cubmapę bazującą na tablicy 6 stringów i załaduj do niej tekstury z foldera skybox.

+

Rysowanie skyboxa

+

Skybox jest sześcianem, wewnątrz którego zamieszamy naszą scenę, przedstawia on dalekie tło, dzięki temu dostajemy iluzję głębi i przestrzeni. Do tego potrzebujemy narysować sześcian i narysować go odpowiednim shaderem. Rysowanie jest bardzo proste, polega wyłącznie na wyświetleniu koloru tekstury. Aby próbkować, teksturę potrzebujemy przesłać pozycję w przestrzeni modelu do shadera fragmentów.

+
#version 430 core
+
+layout(location = 0) in vec3 vertexPosition;
+
+uniform mat4 transformation;
+
+out vec3 texCoord;
+
+void main()
+{
+    texCoord = vertexPosition;
+    gl_Position = transformation * vec4(vertexPosition, 1.0);
+}
+
+

shader_skybox.vert

+
+

W shaderze fragmentów wystarczy odebrać pozycję i próbkować za jej pomocą teksturę.

+
#version 430 core
+
+uniform samplerCube skybox;
+
+in vec3 texCoord;
+
+out vec4 out_color;
+
+void main()
+{
+    out_color = texture(skybox,texCoord);
+}
+
+

shader_skybox.frag

+
+

Zadanie*

+

W modelach znajduje się cube.obj, załaduj go i narysuj shaderami shader_skybox.vert i shader_skybox.vert. Pamiętaj o przesłaniu macierzy transformacji i tekstury skyboxa. Aktywujemy ją za pomocą instrukcji:

+
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
+

Skybox potencjalnie zasłania pewne obiekty, które są umieszczone trochę dalej. Wynika to z tego, że renderowanie go nadpisuje bufor głębokości. Dlatego narysuj cubemapę z wyłączonym testem głębokości na samym początku. Następnie włącz test głębokości dla reszty sceny. Dezaktywację wykonasz za pomocą instrukcji glDisable(GL_DEPTH_TEST);, natomiast aktywację za pomocąglEnable(GL_DEPTH_TEST);.

+

Skybox reprezentuje obiekty, które są bardzo daleko. Tę iluzję możemy utracić, gdy kamera przysunie się zbyt blisko do skyboxa. Aby tego uniknąć, musimy tak umieścić skybox, by kamera zawsze była w jego środku. Przesuń skybox do pozycji kamery z użyciem macierzy translacji.

+ + diff --git a/grk/cw 6/Zadania 7.md b/grk/cw 6/Zadania 7.md new file mode 100644 index 0000000..ab3846d --- /dev/null +++ b/grk/cw 6/Zadania 7.md @@ -0,0 +1,148 @@ +# Normal Mapping + +W tej części będziemy dalej modyfikować shadery **shader_5_tex** poprzez implementację normal mappingu. + +Obliczenia dla map normalnych należy wykonywać w przestrzeni stycznych. Przestrzeń styczna jest wyliczana dla każdego punktu w obiekcie. Jej celem jest takie przekształcenie przestrzeni, żeby wektor normalny był wektorem jednostkowym (0,1,0). + +Do wyliczenia przestrzeni stycznej potrzebujemy dla każdego wierzchołka oprócz wektora normalnego wektor styczny i bistyczny (*tangent* i *bitangent*). Są one wyliczane przez bibliotekę `Assimp`. + +### Wykonaj kopię shaderów shader_4_tex.vert shader_4_tex.frag + +### Przenieś obliczenia światła do przestrzeni stycznej. + +1) Oblicz macierz **TBN**. + + Macierz **TBN** to macierz 3x3 wyznaczana przez wektory *tangent*, *bitangent* i *normal*, służy do przenoszenia wektorów z przestrzeni świata do przestrzeni stycznej. + + 1. W **vertex shaderze** przekrztałć wektory `vertexNormal`, `vertexTangent` i `vertexBitangent` do przestrzeni świata (przemnóż macierz modelu przez te wektory, tak jak to robiliśmy wcześniej z wektorem normalnym, z uwzględnieniem zmiennej w=0) i zapisz wyniki odpowiednio w zmiennych `normal`, `tangent` i `bitangent`. + 1. Stwórz macierz 3x3 TBN jako transpose(mat3(tangent, bitangent, normal)). Macierz transponujemy, aby szybko uzyskać jej odwrotność (możemy tak zrobić przy założeniu, ze jest ortogonalna). + +2. Przenieś wektor światła i wektor widoku do przestrzeni stycznych + 1. Musimy przekształcić wektor światła (L) i wektor widoku (V) do przestrzeni stycznych. Zrobimy to w vertex shaderze. W tym celu przenieś potrzebne dane dotyczące światła i kamery (uniformy `lightPos` i `cameraPos`) z **fragment shadera** do **vertex shadera.** + + 2. Oblicz wektor `viewDir` jako znormalizowana różnice `cameraPos` i `fragPos` (tu jeszcze działamy w przestrzeni świata). Analogicznie oblicz `lightDir` jako różnicę `lightPos` i `fragPos` + + 3. Przekształć wektory `viewDir` i `lightDir` do przestrzeni stycznej mnożąc je przez macierz **TBN**. Wynik zapisz w zmiennych`viewDirTS` i `lightDirTS` odpowiednio. + + 4. Przekaż `viewDirTS` i `lightDirTS` do fragment shadera. (zadeklaruj je jako zmienne `out`) + + > (Sufiks TS oznacza tangent space. Ważne jest, aby oznaczać (np. dopisując coś do nazwy zmiennej) w jakiej przestrzeni znajdują się używane wektory, tak aby poprawnie wykonywać obliczenia. Trzeba zawsze zwracać uwagę na to, w jakiej przestrzeni działamy.) + +3. Przekształć **fragment shader**, by obsługiwał **tangent space** + 1. Nie potrzebujemy już we **fragment shaderze** informacji na temat pozycji fragmentu i wektora normalnego geometrii, skasuj wiec zmienne przekazujące te wektory pomiędzy shaderami. + 2. wektora `lightDir` powinniśmy użyć wektora `lightDirTS` (należy go dodatkowo znormalizować), a jako wektor widoku V powinniśmy użyć wektora `viewDirTS` (również należy go znormalizować). Jako wektora N użyj na razie wektora vec3(0,0,1). + +Efekt finalny powinien wyglądać tak samo, jak przed jakąkolwiek zmianą. Następnym krokiem będzie wykorzystanie map normalnych. + +### Wykorzystaj normalmapy + +1. Chcemy wczytywać normalne z tekstury, w tym celu dodaj we **fragment shaderze** dodatkowy sampler do czytania map normalnych, nazwij go `normalSampler`. Pobierz z niego wektor normalny analogicznie, jak czytamy kolor zwykłej tekstury z samplera `textureSampler` i zapisz go w zmiennej `N`. + 2. Ponieważ w teksturze wartości są w przedziale $[0,1]$, musimy jeszcze przekształcić je do przedziału $[-1,1]$. W tym celu przemnóż wektor N przez 2 i odejmij 1. + Na koniec warto jeszcze znormalizować wektor normalny, aby uniknąć błędów związanych z precyzja lub kompresja tekstury. + 3. Wczytaj pliki zawierające mapy normalnych w kodzie C++ W tym celu załaduj przy użyciu funkcji `Core::LoadTexture` mapy normalnych dla wszystkich modeli. Maja one taką samą nazwę jak zwykle tekstury, tyle że z suffiksem "_normals". + 4. Zmodyfikuj na koniec funkcje `drawObjectTexture`. Dodaj do niej nowy argument `GLuint normalmapId`, który będzie służył do przekazywania id tekstury zawierającej mapę normalnych. Przy użyciu funkcji `Core::SetActiveTexture` załaduj `normalmapId` jako `normalSampler` i ustaw jednostkę teksturowania nr 1. + Argument odpowiadający za normalne w miejscach wywołania funkcji `drawObjectTexture`. + + +### Zadanie* +Ustaw mapy normalne do statku planety i księżyca (lub przynajmniej 3 obiektów, jeżeli rysujesz swoją scenę). Wykorzystaj multitexturing na statku, musisz w takim wypadku mieszać zarówno tekstury koloru i normalanych. + +## SkyBox +Cubemapy są specjalnym rodzajem tekstur. Zawieją one 6 tekstur, każda z niej odpowiada za inną ścianę sześcianu. Nie służy ona do teksturowania zwykłego sześcianu, pozwala ona bowiem próbkować po wektorze kierunku. To znaczy, możemy o tym myśleć jak o kostce, w której środku się znaleźliśmy, co obrazuje poniższy rysunek. W przeciwieństwie do zwykłych tekstur samplujemy ją nie za pomocą dwuwymiarowych współrzędnych UV, ale za pomocą wektora trójwymiarowego, który odpowiada kierunkowi promienia. +![](./img/cubemaps_sampling.png) +Jednym z zastosowań Cubemapy jest wyświetlanie skyboxa, czyli dalekiego tła dla sceny. Może to być na przykład rozgwieżdżone niebo z górami na horyzoncie albo obraz dalekiej galaktyki. + +### Ładowanie cubemapy +Cubemapę generujemy podobnie jak inne tekstury, ale przy bindowaniu należy podać `GL_TEXTURE_CUBE_MAP`. +```C++ +glGenTextures(1, &textureID); +glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); +``` +Skoro składa się ona z 6 tekstur, to należy każdą z nich załadować za pomocą `void glTexImage2D( GLenum target, ...)` `taget` wskazuje którą z tekstur ładujemy. Możliwe wartości rozpisane są w tabeli poniżej +|Layer number|Texture target | Orientation| +|----|--------------------:|-----------:| +|0|`GL_TEXTURE_CUBE_MAP_POSITIVE_X` | Right | +|1|`GL_TEXTURE_CUBE_MAP_NEGATIVE_X`|Left| +|2|`GL_TEXTURE_CUBE_MAP_POSITIVE_Y`|Top| +|3|`GL_TEXTURE_CUBE_MAP_NEGATIVE_Y`|Bottom| +|4|`GL_TEXTURE_CUBE_MAP_POSITIVE_Z`|Back| +|5|`GL_TEXTURE_CUBE_MAP_NEGATIVE_Z`|Front| + +Możemy je ładować w pętli biorąc za kolejne targety `GL_TEXTURE_CUBE_MAP_POSITIVE_X+i`, ale należy pamiętać o powyższej kolejności. Poniższy kod ładuje do wszystkich 6 ścian tę samą teksturę, która znajduje się pod `filepath`. + +```C++ + +int w, h; +unsigned char *data; +for(unsigned int i = 0; i < 6; i++) +{ + unsigned char* image = SOIL_load_image(filepath, &w, &h, 0, SOIL_LOAD_RGBA); + glTexImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, + 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data + ); +} +``` +Na koniec pozostaje ustawić parametry opisujące zachowanie tekstury: +```C++ +glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); +``` + +### Zadanie +Napisz funkcję, która będzie ładować cubmapę bazującą na tablicy 6 stringów i załaduj do niej tekstury z foldera `skybox`. + +### Rysowanie skyboxa +Skybox jest sześcianem, wewnątrz którego zamieszamy naszą scenę, przedstawia on dalekie tło, dzięki temu dostajemy iluzję głębi i przestrzeni. Do tego potrzebujemy narysować sześcian i narysować go odpowiednim shaderem. Rysowanie jest bardzo proste, polega wyłącznie na wyświetleniu koloru tekstury. Aby próbkować, teksturę potrzebujemy przesłać pozycję w przestrzeni modelu do shadera fragmentów. + +```C++ +#version 430 core + +layout(location = 0) in vec3 vertexPosition; + +uniform mat4 transformation; + +out vec3 texCoord; + +void main() +{ + texCoord = vertexPosition; + gl_Position = transformation * vec4(vertexPosition, 1.0); +} + +``` +> shader_skybox.vert + +W shaderze fragmentów wystarczy odebrać pozycję i próbkować za jej pomocą teksturę. + +```C++ +#version 430 core + +uniform samplerCube skybox; + +in vec3 texCoord; + +out vec4 out_color; + +void main() +{ + out_color = texture(skybox,texCoord); +} + +``` +> shader_skybox.frag + +### Zadanie +W modelach znajduje się `cube.obj`, załaduj go i narysuj shaderami `shader_skybox.vert` i `shader_skybox.vert`. Pamiętaj o przesłaniu macierzy transformacji i tekstury skyboxa. Aktywujemy ją za pomocą instrukcji: +```C++ +glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture); +``` + +Skybox potencjalnie zasłania pewne obiekty, które są umieszczone trochę dalej. Wynika to z tego, że renderowanie go nadpisuje bufor głębokości. Dlatego narysuj cubemapę z wyłączonym testem głębokości na samym początku. Następnie włącz test głębokości dla reszty sceny. +Dezaktywację wykonasz za pomocą instrukcji `glDisable(GL_DEPTH_TEST);`, natomiast aktywację za pomocą`glEnable(GL_DEPTH_TEST);`. + +Skybox reprezentuje obiekty, które są bardzo daleko. Tę iluzję możemy utracić, gdy kamera przysunie się zbyt blisko do skyboxa. Aby tego uniknąć, musimy tak umieścić skybox, by kamera zawsze była w jego środku. Przesuń skybox do pozycji kamery z użyciem macierzy translacji. + diff --git a/grk/cw 6/grk-cw6.vcxproj b/grk/cw 6/grk-cw6.vcxproj index 4a90c1d..98418bb 100644 --- a/grk/cw 6/grk-cw6.vcxproj +++ b/grk/cw 6/grk-cw6.vcxproj @@ -38,10 +38,16 @@ + + + + + + {3952C396-B1C6-44CD-96DD-C1AC15D32978} diff --git a/grk/cw 6/grk-cw6.vcxproj.filters b/grk/cw 6/grk-cw6.vcxproj.filters index ed0647a..126ff2f 100644 --- a/grk/cw 6/grk-cw6.vcxproj.filters +++ b/grk/cw 6/grk-cw6.vcxproj.filters @@ -106,5 +106,23 @@ Shader Files + + Shader Files + + + Shader Files + + + Shader Files + + + Shader Files + + + Shader Files + + + Shader Files + \ No newline at end of file diff --git a/grk/cw 6/models/cube.obj b/grk/cw 6/models/cube.obj new file mode 100644 index 0000000..4eb693e --- /dev/null +++ b/grk/cw 6/models/cube.obj @@ -0,0 +1,40 @@ +# Blender v2.90.0 OBJ File: '' +# www.blender.org +mtllib cube.mtl +o Cube +v -10.000000 -10.000000 10.000000 +v -10.000000 10.000000 10.000000 +v -10.000000 -10.000000 -10.000000 +v -10.000000 10.000000 -10.000000 +v 10.000000 -10.000000 10.000000 +v 10.000000 10.000000 10.000000 +v 10.000000 -10.000000 -10.000000 +v 10.000000 10.000000 -10.000000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.625000 0.500000 +vt 0.375000 0.500000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.125000 0.500000 +vt 0.125000 0.750000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +usemtl _PBR +s 1 +f 1/1/1 2/2/1 4/3/1 3/4/1 +f 3/4/2 4/3/2 8/5/2 7/6/2 +f 7/6/3 8/5/3 6/7/3 5/8/3 +f 5/8/4 6/7/4 2/9/4 1/10/4 +f 3/11/5 7/6/5 5/8/5 1/12/5 +f 8/5/6 4/13/6 2/14/6 6/7/6 diff --git a/grk/cw 6/shaders/shader.frag b/grk/cw 6/shaders/shader.frag deleted file mode 100644 index 7c64436..0000000 --- a/grk/cw 6/shaders/shader.frag +++ /dev/null @@ -1,21 +0,0 @@ -#version 430 core - -float AMBIENT = 0.1; - -uniform vec3 color; -uniform vec3 lightPos; -uniform vec3 lightDir; - -in vec3 vecNormal; -in vec3 worldPos; - -out vec4 outColor; - -void main() -{ - //vec3 lightDir = normalize(lightPos - worldPos); - - vec3 normal = normalize(vecNormal); - float diffuse = max(0, dot(normal, lightDir)); - outColor = vec4(color * min(1, AMBIENT + diffuse), 1.0); -} diff --git a/grk/cw 6/shaders/shader.vert b/grk/cw 6/shaders/shader.vert deleted file mode 100644 index d42abef..0000000 --- a/grk/cw 6/shaders/shader.vert +++ /dev/null @@ -1,18 +0,0 @@ -#version 430 core - -layout(location = 0) in vec3 vertexPosition; -layout(location = 1) in vec3 vertexNormal; -layout(location = 2) in vec2 vertexTexCoord; - -uniform mat4 transformation; -uniform mat4 modelMatrix; - -out vec3 vecNormal; -out vec3 worldPos; - -void main() -{ - worldPos = (modelMatrix * vec4(vertexPosition,1)).xyz; - vecNormal = (modelMatrix * vec4(vertexNormal,0)).xyz; - gl_Position = transformation * vec4(vertexPosition, 1.0); -} diff --git a/grk/cw 6/shaders/shader_skybox.frag b/grk/cw 6/shaders/shader_skybox.frag new file mode 100644 index 0000000..0221dbd --- /dev/null +++ b/grk/cw 6/shaders/shader_skybox.frag @@ -0,0 +1,14 @@ +#version 430 core + +uniform samplerCube skybox; +uniform vec3 lightColor; + +in vec3 texCoord; + +out vec4 out_color; + +void main() +{ + vec4 textureColor = texture(skybox, texCoord); + out_color = vec4(vec3(textureColor) * lightColor * 0.03f, 1.0f); +} \ No newline at end of file diff --git a/grk/cw 6/shaders/shader_skybox.vert b/grk/cw 6/shaders/shader_skybox.vert new file mode 100644 index 0000000..90d66bd --- /dev/null +++ b/grk/cw 6/shaders/shader_skybox.vert @@ -0,0 +1,13 @@ +#version 430 core + +layout(location = 0) in vec3 vertexPosition; + +uniform mat4 transformation; + +out vec3 texCoord; + +void main() +{ + texCoord = vertexPosition; + gl_Position = transformation * vec4(vertexPosition, 1.0); +} \ No newline at end of file diff --git a/grk/cw 6/shaders/shader_sun.frag b/grk/cw 6/shaders/shader_sun.frag index 9fa78ea..cb8fd23 100644 --- a/grk/cw 6/shaders/shader_sun.frag +++ b/grk/cw 6/shaders/shader_sun.frag @@ -3,6 +3,7 @@ float AMBIENT = 0.1; uniform vec3 lightPos; +uniform vec3 lightColor; in vec3 vecNormal; in vec3 worldPos; @@ -18,5 +19,5 @@ void main() vec3 normal = normalize(vecNormal); vec4 textureColor = texture2D(colorTexture, vtc); - outColor = vec4(vec3(textureColor) * 1.5, 1.0); + outColor = vec4(vec3(textureColor) * lightColor * 0.015f, 1.0); } \ No newline at end of file diff --git a/grk/cw 6/src/Planet.hpp b/grk/cw 6/src/Planet.hpp index 41f4442..6d512b4 100644 --- a/grk/cw 6/src/Planet.hpp +++ b/grk/cw 6/src/Planet.hpp @@ -57,14 +57,15 @@ namespace textureMaterials { GLuint clouds; } */ -GLuint program; GLuint programSun; GLuint programDepth; GLuint programTex; +GLuint programSkyBox; Core::Shader_Loader shaderLoader; Core::RenderContext sphereContext; +Core::RenderContext cubeContext; const char* const planetTexPaths[] = { "./textures/planets/earth.png", "./textures/planets/mercury.png", "./textures/planets/venus.jpg", "./textures/planets/mars.jpg", "./textures/planets/jupiter.jpg", "./textures/planets/saturn.jpg", "./textures/planets/uranus.jpg", "./textures/planets/neptune.jpg", "./textures/planets/icy.png", @@ -82,8 +83,15 @@ const char* const sunTexPaths[] = { "./textures/suns/sol.jpg", "./textures/suns/ int sunTexIndex = 20; GLuint sunTex; -glm::vec3 sunPos = glm::vec3(12.f, 0.f, 12.f); -float sunSize = 0.04f; +glm::vec3 sunPos = glm::vec3(20.f, 0.f, 20.f); +float sunSize = 0.05f; + +const char* skyBoxPaths[] = { "./textures/skybox/space_rt.png", "./textures/skybox/space_lf.png", "./textures/skybox/space_up.png", "./textures/skybox/space_dn.png", + "./textures/skybox/space_bk.png", "./textures/skybox/space_ft.png" }; +GLuint skyBoxTex; + +glm::vec3 skyBoxPos = glm::vec3(0.f, 0.f, 0.f); +float skyBoxSize = 3.f; glm::vec3 cameraPos = glm::vec3(-2.f, 0.f, 0.f); glm::vec3 cameraDir = glm::vec3(1.f, 0.f, 0.f); @@ -100,7 +108,7 @@ unsigned int depthMapFBO; int HDR_WIDTH = 1024; int HDR_HEIGHT = 1024; -float lightPower = 50.f; +float lightPower = 100.f; glm::vec3 lightColor = glm::vec3(lightPower, lightPower, lightPower); glm::mat4 createCameraMatrix() { @@ -123,8 +131,8 @@ glm::mat4 createCameraMatrix() { glm::mat4 createPerspectiveMatrix() { glm::mat4 perspectiveMatrix; - float n = 0.05f; - float f = 20.f; + float n = 0.01f; + float f = 200.f; float fov = 105.f; float PI = 3.14159265359f; float S = 1 / (tan((fov / 2) * (PI / 180))); @@ -182,7 +190,7 @@ void initDepthMap() { } -void drawObjectTexture(Core::RenderContext& context, glm::mat4 modelMatrix, GLuint texture) { +void drawPlanet(Core::RenderContext& context, glm::mat4 modelMatrix, GLuint texture) { glUseProgram(programTex); Core::SetActiveTexture(texture, "colorTexture", programTex, 0); glm::mat4 viewProjectionMatrix = createPerspectiveMatrix() * createCameraMatrix(); @@ -203,6 +211,19 @@ void drawSun(Core::RenderContext& context, glm::mat4 modelMatrix, GLuint texture glUniformMatrix4fv(glGetUniformLocation(programSun, "transformation"), 1, GL_FALSE, (float*)&transformation); glUniformMatrix4fv(glGetUniformLocation(programSun, "modelMatrix"), 1, GL_FALSE, (float*)&modelMatrix); glUniform3f(glGetUniformLocation(programSun, "lightPos"), sunPos.x, sunPos.y, sunPos.z); + glUniform3f(glGetUniformLocation(programSun, "lightColor"), lightColor.x, lightColor.y, lightColor.z); + Core::DrawContext(context); + glUseProgram(0); +} + +void drawSkyBox(Core::RenderContext& context, glm::mat4 modelMatrix, GLuint texture) { + glUseProgram(programSkyBox); + Core::SetActiveSkyBox(texture, "skybox", programSkyBox, 0); + glm::mat4 viewProjectionMatrix = createPerspectiveMatrix() * createCameraMatrix(); + glm::mat4 transformation = viewProjectionMatrix * modelMatrix; + glUniformMatrix4fv(glGetUniformLocation(programSkyBox, "transformation"), 1, GL_FALSE, (float*)&transformation); + glUniformMatrix4fv(glGetUniformLocation(programSkyBox, "modelMatrix"), 1, GL_FALSE, (float*)&modelMatrix); + glUniform3f(glGetUniformLocation(programSkyBox, "lightColor"), lightColor.x, lightColor.y, lightColor.z); Core::DrawContext(context); glUseProgram(0); } @@ -238,21 +259,30 @@ void drawObjectPBR(Core::RenderContext& context, glm::mat4 modelMatrix, glm::vec } */ void renderScene(GLFWwindow* window) { - glClearColor(0.0f, 0.0f, 0.15f, 1.0f); + glClearColor(0.5f, 0.0f, 0.25f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); float time = glfwGetTime(); + //rysowanie planety glm::mat4 planetScale = glm::scale(glm::vec3(planetSize)); glm::mat4 planetRotate = glm::rotate(time * planetRot, glm::vec3(0, 1, 0)); glm::mat4 planetTranslate = glm::translate(planetPos); - drawObjectTexture(sphereContext, planetTranslate * planetRotate * planetScale, planetTex); + drawPlanet(sphereContext, planetTranslate * planetRotate * planetScale, planetTex); + //rysowanie słońca glm::mat4 sunScale = glm::scale(glm::vec3(sunSize)); glm::mat4 sunTranslate = glm::translate(sunPos); drawSun(sphereContext, sunTranslate * sunScale, sunTex); + //rysowanie skyboxa + skyBoxPos = cameraPos; + glm::mat4 skyBoxScale = glm::scale(glm::vec3(skyBoxSize)); + glm::mat4 skyBoxTranslate = glm::translate(skyBoxPos); + + drawSkyBox(cubeContext, skyBoxTranslate * skyBoxScale, skyBoxTex); + glfwSwapBuffers(window); } @@ -277,6 +307,7 @@ void init(GLFWwindow* window) { glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glEnable(GL_DEPTH_TEST); + //glDisable(GL_DEPTH_TEST); //initDepthMap(); initHDR(); @@ -284,17 +315,22 @@ void init(GLFWwindow* window) { programDepth = shaderLoader.CreateProgram("shaders/shader_smap.vert", "shaders/shader_smap.frag"); programTex = shaderLoader.CreateProgram("shaders/shader_tex.vert", "shaders/shader_tex.frag"); programSun = shaderLoader.CreateProgram("shaders/shader_sun.vert", "shaders/shader_sun.frag"); + programSkyBox = shaderLoader.CreateProgram("shaders/shader_skybox.vert", "shaders/shader_skybox.frag"); loadModelToContext("./models/sphere.obj", sphereContext); + loadModelToContext("./models/cube.obj", cubeContext); planetTex = Core::LoadTexture(planetTexPaths[std::abs(planetTexIndex % 20)]); sunTex = Core::LoadTexture(sunTexPaths[std::abs(sunTexIndex % 5)]); + + skyBoxTex = Core::LoadSkyBox(skyBoxPaths); } void shutdown(GLFWwindow* window) { shaderLoader.DeleteProgram(programDepth); shaderLoader.DeleteProgram(programTex); shaderLoader.DeleteProgram(programSun); + shaderLoader.DeleteProgram(programSkyBox); } //obsluga wejscia @@ -356,11 +392,11 @@ void processInput(GLFWwindow* window) } //siła światła - float powerSpeed = 0.5f; + float powerSpeed = 1.f; - if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS && lightPower < 250.f) + if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS && lightPower < 300.f) lightPower += powerSpeed; - if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS && lightPower > 0.5f) + if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS && lightPower > 10.f) lightPower -= powerSpeed; lightColor = glm::vec3(lightPower, lightPower, lightPower); diff --git a/grk/cw 6/src/Texture.cpp b/grk/cw 6/src/Texture.cpp index 18bab57..fe180aa 100644 --- a/grk/cw 6/src/Texture.cpp +++ b/grk/cw 6/src/Texture.cpp @@ -29,7 +29,29 @@ GLuint Core::LoadTexture( const char * filepath ) return id; } +GLuint Core::LoadSkyBox( const char ** filepath ) +{ + GLuint id; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + int w, h; + for (unsigned int i = 0; i < 6; i++) + { + unsigned char* image = SOIL_load_image(filepath[i], &w, &h, 0, SOIL_LOAD_RGBA); + glTexImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, + 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image + ); + } + + return id; +} void Core::SetActiveTexture(GLuint textureID, const char * shaderVariableName, GLuint programID, int textureUnit) { @@ -37,3 +59,10 @@ void Core::SetActiveTexture(GLuint textureID, const char * shaderVariableName, G glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(GL_TEXTURE_2D, textureID); } + +void Core::SetActiveSkyBox(GLuint textureID, const char* shaderVariableName, GLuint programID, int textureUnit) +{ + glUniform1i(glGetUniformLocation(programID, shaderVariableName), textureUnit); + glActiveTexture(GL_TEXTURE0 + textureUnit); + glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); +} \ No newline at end of file diff --git a/grk/cw 6/src/Texture.h b/grk/cw 6/src/Texture.h index 910228e..caa3cbc 100644 --- a/grk/cw 6/src/Texture.h +++ b/grk/cw 6/src/Texture.h @@ -6,10 +6,11 @@ namespace Core { GLuint LoadTexture(const char * filepath); - + GLuint LoadSkyBox(const char ** filepath); // textureID - identyfikator tekstury otrzymany z funkcji LoadTexture // shaderVariableName - nazwa zmiennej typu 'sampler2D' w shaderze, z ktora ma zostac powiazana tekstura // programID - identyfikator aktualnego programu karty graficznej // textureUnit - indeks jednostki teksturujacej - liczba od 0 do 7. Jezeli uzywa sie wielu tekstur w jednym shaderze, to kazda z nich nalezy powiazac z inna jednostka. void SetActiveTexture(GLuint textureID, const char * shaderVariableName, GLuint programID, int textureUnit); + void SetActiveSkyBox(GLuint textureID, const char * shaderVariableName, GLuint programID, int textureUnit); } \ No newline at end of file diff --git a/grk/cw 6/textures/skybox/space_bk.png b/grk/cw 6/textures/skybox/space_bk.png new file mode 100644 index 0000000..8366b78 Binary files /dev/null and b/grk/cw 6/textures/skybox/space_bk.png differ diff --git a/grk/cw 6/textures/skybox/space_dn.png b/grk/cw 6/textures/skybox/space_dn.png new file mode 100644 index 0000000..4191f53 Binary files /dev/null and b/grk/cw 6/textures/skybox/space_dn.png differ diff --git a/grk/cw 6/textures/skybox/space_ft.png b/grk/cw 6/textures/skybox/space_ft.png new file mode 100644 index 0000000..e7b65cb Binary files /dev/null and b/grk/cw 6/textures/skybox/space_ft.png differ diff --git a/grk/cw 6/textures/skybox/space_lf.png b/grk/cw 6/textures/skybox/space_lf.png new file mode 100644 index 0000000..7a67e73 Binary files /dev/null and b/grk/cw 6/textures/skybox/space_lf.png differ diff --git a/grk/cw 6/textures/skybox/space_rt.png b/grk/cw 6/textures/skybox/space_rt.png new file mode 100644 index 0000000..5aba731 Binary files /dev/null and b/grk/cw 6/textures/skybox/space_rt.png differ diff --git a/grk/cw 6/textures/skybox/space_up.png b/grk/cw 6/textures/skybox/space_up.png new file mode 100644 index 0000000..61626da Binary files /dev/null and b/grk/cw 6/textures/skybox/space_up.png differ