lab 7 added

This commit is contained in:
Wiktoria Grzesik 2024-01-12 20:37:53 +01:00
parent e1dec3ee4e
commit 2595f173e7
116 changed files with 797 additions and 406 deletions

View File

@ -1,92 +0,0 @@
## Oświetlenie Phonga
W trakcie tych zajęć zajmiemy się implementacją modelu oświetlenia Phonga. Na poprzednich zajęciach zbudowaliśmy układ słoneczny. Wykorzystamy go w trakcie tych zajęć. Jeżeli go zrobiłeś, to przekopiuj do `ex_5_1.hpp` kod z poprzednich zajęć. W przeciwnym wypadku wykorzystaj ten, który jest zaimplementowany w `ex_5_1.hpp`. W zadaniu będzie nam potrzebny statek latający przed kamerą, jak nie ma tego w Twojej scenie to skopiuj to z `ex_5_1.hpp`.
## Zadanie - *diffuse*
Oblicz we fragment shaderze oświetlenie obiektu przy użyciu modelu Phonga dla odbicia rozproszonego (*diffuse)
1. Przekaż źródło światła. Na razie przyjmiemy kierunkowy model oświetlenia, dlatego źródło będzie opisane jako wektor kierunkowy:
- Prześlij do shadera fragmentów zmienna typu `uniform vec3` (nazwij ją np. `lightDir`), w której będzie się znajdować wektor kierunkowy.
- Należy to zrobić podobnie do tego, jak przesyłany jest kolor.
- Jako kierunek światła wybierz dowolny wektor jednostkowy. (Możesz wziąć dowolny niezerowy wektor następnie go znormalizować).
* Dodatkowo prześlij drugą zmienną `uniform vec3 lightColor`, w której umieścimy kolor światła. Prześlij tam wartości ze zmiennej `glm::vec3 lightColor`.
2. Oblicz natężenie w shaderze fragmentów:
- prześlij normalne z shadera fragmentów do shadera wierzchołków
- znormalizuj wektor normalny przed użyciem go w obliczeniach (uśrednianie wektorów normalnych wierzchołków może spowodować, że przestaje one być jednostkowe).
- Natężenie to iloczyn skalarny wektora normalnego powierzchni i odwrotnego wektora kierunku padania światła. Skorzystaj z funkcji `dot`.
- Natężenie nie może być ujemne. Przytnij natężenie do zera przy użyciu: `x = max(x, 0.0)`
3. Zastosuj obliczone natężenie, aby zmodyfikować kolor obiektu:
- Przemnóż kolor RGB fragmentu przez obliczone natężenie i przez kolor światła z `lightColor`.
## Zadanie - obsługa obrotów
Dlaczego oświetlenie statku nie zmienia się podczas jego obracania?
(Wektory normalne są w układzie lokalnym modelu, a wektor padania światła w układzie świata)
Należy wykonać transformacje wektorów normalnych do przestrzeni świata:
- Prześlij macierz modelu rysowanego obiektu (_model Matrix_) jako osobna zmienna do vertex shadera (`uniform mat4`).
- Przemnóż przez te macierz wektor normalny wierzchołka przed przesłaniem go do shadera fragmentów.
- Współrzędna **w** dopisana do wektora przed mnożeniem przez macierz powinna być ustawiona na 0. Wynika to z tego, że w przypadku transformacji wektorów reprezentujących kierunki w przestrzeni, nie chcemy dokonywać translacji — np. wektor normalny do powierzchni zależy od orientacji obiektu, ale nie od jego pozycji (przesunięcia) w przestrzeni świata.
## Zadanie - *specular*
Uzupełnił model o czynnik odbicia zwierciadlanego (*specular*). W tym celu:
1. Potrzebny będzie wektor od rysowanego fragmentu do pozycji kamery:
- Wyślij pozycje kamery (`cameraPos`) jako kolejna zmienna do fragment shadera.
- Podobnie jak wektory normalne prześlij z vertex do fragment shadera pozycje wierzchołków (`vertexPosition`) w przestrzeni świata (czyli pomnożone przez macierz **modelMatrix**). Pamiętaj, że tym razem wektory reprezentują punkty, a nie kierunki - współrzędna **w** przed mnożeniem musi być ustawiona na 1. W wyniku rasteryzacji otrzymamy w shaderze fragmentu jego pozycję (nazywaną pozycją fragmentu)
- Oblicz wektor **V** (_view direction_) jako znormalizowaną różnice pozycji kamery i pozycji fragmentu.
2. Oblicz natężenie światła odbitego we _fragment shaderze_:
- Oblicz wektor kierunku odbicia światła **R** przy użyciu funkcji [`reflect`](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/reflect.xhtml). Pamiętaj, żeby przesłać do funkcji odwrócony wektor kierunku światła.
- Oblicz natężenie: iloczyn skalarny **V** i **R**, przycięty do zera ( `max(...,0.0)` ), a następnie podniesiony do wysokiej potęgi (np. 8, 50, 1000), która jest miara połyskliwości powierzchni.
3. Ustal ostateczny kolor piksela na `objectColor * diffuse + lightColor * specular`. Oznacza to najprostszy przypadek, gdy kolor światła odbitego jest biały.
## Zadanie - oświetlenie punktowe
W układzie planetarnym obiektem oświetlającym powinno być słońce, dlatego zamień oświetlenie kierunkowe na punktowe:
- Zamiast przesyłać (w `lightDir`) kierunek światła, prześlij pozycję słońca do fragment shadera (taką jak ustawiłeś w punkcie powyżej) jako uniform vec3 (nazwij go `lightPos`).
- Oblicz kierunek światła odejmując od pozycji fragmentu pozycję światła, znormalizuj wynik. Zapisz wynik w zmiennej `lightDir`.
- Słońce będzie czarne, nie martw się tym, tylko spójrz na punkt następny.
## Zadanie - shader słońca
Źródło światła znajduje się wewnątrz kuli, która reprezentuje słońce, dlatego jest czarna. By to naprawić, utwórz osobny shader, który będzie odpowiadać za renderowanie słońca.
Celem tego zadania jest stworzenie shadera (**shader_4_sun.vert**_ i **shader_4_sun.frag**), który będzie odpowiadał wyłącznie za rysowanie słońca. Poprzednie shadery (**shader_4_1.vert**_ i **shader_4_1.frag**) nadal mają rysować pozostałe obiekty. a) zainicjalizuj _program_ (shadery): - Pliki **shader_4_sun.vert** i **shader_4_sun.frag** są identyczne z 4_1** przed zmianami, będą punktem wyjścia dla _shadera_ słońca.
1. Utwórz zmienną globalną `GLuint programSun` na adres shadera słońca. Stwórz _program_ za pomocą `shaderLoader.CreateProgram` analogicznie jak tworzy się `program` z **shader_4_1.vert** i **shader_4_1.frag** (parametry wejściowe to ścieżka do shadera wierzchołków i fragmentów **shader_4_sun.vert** i **shader_4_sun.frag**).
2. W skomplikowanym projekcie różne typy obiektów rysuje się przy użyciu różnych shaderów, zate potrzebna jest w programie architektura, która na to pozwala. Ustaw odpowiedni _program_ (shadery) do rysowania słońca:
- funkcja `drawObject` korzysta z globalnej zmiennej `program`, żeby wskazywać shadery do rysowania. Dodaj argument do funkcji, który będziesz przekazywać adres _programu_, który ma być wykorzystany do rysowania.
- dodaj odpowiedni _program_ w wywołaniach `drawObject`.
## Osłabienie światła, tone mapping
### Zadanie - Osłabienie światła (attenuation)
Światło pochodzące z punktowego źródła traci na sile wraz z dystansem. Wynika to z tego, że rozprasza się na większą powierzchnię.
Dodaj ten efekt do shadera. Zamiast brać kolor światła bezpośrednio, podziel go przez kwadrat dystansu od źródła świata.
#### Tone mapping
Przez obecną zmianę scena stała się ciemna. Wymaga to od nas zmiany 'koloru' światła na wartości dużo większe niż do tej pory. Jeśli teraz to zrobimy i przesadzimy w drugą stronę, otrzymamy efekt prześwietlenia. Wynika to z ograniczenia zakresu kolorów do $[0,1]$ (obsługą wyższych wartości nazywamy HDR). Rozwiązaniem jest pracowanie na wartościach powyżej 1 wykorzystanie *tone mappingu* do przeniesienia ich w zakres $[0,1]$. Istnieje wiele wzorów, które są wykorzystywane do tego, jeden z nich to:
$$C_{mapped} = 1-e^{-C * E},$$
gdzie C to kolor sceny a E to parametr ekspozycji (z zakresu $(0,\infty)$, który może być dostosowany w zależności od jasności.
### Zadanie - Tone mapping*
Zwiększ siłę słońca przynajmniej stukrotnie. Zaimplementuj powyższą metodę tone mappingu i dodaj możliwość sterowania ekspozycją za pomocą klawiszy 1 i 2.
### Zadanie*
Dodaj drugie źródło oświetlenia w postaci reflektora statku. Reflektor świeci tylko w określonym stożku,dlatego oprócz pozycji `spotPos` posiada również kierunek `spotDir` i kąt świecenia $\phi$. Po obliczeniu dla niego `lightDir` należy sprawdzić, czy iloczyn skalarny pomiędzy `lightDir` a `spodDir` jest większy niż $\cos\phi$ . Jeżeli nie jest, to stożek nie świeci w tym miejscu. Można ułatwić sobie implementację wielu źródeł światła poprzez przeniesienie obliczeń oświetlenia do funkcji, która przyjmuje kierunek światła i siłę naświetlenie.
Zwróć uwagę, że SpotDir to co innego niż light Dir w poprzednich zadaniach
![](./img/spotlight.png)
## Zmień shader słońca na bardziej realistyczny.
### Zadanie*
Na poniższym obrazku jest zdjęcie słońca. Jest ono ciemniejsze na brzegach spróbuj uzyskać podobny efekt. Przydadzą się wektory z poprzednich punktów jak wektor normalny i wektor **V**.
![](./img/sun.png)

View File

@ -1,38 +0,0 @@
#version 430 core
uniform vec3 color;
out vec4 outColor;
uniform vec3 lightColor;
uniform vec3 cameraPos;
uniform vec3 lightPos;
in vec3 FragNormal;
in vec4 vertexPosWorld;
uniform float exposition;
void main()
{
vec3 viewDir = normalize(cameraPos - vertexPosWorld.xyz);
vec3 normalizedNormal = normalize(FragNormal);
vec3 lightDir = normalize(lightPos - vertexPosWorld.xyz);
float diffuse = max(dot(normalizedNormal, lightDir), 0.0);
vec3 normalizedViewDir = normalize(viewDir);
vec3 reflectDir = reflect(-normalize(lightDir), normalizedNormal);
float specular = pow(max(dot(normalizedViewDir, reflectDir), 0.0), 8.0);
//zad_6
float distance = length(lightPos - vertexPosWorld.xyz);
vec3 newLightColor = lightColor / distance;
vec3 finalColor = newLightColor * (color * diffuse+specular);
finalColor = 1.0 - exp(-finalColor * exposition);
outColor = vec4(finalColor, 1.0);
}

View File

@ -1,27 +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;
out vec3 FragNormal;
uniform mat4 modelMatrix;
uniform vec3 cameraPos;
out vec3 viewDir;
out vec4 vertexPosWorld;
void main()
{
gl_Position = transformation * vec4(vertexPosition, 1.0);
vec4 transformedNormal = modelMatrix * vec4(vertexNormal, 0.0);
FragNormal = normalize(transformedNormal.xyz);
vertexPosWorld = modelMatrix * vec4(vertexPosition, 1.0);
}

View File

@ -1,24 +0,0 @@
#version 430 core
uniform vec3 color;
in vec3 interpNormal;
out vec4 out_color;
void main()
{
float rimIntensity = 0.5; // intensywnoϾ
vec3 rimColor = vec3(1.0, 0.0, 0.0); // kolor rim
float rim = dot(normalize(interpNormal), normalize(vec3(0.0, 0.0, 1.0))); // wektor (0, 0, 1) ¿eby na krawêdziach
rim = 1 - pow(rim, 2); // jak szeroki jest ten rim
vec3 finalColor = color;
finalColor = mix(color, rimColor, rimIntensity * rim);
out_color = vec4(finalColor, 1.0);
}

View File

@ -1,116 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Zadania 5</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
</style>
<link rel="stylesheet" href="style.css" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<h2 id="oświetlenie-phonga">Oświetlenie Phonga</h2>
<p>W trakcie tych zajęć zajmiemy się implementacją modelu oświetlenia Phonga. Na poprzednich zajęciach zbudowaliśmy układ słoneczny. Wykorzystamy go w trakcie tych zajęć. Jeżeli go zrobiłeś, to przekopiuj do <code>ex_5_1.hpp</code> kod z poprzednich zajęć. W przeciwnym wypadku wykorzystaj ten, który jest zaimplementowany w <code>ex_5_1.hpp</code>. W zadaniu będzie nam potrzebny statek latający przed kamerą, jak nie ma tego w Twojej scenie to skopiuj to z <code>ex_5_1.hpp</code>.</p>
<h2 id="zadanie---diffuse">Zadanie - <em>diffuse</em></h2>
<p>Oblicz we fragment shaderze oświetlenie obiektu przy użyciu modelu Phonga dla odbicia rozproszonego (*diffuse)</p>
<p> 1. Przekaż źródło światła. Na razie przyjmiemy kierunkowy model oświetlenia, dlatego źródło będzie opisane jako wektor kierunkowy:</p>
<ul>
<li><p>Prześlij do shadera fragmentów zmienna typu <code>uniform vec3</code> (nazwij ją np. <code>lightDir</code>), w której będzie się znajdować wektor kierunkowy.</p></li>
<li><p>Należy to zrobić podobnie do tego, jak przesyłany jest kolor.</p></li>
<li><p>Jako kierunek światła wybierz dowolny wektor jednostkowy. (Możesz wziąć dowolny niezerowy wektor następnie go znormalizować).</p></li>
<li><p>Dodatkowo prześlij drugą zmienną <code>uniform vec3 lightColor</code>, w której umieścimy kolor światła. Prześlij tam wartości ze zmiennej <code>glm::vec3 lightColor</code>.</p></li>
</ul>
<ol start="2" type="1">
<li>Oblicz natężenie w shaderze fragmentów:</li>
</ol>
<ul>
<li><p>prześlij normalne z shadera fragmentów do shadera wierzchołków</p></li>
<li><p>znormalizuj wektor normalny przed użyciem go w obliczeniach (uśrednianie wektorów normalnych wierzchołków może spowodować, że przestaje one być jednostkowe).</p></li>
<li><p>Natężenie to iloczyn skalarny wektora normalnego powierzchni i odwrotnego wektora kierunku padania światła. Skorzystaj z funkcji <code>dot</code>.</p></li>
<li><p>Natężenie nie może być ujemne. Przytnij natężenie do zera przy użyciu: <code>x = max(x, 0.0)</code></p></li>
</ul>
<ol start="3" type="1">
<li>Zastosuj obliczone natężenie, aby zmodyfikować kolor obiektu:</li>
</ol>
<ul>
<li>Przemnóż kolor RGB fragmentu przez obliczone natężenie i przez kolor światła z <code>lightColor</code>.</li>
</ul>
<h2 id="zadanie---obsługa-obrotów">Zadanie - obsługa obrotów</h2>
<p>Dlaczego oświetlenie statku nie zmienia się podczas jego obracania?</p>
<p>(Wektory normalne są w układzie lokalnym modelu, a wektor padania światła w układzie świata)</p>
<p>Należy wykonać transformacje wektorów normalnych do przestrzeni świata: - Prześlij macierz modelu rysowanego obiektu (<em>model Matrix</em>) jako osobna zmienna do vertex shadera (<code>uniform mat4</code>).<br />
- Przemnóż przez te macierz wektor normalny wierzchołka przed przesłaniem go do shadera fragmentów. - Współrzędna <strong>w</strong> dopisana do wektora przed mnożeniem przez macierz powinna być ustawiona na 0. Wynika to z tego, że w przypadku transformacji wektorów reprezentujących kierunki w przestrzeni, nie chcemy dokonywać translacji — np. wektor normalny do powierzchni zależy od orientacji obiektu, ale nie od jego pozycji (przesunięcia) w przestrzeni świata.</p>
<h2 id="zadanie---specular">Zadanie - <em>specular</em></h2>
<p>Uzupełnił model o czynnik odbicia zwierciadlanego (<em>specular</em>). W tym celu:</p>
<ol type="1">
<li>Potrzebny będzie wektor od rysowanego fragmentu do pozycji kamery:</li>
</ol>
<ul>
<li>Wyślij pozycje kamery (<code>cameraPos</code>) jako kolejna zmienna do fragment shadera.<br />
</li>
<li>Podobnie jak wektory normalne prześlij z vertex do fragment shadera pozycje wierzchołków (<code>vertexPosition</code>) w przestrzeni świata (czyli pomnożone przez macierz <strong>modelMatrix</strong>). Pamiętaj, że tym razem wektory reprezentują punkty, a nie kierunki - współrzędna <strong>w</strong> przed mnożeniem musi być ustawiona na 1. W wyniku rasteryzacji otrzymamy w shaderze fragmentu jego pozycję (nazywaną pozycją fragmentu)</li>
<li>Oblicz wektor <strong>V</strong> (<em>view direction</em>) jako znormalizowaną różnice pozycji kamery i pozycji fragmentu.</li>
</ul>
<ol start="2" type="1">
<li>Oblicz natężenie światła odbitego we <em>fragment shaderze</em>:</li>
</ol>
<ul>
<li>Oblicz wektor kierunku odbicia światła <strong>R</strong> przy użyciu funkcji <a href="https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/reflect.xhtml"><code>reflect</code></a>. Pamiętaj, żeby przesłać do funkcji odwrócony wektor kierunku światła.</li>
<li>Oblicz natężenie: iloczyn skalarny <strong>V</strong> i <strong>R</strong>, przycięty do zera ( <code>max(...,0.0)</code> ), a następnie podniesiony do wysokiej potęgi (np. 8, 50, 1000), która jest miara połyskliwości powierzchni.</li>
</ul>
<ol start="3" type="1">
<li>Ustal ostateczny kolor piksela na <code>objectColor * diffuse + lightColor * specular</code>. Oznacza to najprostszy przypadek, gdy kolor światła odbitego jest biały.</li>
</ol>
<h2 id="zadanie---oświetlenie-punktowe">Zadanie - oświetlenie punktowe</h2>
<p>W układzie planetarnym obiektem oświetlającym powinno być słońce, dlatego zamień oświetlenie kierunkowe na punktowe:</p>
<ul>
<li>Zamiast przesyłać (w <code>lightDir</code>) kierunek światła, prześlij pozycję słońca do fragment shadera (taką jak ustawiłeś w punkcie powyżej) jako uniform vec3 (nazwij go <code>lightPos</code>).</li>
<li>Oblicz kierunek światła odejmując od pozycji światła pozycję fragmentu, znormalizuj wynik. Zapisz wynik w zmiennej <code>lightDir</code>.<br />
</li>
<li>Słońce będzie czarne, nie martw się tym, tylko spójrz na punkt następny.</li>
</ul>
<h2 id="zadanie---shader-słońca">Zadanie - shader słońca</h2>
<p>Źródło światła znajduje się wewnątrz kuli, która reprezentuje słońce, dlatego jest czarna. By to naprawić, utwórz osobny shader, który będzie odpowiadać za renderowanie słońca.</p>
<p>Celem tego zadania jest stworzenie shadera (<strong>shader_5_sun.vert</strong>_ i <strong>shader_5_sun.frag</strong>), który będzie odpowiadał wyłącznie za rysowanie słońca. Poprzednie shadery (<strong>shader_4_1.vert</strong>_ i <strong>shader_5_1.frag</strong>) nadal mają rysować pozostałe obiekty. a) zainicjalizuj <em>program</em> (shadery): - Pliki <strong>shader_5_sun.vert</strong> i <strong>shader_5_sun.frag</strong> są identyczne z 5_1** przed zmianami, będą punktem wyjścia dla <em>shadera</em> słońca.</p>
<ol type="1">
<li><p>Utwórz zmienną globalną <code>GLuint programSun</code> na adres shadera słońca. Stwórz <em>program</em> za pomocą <code>shaderLoader.CreateProgram</code> analogicznie jak tworzy się <code>program</code> z <strong>shader_5_1.vert</strong> i <strong>shader_5_1.frag</strong> (parametry wejściowe to ścieżka do shadera wierzchołków i fragmentów <strong>shader_5_sun.vert</strong> i <strong>shader_5_sun.frag</strong>).</p></li>
<li><p>W skomplikowanym projekcie różne typy obiektów rysuje się przy użyciu różnych shaderów, zate potrzebna jest w programie architektura, która na to pozwala. Ustaw odpowiedni <em>program</em> (shadery) do rysowania słońca:</p></li>
</ol>
<ul>
<li>funkcja <code>drawObject</code> korzysta z globalnej zmiennej <code>program</code>, żeby wskazywać shadery do rysowania. Dodaj argument do funkcji, który będziesz przekazywać adres <em>programu</em>, który ma być wykorzystany do rysowania.</li>
<li>dodaj odpowiedni <em>program</em> w wywołaniach <code>drawObject</code>.</li>
</ul>
<h2 id="zadanie---osłabienie-światła-attenuation"> Zadanie - Zmień shader słońca na bardziej realistyczny </h2>
<p>Na poniższym obrazku jest zdjęcie słońca. Jest ono ciemniejsze na brzegach spróbuj uzyskać podobny efekt. Przydadzą się wektory normalnych i wektor <strong>V</strong> jak i funkcja mix.</p>
<p><img src="./img/sun.png" /></p>
<h2 id="osłabienie-światła-tone-mapping">Osłabienie światła, tone mapping</h2>
<h3 id="zadanie---osłabienie-światła-attenuation">Zadanie - Osłabienie światła (attenuation)</h3>
<p>Światło pochodzące z punktowego źródła traci na sile wraz z dystansem. Wynika to z tego, że rozprasza się na większą powierzchnię. Dodaj ten efekt do shadera. Zamiast brać kolor światła bezpośrednio, podziel go przez kwadrat dystansu od źródła świata. Przed kwadratowaniem przemnoz diystans przez 10.0.</p>
<h4 id="tone-mapping">Tone mapping</h4>
<p>Przez obecną zmianę scena stała się ciemna. Wymaga to od nas zmiany koloru światła na wartości dużo większe niż do tej pory. Jeśli teraz to zrobimy i przesadzimy w drugą stronę, otrzymamy efekt prześwietlenia. Wynika to z ograniczenia zakresu kolorów do <span class="math inline">\([0,1]\)</span> (obsługą wyższych wartości nazywamy HDR). Rozwiązaniem jest pracowanie na wartościach powyżej 1 wykorzystanie <em>tone mappingu</em> do przeniesienia ich w zakres <span class="math inline">\([0,1]\)</span>. Istnieje wiele wzorów, które są wykorzystywane do tego, jeden z nich to:</p>
<p><span class="math display">\[C_{mapped} = 1-e^{-C * E},\]</span> gdzie C to kolor sceny a E to parametr ekspozycji (z zakresu <span class="math inline">\((0,\infty)\)</span>, który może być dostosowany w zależności od jasności.
<h3 id="zadanie">Zadanie - Tone mapping</h3>
Zwiększ siłę słońca przynajmniej stukrotnie. Zaimplementuj powyższą metodę tone mappingu i dodaj możliwość sterowania ekspozycją za pomocą klawiszy 1 i 2.</p>
<h3 id="zadanie">Zadanie*</h3>
<p>Dodaj drugie źródło oświetlenia w postaci reflektora statku. Reflektor świeci tylko w określonym stożku,dlatego oprócz pozycji <code>spotPos</code> posiada również kierunek <code>spotDir</code> i kąt świecenia <span class="math inline">\(\phi\)</span>. Po obliczeniu dla niego <code>lightDir</code> należy sprawdzić, czy iloczyn skalarny pomiędzy <code>lightDir</code> a <code>spodDir</code> jest większy niż <span class="math inline">\(\cos\phi\)</span> . Jeżeli nie jest, to stożek nie świeci w tym miejscu. Można ułatwić sobie implementację wielu źródeł światła poprzez przeniesienie obliczeń oświetlenia do funkcji, która przyjmuje kierunek światła i siłę naświetlenie.</p>
Zwróć uwagę, że SpotDir to co innego niż light Dir w poprzednich zadaniach.
<p><img src="./img/spotlight.png" /> </p>
</body>
</html>

197
cw 7/Zadania 7.html Normal file
View File

@ -0,0 +1,197 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Zadania 7</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" />
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
</head>
<body>
<h1 id="normal-mapping">Normal Mapping</h1>
<p>W tej części będziemy dalej modyfikować shadery <strong>shader_5_tex</strong> poprzez implementację normal mappingu.</p>
<p>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).</p>
<p>Do wyliczenia przestrzeni stycznej potrzebujemy dla każdego wierzchołka oprócz wektora normalnego wektor styczny i bistyczny (<em>tangent</em> i <em>bitangent</em>). Są one wyliczane przez bibliotekę <code>Assimp</code>.</p>
<h3 id="wykonaj-kopię-shaderów-shader_4_tex.vert-shader_4_tex.frag">Wykonaj kopię shaderów shader_4_tex.vert shader_4_tex.frag</h3>
<h3 id="przenieś-obliczenia-światła-do-przestrzeni-stycznej.">Przenieś obliczenia światła do przestrzeni stycznej.</h3>
<ol type="1">
<li><p>Oblicz macierz <strong>TBN</strong>.</p>
<p>Macierz <strong>TBN</strong> to macierz 3x3 wyznaczana przez wektory <em>tangent</em>, <em>bitangent</em> i <em>normal</em>, służy do przenoszenia wektorów z przestrzeni świata do przestrzeni stycznej.</p>
<ol type="1">
<li>W <strong>vertex shaderze</strong> przekrztałć wektory <code>vertexNormal</code>, <code>vertexTangent</code> i <code>vertexBitangent</code> 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 <code>normal</code>, <code>tangent</code> i <code>bitangent</code>.
<ol type="1">
<li>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).</li>
</ol></li>
</ol></li>
</ol>
<ol start="2" type="1">
<li>Przenieś wektor światła i wektor widoku do przestrzeni stycznych
<ol type="1">
<li><p>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 <code>lightPos</code> i <code>cameraPos</code>) z <strong>fragment shadera</strong> do <strong>vertex shadera.</strong></p></li>
<li><p>Oblicz wektor <code>viewDir</code> jako znormalizowana różnice <code>cameraPos</code> i <code>fragPos</code> (tu jeszcze działamy w przestrzeni świata). Analogicznie oblicz <code>lightDir</code> jako różnicę <code>lightPos</code> i <code>fragPos</code></p></li>
<li><p>Przekształć wektory <code>viewDir</code> i <code>lightDir</code> do przestrzeni stycznej mnożąc je przez macierz <strong>TBN</strong>. Wynik zapisz w zmiennych<code>viewDirTS</code> i <code>lightDirTS</code> odpowiednio.</p></li>
<li><p>Przekaż <code>viewDirTS</code> i <code>lightDirTS</code> do fragment shadera. (zadeklaruj je jako zmienne <code>out</code>)</p>
<blockquote>
<p>(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.)</p>
</blockquote></li>
</ol></li>
<li>Przekształć <strong>fragment shader</strong>, by obsługiwał <strong>tangent space</strong>
<ol type="1">
<li>Nie potrzebujemy już we <strong>fragment shaderze</strong> informacji na temat pozycji fragmentu i wektora normalnego geometrii, skasuj wiec zmienne przekazujące te wektory pomiędzy shaderami.</li>
<li>wektora <code>lightDir</code> powinniśmy użyć wektora <code>lightDirTS</code> (należy go dodatkowo znormalizować), a jako wektor widoku V powinniśmy użyć wektora <code>viewDirTS</code> (również należy go znormalizować). Jako wektora N użyj na razie wektora vec3(0,0,1).</li>
</ol></li>
</ol>
<p>Efekt finalny powinien wyglądać tak samo, jak przed jakąkolwiek zmianą. Następnym krokiem będzie wykorzystanie map normalnych.</p>
<h3 id="wykorzystaj-normalmapy">Wykorzystaj normalmapy</h3>
<ol type="1">
<li>Chcemy wczytywać normalne z tekstury, w tym celu dodaj we <strong>fragment shaderze</strong> dodatkowy sampler do czytania map normalnych, nazwij go <code>normalSampler</code>. Pobierz z niego wektor normalny analogicznie, jak czytamy kolor zwykłej tekstury z samplera <code>textureSampler</code> i zapisz go w zmiennej <code>N</code>.
<ol start="2" type="1">
<li>Ponieważ w teksturze wartości są w przedziale <span class="math inline">\([0,1]\)</span>, musimy jeszcze przekształcić je do przedziału <span class="math inline">\([-1,1]\)</span>. 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.</li>
<li>Wczytaj pliki zawierające mapy normalnych w kodzie C++ W tym celu załaduj przy użyciu funkcji <code>Core::LoadTexture</code> mapy normalnych dla wszystkich modeli. Maja one taką samą nazwę jak zwykle tekstury, tyle że z suffiksem "_normals".</li>
<li>Zmodyfikuj na koniec funkcje <code>drawObjectTexture</code>. Dodaj do niej nowy argument <code>GLuint normalmapId</code>, który będzie służył do przekazywania id tekstury zawierającej mapę normalnych. Przy użyciu funkcji <code>Core::SetActiveTexture</code> załaduj <code>normalmapId</code> jako <code>normalSampler</code> i ustaw jednostkę teksturowania nr 1. Argument odpowiadający za normalne w miejscach wywołania funkcji <code>drawObjectTexture</code>.</li>
</ol></li>
</ol>
<h3 id="zadanie">Zadanie*</h3>
<p>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.</p>
<h2 id="skybox">SkyBox</h2>
<p>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 src="./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.</p>
<h3 id="ładowanie-cubemapy">Ładowanie cubemapy</h3>
<p>Cubemapę generujemy podobnie jak inne tekstury, ale przy bindowaniu należy podać <code>GL_TEXTURE_CUBE_MAP</code>.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>glGenTextures(<span class="dv">1</span>, &amp;textureID);</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);</span></code></pre></div>
<p>Skoro składa się ona z 6 tekstur, to należy każdą z nich załadować za pomocą <code>void glTexImage2D( GLenum target, ...)</code> <code>taget</code> wskazuje którą z tekstur ładujemy. Możliwe wartości rozpisane są w tabeli poniżej |Layer number|Texture target | Orientation| |—-|——————–:|———–:| |0|<code>GL_TEXTURE_CUBE_MAP_POSITIVE_X</code> | Right | |1|<code>GL_TEXTURE_CUBE_MAP_NEGATIVE_X</code>|Left| |2|<code>GL_TEXTURE_CUBE_MAP_POSITIVE_Y</code>|Top| |3|<code>GL_TEXTURE_CUBE_MAP_NEGATIVE_Y</code>|Bottom| |4|<code>GL_TEXTURE_CUBE_MAP_POSITIVE_Z</code>|Back| |5|<code>GL_TEXTURE_CUBE_MAP_NEGATIVE_Z</code>|Front|</p>
<p>Możemy je ładować w pętli biorąc za kolejne targety <code>GL_TEXTURE_CUBE_MAP_POSITIVE_X+i</code>, 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 <code>filepath</code>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> w, h;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="dt">unsigned</span> <span class="dt">char</span> *data; </span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span>(<span class="dt">unsigned</span> <span class="dt">int</span> i = <span class="dv">0</span>; i &lt; <span class="dv">6</span>; i++)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>{</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">unsigned</span> <span class="dt">char</span>* image = SOIL_load_image(filepath, &amp;w, &amp;h, <span class="dv">0</span>, SOIL_LOAD_RGBA);</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> glTexImage2D(</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, </span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span>, GL_RGBA, w, h, <span class="dv">0</span>, GL_RGBA, GL_UNSIGNED_BYTE, data</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> );</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Na koniec pozostaje ustawić parametry opisujące zachowanie tekstury:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); </span></code></pre></div>
<h3 id="zadanie-1">Zadanie</h3>
<p>Napisz funkcję, która będzie ładować cubmapę bazującą na tablicy 6 stringów i załaduj do niej tekstury z foldera <code>skybox</code>.</p>
<h3 id="rysowanie-skyboxa">Rysowanie skyboxa</h3>
<p>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.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#</span><span class="er">version 430 core</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>layout(location = <span class="dv">0</span>) in vec3 vertexPosition;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>uniform mat4 transformation;</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>out vec3 texCoord;</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> main()</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>{</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> texCoord = vertexPosition;</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a> gl_Position = transformation * vec4(vertexPosition, <span class="fl">1.0</span>);</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<blockquote>
<p>shader_skybox.vert</p>
</blockquote>
<p>W shaderze fragmentów wystarczy odebrać pozycję i próbkować za jej pomocą teksturę.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#</span><span class="er">version 430 core</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>uniform samplerCube skybox;</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>in vec3 texCoord;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>out vec4 out_color;</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> main()</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>{</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a> out_color = texture(skybox,texCoord);</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<blockquote>
<p>shader_skybox.frag</p>
</blockquote>
<h3 id="zadanie-2">Zadanie</h3>
<p>W modelach znajduje się <code>cube.obj</code>, załaduj go i narysuj shaderami <code>shader_skybox.vert</code> i <code>shader_skybox.vert</code>. Pamiętaj o przesłaniu macierzy transformacji i tekstury skyboxa. Aktywujemy ją za pomocą instrukcji:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c++"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);</span></code></pre></div>
<p>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 <code>glDisable(GL_DEPTH_TEST);</code>, natomiast aktywację za pomocą<code>glEnable(GL_DEPTH_TEST);</code>.</p>
<p>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.</p>
</body>
</html>

148
cw 7/Zadania 7.md Normal file
View File

@ -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.

BIN
cw 7/assimp-vc141-mt.dll Normal file

Binary file not shown.

BIN
cw 7/assimp-vc141-mtd.dll Normal file

Binary file not shown.

View File

@ -20,10 +20,11 @@
<ClCompile Include="src\SOIL\image_helper.c" />
<ClCompile Include="src\SOIL\SOIL.c" />
<ClCompile Include="src\SOIL\stb_image_aug.c" />
<ClCompile Include="src\Texture.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Camera.h" />
<ClInclude Include="src\ex_5_1.hpp" />
<ClInclude Include="src\ex_7_1.hpp" />
<ClInclude Include="src\objload.h" />
<ClInclude Include="src\Render_Utils.h" />
<ClInclude Include="src\Shader_Loader.h" />
@ -33,19 +34,26 @@
<ClInclude Include="src\SOIL\stbi_DDS_aug.h" />
<ClInclude Include="src\SOIL\stbi_DDS_aug_c.h" />
<ClInclude Include="src\SOIL\stb_image_aug.h" />
<ClInclude Include="src\Texture.h" />
</ItemGroup>
<ItemGroup>
<None Include="shaders\shader_5_1.frag" />
<None Include="shaders\shader_5_1.vert" />
<None Include="shaders\shader_5_1_tex.frag" />
<None Include="shaders\shader_5_1_tex.vert" />
<None Include="shaders\shader_5_sun.frag" />
<None Include="shaders\shader_5_sun.vert" />
<None Include="shaders\shader_5_tex.frag" />
<None Include="shaders\shader_5_tex.vert" />
<None Include="shaders\shader_skybox.frag" />
<None Include="shaders\shader_skybox.vert" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{7B84D06D-946D-4DCB-BD1A-B5635B0F83F0}</ProjectGuid>
<ProjectGuid>{F2FC2E8F-CBA6-49D7-8B73-4BFBCB64D310}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>grk-cw5</RootNamespace>
<RootNamespace>grk-cw7</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>grk-cw5</ProjectName>
<ProjectName>grk-cw7</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

View File

@ -17,7 +17,7 @@
<UniqueIdentifier>{0a247bb8-2e8e-4a90-b0ef-17415b0941ba}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\SOIL">
<UniqueIdentifier>{fd2042cb-5cbc-4508-9e27-cb1e07254eb9}</UniqueIdentifier>
<UniqueIdentifier>{0af44075-33f4-4953-b1d6-1d28d61d758f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
@ -39,18 +39,18 @@
<ClCompile Include="src\Texture.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\SOIL\image_DXT.c">
<Filter>Source Files\SOIL</Filter>
</ClCompile>
<ClCompile Include="src\SOIL\image_helper.c">
<Filter>Source Files\SOIL</Filter>
</ClCompile>
<ClCompile Include="src\SOIL\SOIL.c">
<Filter>Source Files\SOIL</Filter>
</ClCompile>
<ClCompile Include="src\SOIL\stb_image_aug.c">
<Filter>Source Files\SOIL</Filter>
</ClCompile>
<ClCompile Include="src\SOIL\image_DXT.c">
<Filter>Source Files\SOIL</Filter>
</ClCompile>
<ClCompile Include="src\SOIL\image_helper.c">
<Filter>Source Files\SOIL</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\objload.h">
@ -65,15 +65,9 @@
<ClInclude Include="src\Camera.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\ex_5_1.hpp">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\Texture.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="src\SOIL\image_DXT.h">
<Filter>Source Files\SOIL</Filter>
</ClInclude>
<ClInclude Include="src\SOIL\image_helper.h">
<Filter>Source Files\SOIL</Filter>
</ClInclude>
@ -89,11 +83,14 @@
<ClInclude Include="src\SOIL\stbi_DDS_aug_c.h">
<Filter>Source Files\SOIL</Filter>
</ClInclude>
<ClInclude Include="src\SOIL\image_DXT.h">
<Filter>Source Files\SOIL</Filter>
</ClInclude>
<ClInclude Include="src\ex_7_1.hpp">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="shaders\shader_5_1.vert">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_5_sun.frag">
<Filter>Shader Files</Filter>
</None>
@ -103,5 +100,26 @@
<None Include="shaders\shader_5_1.frag">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_5_1.vert">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_5_1_tex.vert">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_5_1_tex.frag">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_skybox.frag">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_skybox.vert">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_5_tex.vert">
<Filter>Shader Files</Filter>
</None>
<None Include="shaders\shader_5_tex.frag">
<Filter>Shader Files</Filter>
</None>
</ItemGroup>
</Project>

View File

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 178 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 190 KiB

View File

Before

Width:  |  Height:  |  Size: 329 KiB

After

Width:  |  Height:  |  Size: 329 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 978 KiB

After

Width:  |  Height:  |  Size: 978 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 260 KiB

View File

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

12
cw 7/models/cube.mtl Normal file
View File

@ -0,0 +1,12 @@
# Blender MTL File: 'None'
# Material Count: 1
newmtl _PBR
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.053704 0.053704 0.053704
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 3

7
cw 7/render.py Normal file
View File

@ -0,0 +1,7 @@
import os
rootdir = './'
for filename in os.listdir(rootdir):
if filename.endswith(".md"):
name = filename[:-3]
os.system(f'pandoc -s -o "{name}.html" "{name}.md" --mathjax --css style.css')

View File

@ -0,0 +1,18 @@
#version 430 core
float AMBIENT = 0.1;
uniform vec3 color;
uniform vec3 lightPos;
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);
}

View File

@ -4,12 +4,15 @@ layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec3 vertexNormal;
layout(location = 2) in vec2 vertexTexCoord;
uniform mat4 transformation;
out vec3 interpNormal;
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);
interpNormal = normalize(transformation * vec4(vertexNormal, 0.0)).xyz;
}

View File

@ -0,0 +1,21 @@
#version 430 core
float AMBIENT = 0.1;
uniform vec3 color;
uniform vec3 lightPos;
uniform sampler2D colorTexture;
in vec3 vecNormal;
in vec3 worldPos;
in vec2 vecTex;
out vec4 outColor;
void main()
{
vec3 lightDir = normalize(lightPos-worldPos);
vec3 normal = normalize(vecNormal);
vec3 textureColor = texture2D(colorTexture, vecTex).xyz;
float diffuse=max(0,dot(normal,lightDir));
outColor = vec4(textureColor*min(1,AMBIENT+diffuse), 1.0);
}

View File

@ -0,0 +1,23 @@
#version 430 core
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec3 vertexNormal;
layout(location = 2) in vec2 vertexTexCoord;
layout(location = 3) in vec3 vertexTangent;
layout(location = 4) in vec3 vertexBitangent;
uniform mat4 transformation;
uniform mat4 modelMatrix;
out vec3 vecNormal;
out vec3 worldPos;
out vec2 vecTex;
void main()
{
worldPos = (modelMatrix* vec4(vertexPosition,1)).xyz;
vecNormal = (modelMatrix* vec4(vertexNormal,0)).xyz;
vecTex = vertexTexCoord;
vecTex.y = 1.0 - vecTex.y;
gl_Position = transformation * vec4(vertexPosition, 1.0);
}

View File

@ -0,0 +1,10 @@
#version 430 core
uniform vec3 objectColor;
in vec3 interpNormal;
void main()
{
gl_FragColor = vec4(objectColor, 1.0);
}

View File

@ -0,0 +1,15 @@
#version 430 core
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 2) in vec3 vertexNormal;
uniform mat4 transformation;
out vec3 interpNormal;
void main()
{
gl_Position = transformation * vec4(vertexPosition, 1.0);
interpNormal = vertexNormal;
}

View File

@ -0,0 +1,31 @@
#version 430 core
float AMBIENT = 0.1;
uniform vec3 color;
uniform sampler2D colorTexture;
uniform sampler2D normalSampler;
in vec3 worldPos;
in vec2 vecTex;
in vec3 viewDirTS;
in vec3 lightDirTS;
out vec4 outColor;
void main()
{
vec3 normal = vec3(0,0,1);
vec3 lightDir = normalize(lightDirTS);
vec3 textureColor = texture2D(colorTexture, vecTex).xyz;
vec3 N = texture2D(normalSampler, vecTex).xyz;
N = 2.0 * N - 1.0;
N = normalize(N);
//float diffuse=max(0,dot(normal,lightDir));
float diffuse=max(0,dot(N,lightDir));
outColor = vec4(textureColor*min(1,AMBIENT+diffuse), 1.0);
}

View File

@ -0,0 +1,43 @@
#version 430 core
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec3 vertexNormal;
layout(location = 2) in vec2 vertexTexCoord;
layout(location = 3) in vec3 vertexTangent;
layout(location = 4) in vec3 vertexBitangent;
uniform mat4 transformation;
uniform mat4 modelMatrix;
out vec3 worldPos;
out vec2 vecTex;
uniform vec3 lightPos;
uniform vec3 cameraPos;
out vec3 viewDirTS;
out vec3 lightDirTS;
mat3 TBN;
void main()
{
vec3 tangent = normalize(mat3(modelMatrix) * vertexTangent);
vec3 bitangent = normalize(mat3(modelMatrix) * vertexBitangent);
vec3 normal = normalize(mat3(modelMatrix) * vertexNormal);
TBN = transpose(mat3(tangent, bitangent, normal));
vec3 worldPos = (modelMatrix * vec4(vertexPosition, 1)).xyz;
vec3 viewDir = normalize(cameraPos - worldPos);
vec3 lightDir = normalize(lightPos - worldPos);
viewDirTS = vec3(TBN * viewDir);
lightDirTS = vec3(TBN * lightDir);
vecTex = vertexTexCoord;
vecTex.y = 1.0 - vecTex.y;
gl_Position = transformation * vec4(vertexPosition, 1.0);
}

View File

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

View File

@ -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);
}

39
cw 7/src/Texture.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "Texture.h"
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
#include "SOIL/SOIL.h"
typedef unsigned char byte;
GLuint Core::LoadTexture( const char * filepath )
{
GLuint id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
int w, h;
unsigned char* image = SOIL_load_image(filepath, &w, &h, 0, SOIL_LOAD_RGBA);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(image);
return id;
}
void Core::SetActiveTexture(GLuint textureID, const char * shaderVariableName, GLuint programID, int textureUnit)
{
glUniform1i(glGetUniformLocation(programID, shaderVariableName), textureUnit);
glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, textureID);
}

15
cw 7/src/Texture.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "glew.h"
#include "freeglut.h"
namespace Core
{
GLuint LoadTexture(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);
}

View File

@ -1,4 +1,4 @@
#include "glew.h"
#include "glew.h"
#include <GLFW/glfw3.h>
#include "glm.hpp"
#include "ext.hpp"
@ -7,28 +7,46 @@
#include "Shader_Loader.h"
#include "Render_Utils.h"
#include "Camera.h"
#include "Texture.h"
#include "Box.cpp"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <string>
#include "SOIL/SOIL.h"
namespace texture {
GLuint earth;
GLuint clouds;
GLuint moon;
GLuint ship;
GLuint rust;
GLuint grid;
GLuint earthNormal;
GLuint moonNormal;
GLuint shipNormal;
GLuint rustNormal;
}
GLuint program;
GLuint programSun;
GLuint programTex;
GLuint programEarth;
GLuint programProcTex;
GLuint programSkyBox;
Core::Shader_Loader shaderLoader;
Core::RenderContext shipContext;
Core::RenderContext sphereContext;
Core::RenderContext cubeContext;
glm::vec3 cameraPos = glm::vec3(-4.f, 0, 0);
glm::vec3 cameraDir = glm::vec3(1.f, 0.f, 0.f);
glm::vec3 lightColor = glm::vec3(1.f, 1.f, 1.f);
glm::vec3 lightDir = glm::vec3(0.5, 0.5, 0.5);
glm::vec3 spaceshipPos = glm::vec3(-4.f, 0, 0);
glm::vec3 spaceshipDir = glm::vec3(1.f, 0.f, 0.f);
@ -36,23 +54,7 @@ GLuint VAO,VBO;
float aspectRatio = 1.f;
float lastTime = -1.f;
float deltaTime = 0.f;
float exposition = 5.0f;
GLuint programSun;
void updateDeltaTime(float time) {
if (lastTime < 0) {
lastTime = time;
return;
}
deltaTime = time - lastTime;
if (deltaTime > 0.1) deltaTime = 0.1;
lastTime = time;
}
unsigned int textureID;
glm::mat4 createCameraMatrix()
{
@ -91,27 +93,42 @@ glm::mat4 createPerspectiveMatrix()
return perspectiveMatrix;
}
void drawObjectColor(Core::RenderContext& context, glm::mat4 modelMatrix, glm::vec3 color, GLuint program) {
void drawObjectColor(Core::RenderContext& context, glm::mat4 modelMatrix, glm::vec3 color) {
glUseProgram(program);
glm::mat4 viewProjectionMatrix = createPerspectiveMatrix() * createCameraMatrix();
glm::mat4 transformation = viewProjectionMatrix * modelMatrix;
glUniformMatrix4fv(glGetUniformLocation(program, "transformation"), 1, GL_FALSE, (float*)&transformation);
glUniform3f(glGetUniformLocation(program, "color"), color.x,color.y,color.z);
glUniformMatrix4fv(glGetUniformLocation(program, "modelMatrix"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
glm::vec3 lightDir = glm::normalize(glm::vec3(1.0f, 1.0f, 1.0f));
glm::vec3 lightColor = glm::vec3(0.0f, 1.0f, 1.0f);
glUniform3fv(glGetUniformLocation(program, "lightDir"), 1, glm::value_ptr(lightDir));
glUniform3fv(glGetUniformLocation(program, "lightColor"), 1, glm::value_ptr(lightColor));
glUniform3fv(glGetUniformLocation(program, "cameraPos"), 1, glm::value_ptr(cameraPos));
glUniform1f(glGetUniformLocation(program, "exposition"), exposition);
glUniformMatrix4fv(glGetUniformLocation(program, "modelMatrix"), 1, GL_FALSE, (float*)&modelMatrix);
glUniform3f(glGetUniformLocation(program, "color"), color.x, color.y, color.z);
glUniform3f(glGetUniformLocation(program, "lightPos"), 0,0,0);
Core::DrawContext(context);
glUseProgram(0);
}
void drawObjectTexture(Core::RenderContext& context, glm::mat4 modelMatrix, GLuint textureID, GLuint normalMapId) {
glUseProgram(programTex);
glm::mat4 viewProjectionMatrix = createPerspectiveMatrix() * createCameraMatrix();
glm::mat4 transformation = viewProjectionMatrix * modelMatrix;
glUniformMatrix4fv(glGetUniformLocation(programTex, "transformation"), 1, GL_FALSE, (float*)&transformation);
glUniformMatrix4fv(glGetUniformLocation(programTex, "modelMatrix"), 1, GL_FALSE, (float*)&modelMatrix);
glUniform3f(glGetUniformLocation(programTex, "lightPos"), 0, 0, 0);
Core::SetActiveTexture(normalMapId, "normalSampler", programTex, 1);
Core::SetActiveTexture(textureID, "colorTexture", programTex, 0);
Core::DrawContext(context);
}
void drawObjectSkyBox(Core::RenderContext& context, glm::mat4 modelMatrix) {
glDisable(GL_DEPTH_TEST);
glUseProgram(programSkyBox);
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, "lightPos"), 0, 0, 0);
//Core::SetActiveTexture(textureID, "colorTexture", programSkyBox, 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
Core::DrawContext(context);
glEnable(GL_DEPTH_TEST);
}
void renderScene(GLFWwindow* window)
@ -120,25 +137,15 @@ void renderScene(GLFWwindow* window)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 transformation;
float time = glfwGetTime();
updateDeltaTime(time);
drawObjectSkyBox(cubeContext, glm::translate(cameraPos));
//Uniform3fv(glGetUniformLocation(program, "lightDir"), 1, glm::value_ptr(lightDir));
//glUniform3fv(glGetUniformLocation(program, "lightColor"), 1, glm::value_ptr(lightColor));
drawObjectTexture(sphereContext, glm::mat4(), texture::rust, texture::rustNormal);
drawObjectTexture(sphereContext, glm::eulerAngleY(time / 3) * glm::translate(glm::vec3(4.f, 0, 0)) * glm::eulerAngleY(time) * glm::scale(glm::vec3(0.3f)), texture::earth, texture::earthNormal);
glm::vec3 sunPosition = glm::vec3(0.0, 0.0, 0.0);
glm::mat4 sunModelMatrix = glm::translate(glm::vec3(1.0f, 1.0f, 0.3f));
drawObjectColor(sphereContext, sunModelMatrix, glm::vec3(1.0, 1.0, 0.3), programSun);
glUniform3fv(glGetUniformLocation(program, "lightPos"), 1, glm::value_ptr(sunPosition));
drawObjectColor(sphereContext, glm::eulerAngleY(time / 3) * glm::translate(glm::vec3(4.f, 0, 0)) * glm::scale(glm::vec3(0.3f)), glm::vec3(0.2, 0.7, 0.3), program);
drawObjectColor(sphereContext,
glm::eulerAngleY(time / 3) * glm::translate(glm::vec3(4.f, 0, 0)) * glm::eulerAngleY(time) * glm::translate(glm::vec3(1.f, 0, 0)) * glm::scale(glm::vec3(0.1f)),
glm::vec3(0.5, 0.5, 0.5), program);
drawObjectTexture(sphereContext,
glm::eulerAngleY(time / 3) * glm::translate(glm::vec3(4.f, 0, 0)) * glm::eulerAngleY(time) * glm::translate(glm::vec3(1.f, 0, 0)) * glm::scale(glm::vec3(0.1f)), texture::moon, texture::moonNormal);
glm::vec3 spaceshipSide = glm::normalize(glm::cross(spaceshipDir, glm::vec3(0.f, 1.f, 0.f)));
glm::vec3 spaceshipUp = glm::normalize(glm::cross(spaceshipSide, spaceshipDir));
@ -154,13 +161,16 @@ void renderScene(GLFWwindow* window)
// glm::translate(cameraPos + 1.5 * cameraDir + cameraUp * -0.5f) * inveseCameraRotrationMatrix * glm::eulerAngleY(glm::pi<float>()),
// glm::vec3(0.3, 0.3, 0.5)
// );
drawObjectColor(shipContext,
glm::translate(spaceshipPos) * specshipCameraRotrationMatrix * glm::eulerAngleY(glm::pi<float>()) * glm::scale(glm::vec3(0.2f)),
glm::vec3(0.3, 0.3, 0.5),
program
);
drawObjectTexture(shipContext,
glm::translate(spaceshipPos) * specshipCameraRotrationMatrix * glm::eulerAngleY(glm::pi<float>()),
texture::ship, texture::shipNormal
);
glUseProgram(0);
glfwSwapBuffers(window);
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
@ -188,20 +198,75 @@ void init(GLFWwindow* window)
glEnable(GL_DEPTH_TEST);
program = shaderLoader.CreateProgram("shaders/shader_5_1.vert", "shaders/shader_5_1.frag");
programSun = shaderLoader.CreateProgram("shaders/shader_5_sun.vert", "shaders/shader_5_sun.frag");
//programTex = shaderLoader.CreateProgram("shaders/shader_5_1_tex.vert", "shaders/shader_5_1_tex.frag");
//programEarth = shaderLoader.CreateProgram("shaders/shader_5_1_tex.vert", "shaders/shader_5_1_tex.frag");
//programProcTex = shaderLoader.CreateProgram("shaders/shader_5_1_tex.vert", "shaders/shader_5_1_tex.frag");
programTex = shaderLoader.CreateProgram("shaders/shader_5_tex.vert", "shaders/shader_5_tex.frag");
programEarth = shaderLoader.CreateProgram("shaders/shader_5_tex.vert", "shaders/shader_5_tex.frag");
programProcTex = shaderLoader.CreateProgram("shaders/shader_5_tex.vert", "shaders/shader_5_tex.frag");
programSkyBox = shaderLoader.CreateProgram("shaders/shader_skybox.vert", "shaders/shader_skybox.frag");
loadModelToContext("./models/sphere.obj", sphereContext);
loadModelToContext("./models/spaceship.obj", shipContext);
loadModelToContext("./models/cube.obj", cubeContext);
texture::earth = Core::LoadTexture("textures/earth.png");
texture::ship = Core::LoadTexture("textures/spaceship.jpg");
texture::moon = Core::LoadTexture("textures/moon.jpg");
texture::rust = Core::LoadTexture("textures/rust.jpg");
texture::earthNormal = Core::LoadTexture("textures/earth_normalmap.png");
texture::shipNormal = Core::LoadTexture("textures/spaceship_normal.jpg");
texture::rustNormal = Core::LoadTexture("textures/rust_normal.jpg");
texture::moonNormal = Core::LoadTexture("textures/moon_normal.jpg");
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
std::vector<std::string> filepaths = {
"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",
// Ustaw wartości dla lightDir i lightColor potem prześlij do shadera
//glm::vec3 lightDir = glm::normalize(glm::vec3(1.0f, 1.0f, 1.0f));
//glm::vec3 lightColor = glm::vec3(0.0f, 1.0f, 1.0f);
//"textures/skybox/corona_rt.png",
//"textures/skybox/corona_lf.png",
//"textures/skybox/corona_up.png",
//"textures/skybox/corona_dn.png",
//
//"textures/skybox/corona_bk.png",
//"textures/skybox/corona_ft.png",
//glUseProgram(program);
//glUniform3fv(glGetUniformLocation(program, "lightDir"), 1, glm::value_ptr(lightDir));
//glUniform3fv(glGetUniformLocation(program, "lightColor"), 1, glm::value_ptr(lightColor));
//glUseProgram(0);
//"textures/skybox_new/posx.jpg",
//"textures/skybox_new/negx.jpg",
//"textures/skybox_new/posy.jpg",
//"textures/skybox_new/negy.jpg",
//"textures/skybox_new/posz.jpg",
//"textures/skybox_new/negz.jpg"
};
int w, h;
unsigned char* image;
for (unsigned int i = 0; i < 6; i++)
{
image = SOIL_load_image(filepaths[i].c_str(), &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
);
}
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);
}
@ -215,12 +280,8 @@ void processInput(GLFWwindow* window)
{
glm::vec3 spaceshipSide = glm::normalize(glm::cross(spaceshipDir, glm::vec3(0.f, 1.f, 0.f)));
glm::vec3 spaceshipUp = glm::vec3(0.f, 1.f, 0.f);
float angleSpeed = 0.05f * deltaTime * 60;
float moveSpeed = 0.05f * deltaTime * 60;
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) {
angleSpeed *= 3;
moveSpeed *= 3;
}
float angleSpeed = 0.005f;
float moveSpeed = 0.0025f;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
@ -241,13 +302,7 @@ void processInput(GLFWwindow* window)
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
spaceshipDir = glm::vec3(glm::eulerAngleY(-angleSpeed) * glm::vec4(spaceshipDir, 0));
if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS)
exposition += 0.1;
if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS)
exposition -= 0.1;
cameraPos = spaceshipPos - 0.3f * spaceshipDir + glm::vec3(0, 1, 0) * 0.1f;
cameraPos = spaceshipPos - 1.5 * spaceshipDir + glm::vec3(0, 1, 0) * 0.5f;
cameraDir = spaceshipDir;
//cameraDir = glm::normalize(-cameraPos);

View File

@ -6,7 +6,7 @@
#include <iostream>
#include <cmath>
#include "ex_5_1.hpp"
#include "ex_7_1.hpp"

BIN
cw 7/textures/clouds.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 MiB

BIN
cw 7/textures/earth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
cw 7/textures/earth2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

BIN
cw 7/textures/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
cw 7/textures/moon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

BIN
cw 7/textures/rust.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

BIN
cw 7/textures/scratches.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

Some files were not shown because too many files have changed in this diff Show More