diff --git a/.gitignore b/.gitignore index 5b0113c..29ee2fa 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ idea/ /07/test.html /appendix/04/index.html /09/test.html + +.vscode \ No newline at end of file diff --git a/00/README-pl.md b/00/README-pl.md new file mode 100644 index 0000000..485ba7e --- /dev/null +++ b/00/README-pl.md @@ -0,0 +1,50 @@ +# Wprowadzenie + + + +Powyższe obrazy zostały stworzone na różny sposób. Pierwszy stworzył Van Gogh, aplikując farbę warstwa po wartwie. Zajęło mu to godziny. Drugi z nich stworzono poprzez połączenie czterech macierzy zawierających piksele koloru niebieskozielonego (cyjan), magenty, żółtego i czarnego. Kluczowa różnicę stanowi fakt, że drugi obraz stworzny został natychmiastowo (przez komputer), a nie seryjnie, krok po kroku (przez malarza). + +Ta książka jest o rewolucyjnej technice obliczeniowej, tzw. *fragment shaderach* (zwanych też *pixel shaderami*), które wznoszą cyfrowo generowane obrazy na wyższy poziom. Możesz o nich myśleć jak o ekwiwalencie maszyny drukarskiej Gutenberga dla zastosowań graficznych. + +![Gutenberg's press](gutenpress.jpg) + + +Fragment shadery dają ci pełnię kontroli nad błyskawicznym renderowaniem pikseli na ekranie. Właśnie dlatego są one używane w przeróżnych sytuacjach: od filtrów wideo w telefonach do niesamowitych twójwymiarowych gier wideo. + +![Journey by That Game Company](journey.jpg) + +W następujących rozdziałach odkryjesz jak niewiarygodnie szybkie i potężne są te techniki i jak zastosować je w twojej pracy zawodowej i osobistej. + +## Dla kogo jest ta książka? + +Ta książka jest napisana dla osób zainteresowanych *creative coding*'iem, game developerów i inżynierów, którzy posiadają doświadczenie programistyczne, podstawową wiedzę z algebry liniowej i trygonometrii, i którzy chcą podnieść jakość swoich prac graficzny na wyższy poziom. (Jeżeli chcesz nauczyć się programować, polecam zacząć od [Processing](https://processing.org/) i wrócić, gdy opanujesz go do komfortowego poziomu. + +Ta książka nauczy cię jak używać shadery w celu polepszenia wydajności i wyglądu twoich projektów. Ponieważ shadery GLSL (OpenGL Shading Language) kompilują i uruchamiają się na różnorodnych platformach, będziesz w stanie zaaplikować tutaj zdobytą wiedzę do jakiegokolwiek środowiska wykorzystującego OpenGL, OpenGL ES lub WebGL. Innymi słowy, będziesz w stanie wykorzystać tę wiedzę przy tworzeniu szkiców z [Processing](https://processing.org/), aplikacji z [openFrameworks](http://openframeworks.cc/), interaktywnych instalacji z [Cinder](http://libcinder.org/) czy stron internetowych z [Three.js](http://threejs.org/) i gier iOS/Android. + +## Jaki materiał pokrywa ta książka? + +Ta książka skupia się na użyciu fragment shaderów GLSL. Wpierw zdefiniujemy czym shadery są; potem dowiemy się jak, z ich pomocą, tworzyć proceduralne kształty, wzory, tekstury i animacje. Nauczysz się podstaw języka shadingowego i jego przydatnych aplikacji w przetwarzaniu obrazów (operacje na obrazach, sploty macierzowe, rozmycia, filtry koloru, "lookup tables" i inne efekty) czy symulacji ("Gra w życie" Conwaya, model reakcji-dyfuzji Graya-Scotta, plusk wody, efekt akwareli, komórki Voronoi, itp.). Pod koniec książki zobaczymy kilka zaawansowanych technik opartych o Ray Marching. + +*W każdym rozdziale znajdziesz interaktywne przykłady do wypróbowania.* Kiedy zmodyfikujesz kod, natychmiastowo zobaczysz zmiany. Zagadnienia mogą być abstrakcyjne i mylące, więc takie interkatywne przykłady stanowią konieczną pomoc w zrozumieniu materiału. Im szybciej złapiesz praktykę, tym prostsza będzie dalsza nauka. + +Materiał, którego ta książka nie pokrywa: + +* To *nie jest* książka o OpenGL lub WebGL. OpenGL/WebGL jest większym tematem niż GLSL czy fragment shadery. Jeśli chcesz wiedzieć więcej o OpenGL i WebGL, polecam zajrzeć do [OpenGL Introduction](https://open.gl/introduction), [the 8th edition of the OpenGL Programming Guide](http://www.amazon.com/OpenGL-Programming-Guide-Official-Learning/dp/0321773039/ref=sr_1_1?s=books&ie=UTF8&qid=1424007417&sr=1-1&keywords=open+gl+programming+guide) (zwana również "czerwoną książką") lub [WebGL: Up and Running](http://www.amazon.com/WebGL-Up-Running-Tony-Parisi/dp/144932357X/ref=sr_1_4?s=books&ie=UTF8&qid=1425147254&sr=1-4&keywords=webgl) + +* To *nie jest* książka do nauki matematyki. Choć opisane są w niej algorytmy i techniki, które opierają się zrozumieniu algebry i trygonometrii, to nie będziemy ich szczegółowo tłumaczyć. Z pytaniami dotyczącymi matematyki polecam zajrzeć do następujących książek: +[3rd Edition of Mathematics for 3D Game Programming and computer Graphics](http://www.amazon.com/Mathematics-Programming-Computer-Graphics-Third/dp/1435458869/ref=sr_1_1?ie=UTF8&qid=1424007839&sr=8-1&keywords=mathematics+for+games) lub [2nd Edition of Essential Mathematics for Games and Interactive Applications](http://www.amazon.com/Essential-Mathematics-Games-Interactive-Applications/dp/0123742978/ref=sr_1_1?ie=UTF8&qid=1424007889&sr=8-1&keywords=essentials+mathematics+for+developers). + +## Co potrzeba, żeby zacząć? + +Niewiele! Jeśli masz współczesną przeglądarkę, która obsługuje WebGL (jak Chrome, Firefox czy Safari) i połączenie internetowe, to kliknij "Dalej" na dole strony, aby zacząć. + +Alternatywnie, w zależności od tego, co masz albo co potrzebujesz od tej książki, możesz: + +- [Stworzyć wersję off-line tej książki](https://thebookofshaders.com/appendix/00/?lan=pl) + +- [Uruchomić przykłady na Raspberry PI bez przeglądarki](https://thebookofshaders.com/appendix/01/?lan=pl) + +- [Stworzyć wersję PDF tej książki do wydrukowania](https://thebookofshaders.com/appendix/02/?lan=pl) + +- Sprawdź [repozytorium GitHub](https://github.com/patriciogonzalezvivo/thebookofshaders) tej książki, by pomóc rożwiązać issues i podzielić się swoim kodem. + diff --git a/01/README-pl.md b/01/README-pl.md new file mode 100644 index 0000000..555a18c --- /dev/null +++ b/01/README-pl.md @@ -0,0 +1,77 @@ +# Początki +## Czym jest fragment shader? + +W poprzednim rozdziale nazwaliśmy shadery ekwiwalentem prasy drukarskiej Gutenberga dla grafiki. Dlaczego? A co ważniejsze: czym jest shader? + +![Od litera po literze, po lewej: William Blades (1891); do strona po stronie, po prawej: Rolt-Wheeler (1920).](print.png) + +Jeżeli masz doświadczenie w rysowaniu z użyciem komputera (np. w *Paint*), to wiesz, że proces ten polega na rysowaniu kółek, prostokątów, linii oraz trójkątów do momentu skomponowania pożądanego obrazu. Proces ten jest bardzo podobny do pisania listów lub książek odręcznie - jest to zbiór instrukcji wykonujących zadanie po zadaniu. + + + +Shader również jest zbiorem instrukcji, ale wykonywanych równocześnie dla każdego piksela na ekranie. Oznacza to, że kod, który piszesz musi działać inaczej w zależności od pozycji piksela na ekranie. Podobnie jak maszyna drukarska, twój program będzie działał jak funkcja matematyczna otrzymująca pozycję piksela i zwracająca jego kolor. Po skompilowaniu twój program będzie działał błyskawicznie. + + +![Chińska ruchoma czcionka](typepress.jpg) + +## Dlaczego shadery są szybkie? + +Aby odpowiedzieć na pytanie, omówmy cud *przetwarzania równoległego* (ang. *parallel processing*) + + + +Wyobraź sobie procesor twojego komputera jako potok przetwarzania (ang. "pipeline"), przez który przechodzą różnorakie zadania (jak na linii produkcyjnej w fabryce). Niektóre zadania są większe od innych, co oznacza, że wymagają więcej czasu i energii. Mówimy wtedy, że wymagają więcej *mocy obliczeniowej* (ang. *processing power*). Ze względu na architekturę współczesnych komputerów, zadania te wykonują się seryjnie (jeden po drugim) - każde zadanie musi poczekać, dopóki poprzednie zadanie nie zostanie ukończone. Jednakże, współczesne komputery posiadają zwykle więcej niż jedną jednostkę przetwarzającą (np. 2, 4 lub 8 rdzeni procesora), które funkcjonują jak pomniejsze potoki przetwarzania. Każdy taki pomniejszy potok nazywany jest również *wątkiem* (ang. *thread*). + + + +![CPU](00.jpeg) + +Gry video i inne aplikacje graficzne wymagają zdecydowanie więcej mocy obliczeniowej niż większość programów, gdyż muszą wykonywać ogromne ilości operacji piksel po pikselu. Nie dość, że każdy pojedynczy piksel musi być obliczony, to w wypadku gier 3D dochodzą do tego obliczenia geometryczne i obliczenie perspektywy. + + + +Wróćmy do naszej metafory potoku przetwarzania. Każdy piksel na ekranie reprezentuje proste zadanie. Indywidualnie zadania te nie stanowią problemu dla CPU, jednak sytuacja zmienia się, gdy takie zadanie musi być wykonane dla każdego piksela na ekranie. Oznacza to, że na starym monitorze 800x600 na jedną klatkę przypada 480.000 obliczeń, co oznacza 14.400.000 obliczeń na jedną sekundę! Właśnie tak! Skala problemu może przeciążyć mikroprocesor. Co więcej, na współczesnym monitorze 2560x1440 przy 60 FPS osiągamy 221.356.800 obliczeń na sekundę. Jak inżynierowie graficzni rozwiązują ten problem? + + + +![](03.jpeg) + +Z pomocą przychodzi przetwarzanie równoległe. Zamiast kilku dużych, potężnych mikroprocesorów (potoków) lepiej mieć wiele małych mikroprocesorów działających równolegle. Tak właśnie działa procesor graficzny (GPU) w karcie graficznej. + + + +![GPU](04.jpeg) + +Wyobraź sobie mały mikroprocesor jako tablicę rur (spójrz na obrazek powyżej), a dane jako piłeczki ping pongowe. 14.400.000 piłeczek ping pongowych na sekundę może zablokować prawie każdą pojedynczą rurę. Ale tabela 800x600 malutkich rur przyjmująca co sekundę 30 fal po 480.000 piłeczek poradzi sobie z nimi bez problemu. Tak samo działa to na wyższych rozdzielczościach - im więcej równolegle pracującego hardware'u, tym większy potok, z którymi GPU sobie poradzi. + + + +Inną "super umiejętnością" GPU jest fakt, że złożone funkcje matematyczne wykonywane są bezpośrednio na poziomie hardware'u przez mikroczipy, a nie przez software. Skutkiem tego są super szybkie operacje trygonometryczne i macierzowe. + + + +## Czym jest GLSL? + +GLSL oznacza "Open**GL** **S**hading **L**anguage" i stanowi standard pisania shaderów, który zobaczysz w następnych rozdziałach tej książki. W zależności od hardware'u i systemu operacyjnego wyróżnia się też inne rodzaje shaderów. Tutaj skupimy się na specyfikacji OpenGL uregulowanej przez [Khronos Group](https://www.khronos.org/opengl/). Zrozumienie historii OpenGL może pomóc w zrozumieniu wielu dziwnych konwencji; w tym celu polecam zajrzeć do: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html). + + + +## Dlaczego shadery budzą postrach? + +Jak to mówią: "with great power comes great responsibility". Stosuje się to również do obliczeń równoległych - potężne rozwiązania architektoniczne w GPU wiążą się również z pewnymi ograniczeniami. + + + +Aby wątki mogły działać równolegle, muszą być od siebie niezależne. Mówimy, że wątki są *ślepe* na to, co robi reszta wątków. Ograniczenie to implikuje, że dane muszą "płynąć w ten samą stronę" - nie jest możliwe sprawdzić dane wyjściowe innego wątku, zmodyfikować jego dane wejściowe albo przekazać dane wyjściowe jednego wątku jako dane wejściowe innego. + + + +Poza tym GPU odpowiada za to, żeby każdy wątek miał coś do roboty, i żeby otrzymał dane potrzebne do wykonania tej roboty. Trzeba też pamiętać, że nie jest możliwe, aby wątek wiedział, co robił sekundę temu - mógł rysować przycisk w UI systemu operacyjnego, a potem renderować fragment nieba w grze wideo, a jeszcze potem wyświetlać treść maila. Każdy wątek jest nie tylko **ślepy**, ale również **bez pamięci**. Te cechy sprawiają, że pisanie shaderów nie cieszy się dużą popularnością wśród początkujących programistów. + + + +Ale nie martw się! W następnych rozdziałąch nauczymy się, krok po kroku, prostych i zaawansowanych obliczeń shadingowych. Jeżeli czytasz to we współczesnej przeglądarce, to z pewnością docenisz zabawę z interaktywnymi przykładami. Ale nie przedłużajmy! Naciśnij *Next>>* aby przejść dalej. + + diff --git a/02/README-pl.md b/02/README-pl.md new file mode 100644 index 0000000..ae8196a --- /dev/null +++ b/02/README-pl.md @@ -0,0 +1,71 @@ +## Witaj świecie! + +Zazwyczaj przykład "Hello world!" stanowi pierwszy krok przy nauce nowego języka. Jest to prosty jednolinijkowy programy, który zwraca pełną entuzjazmu wiadomość powitalną i tym samym zapowiada nadchodzące przygody. + + + +W świecie GPU renderowanie tekstu jest jednak zbyt skomplikowanym zadaniem dla żółtodzioba. Zamiast tego wybierzemy jasny, serdeczny kolor by wykrzyczeć naszą ekscytację! + + + +
+ +Jeżeli czytasz tę książkę w przeglądarce: powyższy blok kodu jest interaktywny. Oznacza to, że możesz edytować dowolną linijkę kodu w celach eksploracyjnych. Shader kompiluje się na bieżąco, więc zmiany widoczne będą natychmiast. Spróbuj pozmieniać wartości w linijce 8. + + + +Choć kod jest prosty, to możemy wyciągnąć z niego ważne wnioski: + +1. Podobnie jak w C, GLSL ma jedną funkcje `main`. Pod koniec zwraca ona kolor. + +2. Finalny kolor piksela przypisywany jest do zarezerowanej zmiennej globalnej `gl_FragColor`. + +3. Ten C-podobny język ma wbudowane *zmienne* (jak `gl_FragColor`), *funkcje* i *typy*. W aktualnym przykładzie występuje jedynie typ `vec4`, oznaczający czterowymiarowy wektor zmiennoprzecinkowy (ang. "float vector"). Później zobaczymy również takie typy jak `vec3`, `vec2` oraz znajome `float`, `int` i `bool`. + +4. Patrząc na typ `vec4`, możemy wywnioskować, że jego cztery argumenty odnoszą się do kanałów CZERWONEGO, ZIELONEGO, NIEBIESKIEGO i ALPHA. Widać też, że jego wartości są *znormalizowane*, więc znajdują się w zakresie od `0.0` do `1.0`. Później zobaczymy, jak normalizowanie wartości pomaga w *mapowaniu* wartości między zakresami. + +5. Kolejną ważną C-podobną własnością w tym przykładzie jest obecność makr preprocessora. Dzięki nim można definiować zmienne globalne za pomocą `#define` oraz operacje warunkowe za pomocą `#ifdef` ("if defined"), `#ifndef` ("if not defined") i `#endif`. Wszystkie makra zaczynają się od płotka `#` i ewaluowane są podczas procesu prekompilacji poprzedzającego kompilację. W naszym powyższym przykładzie linijka 2 kompilowana jest tylko wtedy, gdy zmienna `GL_ES` jest zdefiniowana (co występuje na urządzeniach mobilnych i w przeglądarkach). + + + +6. Typy zmiennoprzecinkowe są kluczowe w shaderach, więc ich poziom precyzji (ang. *precision*) jest kluczowy. Niższa precyzja oznacza szybsze renderowanie, ale kosztem jakości. Możesz być wybredny i określać precyzję każdej zmiennej zmiennoprzecinkowej z osobna. W linijce 2 (`precision mediump float;`) ustawiamy średnią precyzję zmiennych zmiennoprzecinkowych ("mediump", bo "medium precision"). Możemy też ustawić ją jako niską (`precision lowp float;`) lub wysoką (`precision highp float;`). + +7. Ostatni i chyba najważniejszy szczegół specyfikacji GLSL: nie ma gwaracji, że zmienne będą automatycznie castowane (np. z `int` do `float` przy dzieleniu liczby 5 przez 2). Producenci GPU mogą stosować przeróżne optymalizacje w kartach graficzncyh, ale muszą przy tym przestrzegać pewnych wytycznych. Automatyczne castowanie nie jest jednym z nich. W naszym przykładzie `vec4` ma precyzję zmiennoprzecinkową i dlatego jego argumenty wymagają `float`ów. Przezwyczaj się do stawiania kropek (`.`) we `float`ach (`1.` lub `1.0`, a nie `1`), jeżeli nie chcesz spędzić godzin przy debugowaniu. Poniższy kod nie zawsze będzie, zatem, działał: + +```glsl +void main() { + gl_FragColor = vec4(1,0,0,1); // ERROR +} +``` + +Czas na ćwiczenia! Pamiętaj, że w wypadku błędu kompilacji pokaże się informacje o błędzie i linijce w której wystąpił, a kanwa zmieni kolor na biały. + +* Spróbuj zamienić `float`y na `int`y. Jeśli kod się nie kompiluje, to widocznie twoja karta graficzna tego nie toleruje + +* Zakomentuj linię 8 + +* Stwórz osobną funckję, która zwraca dowolny kolor i użyj jej w `main()`. Wskazówka: poniższy kod zwraca kolor czerwony: + +```glsl +vec4 red(){ + return vec4(1.0,0.0,0.0,1.0); +} +``` + +* Jest wiele sposobów tworzenia typu `vec4` - spróbuj je znaleźć. Jeden z nich wygląda tak: + +```glsl +vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); +``` + +Choć przykład ten nie jest zbyt ekscytujący, ale stanowi ważną podstawę. W następnych rozdziałach zobaczymy, jak zmienić kolor piksela z pomocą inputu przestrzennego (położenie piksela na ekranie) i temporalnego (okres czasu od momentu załadowania się strony). \ No newline at end of file diff --git a/03/README-pl.md b/03/README-pl.md new file mode 100644 index 0000000..67e5556 --- /dev/null +++ b/03/README-pl.md @@ -0,0 +1,98 @@ +## Uniformy + +Do tej pory widzieliśmy jak GPU zarządza wieloma równoległymi wątkami, z których każdy odpowiada za kolor części renderowanego obrazu. Choć wątki nie komunikują się między sobą, to jednak muszą jakoś otrzymywać input z CPU. Ze względu na architekturę karty graficznej taki input musi być jednakowy (ang. "*uniform*") dla wszystkich wątków i, z konieczności, tylko do odczytu (ang. "read-only"). Innymi słowy, każdy wątek otrzymuje takie same dane, które może odczytać, ale nie nadpisać, zmienić. + + + +Inputy te nazywamy `uniform`ami i mogę być większości wspieranych typów: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` i `samplerCube`. Uniformy definiowane są zwykle na górze shaderu zaraz po przypisaniu domyślnej precyzji float'ów. + + + +```glsl +#ifdef GL_ES +precision mediump float; +#endif + +uniform vec2 u_resolution; // wielkość/rozdzielczość kanwy (szerokość, wysokość) +uniform vec2 u_mouse; // pozycja myszy na kanwie (wyrażona w pikselach) +uniform float u_time; // czas w sekundach od załadowania shadera +``` + +Wyobraź sobie te uniformy jak małe mosty między CPU i GPU. Ich nazwy bywają różne, ale w tej książce używam: `u_time`, `u_resolution` i `u_mouse` (przeczytaj komentarze w kodzie, aby wiedzieć, co robią). Podążam za konwencją dodawnaia `u_` przed nazwą uniformów, aby było wiadomo, że nie są to zwykłe zmienne, ale ostatecznie jest to kwestia gustu. Przykładowo, [ShaderToy.com](https://www.shadertoy.com/) używa takich samych uniformów, ale z następującym nazewnictwem: + + + +```glsl +uniform vec3 iResolution; +uniform vec4 iMouse; +uniform float iTime; +``` +(zwróć uwagę, że `iResolution` jest typu `vec3`, a `iMouse` typu `vec4`; uniformy te zawierają po prostu dodatkowe informacje, np.: stosunek szerokości do wysokości pikseli na ekranie, czy któryś z przycisków myszy został kliknięty albo czy jest przytrzymywany) + +Koniec gadania, czas zobaczyć uniformy w akcji. W pożniszym kodzie używamy `u_time` (liczby sekund od uruchomienia shadera) razem z funkcją sinus, aby stworzyć animację przejścia od koloru czerwonego do czarnego. + + + +
+ +Jak widać GLSL skrywa wiele niespodzianek, na przykład w postaci specjalnych, zaimplementowanych w hardware'rze, funkcji trygonometryczne czy wykładniczych. Tutaj podaję część z nich: [`sin()`](../glossary/?search=sin), [`cos()`](../glossary/?search=cos), [`tan()`](../glossary/?search=tan), [`asin()`](../glossary/?search=asin), [`acos()`](../glossary/?search=acos), [`atan()`](../glossary/?search=atan), [`pow()`](../glossary/?search=pow), [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log), [`sqrt()`](../glossary/?search=sqrt), [`abs()`](../glossary/?search=abs), [`sign()`](../glossary/?search=sign), [`floor()`](../glossary/?search=floor), [`ceil()`](../glossary/?search=ceil), [`fract()`](../glossary/?search=fract), [`mod()`](../glossary/?search=mod), [`min()`](../glossary/?search=min), [`max()`](../glossary/?search=max) i [`clamp()`](../glossary/?search=clamp). + + +Pobawmy się powyższym kodem: + +* Zmniejsz częstotliwość tak bardzo, aby zmiany koloru stały się nie zauważalne. + +* Zwiększ częstotliwość do takiego stopnia, aby ujrzeć stały kolor bez migotania. + +* Wstaw funkcje sinus o różnych częstotliowściach do pozostałych kanałów (zielonego i niebieskiego), aby uzyskać ciekawe efekty. + + + +## gl_FragCoord + +GLSL daje nam nie tylko domyślny output `vec4 gl_FragColor`, ale również domyślny input w postaci `vec4 gl_FragCoord`, który przechowuje współrzędne *piksela* (inaczej: *fragmentu*), nad którym aktualnie pracuje wątek - dzięki `vec4 gl_FragCoord` wiemy, gdzie wątek pracuje wewnątrz kanwy. Nie nazywamy go `uniform`em, ponieważ jego wartość *różni się* między wątkami. Zamiast tego `gl_FragCoord` nazywamy *varying* (z ang. "zmieniający się", "różniący się"). + + + +
+ +W powyższy kodzie, *normalizujemy* współrzędne fragmentu poprzez podzielenie go przez rozdzielczość kanwy. W ten sposó otrzymujemy wartości z przedziału od `0.0` do `1.0`, co ułatwia zmapowanie współrzędnych x i y do, odpowiednio, czerwonego i zielonego kanału. + + + +W świecie shaderów nie mamy zbyt dużo sposóbów debuggowania poza przypisywaniem jaskrawych kolorów do zmiennych i wyciągania wniosków o działaniu shadera, na podstawie tego, co widzimy. Odkryjesz, że programowania GLSL jest często jak wkładanie miniaturowych statków do butelki - jest to trudne, ale tez piękne i satysfakcjonujące. + + + +![](08.png) + +Czas przetestować nasze rozumienie kodu: + +* Czy jesteś w stanie powiedzieć, gdzie na naszej kanwie znajduje się fragment o znormalizowanych współrzędnych `(0.0, 0.0)`? + +* Co z framgentami o znormalizowanych współrzędnych `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` i `(1.0, 1.0)`? + +* Czy jesteś w stanie użyć uniforma `u_mouse` wiedząc, że wartości są nieznormalizowane? Spróbuj użyć go do manipulacji kolorem za pomocą ruchów myszki. + +* Czy jesteś sobie w stanie wyobrazić ciekawy sposób zmieniania koloru, łącząc współrzędne `u_mouse` z `u_time`? + +Po wykonaniu tych ćwiczeń, zapewne zastanawiasz się, gdzie jeszcze można użyć twoich nowych shaderowych mocy. W następnym rozdziale zobaczymy jak stworzyć swój własny shader w three.js, Processing i openFrameworks. + + diff --git a/04/README-pl.md b/04/README-pl.md new file mode 100644 index 0000000..1b231ea --- /dev/null +++ b/04/README-pl.md @@ -0,0 +1,276 @@ + +## Korzystanie z shaderów + +W ramach prac nad tą książką stworzyłem ekosystem narzędzi do tworzenia, wyświetlania, udostępniania i organizowania shaderów. Narzędzia te działają, bez konieczności dostosowywania kodu, na systemach Linux, MacOS, Windows i [Raspberry Pi](https://www.raspberrypi.org/) oraz w przeglądarce. + + + + + +## Korzystanie z shaderów w przeglądarce + +**Wyświetlaj**: wszystkie interaktywne przykłady w tej książce wyświetlane są dzięki [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas), który znacząco ułatwia proces korzystania z shaderów. + + + +```html + +``` + +Jak widać, `glslCanvas` wymaga jedynie elementu `canvas` z `class="glslCanvas"` oraz URL do twojego shadera w `data-fragment-url`. Aby dowiedzieć się więcej, kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslCanvas). + + + +Jeśli podobnie jak ja chciałbyś móć korzysatć z shaderów w konsoli, to [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) powinien cie zainteresować. Aplikacja ta pozwala zintegrować shadery z `bash`owymi skryptami i Unixowymi pipeline'ami, podobnie jak [ImageMagick](http://www.imagemagick.org/script/index.php). Ponadto, [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) pozwala ci kompilować shadery na [Raspberry Pi](https://www.raspberrypi.org/) - właśnie dlatego [openFrame.io](http://openframe.io/) używa go do wyświetalania swoich shaderowych dział sztuki. Kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslViewer), aby dowiedzieć się więcej. + + + +```bash +glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png +``` + +**Twórz**: w celu usprawnienia procesu pisania shaderów stworzyłem edytor online [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Edytor ten jest wykorzystywany w interaktywnych przykładach tej książki. Dodaje on poręczne widżety, czyniące abstrakcyjne doświadczenie pracy z kodem GLSL bardziej uchwytnym. Możesz również korzystać z niego jako samodzielnej aplikacji webowej pod adresem [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslEditor), aby dowiedzieć się więcej. + + + + +![](glslEditor-01.gif) + +Jeśli preferujesz pracę offline z wykorzystaniem [SublimeText](https://www.sublimetext.com/), [rozszerzenie glslViewer](https://packagecontrol.io/packages/glslViewer) może cie zainteresować. Dowiedz się o nim więcej [tutaj](https://github.com/patriciogonzalezvivo/sublime-glslViewer). + + + +![](glslViewer.gif) + +**Udostępniaj**: dzięki edytorowi online ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) możesz udstępniać swoje shadery! Zarówno webowa jak i stacjonarna wersja ma funkcję eksportu, generującą unikalny URL do twojego shadera. Ponadto, ma też funkcję bezpośredniego eksportu do [openFrame.io](http://openframe.io/). + + + +![](glslEditor-00.gif) + +**Organizuj**: udostępnianie kodu stanowi początek dzielenia się twoimi shaderowymi dziełami! Poza opcją eksportu do [openFrame.io](http://openframe.io/) stworzyłem narzędzie do organizowania twoich shaderów w galerię, którą można wstawić na dowolną stronę internetową; nazywa się [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslGallery), aby dowiedzieć się więcej. + + + +![](glslGallery.gif) + + + +## Korzystanie shaderów w twoim ulubionym frameworku + +Jeżeli programowanie we frameworkach jak [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) or [SFML](https://www.sfml-dev.org/) nie jest ci obce, to opcja wypróbowania w nich swoich shaderów zapewne cie zainteresuje. Poniżej znajdziesz przykłady, jak wykorzystać shadery w każdym z nich (z takimi samymi uniformami jak w tej książce). (W [repozytorium GitHub'owym dla tego rozdziału](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) znajdziesz pełny kod źródłowy dla tych frameworków. + + + +### W **Three.js** + +Znakomity i bardzo skromny Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) razem z [kontrybutorami](https://github.com/mrdoob/three.js/graphs/contributors) tworzą prawdopodobnie najbardziej popularny framework WebGL'owy zwany [Three.js](http://threejs.org/). Znajdziesz wiele przykładów, tutoriali i książek, które uczą, jak wykorzstać tę JavaScriptową bibliotekę do tworzenia odjazdowej grafiki 3D. + + + +Poniżej znajduje się przykład kodu w HTML i JS potrzebny do rozpoczęcia przygody z shaderami w three.js. Zwróć uwage na skrypt z `id="fragmentShader"` - do niego możesz wstawiać kod shaderów, które znajdziesz, przykładowo, w tej książce. + + + +```html + +
+ + + + + +``` + +### W **Processing** + +Stworzony przez [Ben Fry](http://benfry.com/) i [Casey Reas](http://reas.com/) w 2001, [Processing](https://processing.org/) jest nadzwyczaj prostym i potężnym środowiskiem, w którym możesz zacząć swoją przygodę z programowaniem (tak było w moim wypadku). [Andres Colubri](https://codeanticode.wordpress.com/) wniósł istotne zmiany do OpenGL i funkcji wideo w Processing, znacząco ułatwiając wykorzystanie w nim shaderów GLSL. Processing szuka pliku `shader.frag` w folderze `data`. Zatem, jeśli chcesz spróbować uruchomić przykłady z tej książki w Processing, to pamiętaj umieścić je w tym folderze i odpowiednio nazwać. + + + +```cpp +PShader shader; + +void setup() { + size(640, 360, P2D); + noStroke(); + + shader = loadShader("shader.frag"); +} + +void draw() { + shader.set("u_resolution", float(width), float(height)); + shader.set("u_mouse", float(mouseX), float(mouseY)); + shader.set("u_time", millis() / 1000.0); + shader(shader); + rect(0,0,width,height); +} +``` + +Aby shader działał na wersjach wcześniejszych niż 2.1, dodaj poniższą linijkę na początku shadera: `#define PROCESSING_COLOR_SHADER`. Powinno to wyglądać tak: + + + +```glsl +#ifdef GL_ES +precision mediump float; +#endif + +#define PROCESSING_COLOR_SHADER + +uniform vec2 u_resolution; +uniform vec3 u_mouse; +uniform float u_time; + +void main() { + vec2 st = gl_FragCoord.st/u_resolution; + gl_FragColor = vec4(st.x,st.y,0.0,1.0); +} +``` + +Jeśli chcesz wiedzieć więcej o sahderach w Processing, sprawdź ten [tutorial](https://processing.org/tutorials/pshader/). + + + +### W **openFrameworks** + +Każda ma takie miejsce, gdzie czuje się najabrdziej komfortowo. W moim wypadku jest to społeczność [openFrameworks](http://openframeworks.cc/). Ten C++'owy framework jest wrapperem OpenGL i innych open source'owych bibliotek C++. Pod pewnym względem jest całkiem podobny do Processing, ale z dodanym utrudnieniem radzenia sobie z kompilatorami C++. + + + +```cpp +void ofApp::draw(){ + ofShader shader; + shader.load("","shader.frag"); + + shader.begin(); + shader.setUniform1f("u_time", ofGetElapsedTimef()); + shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight()); + ofRect(0,0,ofGetWidth(), ofGetHeight()); + shader.end(); +} +``` + +Polecam addon [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) do openFrameworks, jeśli potrzbujesz takiego zestawu uniformów jak w GlslViewer i GlslCanvas, wsparcia dla "multiple buffering", "material shaders", hot reload'owania oraz automatycznej konwersji do OpenGL ES na Raspberry Pi. Twój kod stanie się tak prosty jak poniżej: + + + +```cpp +//-------------------------------------------------------------- +void ofApp::setup(){ + ofDisableArbTex(); + + sandbox.allocate(ofGetWidth(), ofGetHeight()); + sandbox.load("grayscott.frag"); +} + +//-------------------------------------------------------------- +void ofApp::draw(){ + sandbox.render(); + sandbox.draw(0, 0); +} +``` + +Po więcej informacji na temat shaderów w openFrameworks zajrzyj do znakomitego [tutoriala](http://openframeworks.cc/ofBook/chapters/shaders.html) autorstwa [Joshua Noble](http://thefactoryfactory.com/). + + + +### W **Blender** + +[GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) to addon pozwalający programistycznie generować textury z użyciem shaderów GLSL. Jest on w pełni kompatybilny z resztą sandboxów w tym rozdziale. Jak go użyć? + + + + +1. Operator Search: `F3` (lub `Spacja`, w zależności od twojego setupu ). Wpisz `GlslTexture` + +![](blender/00.png) + +2. Zmień pola `width` (szerokość), `height` (wysokość) oraz `Source` (ścieżka pliku źródłowego; może być ścieżką do zewnętrznego pliku). + +![](blender/01.png) + +3. Wykorzystaj węzeł Image w zakładce Materials. Nazwa węzła Image będzie taka sama jak nazwa pliku źródłowego. + + +![](blender/02.png) + +4. Idź do zakładki Scripting (lub zewnętrznego edytora, jeśli twój plik źródłowy jest zewnętrzny) i zacznij edytować shader. Będzie hot reload'owany. + + +![](blender/03.png) diff --git a/05/README-pl.md b/05/README-pl.md new file mode 100644 index 0000000..a05c9cc --- /dev/null +++ b/05/README-pl.md @@ -0,0 +1,234 @@ +# Rysowanie algorytmiczne +## Shaping functions + +Rozdział ten mógłby się nazywać "lekcja płota Pana Miyagiego". Poprzednio, mapowaliśmy znormalizowane pozycje *x* i *y* do *czerwonego* i *zielonego* kanału. W skróćie, stworzyliśmy fumkcję, która przyjmuje dwuwymiarowy wektor (x i y) i zwraca czterowymiarowy wektor (r, g, b i a). Jednak zanim zagłębimy się w takie transformacje między wymiarami, wypada najpierw opanować tworzenie jednowymiarowych funkcji w pełni. Im więcej czasu spędzisz na szlifowaniu tej umiejętności, tym lepsze będzie twoje "shader karate". + + + +![The Karate Kid (1984)](mr_miyagi.jpg) + +Poniższy kod będzie naszym płotem. Wizualizujemy w nim znormalizowaną wartość współrzędnej *x* (`st.x`) w dwojaki sposób: poprzez jasność (zauważ płynny gradient od czerni do bieli) oraz przez rysowanie zielonego wykresu funkcji (w poniższym przykładzie funkcji *x* = *y*). Nie przejmuj się za bardzo funkcją `plot` - wrócimy do niej później. + + + +
+ +**Krótka uwaga**: Konstruktor typu `vec3` "rozumie", że chcesz przypisać tę samą wartość do każdego z trzech kanałów koloru, natomaist typu `vec4` rozumie, że chcesz stworzyć czterowymiarowy wektor z wektora trójwymiarowego i czwartej wartości (w tym wypadku wartość ta kontroluje alphę, czyli przezroczystość). Spójrz na linjki 19 i 25 powyżej. + + + +Kod jest twoim płotem - ważne, żebyś umiał na niego spojrzeć i go zrozumieć. Zakres od *0.0* do *1.0* będzie ci stale towarzyszył. Opanujesz sztukę blendowania (pol. "mieszania", "łączenia") i kształtowania tej linii + + + +Tę wzajmnie jednoznaczną (ang. "one-to-one") funkcję między *x* i *y* (lub jasnością) nazywamy *interpolacją liniową*. Możemy użyć funkcji matematycznych by *uformować* tę linię. Przykładowo, możemy podnieść *x* do potęgi 5, aby utworzyć *krzywą* linię. + + + +
+ +Ciekawe, prawda? W linijce 22 spróbuj użyć następujących wykładników: 20.0, 2.0, 1.0, 0.0, 0.2 lub 0.02. Zrozumienie związków między końcową wartością a wykładnikiem będzie bardzo przydatne. Używanie tego typu funkcji matematycznych tu i tam da ci pełnię kontroli nad twoim kodem. + + + +[`pow()`](../glossary/?search=pow) to natywna funkcja w GLSL, więc zaimplementowana jest na poziomie hardware'u, co oznacza większą wydajność. + + + +Zastąp funkcję potęgową w linijce 22 inną natywną funkcją. Spróbuj [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log) i [`sqrt()`](../glossary/?search=sqrt). W wypadku funkcji trygonometrycznych warto użyć liczby PI. Jest ona zdefiniowana w 8 linijce za pomocą makra, który zastąpi każde użycie `PI` wartością `3.14159265359`. + + + +### Step i Smoothstep + +GLSL posiada też unikalne natywne funckje interpolacyjne wykorzystujące akcelerację sprzętową. + + +Funkcja [`step()`](../glossary/?search=step) otrzymuje dwa argumenty. Pierwszy z nich to limit lub próg, natomiast drugi to wartość, którą chcemy porównać z tym progiem. Każda wartość poniżej limitu zwróci `0.0`, natomiast wszystko powyżej limitu zwróci `1.0`. + + + +Spróbuj zmienić tę wartość progową w linijce 20 poniższego kodu. + +
+ +Druga unikalna funkcja znana jest jako [`smoothstep()`](../glossary/?search=smoothstep) i otrzymuje trzy argumenty Dwa pierwsze argumenty służą do określenia początku i końca interpolacji (tranzycji/przejścia), natomiast trzeci jest wartością interpolowaną. + + + +
+ +W poprzednim przykładzie, w linii 12, zauważ, że użyliśmy smoothstep wewnątrz funkcji `plot()` do narysowania zielonej linii. Dla każdej pozycji wzdłuż osi x funkcja ta zwraca odpowiednią wartość y. Jak? Poprzez połączenie ze sobą dwóch [`smoothstep()`](../glossary/?search=smoothstep). Spójrz na poniżśzy fragment kodu (zauważ, że jest analogiczny do kodu w funkcji `plot()`) i wstaw go w linijce 20 powyższego przykładu. Wyobraź sobie, że widoczny wykres o kształcie dzwona (o kształcie rozkładu normalnego) "wędruje" wzdłuż funkcji przekazanej do argumentu `pct` funkcji `plot()`. + + + +```glsl +float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); +``` + +### Sinus i Cosinus + +Kiedy chcesz użyć matematyki do animacji, kształtowania lub blendowania wartości, nie ma nic lepszego niż zaprzyjaźnienie się z sinusem i cosinusem. + + + +Te dwie podstawowe funkcje trygonometryczne współpracują ze sobą, aby skonstruować okręgi, które są tak poręczne jak szwajcarski scyzoryk MacGyvera. Warto wiedzieć, jak się zachowują i na jakie sposoby można je łączyć. W skrócie, otrzymawszy kąt (w radianach), zwrócą one współrzędne *x* ([cosinus](../glossary/?search=cos)) i *y* ([sinus](../glossary/?search=sin)) punktu na brzegu okręgu o promieniu równym 1. Jednak fakt, że zwracają one znormalizowane wartości (wartości pomiędzy -1 a 1) w tak płynny sposób, czyni z nich niesamowite narzędzie. + + + +![](sincos.gif) + +Choć trudno opisać wszystkie związki między funkcjami trygonometrycznymi i okręgami, powyższa animacja pięknie je wizualizuje. + + + +
+ +Przyjrzyj się uważnie powyższej fali sinusoidalnej. Zauważ, jak wartości *y* oscylują płynnie między +1 a -1. Jak widzieliśmy w przykładzie z czasem w poprzednim rozdziale, możesz wykorzystać to rytmiczne zachowanie [`sin()`](../glossary/?search=sin) do animowania dowolnych wartości. Jeśli czytasz ten przykład w przeglądarce, spróbuj zmienić kod w powyższym jedno-linjkowym przykładzie i zaobserwuj, jak zmienia się fala. (Uwaga: nie zapomnij o średniku na końcu linii). + + + + +Spróbuj następnujących ćwiczeń i zobacz, co się stanie + +* Dodaj czas (`u_time`) do *x* wewnątrz funkcji `sin`. Zapamiętaj ten **ruch** wzdłuż *x*. + +* Pomnóż *x* przez `PI` wewnątrz funkcji `sin`. Zauważ, jak okres sinusa **zmniejsza się** do 2. Zwiększyliśmy w ten sposób częstotliwość. + +* Pomnóż czas (`u_time`) przez *x* wewnątrz funkcji `sin`. Zobacz jak **częstotliwość** zwiększa się, a okres maleje. Możliwe że u_time może być już bardzo duży, co czyni wykres trudnym do odczytania - odśwież stronę i spróbuj ponownie. + +* Dodaj 1.0 do [`sin(x)`](../glossary/?search=sin). Zobacz jak cała fala jest **przesunięta** w górę i wszystkie wartości są pomiędzy 0.0 a 2.0. + +* Pomnóż [`sin(x)`](../glossary/?search=sin) przez 2.0. Zobacz jak **amplituda** podwaja się. + +* Oblicz wartość bezwzględną ([`abs()`](../glossary/?search=abs)) funkcji `sin(x)`. Wygląda to jak ślad **odbijającej się** piłki. + +* Wyciągnij tylko część ułamkową ([`fract()`](../glossary/?search=fract)) z funkcji [`sin(x)`](../glossary/?search=sin). + +* Dodaj sufit ([`ceil()`](../glossary/?search=ceil)) oraz podłogę ([`floor()`](../glossary/?search=floor)) z [`sin(x)`](../glossary/?search=sin), aby otrzymać falę cyfrową o wartościach 1 i -1. + + + + +### Kilka dodatkowych przydatnych funkcji + +Pod koniec ostatniego ćwiczenia wprowadziliśmy kilka nowych funkcji. Teraz czas na eksperymentowanie z każdą z nich poprzez odkomentowanie poniższych linii po kolei. Poznaj te funkcje i zbadaj jak się zachowują. Wiem, zastanawiasz się... dlaczego? Szybkie wyszukiwanie w google "generative art" powie Ci to. Pamiętaj, że te funkcje to nasz płot. Opanowujemy ruch w jednym wymiarze, w górę i w dół. Już niedługo przyjdzie czas na dwa, trzy i cztery wymiary! + + + +![Anthony Mattox (2009)](anthony-mattox-ribbon.jpg) + +
+ + + +### Zaawansowane funkcje kształtujące + +[Golan Levin](http://www.flong.com/) ma świetną dokumentację bardziej złożonych shaping functions, które są niezwykle pomocne. Samodzielene przeniesienie ich do GLSL jest dobrym krokiem w stronę budowania własnego zasobu snippetów kodu. + + + +* Wielomianowe shaping fucntions: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) + +* Wykładnicze shaping functions: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) + +* Kołowe i Eliptyczne shaping functions: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) + +* Parametryczne (Beziera) shaping functions: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) + + + + +
+ +Podobnie jak szefowie kuchni, którzy zbierają przyprawy i egzotyczne składniki, artyści cyfrowi mają szczególne zamiłowanie do pracy nad własnymi shaping functions. + + + +[Iñigo Quiles](http://www.iquilezles.org/) ma wspaniałą kolekcję [użytecznych funkcji](http://www.iquilezles.org/www/articles/functions/functions.htm). Po przeczytaniu [tego artykułu](http://www.iquilezles.org/www/articles/functions/functions.htm) spójrz na poniższe tłumaczenie tych funkcji na GLSL. Zwróć uwagę na małe zmiany, jak stawianie "." (kropki) przy liczbach zmiennoprzecinkowych i używanie nazw GLSL dla funkcji z *C* (na przykład zamiast `powf()` użyj `pow()`): + + + +
+ +Aby podtrzymać twoją motywację, oto elegancki przykład (wykonany przez [Danguafer](https://www.shadertoy.com/user/Danguafer)) ilustrujący opanowanie karate shaping functions. + + + + + +W następnym rozdziale zaczniemy używać naszych nowych sztuczek. Najpierw z mieszaniem kolorów, a potem z rysowaniem kształtów. + + + +#### Ćwiczenia + + + +Przyjrzyj się poniższej tabeli wzorów wykonanej przez [Kynd](http://www.kynd.info/log/). Zobacz jak łączy on funkcje i ich właściwości, aby kontrolować wartości pomiędzy 0.0 a 1.0. Teraz nadszedł czas, abyś poćwiczył, odtwarzając te funkcje. Pamiętaj im więcej będziesz ćwiczył tym lepsze będzie twoje karate. + + + +![Kynd - www.flickr.com/photos/kynd/9546075099/ (2013)](kynd.png) + +#### Pomocne narzędzia + +Oto kilka narzędzi, które ułatwią ci wizualizację tego typu funkcji. + +* Grapher: jeśli masz komputer z systemem MacOS, wpisz `grapher` w swoim Spotlight, a będziesz mógł użyć tego super poręcznego narzędzia. + +![OS X Grapher (2004)](grapher.png) + +* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): po raz kolejny [Iñigo Quilez](http://www.iquilezles.org) stworzył narzędzie do wizualizacji funkcji GLSL w WebGL. + +![Iñigo Quilez - GraphToy (2010)](graphtoy.png) + +* [Shadershop](http://tobyschachman.com/Shadershop/): to niesamowite narzędzie stworzone przez [Toby Schachman](http://tobyschachman.com/) nauczy cię jak konstruować złożone funkcje w niesamowicie wizualny i intuicyjny sposób. + + + +![Toby Schachman - Shadershop (2014)](shadershop.png) diff --git a/06/README-pl.md b/06/README-pl.md new file mode 100644 index 0000000..a9315e3 --- /dev/null +++ b/06/README-pl.md @@ -0,0 +1,219 @@ +![Paul Klee - Color Chart (1931)](klee.jpg) + +## Kolory + + +Nie mieliśmy zbytnio okazji porozmawiać o typach wektorowych w GLSL. +Zanim przejdziemy dalej, ważne jest żebyśmy dowiedzieli się o nich więcej, a temat kolorów może być w tym bardzo pomocny. + + + +Jeżeli paradgymat programowania obiektowego jest ci bliski, to prawdopodobnie zauważyłeś, że proces ekstrakcji danych z wektorów wygląda podobnie jak ekstracja danych z `struct`'ów w C. + + + +```glsl +vec3 red = vec3(1.0,0.0,0.0); +red.x = 1.0; +red.y = 0.0; +red.z = 0.0; +``` + +Definiowanie kolor za pomocą notacji *x*, *y* i *z* jest trochę mylące, prawda? Właśnie dlatego istnieją inne sposoby dostępu do tej samej informacji, ale za pomocą innych nazw. Wartości `.x`, `.y` i `.z` mogą być również uzyskane za pomocą `.r`, `.g` i `.b`, jak i `.s`, `.t` i `.p` (`.s`, `.t` i `.p` są zwykle używane przy współrzędnych tekstur, które zobaczymy w następnych rozdziałach). Możesz również uzyskać dane wektora za pomocą indeksów `[0]`, `[1]` i `[2]`. + + + +Następujący kod przedstawia wszystkkie sposoby uzysakania tych samych danych: + + + +```glsl +vec4 vector; +vector[0] = vector.r = vector.x = vector.s; +vector[1] = vector.g = vector.y = vector.t; +vector[2] = vector.b = vector.z = vector.p; +vector[3] = vector.a = vector.w = vector.q; +``` + +Ta mnogość metod uzyskiwania tych samych danych jest tylko po to, aby ułatwić pisanie zrozumiałego kodu. Ta elastyczność wbudowana w język shadingowy stanowi też okazję, żebyś zaczął myśleć o współrzędnych koloru i przestrzeni jako wzjamenie zastępowalnych. + + + +Inną świetną własnością typów wektorowych w GLSL jest to, że współrzędne mogą być mieszane w dowolnej kolejności, co ułatwia castowanie i mieszanie wartości. Właśność ta nazywana jest *swizzle*'owaniem. + + + +```glsl +vec3 yellow, magenta, green; + +// Tworzenie żółtego +yellow.rg = vec2(1.0); // Przypisanie 1. do kanału czerwonego i zielonego +yellow[2] = 0.0; // Przypisanie 0. do kanału niebieskiego + +// Tworzenie magenty +magenta = yellow.rbg; // Przypisanie wektora z przestawionym kanałem zielonym i niebieskim + +// Tworzenie zielonego +green.rgb = yellow.bgb; // Przypisanie kanału niebieskiego do kanału czerwonego i niebieskiego +``` + + +### Mieszanie koloru + +Teraz, gdy już wiesz jak definiuje się kolory, pora na połączenie tego z naszą wcześniejszą wiedzą. W GLSL istnieje bardzo przydatna funkcja [`mix()`](../glossary/?search=mix), która pozwala mieszać dwie wartości wobec określonego stosunku wyrażonego w procentach. Potrafisz zgadnąć jaki jest zakres procentów? Oczywiście, że 0.0 i 1.0! Czas na wykorzystanie naszego shadingowego karate! + + + +![](mix-f.jpg) + +Sprawdź linijkę 18 poniższego kodu i zoabcz jak używamy wartości bezwględnej z sinusa od czasu, aby mieszać `colorA` i `colorB`. + + + +
+ +Pokaż na co cie stać: + + + +* Stwórz ekspresywną tranzycje między kolorami. Pomyśl o konkretnej emocji. Jaki kolor najlepiej ją reprezentuje? Jak wygląda? Jak zanika? Pomyśl o innej emocji i pasującym do niej kolorze. Zmień `colorA` i `colorB` w kodzie powyżej, aby pasowały do tych emocji. Następnie zanimuj tę tranzycję za pomocą shaping function. Robert Penner stworzył serię popularnych shaping functions, z zasotoswaniami w animacji komputerowej, zwanych [easing functions](http://easings.net/), skorzystaj z [tego przykładu](../edit.php#06/easing.frag) jako inspiracji, jednak najlepsze rezultaty osiągniesz tworząc własne tranzycje. + + + +### Zabawa z gradientem + +Funkcja [`mix()`](../glossary/?search=mix) ma więcej do zaoferowania. Zamiast pojedynczego `float`a, możemy podać zmienną tego samego typu, co dwa pierwsze argumenty; w naszym wypadku jest to `vec3`. W ten sposób zdobywamy kontrolę nad stosunkiem mieszania każdego indywidualnego kanału koloru, `r`, `g` i `b`. + + + +![](mix-vec.jpg) + +Spójrz na poniższy przykład. Tak jak w przykładach z poprzedniego rozdziału, dzięki znormalizowanej współrzędnej `x` tworzymy gradient i wizualizujemy go za pomocą linii. Aktualnie, wszystkie kanały leżą na tej samej linii. + + +Odkomentuj linjkę 25 i zobacz, co się stanie. Następnie odkomentuj linijki 26 i 27. Pamiętaj, że linie wizualizują, w jakim stosunku kanały (R, G, B) kolorów `colorA` i `colorB` są obecne w ostatecznym gradiencie. + + + +
+ +Prawdopodobnie rozpoznajesz trzy shaping functions, które używamy w linijkach 25 i 27. Baw się nimi! Czas pokazać swoje umiejętności z poprzednich rozdziałów, tworząc interesujące gradienty. Spróbuj następujących ćwiczeń: + +![William Turner - The Fighting Temeraire (1838)](turner.jpg) + +* Skomponuj gradient przypominający zachód słońca Williama Turnera. + +* Zanimuj tranzycje między wschodem i zachodem za pomocą `u_time`. + +* Czy potrafisz stworzyć tęczę korzystając z tego, czego nauczyliśmy się dotychaczas? + +* Użyj `step()`, by stworzyć kolorową flagę. + + + +### HSB + +Nie da się mówić o kolorze bez poruszenia tematu przestrzeni barw. Jak prawdopodobnie wiesz, istnieją też inne sposoby reprezentacji koloru poza RGB (z kanałem czerwonym, zielonym i niebieskim). + +[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) oznacza Hue (pol. "barwa"), Saturation (pol. "nasycenie") i Brightness (pol. "jasność) i jest o wiele bardziej intuicyjną reprezentacją koloru niż RGB. Czasem Brightness nazywany jest "Value", stąd zamiast HSB można spotkać się też ze skrótem HSV. Przyjrzyj się funkcjom `rgb2hsv()` i `hsv2rgb()` w następującym kodzie: + + + + + +Mapując pozycję na osi x do barwy i pozycję na osi y do jasności, otrzymujemy spektrum widzialnych kolorów. O wiele bardziej intuicyjnie wybiera się kolor HSB niż RGB. + + + +
+ +### HSB we współrzędnych biegunowych + +Oryginalnie, HSB miało być reprezentowane z pomocą współrzędnych biegunowych (opartych na kącie i promieniu), a nie kartezjańskich (opartych na x i y). By zmapować naszą funkcję HSB do współrzędnych biegunowych, musimy otrzymać kąt i dystans od centrum kanwy do współrzędnej piksela. W tym celu użyjemy funkcje [`length()`](../glossary/?search=length) i [`atan(y,x)`](../glossary/?search=atan) (który jest odpowiednikiem `atan2(y,x)` w GLSL). + + + +Pamiętaj: `vec2`, `vec3` i `vec4` traktowane są jak wektory nawet jeśli reprezentują kolor. Zaczniemy traktować kolory i wektory bardzo podobnie. + + + +**Uwaga:** Jest weięcej funkcji geometrycznych poza [`length`](../glossary/?search=length) jak: [`distance()`](../glossary/?search=distance), [`dot()`](../glossary/?search=dot), [`cross`](../glossary/?search=cross), [`normalize()`](../glossary/?search=normalize), [`faceforward()`](../glossary/?search=faceforward), [`reflect()`](../glossary/?search=reflect) i [`refract()`](../glossary/?search=refract). Ponadto, GLSL ma specjalne funkcje do porównywania wektorów: [`lessThan()`](../glossary/?search=lessThan), [`lessThanEqual()`](../glossary/?search=lessThanEqual), [`greaterThan()`](../glossary/?search=greaterThan), [`greaterThanEqual()`](../glossary/?search=greaterThanEqual), [`equal()`](../glossary/?search=equal) i [`notEqual()`](../glossary/?search=notEqual). + + + +Gdy już zdobędziemy kąt i promień, musimy znormalizować ich wartości do zakresu od 0.0 do 1.0. W linijce 27, [`atan(y,x)`](../glossary/?search=atan) zwróci kąt w radianach między -PI a PI (-3.14 a 3.14), więc musimy podzielić tę liczbę przez `TWO_PI` (zdefiniowane na górze kodu), uzyskując wartości między -0.5 i 0.5, które, przez proste dodawanie, mapujemy dalej do zakresu od 0.0 do 1.0. Promień ma długość 0.5 (ponieważ liczymy odległość od środka kanwy), więc musimy podwoić ten zakres (mnożąc przez 2), by uzyskać 1.0. + + + +Jak widzisz, sedno leży w transformowaniu i mapowaniu zakresów do 0.0 i 1.0. + + + +
+ +Spróuj poniższych ćwiczeń: + + + +* Zmodyfikuj przykład ze współrzędnymi biegunowymi, aby uzyskać kręcące się (jak w ikonce czekania myszki) koło barw. + +* Użyj shaping function razem z funkcją konwersji z HSB do RGB, aby rozszerzyć jedną barwę i zwężyć inną. + + + + +![William Home Lizars - Red, blue and yellow spectra, with the solar spectrum (1834)](spectrums.jpg) + +* Jeśli przyjrzysz się uważnie kołom barw używanym w narzędziach do wybierania koloru (ang "color picker") (spójrz na obrazek poniżej), zobaczysz, że używają innego spektrum koloru, zgodnego z przestrzenią barw RYB. Przykładowo, w RGB kolorem przeciwnym do czerwonego jest cyjan, a w RYB - zielony. Czy potrafiłbyś zrekonstruować poniższy obrazek? [Wskazówka: to dobry moment, by użyć shaping functions] + + + +![](colorwheel.png) + +* Przeczytaj [książkę Josefa Albersa _Interaction of Color_](http://www.goodreads.com/book/show/111113.Interaction_of_Color) i przestudiuj poniższe przykłady shaderów. + + + +
+ +#### Uwaga o funkcjach i ich argumentach + +Zanim przeskoczysz do następnego rozdziału, zatrzymajmy się na chwilę. Wróć do funkcji `hsb2rgb` z poprzedniego interaktywnego przykładu. Zauważysz `in` przed typem argumentu. Jest to [*kwalifikator*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) (ang. "qualifier") i akurat ten oznacza, że zmienna jest tylko do odczytu. W przyszłości zobaczymy, że jest również możliwe, by poprzedzić argumenty kwalifikatorami `out` i `inout`. Kwalifikator `out` określa, że argument jest tylko do zapisu (ang. "write-only"), natomiast `inout` działa podobnie jak przekazywanie argumentu przez referencje, co umożliwia również modyfikowanie go. + + + +```glsl +int newFunction(in vec4 aVec4, // read-only + out vec3 aVec3, // write-only + inout int aInt); // read-write +``` + +Może w to nie uwierzysz, ale mamy wszystkie składniki potrzbne do tworzenia fajnych rysunków. W następnym rozdziale nauczymy się jak połączyć wszystkie poznane tricki, by stworzyć geometryczne formy/kształty przez *blendowanie* przestrzeni. Dobrze słyszysz... *blendowanie* przestrzeni. + + diff --git a/07/README-pl.md b/07/README-pl.md new file mode 100644 index 0000000..384f95a --- /dev/null +++ b/07/README-pl.md @@ -0,0 +1,361 @@ +![Alice Hubbard, Providence, USA, ca. 1892. Zdjęcie: Zindman/Freemont.](froebel.jpg) + +## Kształty + +Nareszcie! Czekaliśmy na ten moment! Poznałeś większość podstaw GLSL, jego typów i funkcji. Ćwiczyłeś również wykorzystanie shaping functions. Teraz nadszedł czas, aby połączyć to wszystko w całość. Jesteś w stanie sprostać temu wyzwaniu! W tym rozdziale dowiesz się, jak procedrualnie i równolegle rysować proste kształty. + + + +### Prostokąt + +Wyobraźmy sobie, że mamy papier w kratkę, taki jaki używaliśmy na lekcjach matematyki i naszym zadaniem domowym jest narysowanie kwadratu. Kartka papieru jest w wymiarach 10x10, a kwadrat w 8x8. Co zrobisz? + + + +![](grid_paper.jpg) + +Zamalowałbyś wszystko poza pierwszym i ostatnim rzędem oraz pierwszą i ostatnią kolumną, tak? + + + +Jak to się ma do shaderów? Każdy mały kwadracik naszej kartki papieru to wątek (piksel). Każdy mały kwadrat zna swoje położenie, podobne do współrzędnych na szachownicy. W poprzednich rozdziałach zmapowaliśmy *x* i *y* na kanały kolorów *czerwony* i *zielony* oraz nauczyliśmy się korzystać z ciasnego dwuwymiarowego terytorium pomiędzy 0.0 a 1.0. Jak możemy tę wiedzę wykorzystać, aby narysować wyśrodkowany kwadrat na środku naszej kanwy? + + + +Zacznijmy od naszkicowania pseudokodu, który używa `if`ów na współrzędnych kanwy. Idea jest podobna jak w przypadku z papieram w kratke. + + + +```glsl +if ( (X WIĘKSZE NIŻ 1) ORAZ (Y WIĘKSZE NIŻ 1) ) + pomaluj na biało +else + pomaluj na czarno +``` + +Teraz, gdy mamy lepsze wyobrażenie o tym, jak to będzie działać, zastąpimy `if`a funkcją [`step()`](../glossary/?search=step), a zamiast używać siatki 10x10 użyjmy znormalizowanych odpowiedników pomiędzy 0.0 a 1.0: + + + +```glsl +uniform vec2 u_resolution; + +void main(){ + vec2 st = gl_FragCoord.xy/u_resolution.xy; + vec3 color = vec3(0.0); + + // Obie linijki zwracają 1.0 (biały) lub 0.0 (czarny). + float left = step(0.1,st.x); // Równoważnie: (X WIĘKSZE NIŻ 0.1) + float bottom = step(0.1,st.y); // Równoważnie: (Y WIĘKSZE NIŻ 0.1) + + // Mnożenie left*bottom jest podobne do logicznego AND. + color = vec3( left * bottom ); + + gl_FragColor = vec4(color,1.0); +} +``` + +Funkcja [`step()`](../glossary/?search=step) "pomaluje" każdy piksel poniżej 0.1 na czarno (`vec3(0.0)`) a resztę na biało (`vec3(1.0)`). Mnożenie pomiędzy `left` i `bottom` działa jak logiczna operacja `AND`, gdzie obie muszą być 1.0 aby zwrócić 1.0, a gdy przynajmniej jedna jest 0.0, to obie są 0.0. W efekcie otrzymujemy dwie czarne linie, jedną na dole, a drugą po lewej stronie kanwy. + + + +![](rect-01.jpg) + +W poprzednim kodzie powtarzamy funkcję [`step()`](../glossary/?search=step) dla każdej osi (lewej i dolnej). Możemy zaoszczędzić kilka linii kodu, przekazując obie wartości razem zamiast pojedynczo. Wygląda to następująco: + + + +```glsl +vec2 borders = step(vec2(0.1),st); +float pct = borders.x * borders.y; +``` + +Do tej pory narysowaliśmy tylko dwie krawędzie (dolna-lewa) naszego prostokąta. Dorysujmy teraz dwie pozostałe (górna-prawa). Sprawdź następujący kod: + + + +
+ +Odkomentuj *linijki 21-22* i zobacz jak odwracamy współrzędne `st` - w ten sposób `vec2(0,0,0)` znajdzie się w prawym górnym rogu. Otrzymaliśmy odbicie lustrzane. Teraz wystarczy przekazać te odwrócone współrzędne do [`step()`](../glossary/?search=step). + + + +![](rect-02.jpg) + +Zwróć uwagę, że w *linijkach 18 i 22* wszystkie boki są mnożone przez siebie. Jest to równoznaczne z napisaniem: + + + +```glsl +vec2 bl = step(vec2(0.1),st); // bottom-left +vec2 tr = step(vec2(0.1),1.0-st); // top-right +color = vec3(bl.x * bl.y * tr.x * tr.y); +``` + +Ciekawe, prawda? W tej technice chodzi o wykorzystanie [`step()`](../glossary/?search=step), odwracania (ang. "flip") współrzędnych oraz mnożenia (jako operację logiczną AND). + + + +Zanim przejdziesz dalej, spróbuj wykonać następujące ćwiczenia: + +* Zmień rozmiar i proporcje prostokąta. + +* Użyj [`smoothstep()`](../glossary/?search=smoothstep) zamiast [`step()`](../glossary/?search=step). Zauważ, że zmieniając wartości, możesz przejść od rozmytych krawędzi do eleganckich gładkich granic. + +* Zaimplementuj to samo, ale za pomocą [`floor()`](../glossary/?search=floor) (+ mnożenie i dzielenie). + +* Wybierz implementację, którą najbardziej lubisz i zrób z niej funkcję, którą możesz ponownie wykorzystać w przyszłości. Spraw, aby twoja funkcja była elastyczna i wydajna. + +* Zrób inną funkcję, która po prostu rysuje kontur prostokąta. + +* Jak myślisz, jak można narysować różne prostokąty na tej samej kanwie? Jeśli wymyślisz jak, pochwal się swoimi umiejętnościami, tworząc kompozycję z prostokątów i kolorów, która przypomina obraz [Pieta Mondriana](http://en.wikipedia.org/wiki/Piet_Mondrian). + + + +![Piet Mondrian - Tableau (1921)](mondrian.jpg) + +### Koła + +Łatwo jest rysować kwadraty na papierze w kratkę i prostokąty na współrzędnych kartezjańskich, ale okręgi wymagają innego podejścia, zwłaszcza że potrzebujemy algorytmu działającego na każdym pikselu z osobna. Jednym z rozwiązań jest *zmapowanie* współrzędnych tak, abyśmy mogli użyć funkcji [`step()`](../glossary/?search=step) do narysowania okręgu. + +Jak to zrobić? Przypomnijmy sobie lekcje matematyki, gdzie rozpościeraliśmy ramiona cyrkla na długość promienia okręgu, wciskaliśmy jedno ramię cyrkla w środek okręgu, a następnie obrysowywaliśmy krawędź okręgu obracając drugie ramię. + + + +![](compass.jpg) + +Przełożenie tego na shader, w którym każdy piksel jast jak kratka na papierze, implikuje *zadawanie* każdemu pikselowi (wątkowi) pytania, czy znajduje się wewnątrz obszaru koła. Robimy to poprzez obliczenie odległości od danego piksela do środka okręgu. + + + +![](circle.jpg) + +Istnieje kilka sposobów na obliczenie tej odległości. Najprostszy z nich wykorzystuje funkcję [`distance()`](../glossary/?search=distance), która oblicza [`length()`](../glossary/?search=length) różnicy pomiędzy dwoma punktami (w naszym przypadku współrzędną piksela i środkiem kanwy). Funkcja `length()` to nic innego jak przekształcone twierdzenie Pitagorasa: + + + +![](hypotenuse.png) + +Możesz użyć [`distance()`](../glossary/?search=distance), [`length()`](../glossary/?search=length) lub [`sqrt()`](../glossary/?search=sqrt) aby obliczyć odległość do centrum kanwy. Poniższy kod zawiera te trzy funkcje i nie zaskakuje fakt, że każda z nich zwraca dokładnie taki sam wynik. + + + +Zakomentuj i odkomentuj linijki, aby wypróbować różne sposoby uzyskania tego samego wyniku. + + + +
+ +W powyższym przykładzie mapujemy odległość do centrum kanwy na jasność piksela. Im bliżej centrum znajduje się piksel, tym niższą (ciemniejszą) ma wartość. Zauważ, że wartości nie są zbyt wysokie, ponieważ od centrum ( `vec2(0.5, 0.5)` ) maksymalna odległość ledwo przekracza 0.5. Pokontempluj nad dokonanym mapowaniem i pomyśl: + + + +* Co można z niego wywnioskować? + +* Jak możemy je użyć do narysowania koła? + +* Zmodyfikuj powyższy kod, aby zawrzeć cały gradient wewnątrz kanwy. (Wskazówka: użyj mnożenia) + + + +### Pole odległości + +Możemy również myśleć o powyższym przykładzie jako o mapie wysokości, gdzie im ciemniej tym wyżej. Gradient pokazuje nam coś podobnego do wzoru tworzonego przez stożek. Wyobraź sobie, że jesteś na szczycie tego stożka. Pozioma odległość do krawędzi stożka wynosi 0.5. Będzie ona stała we wszystkich kierunkach. Wybierając miejsce "przecięcia" stożka otrzymamy większą lub mniejszą powierzchnię kołową. + + + +![](distance-field.jpg) + +Zasadniczo używamy reinterpretacji przestrzeni (w oparciu o odległość do centrum), aby tworzyć kształty. Ta technika jest znana jako "pole odległości" (ang "distance field") i jest używana na różne sposoby, od konturów czcionek do grafiki 3D. + + + +Spróbuj następujących ćwiczeń: + +* Użyj [`step()`](../glossary/?search=step), aby zamienić wszystko powyżej 0.5 na białe, a wszystko poniżej na czarne. + +* Odwróć kolory tła i pierwszego planu. + +* Używając [`smoothstep()`](../glossary/?search=smoothstep), poeksperymentuj z różnymi wartościami, aby uzyskać ładne, gładkie granice na swoim okręgu. + +* Gdy już będziesz zadowolony ze swojej implementacji, stwórz z niej funkcję, którą będziesz mógł ponownie wykorzystać w przyszłości. + +* Dodaj kolor do koła. + +* Czy możesz zanimować swój krąg, aby rosnął i kurczył się, symulując bijące serce? (Możesz zaczerpnąć inspirację z animacji w poprzednim rozdziale). + +* A co z przesuwaniem tego okręgu? Czy możesz go przesuwać i umieszczać różne okręgi na jednej kanwie? + +* Co się stanie, jeśli połączysz pola odległości razem, używając różnych funkcji i operacji? + + + + +```glsl +pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6)); +pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6)); +pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +``` + +* Zrób trzy kompozycje z wykorzystaniem tej techniki. Jeśli są one animowane, jeszcze lepiej! + + + +#### Twoja skrzynka z narzędziami + +Pod względem mocy obliczeniowej funkcja [`sqrt()`](../glossary/?search=sqrt) - i wszystkie funkcje, które od niej zależą - mogą być kosztowne. Oto inny sposób tworzenia okrągłego pola odległości za pomocą produktu skalarnego [`dot()`](../glossary/?search=dot): + + + +
+ +### Przydatne własności pól odległości + +![ogród Zen](zen-garden.jpg) + +Pola odległości mogą być używane do rysowania prawie wszystkiego. Oczywiście im bardziej złożony jest kształt, tym bardziej skomplikowane będzie jego równanie, ale gdy już masz formułę do tworzenia pól odległości danego kształtu, bardzo łatwo jest połączyć i/lub zastosować do niego efekty, takie jak gładkie krawędzie i wiele konturów. Z tego powodu, pola odległości są popularne w renderowaniu czcionek, takich jak [Mapbox GL Labels](https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817), [Matt DesLauriers](https://twitter.com/mattdesl) [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu) i [jak to jest opisane w rozdziale 7 iPhone 3D Programming, O'Reilly](http://chimera.labs.oreilly.com/books/1234000001814/ch07.html#ch07_id36000921). + +Przyjrzyj się następującemu kodowi. + + + +
+ +Zaczynamy od przeniesienia układu współrzędnych na środek i skurczenia go o połowę, mapując wartości pozycji pomiędzy -1 a 1. W *linijce 24* wizualizujemy wartości pola odległości za pomocą funkcji [`fract()`](../glossary/?search=fract) ułatwiając dostrzeżenie tworzonego przez nie wzoru. Wzór pola odległości powtarza się jak pierścienie w ogrodzie Zen. + +Przyjrzyjmy się wzorowi pola odległości w *linijce 19*. Obliczamy tam odległość do współrzędnej `(.3,.3)` lub `vec3(.3)` we wszystkich czterech kwadrantach (właśnie po to jest tam [`abs()`](../glossary/?search=abs)). + + + +Jeśli odkomentujesz *linijkę 20*, zauważysz, że łączymy odległości do tych czterech punktów za pomocą [`min()`](../glossary/?search=min) do zera. W rezultacie otrzymujemy nowy interesujący wzór. + +Spróbuj teraz odkomentować *linijkę 21*; robimy to samo, ale używamy funkcji [`max()`](../glossary/?search=max). Rezultatem jest prostokąt z zaokrąglonymi rogami. Zauważ, jak pierścienie pola odległości stają się gładsze, im bardziej oddalają się od środka. + +Dokończ odkomentowywanie *linijek 27 do 29* jedna po drugiej, aby zrozumieć różne zastosowania pól odległości. + + + +### Krzywe biegunowe + +![Robert Mangold - Untitled (2008)](mangold.jpg) + +W rozdziale o kolorze mapujemy współrzędne kartezjańskie na współrzędne biegunowe, obliczając *promień* i *kąt* każdego piksela za pomocą następującego wzoru: + + + +```glsl +vec2 pos = vec2(0.5)-st; +float r = length(pos)*2.0; +float a = atan(pos.y,pos.x); +``` +Część tego wzoru wykorzystaliśmy na początku rozdziału do narysowania okręgu. Odległość do środka obliczyliśmy za pomocą [`length()`](../glossary/?search=length). Teraz, gdy wiemy już o polach odległości, możemy poznać inny sposób rysowania kształtów za pomocą współrzędnych biegunowych. + +Technika ta jest nieco restrykcyjna, ale bardzo prosta. Polega ona na zmianie promienia okręgu w zależności od kąta, aby uzyskać różne kształty. Jak dokonuje się ta zmiana? Z użyciem shaping functions! + +Poniżej znajdziesz dwa interaktywne przykłady, w których te same funkcje występują we współrzędnych kartezjańskich i w biegunowych (pomiędzy *linijkami 21 i 25*). Odkomentuj te funkcje jedna za drugą, zwracając uwagę na zależności między jednym układem współrzędnych a drugim. + + + +
+ +
+ +Spróbuj: + + + +* Zanimować te kształty +* Połącz różne shaping functions by *zrobić dziury* w kształtach, aby powstały kwiaty, płatki śniegu i zębatki. +* Użyj funkcji `plot()` z rodziału *Shaping functions* i narysuj sam kontur (bez wypełnienia) + + + +### Łącząc siły + +Teraz gdy wiemy, jak zmieniać promień koła w zależności od kąta z użyciem [`atan()`](../glossary/?search=atan), możemy spróbować połączyć `atan()` z polami odległości. + + + +Trik polega na wykorzystaniu liczby krawędzi wielokąta, by skonstruować pole odległości z użyciem współrzędnych polarnych. Sprawdź [następujący kod](http://thndl.com/square-shaped-shaders.html) od [Andrew Baldwin](https://twitter.com/baldand). + + + +
+ +* Korzystając z tego przykładu, stwórz funkcję, która przyjmuje położenie i liczbę kątów pożądanego wielokąta, a zwraca wartość pola odległości. + + + +* Połącz pola odległości ze sobą z użyciem [`min()`](../glossary/?search=min) i [`max()`](../glossary/?search=max). + + + +* Zreplikuj dowolne logo z użyciem pól odległości + + + +Gratulacje! Udało ci się przebrnąć przez bardzo trudny materiał! Choć rysowanie prostych kształtów w Processing jest proste, to tutaj już nie. W świecie shaderów rysowanie kształtów jest zawiłe; przestawienie się na ten nowy sposób programowania może być męczące. + + + +Na dole strony znajdziesz link do [PixelSpirit Deck](https://patriciogonzalezvivo.github.io/PixelSpiritDeck/). Jest to talia kart, która pomoże ci nauczyć się nowych funkcji SDF (ang. "Signed distance field" - pole odległości z uwzględnieniem wartości ujemnych), które wykorzystasz w swoich pracach i shaderach. Poziom trudności jest progresywny, więc praca nad jedną kartą dziennie zapewni ci wyzwania na kolejne miesiące. + + + +Wiedząc jak rysować kształty, z pewnością przyjdą ci do głowy nowe pomysły. W następnym rozdziale nauczysz się przesuwać, obracać i skalować kształty. Pozwoli ci to tworzyć kompozycje! + + diff --git a/08/README-pl.md b/08/README-pl.md new file mode 100644 index 0000000..b52a86f --- /dev/null +++ b/08/README-pl.md @@ -0,0 +1,165 @@ +## Macierze 2D + + + +### Translacja + +W poprzednim rozdziale dowiedzieliśmy się, jak tworzyć różne kształty. Przesuwanie tych kształtów polega na przesuwaniu samego układu współrzędnych. Możemy to osiągnąć poprzez proste dodanie wektora do zmiennej ``st``, zawierającej położenie każdego fragmentu. Powoduje to przesunięcie całego układu współrzędnych. + + + +![](translate.jpg) + +Łatwiej jest to zobaczyć niż wytłumaczyć, zatem: + +*Odkomentuj linijkę 35 poniższego kodu, by zobaczyć jak przestrzeń się przesuwa. + + + +
+ +Spróbuj teraz wykonać następujące ćwiczenie: + +* Używając ``u_time`` wraz z shaping functions poruszaj małym krzyżem w ciekawy sposób. Poszukaj interesującego cię ruchu i spróbuj sprawić, by krzyż poruszał się w ten sam sposób. Przydatne może być nagranie najpierw czegoś z "prawdziwego świata" - może to być przypływ i odpływ fal, ruch wahadła, odbijająca się piłka, przyspieszający samochód, zatrzymujący się rower. + +### Rotacja + +Aby obracać obiekty również musimy poruszać całym układem przestrzennym. Do tego celu będziemy używać [macierzy](http://en.wikipedia.org/wiki/Matrix_%28mathematics%29). Macierz to uporządkowany zbiór liczb w kolumnach i wierszach. Wektory są mnożone przez macierze według ściśle określonych reguł w celu zmodyfikowania wartości wektora w określony sposób. + +[![wpis Wikipedii dotyczący macierzy](matrixes.png)](https://en.wikipedia.org/wiki/Matrix) + +GLSL posiada natywne wsparcie dla dwu, trzy i czterowymiarowych macierzy: [``mat2``](../glossary/?search=mat2) (2x2), [``mat3``](../glossary/?search=mat3) (3x3) i [``mat4``](../glossary/?search=mat4) (4x4). GLSL obsługuje również mnożenie macierzy (``*``) oraz specyficzną dla macierzy funkcję [``matrixCompMult()``](../glossary/?search=matrixCompMult). + +Na podstawie tego, jak zachowują się macierze, możliwe jest skonstruowanie macierzy w celu wytworzenia określonych zachowań. Na przykład możemy użyć macierzy do translacji wektora: + + + +![](3dtransmat.png) + +Co ciekawsze, możemy użyć macierzy do obrócenia całego układu współrzędnych + + + +![](rotmat.png) + +Spójrz na poniższy kod funkcji, która konstruuje dwuwymiarową macierz rotacji. Funkcja ta oparta jest na [wzorze](http://en.wikipedia.org/wiki/Rotation_matrix) dla dwuwymiarowych wektorów, aby obrócić współrzędne wokół punktu ``vec2(0,0)``. + + + +```glsl +mat2 rotate2d(float _angle){ + return mat2(cos(_angle),-sin(_angle), + sin(_angle),cos(_angle)); +} +``` + +Zgodnie ze sposobem, w jaki rysowaliśmy kształty, nie jest to dokładnie to, czego chcemy. Nasz krzyż jest rysowany w centrum płótna, co odpowiada pozycji ``vec2(0.5)``. Tak więc, zanim obrócimy przestrzeń musimy przenieść ten krzyż z `centrum` na współrzędną ``vec2(0.0)``, obrócić przestrzeń, a następnie ostatecznie przenieść go z powrotem na pierwotne miejsce. + + + +![](rotate.jpg) + +Co odpowiada ponizszemu kodowi: + + + +
+ +Spróbuj wykonać następujące ćwiczenia: + +* Odkomentuj linię 45 powyższego kodu i zwróć uwagę na to, co się stanie. + +* Zakomentuj translacje przed i po rotacji, w liniach 37 i 39, i zaobserwuj konsekwencje. + +* Użyj rotacji, aby poprawić ruch, który zasymulowałeś w ćwiczeniu z podrozdziału "Translcja". + +### Skalowanie + +Widzieliśmy już, jak macierze służą do translacji i rotacji obiektów w przestrzeni. (A dokładniej do przekształcania układu współrzędnych w celu obracania i przesuwania obiektów). Jeśli używałeś programów do modelowania 3D albo funkcji macierzowych push i pop w Processing, to pewnie wiesz, że macierze mogą być również używane do skalowania rozmiaru obiektu. + + + +![](scale.png) + +Na podstawie powyższego wzoru, możemy stworzyć 2D macierz skalowania w GLSL: + + + +```glsl +mat2 scale(vec2 _scale){ + return mat2(_scale.x,0.0, + 0.0,_scale.y); +} +``` + +
+ +Spróbuj następujących ćwiczeń, aby głębiej zrozumieć, jak to działa. + +* Odkomentuj linię 42 powyższego kodu, aby zobaczyć skalowanie współrzędnych przestrzeni. + +* Zobacz, co się stanie, gdy zakomentujesz translacje przed i po skalowaniu w liniach 37 i 39. + +* Spróbuj połączyć macierz rotacji wraz z macierzą skalowania. Bądź świadomy, że kolejność ma znaczenie. Najpierw pomnóż przez macierz, a potem pomnóż wektory. + +* Teraz, gdy wiesz już, jak rysować różne kształty oraz przesuwać, obracać i skalować je, czas na stworzenie ładnej kompozycji. Zaprojektuj i skonstruuj [UI lub HUD](https://www.pinterest.com/patriciogonzv/huds/) (ang. "heads up display"). Użyj następującego przykładu ShaderToy autorstwa [Ndel](https://www.shadertoy.com/user/ndel) jako inspiracji. + + + + + +### Inne zastosowania macierzy: Kolor YUV + +[YUV](http://en.wikipedia.org/wiki/YUV) to przestrzeń barw stosowana do analogowego kodowania zdjęć i filmów, która uwzględnia ludzką percepcję w celu zmniejszenia redundantnych informacji zawartych w reprezentacji RGB. + +Poniższy kod jest ciekawą okazją do wykorzystania operacji macierzowych w GLSL do transformacji kolorów z jednej przestrzeni do drugiej. + +
+ +Jak widać traktujemy kolory jak wektory, które można mnożyć przez macierze. W ten sposób mapujemy wartości. + +W tym rozdziale dowiedzieliśmy się, jak używać przekształceń macierzowych do przesuwania, obracania i skalowania wektorów. Przekształcenia te będą niezbędne do tworzenia kompozycji z kształtów, które poznaliśmy w poprzednim rozdziale. W następnym rozdziale zastosujemy wszystko, czego dotychczas się nauczyliśmy, do tworzenia pięknych proceduralnych wzorów. Zobaczysz, że programowanie powtórzeń i wariacji może być bardzo ekscytujące. + + diff --git a/09/README-pl.md b/09/README-pl.md new file mode 100644 index 0000000..584bd3c --- /dev/null +++ b/09/README-pl.md @@ -0,0 +1,200 @@ +## Wzory kafelkowe + +Ponieważ shadery wykonywane są piksel po pikselu, więc niezależnie od tego, jak często powtarzasz (duplikujesz) dany kształt, liczba obliczeń pozostaje stała. Oznacza to, że fragment shadery nadają się szczególnie do wzorów kafelkowych. + +[ ![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag) + +W tym rozdziale zamierzamy zastosować to, czego nauczyliśmy się do tej pory, dodając powtarzalność. Podobnie jak w poprzednich rozdziałach, nasza strategia będzie opierała się na mnożeniu współrzędnych przestrzeni (z przedziału 0.0 a 1.0), dzięki czemu kształty, które narysujemy pomiędzy wartościami 0.0 a 1.0, będą się powtarzać, tworząc siatkę. + +*Siatka* (ang. "grid") *zapewnia ramy, w których może działać ludzka intuicja i inwencja, i które może obalić. W chaosie natury wzory zapewniają kontrast i obietnicę porządku. Od wczesnych wzorów na ceramice do geometrycznych mozaik w rzymskich łaźniach, ludzie od dawna używali siatek, by wzbogacić swoje życie o dekoracje. "* [*10 PRINT*, Mit Press, (2013)](http://10print.org/) + +Najpierw przypomnijmy sobie funkcję [``fract()``](../glossary/?search=fract). Zwraca ona część ułamkową liczby, dzięki czemu ``fract()`` to w istocie funkcja modulo jeden ([``mod(x,1.0)``](../glossary/?search=mod)). Innymi słowy, [``fract()``](../glossary/?search=fract) zwraca liczbę po przecinku. Nasza zmienna znormalizowanego układu współrzędnych (``st``) już znajduje sie w zakresie od 0.0 do 1.0, więc nie ma sensu robić czegoś takiego jak: + + + +```glsl +void main(){ + vec2 st = gl_FragCoord.xy/u_resolution; + vec3 color = vec3(0.0); + st = fract(st); + color = vec3(st,0.0); + gl_FragColor = vec4(color,1.0); +} +``` + +Ale jeśli przeskalujemy znormalizowany układ współrzędnych w górę - powiedzmy o trzy - otrzymamy trzy sekwencje interpolacji liniowych między 0-1: pierwszą między 0-1, drugą dla punktów między 1-2 i trzecią dla punktów między 2-3. + + + +
+ +Teraz nadszedł czas, aby narysować coś w każdej podprzestrzeni, odkomentowując linię 27. (Ponieważ mnożymy x i y po równo, współczynnik proporcji przestrzeni nie zmienia się i kształty będą zgodne z oczekiwaniami). + +Spróbuj wykonać niektóre z poniższych ćwiczeń, aby uzyskać głębsze zrozumienie: + + + +* Pomnóż przestrzeń przez różne liczby. Spróbuj z wartościami zmiennoprzecinkowymi, a także z różnymi wartościami dla x i y. + +* Zrób funkcję z tej kafelkowej sztuczki, abyś mógł ją ponownie wykorzystać. + +* Podziel przestrzeń na 3 wiersze i 3 kolumny. Znajdź sposób identyfikowania, w której kolumnie i rzędzie znajduje się wątek (piksel). Użyj tego, aby zmienić kształt, który jest wyświetlany. Spróbuj stworzyć mecz Kółko i krzyżyk + + + +### Macierze wewnątrz kafelków + +Ponieważ każdy kafelek jest pomniejszą wersją znormalizowanego układu współrzędnych, którego już używaliśmy, więc możemy zastosować do niego przekształcenie macierzowe w celu translacji, obrotu lub skalowania przestrzeni wewnątrz. + + + +
+ +* Pomyśl o ciekawych sposobach animacji tego wzoru. Rozważ animowanie koloru, kształtu i ruchu. Wykonaj trzy różne animacje. + +* Odtwórz bardziej skomplikowane wzory poprzez skomponowanie różnych kształtów. + + + + +[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag) + +* Połącz różne warstwy wzorów, aby skomponować własny [szkocki tartan](https://www.google.com/search?q=scottish+patterns+fabric&tbm=isch&tbo=u&source=univ&sa=X&ei=Y1aFVfmfD9P-yQTLuYCIDA&ved=0CB4QsAQ&biw=1399&bih=799#tbm=isch&q=Scottish+Tartans+Patterns). + + + +[ ![Vector Pattern Scottish Tartan By Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076) + +### Przesunięcia kafelków + +Powiedzmy, że chcemy odtworzyć mur z cegły. Patrząc na ścianę, można zauważyć przesunięcie pół cegły na osi x w co drugim rzędzie. Jak możemy to zrobić? + +![](brick.jpg) + +Jako pierwszy krok musimy wiedzieć, czy rząd naszego wątku (piksela) jest liczbą parzystą czy nieparzystą, co pomoże określić, czy musimy przesunąć x w tym rzędzie. W tym celu użyjemy [``mod()``](../glossary/?search=mod) z ``2.0``, a następnie zobaczymy, czy wynik jest mniejszy niż ``1.0`` czy nie. Spójrz na poniższy kod i odkomentuj dwie ostatnie linie. + + + +
+ +Jak widać możemy użyć [operatora warunkowego](https://en.wikipedia.org/wiki/%3F:) do sprawdzenia czy [``mod()``](../glossary/?search=mod) z ``2.0`` jest mniejszy od ``1.0`` (druga linia) lub podobnie możemy użyć funkcji [``step()``](../glossary/?search=step), która wykonuje tę samą operację, ale szybciej. Dlaczego? Chociaż trudno jest wiedzieć jak każda karta graficzna optymalizuje i kompiluje kod, to można bezpiecznie założyć, że funkcje wbudowane są szybsze od tych niewbudowanych. Zawsze, gdy możesz użyć wbudowanej funkcji, użyj jej! + +Korzystając z powyższej metody wykrywania liczb nieparzystych, możemy przesunąć nieparzyste rzędy, aby upodobnić naszą kawnę do ceglanej ściany. W linii 14 poniższego kodu identyfikujemy parzystość rzędów i nadajemy im przesunięcie na ``x``. Zauważ, że dla parzystych rzędów, wynikiem obliczeń w `step()` jest ``0.0``, co, mnożąc przez ``0.5``, daje przesunięcie ``0.0``. Natomiast w nieparzystych rzędach mnożymy ``1.0`` przez ``0.5``, co powoduje przesunięcie osi ``x`` układu współrzędnych o ``0.5``. + + + +Teraz spróbuj odkomentować linię 32 - rozciąga ona proporcje układu współrzędnych, aby odtworzyć wymiary "nowoczesnej cegły". Odkomentowując linię 40 możesz zobaczyć jak wygląda układ współrzędnych zmapowany na kolor czerwony i zielony. + + + +
+ +* Zanimuj ten przykład, zwiększając przesunięcie w zależności od czasu. + +* Zrób kolejną animację, w której parzyste wiersze przesuwają się w lewo, a nieparzyste w prawo. + +* Czy możesz powtórzyć ten efekt, ale z kolumnami? + +* Spróbuj połączyć przesunięcie na osi ``x`` i ``y``, aby uzyskać coś takiego: + + + + + +## Kafelki Truchet'a + +Teraz, gdy dowiedzieliśmy się, jak określić, czy nasza komórka znajduje się w parzystym czy nieparzystym wierszu lub kolumnie, możliwe jest ponowne wykorzystanie pojedynczego elementu projektu w zależności od jego pozycji. Rozważmy przypadek [kafelków Truchet'a](http://en.wikipedia.org/wiki/Truchet_tiles), gdzie pojedynczy kafelek może być przedstawiony na cztery różne sposoby: + + + +![](truchet-00.png) + +Zmieniając wzór na kafelkach, można zbudować nieskończony zestaw skomplikowanych wzorów. + + + +![](truchet-01.png) + +Zwróć uwagę na funkcję ``rotateTilePattern()``, która dzieli przestrzeń na cztery komórki i każdej z nich przypisuje kąt obrotu. + + + +
+ +* Zakomentowywuj, odkomentowywuj i powielaj linie od 69 do 72, aby komponować nowe wzory. + +* Zmień czarno-biały trójkąt na inny element, taki jak: półkola, obrócone kwadraty lub linie. + +* Zakoduj inne wzory, w których elementy są obracane w zależności od ich położenia. + +* Zrób wzór, który zmienia inne właściwości w zależności od położenia elementów. + +* Pomyśl o czymś innym, co niekoniecznie jest wzorem, gdzie możesz zastosować zasady z tego działu. (Na przykład: heksagramy I Ching) + + + + + +## Tworzenie własnych reguł + +Tworzenie wzorców proceduralnych to ćwiczenie umysłowe polegające na znajdowaniu minimalnych elementów wielokrotnego użytku. Praktyka ta jest stara; my jako gatunek od dawna używamy siatek i wzorów do dekorowania tkanin, podłóg i obramowań obiektów: od meandrowych wzorów w starożytnej Grecji, po chińskie wzory kratowe, przyjemność z powtórzeń i wariacji przykuwa naszą uwagę i pobudza wyobraźnię. Poświęć trochę czasu, aby spojrzeć na [dekoracyjne](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) [wzory](https://www.pinterest.com/patriciogonzv/paterns/) i zobacz długą historię tego, jak artyści i projektanci poruszają się po cienkiej krawędzi między przewidywalnością porządku a niespodzianką zmienności i chaosu. Od arabskich wzorów geometrycznych do wspaniałych afrykańskich wzorów tkanin, istnieje cały wszechświat wzorów, z których można się uczyć. + + + +![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png) + +Tym rozdziałem kończymy część poświęconą Rysowaniu Algorytmicznemu. W kolejnych rozdziałach dowiemy się, jak wprowadzić trochę entropii do naszych shaderów, tworząc generatywny design. + + diff --git a/10/README-pl.md b/10/README-pl.md new file mode 100644 index 0000000..26fa5a0 --- /dev/null +++ b/10/README-pl.md @@ -0,0 +1,152 @@ +# Design generatywny + +Nie jest zaskoczeniem, że po tylu zagadnieniach ładu i porządku autor zmuszony jest wprowadzić trochę chaosu. + +## Losowość + +[![Ryoji Ikeda - test pattern (2008) ](ryoji-ikeda.jpg) ](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set) + +Losowość jest maksymalnym wyrazem entropii. Jak możemy wygenerować losowość wewnątrz pozornie przewidywalnego i sztywnego środowiska kodu? + +Zacznijmy od analizy następującej funkcji: + + + +
+ +Powyżej wyodrębniamy zawartość ułamkową sinusoidy. Wartości [``sin()``](../glossary/?search=sin), które oscylują pomiędzy ``-1.0`` a ``1.0`` zostały posiekane, i sprowadzone do zakresu pomiędzy ``0.0`` a ``1.0``. Możemy wykorzystać ten efekt do uzyskania pseudolosowych wartości. W jaki sposób? Mnożąc wypadkową [``sin(x)``](../glossary/?search=sin) przez większe liczby. Śmiało, zmodyfikuj powyższą funkcję, dodając zera do `1.0`. + +Do czasu, gdy dojdziesz do ``100000.0`` (i równanie będzie wyglądało tak: ``y = fract(sin(x)*100000.0)`` ) nie jesteś już w stanie dostrzec sinusoidę. Ziarnistość części ułamkowej zepsuła falę sinusoidy w pseudolosowy chaos. + + + +## Kontrolowanie chaosu + +Używanie losowości może być trudne - czasami jest ona zbyt chaotyczna, a czasami niewystarczająco losowa. Przyjrzyj się poniższemu wykresowi. Aby go stworzyć, używamy funkcji ``rand()``, która jest zaimplementowana dokładnie tak, jak opisaliśmy powyżej. + +Przyglądając się bliżej, możesz dostrzec osobiliwości przy ``-1.5707`` i ``1.5707``. Założę się, że teraz rozumiesz dlaczego - to właśnie tam występuje maksimum i minimum fali sinusoidalnej. + +Jeśli przyjrzysz się bliżej rozkładowi losowemu, zauważysz, że istnieje pewne skupienie wokół środka w porównaniu do brzegów. + + + +
+ +Jakiś czas temu [Pixelero](https://pixelero.wordpress.com) opublikował [ciekawy artykuł o rozkładzie losowym](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/). Dodałem kilka zakomentowanych funkcji, których używa, abyś mógł zobaczyć, jak można ten rozkład zmienić. Odkomentuj te funkcje i zobacz, co się stanie. + +Czytając [artykuł Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/), ważne jest, aby pamiętać, że nasza funkcja ``rand()`` jest deterministyczna, pseudolosowa. Co oznacza, że na przykład ``rand(1.)`` zawsze zwróci tę samą wartość. [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) odwołuje się do funkcji ActionScript ``Math.random()``, która jest niedeterministyczna - każde jej wywołanie zwróci inną wartość. + + + +## Losowość 2D + +Teraz, gdy mamy już lepsze zrozumienie losowości, czas zastosować ją w dwóch wymiarach, zarówno na osi ``x`` jak i ``y``. W tym celu potrzebujemy sposobu na przekształcenie dwuwymiarowego wektora w jednowymiarową wartość zmiennoprzecinkową. Można to zrobić na różne sposoby, ale szczególnie pomocna w tym przypadku jest funkcja [``dot()``](../glossary/?search=dot). Zwraca ona pojedynczą wartość zmiennoprzecinkową pomiędzy ``0.0`` a ``1.0`` w zależności od wzajemnej orientacji dwóch wektorów. + + + +
+ +Przyjrzyj się liniom od 13 do 15 i zauważ, jak porównujemy ``vec2 st`` z innym dwuwymiarowym wektorem ( ``vec2(12,9898,78,233)``). + +* Spróbuj zmienić wartości w liniach 14 i 15. Zobacz, jak zmienia się wyświetlany losowy wzór i zastanów się, czego możemy się z tego nauczyć. + +* Uzależnij tę funkcję losową od myszy (``u_mouse``) i czasu (``u_time``), aby lepiej zrozumieć, jak działa. + + + +## Wykorzystanie chaosu + +Losowość w dwóch wymiarach wygląda bardzo podobnie do szumu telewizyjnego, prawda? To trudne do wykorzystania narzędzie do komponowania obrazów. Nauczmy się, jak zrobić z niego użytek. + +Naszym pierwszym krokiem jest stworzenie tablicy kafelków; używając funkcji [``floor()``](../glossary/?search=floor) wygenerujemy tablicę, w której każdemu kafelkowi przyporządkowany jest unikalny wektor liczb całkowitych. Przyjrzyj się poniższemu kodowi, szczególnie liniom 22 i 23. + + + +
+ +Po przeskalowaniu przestrzeni przez 10 (w linii 21) oddzielamy część całkowitą współrzędnych od części ułamkowej. Operacja uzyskiwania części ułamkowej jest nam dobrze znana, ponieważ używaliśmy jej do dzielenia przestrzeni na mniejsze kafelki o wartościach od ``0.0`` do ``1.0``. Uzyskując część całkowitą współrzędnej wyodrębniamy wspólną wartość dla całego kafelka. Następnie możemy użyć tej wspólnej liczby całkowitej, aby uzyskać losową wartość dla tego kafelka. Ponieważ nasza funkcja losowa jest deterministyczna, zwrócona wartość losowa będzie stała dla wszystkich pikseli w tym kafelku. + +Odkomentuj linię 29, aby zobaczyć, że zachowujemy część ułamkową współrzędnej, więc możemy nadal używać jej jako układu współrzędnych do rysowania rzeczy wewnątrz każdego kafelka. + + + +Połączenie tych dwóch wartości - części całkowitej i części ułamkowej współrzędnej - pozwoli ci wymieszać zmienność i porządek. + +Spójrz na poniższy GLSL'owy port słynnego generatora labiryntów ``10 PRINT CHR$(205,5+RND(1)); : GOTO 10``. + + + +
+ +Tutaj wykorzystuję losowe wartości kafelków do rysowania linii w jednym lub drugim kierunku, używając funkcji ``truchetPattern()`` z poprzedniego rozdziału (linie 41 do 47). + +Możesz uzyskać inny ciekawy wzór, odkomentowując blok linii między 50 a 53, natomiast odkomentowując linie 35 i 36 dodasz animację. + + + +## Ujarzmij losowość + +[Ryoji Ikeda](http://www.ryojiikeda.com/), japoński kompozytor elektroniczny i artysta wizualny, ujarzmił losowość - trudno nie być poruszonym i zahipnotyzowanym przez jego prace. Jego użycie losowości w mediach audio-wizualnych to nie irytujący chaos, ale lustro złożoności naszej technologicznej kultury. + + + + + +Zapoznaj się z pracami [Ikedy](http://www.ryojiikeda.com/) i spróbuj wykonać następujące ćwiczenia: + +* Utwórz rzędy ruchomych komórek (w przeciwnych kierunkach) o losowych wartościach. Wyświetlaj tylko komórki z jaśniejszymi wartościami. Spraw, aby prędkość rzędów zmieniała się w czasie. + + + + + +* Podobnie jak poprzednio, stwórz kilka rzędów kafelków, ale każdy z nich z inną prędkością i kierunkiem. Uzależnij próg wyświetlania kafelków od położenia myszy. + + + + + +* Stwórz inne ciekawe efekty. + + + + + +Używanie losowości w estetyczny sposób może być problematyczne, zwłaszcza jeśli chcesz zrobić naturalnie wyglądające symulacje. Losowość jest po prostu zbyt chaotyczna i bardzo niewiele rzeczy wygląda ``random()`` w prawdziwym życiu. Jeśli spojrzysz na wzór deszczu lub wykres giełdowy, które są dość losowe, nie przypominają one w niczym losowego wzoru, który stworzyliśmy na początku tego rozdziału. Powód? Cóż, wartości losowe nie mają żadnej korelacji między sobą, podczas gdy większość naturalnych wzorów ma jakąś pamięć o poprzednim stanie. + +W następnym rozdziale poznamy szum (ang. "noise"), płynny i *naturalnie wyglądający* sposób tworzenia chaosu obliczeniowego. + + diff --git a/11/README-pl.md b/11/README-pl.md new file mode 100644 index 0000000..79b1535 --- /dev/null +++ b/11/README-pl.md @@ -0,0 +1,339 @@ + +![NASA / WMAP science team](mcb.jpg) + +## Noise (pol. "szum") + +Czas na przerwę! Bawiliśmy się losowymi funkcjami, które wyglądają jak szum telewizyjny (tzw. "szum biały", ang. "white noise"), w głowie wciąż się kręci od myślenia o shaderach, a oczy są po prostu zmęczone. Czas wyjść na spacer! + +Czujemy powietrze na skórze, słońce na twarzy. Świat jest tak żywym i bogatym miejscem. Kolory, tekstury, dźwięki. Podczas spaceru widzimy powierzchnię dróg, skał, drzew i chmur. + + + +![](texture-00.jpg) +![](texture-01.jpg) +![](texture-02.jpg) +![](texture-03.jpg) +![](texture-04.jpg) +![](texture-05.jpg) +![](texture-06.jpg) + +Nieprzewidywalność tych tekstur można by nazwać "losową", ale nie przypominają one losowości, z którą bawiliśmy się wcześniej. "Prawdziwy świat" jest tak bogatym i złożonym miejscem! Jak możemy zamodelować tę różnorodność obliczeniowo? + +To było pytanie, które [Ken Perlin](https://mrl.nyu.edu/~perlin/) próbował rozwiązać we wczesnych latach 80-tych, kiedy otrzymał zlecenie wygenerowania bardziej realistycznych tekstur do filmu "Tron". W odpowiedzi na to wymyślił elegancki algorytm szumu, za który później otrzymał Oskara. + + + +![Disney - Tron (1982)](tron.jpg) + +Poniższy kod nie jest klasycznym algorytmem szumu Perlina, ale jest dobrym punktem wyjścia do zrozumienia sposobu generowania szumu. + + + +
+ +W tych liniach robimy coś podobnego do tego, co robiliśmy w poprzednim rozdziale. Dzielimy ciągłą liczbę zmiennoprzecinkową (``x``) na jej składowe całkowitą (``i``) i ułamkową (``f``). Używamy [``floor()``](../glossary/?search=floor) aby uzyskać ``i`` oraz [``fract()``](../glossary/?search=fract) aby uzyskać ``f``. Następnie stosujemy ``rand()`` do części całkowitej ``x``, co daje unikalną wartość losową dla każdej liczby całkowitej. + +Spójrz na dwie skomentowane linie. Pierwsza z nich interpoluje liniowo każdą wartość losową. + + + + +```glsl +y = mix(rand(i), rand(i + 1.0), f); +``` + +Odkomentuj tę linię, aby zobaczyć jak to wygląda. Używamy `f` do interpolacji liniowej dwóch sąsiadujących wartości losowych za pomocą funkcji [``mix()``](../glossary/?search=mix). + +Nauczyliśmy się, że możemy zrobić coś lepszego niż interpolacja liniowa, prawda? +Spróbuj teraz odkomentować kolejną drugą linię, która używa interpolacji [``smoothstep()``](../glossary/?search=smoothstep) zamiast liniowej. + + + +```glsl +y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); +``` + +Po odkomentowaniu zauważ, jak przejście między szczytami staje się gładkie. W niektórych implementacjach szumu można zauważyć, że programiści wolą kodować własne krzywe sześcienne (ang. "cubic curves") (jak w kodzie poniżej) zamiast używać [``smoothstep()``](../glossary/?search=smoothstep). + + + +```glsl +float u = f * f * (3.0 - 2.0 * f ); // spersonalizowana funkcja sześcienna +y = mix(rand(i), rand(i + 1.0), u); // interpolacja z jej pomocą +``` + +Ta *płynna losowość* jest przełomem dla programistów grafiki i artystów - daje możliwość generowania organicznych obrazów i geometrii. Algorytm Szumu Perlina był wielokrotnie implementowany w różnych językach i wymiarach, aby móc tworzyć hipnotyzujące dzieła w celach kreatywnych. + + + +![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg) + +Teraz twoja kolej: + +* Stwórz własną funkcję ``float noise(float x)``. + +* Użyj swojej funkcji szumu do animowania kształtu poprzez przesuwanie go, obracanie lub skalowanie. + +* Zrób animowaną kompozycję kilku kształtów "tańczących" razem przy użyciu szumu. + +* Skonstruuj "organicznie wyglądające" kształty używając funkcji noise. + + + +## Szum 2D + +![](02.png) + +Teraz, gdy wiemy jak zrobić szum w 1D, czas przejść do 2D. W 2D zamiast interpolować między dwoma punktami linii (``rand(x)`` i ``rand(x)+1.0``), będziemy interpolować pomiędzy czterema narożnikami kwadratowego obszaru płaszczyzny (``rand(st)``, ``rand(st)+vec2(1.,0.)``, ``rand(st)+vec2(0.,1.)`` oraz ``rand(st)+vec2(1.,1.)``). + + + +![](01.png) + +Podobnie, jeśli chcemy uzyskać szum 3D musimy interpolować pomiędzy ośmioma rogami sześcianu. W tej technice chodzi o interpolację losowych wartości ang. (ang. "random **value**s"), dlatego nazywa się ją **value noise**. + + + +![](04.jpg) + +Podobnie jak w przykładzie 1D, interpolacja ta nie jest liniowa, ale sześcienna, więc płynnie interpoluje wszelkie punkty wewnątrz naszego kwadratowego obszaru. + + + +![](05.jpg) + +Przyjrzyj się następującej funkcji szumu. + + + +
+ +Zaczynamy od przeskalowania przestrzeni o 5 (linia 45). Następnie wewnątrz funkcji szumu dzielimy przestrzeń na kafellki. Przechowujemy pozycję kafelka jako cześć całkowitą oraz pozycje wewnątrz kafelka jako część ułamkową. Używamy części całkowitej do obliczenia współrzędnych czterech narożników, otrzymując losową wartość dla każdego z nich (linie 23-26). Na koniec, w linii 35 interpolujemy pomiędzy 4 losowymi wartościami narożników używając części ułamkowej. + + + +Teraz twoja kolej. Spróbuj wykonać następujące ćwiczenia: + +* Zmień mnożnik w linii 45. Spróbuj go zanimować. + +* Przy jakim poziomie powiększenia szum zaczyna znowu wyglądać kompletnie losowo (jak, wspomniany na początku rozdziału, biały szum)? + +* Przy jakim poziomie powiększenia szum jest niezauważalny? + +* Spróbuj podpiąć tę funkcję szumu do współrzędnych myszy. + +* A gdyby tak potraktować gradient szumu jako pole odległości? Zrób z tym coś ciekawego. + +* Teraz, gdy osiągnąłeś już pewną kontrolę nad porządkiem i chaosem, czas wykorzystać tę wiedzę. Stwórz kompozycję z prostokątów, kolorów i szumu, która przypomina nieco złożoność obrazu [Marka Rothko](http://en.wikipedia.org/wiki/Mark_Rothko). + + + +![Mark Rothko - Three (1950)](rothko.jpg) + +## Szum a design generatywny + +Algorytmy szumu zostały pierwotnie zaprojektowane w celu nadania naturalnego *je ne sais quoi* cyfrowym teksturom. Implementacje 1D i 2D, które widzieliśmy do tej pory, były interpolacjami pomiędzy losowymi *wartościami*, dlatego nazywane są **Value Noise**, ale istnieje więcej sposobów na uzyskanie szumu... + + + +[ ![Inigo Quilez - Value Noise](value-noise.png) ](../edit.php#11/2d-vnoise.frag) + +Jak odkryłeś w poprzednich ćwiczeniach, value noise ma tendencję do wyglądania "blokowo". Aby zmniejszyć ten blokowy efekt, w 1985 roku [Ken Perlin](https://mrl.nyu.edu/~perlin/) opracował inną implementację algorytmu o nazwie **Gradient Noise**. Ken wymyślił jak interpolować losowe *gradienty* zamiast wartości. Gradienty te były wynikiem funkcji losowej 2D, która zwraca kierunki (reprezentowane przez ``vec2``) zamiast pojedynczych wartości (``float``). Kliknij na poniższy obrazek, aby zobaczyć kod i sposób jego działania. + + + +[ ![Inigo Quilez - Gradient Noise](gradient-noise.png) ](../edit.php#11/2d-gnoise.frag) + +Poświęć chwilę na przyjrzenie się tym dwóm przykładom autorstwa [Inigo Quilez](http://www.iquilezles.org/) i zwróć uwagę na różnice pomiędzy [value noise](https://www.shadertoy.com/view/lsf3WH) a [gradient noise](https://www.shadertoy.com/view/XdXGW8). + +Podobnie jak malarz, który rozumie, jak działają pigmenty jego farb, im więcej wiemy o implementacjach szumu, tym lepiej będziemy mogli z nich korzystać. Na przykład, jeśli użyjemy dwuwymiarowej implementacji szumu do obrócenia przestrzeni, w której renderowane są linie proste, możemy uzyskać następujący drewno-podobny efekt. Ponownie możesz kliknąć na obrazek, aby zobaczyć, jak wygląda kod. + + + +[ ![Wood texture](wood-long.png) ](../edit.php#11/wood.frag) + +```glsl + pos = rotate2d( noise(pos) ) * pos; // obracanie przestrzeni + pattern = lines(pos,.5); // rysowanie linii +``` + +Innym sposobem na uzyskanie ciekawych wzorów z szumu jest potraktowanie go jak pola odległości i zastosowanie niektórych sztuczek opisanych w rozdziale [Kształty](../07/). + + + +[ ![Splatter texture](splatter-long.png) ](../edit.php#11/splatter.frag) + +```glsl + color += smoothstep(.15,.2,noise(st*10.)); // Czarny rozprysk + color -= smoothstep(.35,.4,noise(st*10.)); // Dziury w rozprysku +``` + +Trzecim sposobem wykorzystania funkcji szumu jest modulowanie kształtu. To również wymaga pewnych technik, które poznaliśmy w [rozdziale o kształtach](../07/). + + + + + +Do poćwiczenia: + +* Jaki inny wzór generatywny możesz stworzyć? Co z granitem? marmurem? magmą? wodą? Znajdź trzy zdjęcia interesujących Cię tekstur i zaimplementuj je algorytmicznie za pomocą szumu. +* Użyj szumu do modulacji kształtu. +* A co z wykorzystaniem szumu do ruchu? Wróć do rozdziału [Macierze](../08/). Użyj przykładu z translacją kształtu "+" i zastosuj do niego kilka *losowych* i *szumowych* ruchów. +* Zrób generatywnego Jacksona Pollocka. + + + +![Jackson Pollock - Number 14 gray (1948)](pollock.jpg) + +## Lepszy szum + +Ulepszenie oryginalnego szumu Perlina, zwane **Simplex Noise**, polega na zastąpieniu sześciennej krzywej Hermite'a ( _f(x) = 3x^2-2x^3_ , która jest identyczna z funkcją [``smoothstep()``](../glossary/?search=smoothstep)) kwintową krzywą interpolacyjną ( _f(x) = 6x^5-15x^4+10x^3_ ). Dzięki temu oba końce krzywej są bardziej "płaskie", więc każda granica z wdziękiem zszywa się z następną. Innymi słowy, otrzymujesz bardziej ciągłe przejście między komórkami. Możesz to zobaczyć, odkomentowując drugą formułę w poniższym przykładzie wykresu (lub zobacz [dwa równania obok siebie tutaj](https://www.desmos.com/calculator/2xvlk5xp8b)). + + + +
+ +Zauważ, jak zmieniają się końce krzywej. Więcej na ten temat możesz usłyszeć [z ust Kena Perlina](http://mrl.nyu.edu/~perlin/paper445.pdf). + + + + +## Simplex Noise + +Dla Kena Perlina sukces jego algorytmu nie był wystarczający. Uważał, że może on działać lepiej. Na Siggraph 2001 zaprezentował "simplex noise", w którym osiągnął następujące ulepszenia w stosunku do poprzedniego algorytmu: + +* Algorytm o mniejszej złożoności obliczeniowej i mniejszej liczbie mnożeń. +* Szum, który skaluje się do wyższych wymiarów przy mniejszym koszcie obliczeniowym. +* Szum bez artefaktów kierunkowych. +* Szum z dobrze zdefiniowanymi i ciągłymi gradientami, o niskim koszcie obliczeniowym. +* Algorytm, który jest łatwy do zaimplementowania w hardware'rze. + + + +Wiem, co myślisz... "Kim jest ten człowiek?" Tak, jego praca jest fantastyczna! Ale poważnie, w jaki sposób ulepszył ten algorytm? Cóż, widzieliśmy jak dla dwóch wymiarów interpolował 4 punkty (rogi kwadratu); możemy więc poprawnie zgadnąć, że dla [trzech (zobacz implementację tutaj)](../edit.php#11/3d-noise.frag) i czterech wymiarów musimy interpolować 8 i 16 punktów. Prawda? Innymi słowy dla N wymiarów musisz płynnie interpolować 2 do N punktów (2^N). Ale Ken sprytnie zauważył, że chociaż oczywistym wyborem dla kształtu wypełniającego przestrzeń jest kwadrat, najprostszym kształtem w 2D jest trójkąt równoboczny. Zaczął więc od zastąpienia siatki kwadratowej (niedawno nauczyliśmy się jej używać) siatką trójkątów równobocznych (inaczej zwaną *siatką sympleksową*). + + + +![](simplex-grid-00.png) + +Kształt dla N wymiarów to kształt z N + 1 wierzchołkami. Innymi słowy jeden wierzchołek mniej do obliczenia w 2D, 4 wierzchołki mniej w 3D i 11 wierzchołków mniej w 4D! To ogromna poprawa! + +W dwóch wymiarach interpolacja odbywa się podobnie do zwykłego szumu, poprzez interpolację wartości wierzchołków odcinka. Ale w tym przypadku, dzięki zastosowaniu siatki sympleksowej, musimy tylko interpolować sumę 3 wierzchołków. + + + +![](simplex-grid-01.png) + +Jak powstaje siatka sympleksowa? W kolejnym błyskotliwym i eleganckim posunięciu, można ją uzyskać poprzez podział kwadratowych kafelków na dwa trójkąty równoramienne, a następnie przekrzywienia ich, aż każdy trójkąt będzie równoboczny. Proces ten szerzej opisany jest w [artykule Stefana Gustavsona](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf). + + + +![](simplex-grid-02.png) + + + + + + +W poniższym kodzie możesz odkomentować linię 44, aby zobaczyć jak siatka jest przekrzywiona, a następnie odkomentować linię 47, aby zobaczyć siatkę simpleksową. Zauważ jak w linii 22 dzielimy przekrzywiony kwadrat na dwa trójkąty równoboczne poprzez wykrycie czy ``x > y`` (dolny" trójkąt) lub ``y > x`` (górny" trójkąt). + +
+ + + +Wszystkie te ulepszenia skutkują algorytmicznym arcydziełem, jakim jest **Simplex Noise**. Poniżej znajduje się implementacja GLSL tego algorytmu wykonana przez Iana McEwana i Stefana Gustavsona (i przedstawiona w [tym artykule](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)), która w celach edukacyjnych jest nadmiernie skomplikowana , ale przekonasz się, że jest też mniej enigmatyczna niż można by się spodziewać, a kod jest krótki i szybki. + +[ ![Ian McEwan of Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.php#11/2d-snoise-clear.frag) + +Cóż... dość technicznych rozważań, czas na wykorzystanie tego narzędzia we własny, ekspresyjny sposób: + +* Kontempluj, jak wygląda każda implementacja szumu. Wyobraź sobie je jako surowy materiał, jak marmurowy kamień dla rzeźbiarza. Co możesz powiedzieć o "uczuciu", jakie ma każda z nich? Zmruż oczy, aby uruchomić wyobraźnię, tak jak wtedy, gdy chcesz znaleźć kształty w chmurze. Co widzisz? Co ci się przypomina? W co każda implementacja szumu mogłaby zostać przeobrażana? Podążając za swoją intuicją, spróbuj zrealizować to w kodzie. + +* Zrób shader, który tworzy iluzję przepływu. Jak lampa lawowa, krople atramentu, woda itp. + + + + + +* Użyj Simplex Noise, aby dodać trochę tekstury do pracy, którą już wykonałeś. + + + + + +W tym rozdziale wprowadziliśmy pewną kontrolę nad chaosem. Nie była to łatwa praca! Zostanie zaklinaczem chaosu wymaga czasu i wysiłku. + +W następnych rozdziałach zobaczymy kilka dobrze znanych technik, które pozwolą ci udoskonalić swoje umiejętności i wydobyć więcej z szumu, aby zaprojektować wysokiej jakości generatywne dzieła za pomocą shaderów. Do tego czasu ciesz się czasem na zewnątrz, kontemplując naturę i jej zawiłe wzory. Twoja umiejętność obserwacji wymaga równego (a może nawet większego) poświęcenia niż twoje umiejętności tworzenia. Wyjdź na zewnątrz i ciesz się resztą dnia! + + + +

"Talk to the tree, make friends with it." Bob Ross +

diff --git a/12/README-pl.md b/12/README-pl.md new file mode 100644 index 0000000..beae7b5 --- /dev/null +++ b/12/README-pl.md @@ -0,0 +1,287 @@ +![](dragonfly.jpg) + +## Cellular Noise (pol. "szum komórkowy") + +W 1996 roku, szesnaście lat po oryginalnym algorytmie szumu Perlina i pięć lat przed jego Simplex Noise, [Steven Worley napisał pracę zatytułowaną "A Cellular Texture Basis Function"](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Opisuje w niej technikę teksturowania proceduralnego, która jest obecnie szeroko stosowana przez grafików. + +Aby zrozumieć jej zasady, musimy zacząć myśleć w kategoriach **iteracji**. Zapewne wiesz, co to oznacza: używanie pętli ``for``. Jest tylko jeden haczyk z pętlami ``for`` w GLSL: warunek, który sprawdzamy musi być stałą (``const``). Tak więc nie ma dynamicznych pętli - liczba iteracji musi być stała. + +Przyjrzyjmy się przykładowi. + + + +### Punkty w polu odległości + +Cellular Noise opiera się na polach odległości, a dokładniej odległości do najbliższego ze zbioru punktów. Załóżmy, że chcemy stworzyć pole odległości składające się z 4 punktów. Co musimy zrobić? Cóż, **dla każdego piksela chcemy obliczyć odległość do najbliższego punktu**. Oznacza to, że musimy iterować po wszystkich punktach, obliczać ich odległości do bieżącego piksela i przechować odległość do tego najbliższego. + + + +```glsl + float min_dist = 100.; // Zmienna przechowująca odległość do najbliższego punktu + + min_dist = min(min_dist, distance(st, point_a)); + min_dist = min(min_dist, distance(st, point_b)); + min_dist = min(min_dist, distance(st, point_c)); + min_dist = min(min_dist, distance(st, point_d)); +``` + + + +![](cell-00.png) + +Nie jest to zbyt eleganckie, ale załatwia sprawę. Teraz zaimplementujmy go ponownie, używając tablicy i pętli ``for``. + + + +```glsl + float m_dist = 100.; // minimum distance + for (int i = 0; i < TOTAL_POINTS; i++) { + float dist = distance(st, points[i]); + m_dist = min(m_dist, dist); + } +``` + +Zauważ, jak używamy pętli ``for`` do iteracji po tablicy punktów i funkcji [``min()``](../glossary/?search=min) do śledzenia odległości do najbliższego punktu. Oto krótka działająca implementacja tego pomysłu: + + + +
+ +W powyższym kodzie jeden z punktów jest przypisany do pozycji myszy. Pobaw się nim, abyś mógł zrozumieć intuicję stojącą za tym kodem. Następnie spróbuj ćwiczeń: + +- Jak można animować pozostałe punkty? +- Po przeczytaniu [rozdziału o kształtach](../07/), wyobraź sobie ciekawe sposoby wykorzystania tego pola odległości! +- Co, jeśli chcemy dodać więcej punktów do tego pola odległości? Co jeśli chcemy dynamicznie dodawać/odejmować punkty? + + + +### Kafelkowanie i iteracja + +Zapewne zauważyłeś, że pętle ``for`` i tablice nie są zbyt dobrymi przyjaciółmi GLSL. Jak już wspomnieliśmy, pętle nie akceptują dynamicznych warunków wyjścia. Ponadto, iteracja przez wiele instancji znacznie zmniejsza wydajność twojego shadera. Oznacza to, że nie możemy użyć tego prostego, brute-force'owego podejścia dla dużych ilości punktów. Musimy znaleźć inną strategię, taką, która wykorzystuje architekturę przetwarzania równoległego GPU. + + + +![](cell-01.png) + +Jednym ze sposobów podejścia do tego problemu jest podzielenie przestrzeni na rozłączne obszary/komórki. Nie każdy piksel musi sprawdzać odległość do każdego punktu, prawda? Biorąc pod uwagę fakt, że każdy piksel działa w swoim własnym wątku, możemy podzielić przestrzeń na komórki, z których każda ma jeden unikalny punkt do oglądania. Ponadto, aby uniknąć aberracji na krawędziach między komórkami musimy sprawdzić odległości do punktów w sąsiednich komórkach. Jest to główna idea [artykułu Stevena Worleya](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Ostatecznie każdy piksel musi sprawdzić tylko dziewięć pozycji: punkt własnej komórki i punkty w 8 komórkach wokół niego. Dzieliliśmy już przestrzeń na komórki w rozdziałach o: [wzorach kafelkowych](../09/), [losowości](../10/) i [szumie](../11/), więc mam nadzieję, że jesteś już zaznajomiony z tą techniką. + + + +```glsl + // skalowanie + st *= 3.; + + // dzielenie przestrzeni na kafelki + vec2 i_st = floor(st); + vec2 f_st = fract(st); +``` + +Jaki jest więc plan? Użyjemy współrzędnych kafelka (przechowywanych w części całkowitej, ``i_st``) do skonstruowania losowej pozycji punktu. Funkcja ``random2f``, której użyjemy, przyjmuje ``vec2`` i zwraca ``vec2`` z losową pozycją (o wartościach z zakresu od 0.0 do 1.0). Tak więc, dla każdego kafla będziemy mogli otrzymać jeden punkt losowo położony wewnątrz tego kafla. + + + +```glsl + vec2 point = random2(i_st); +``` + +Każdy piksel wewnątrz tego kafla (przechowywany w części ułamkowej, ``f_st``) sprawdzi swoją odległość do tego nowego, losowego punktu. + + + +```glsl + vec2 diff = point - f_st; + float dist = length(diff); +``` + +Wynik będzie wyglądał tak: + + + + + +Musimy też sprawdzić odległości do punktów w okolicznych kafelkach, a nie tylko do tego w bieżącym kafelku. W tym celu **iterujemy** po sąsiednich kafelkach. Nie po wszystkich kafelkach, tylko po tych bezpośrednio otaczających bieżącego. Czyli od ``-1`` (lewy) do ``1`` (prawy) na osi ``x`` oraz od ``-1`` (dolny) do ``1`` (górny) na osi ``y``. Region 3x3 składający się z 9 kafelków może być iterowany przy użyciu podwójnej pętli ``for``, jak poniżej: + + + +```glsl +for (int y= -1; y <= 1; y++) { + for (int x= -1; x <= 1; x++) { + // Względne położenie sąsiadującego kafelka + vec2 neighbor = vec2(float(x),float(y)); + ... + } +} +``` + +![](cell-02.png) + +Teraz możemy obliczyć położenie punktów w każdym z sąsiadujących kafelków z pomocą podwójnej pętli ``for``, dodając przesunięcie sąsiedniego kafelka (``neighbor``) do współrzędnej bieżącego kafelka (``i_st``). + + + +```glsl + ... + // Losowe położenie punktu wewnątrz sąsiedniego kafelka + vec2 point = random2(i_st + neighbor); + ... +``` + + + +Reszta polega na obliczeniu odległości do każdego z sąsiednich punktów i zapisaniu najmniejszej odległości w zmiennej o nazwie ``m_dist`` (z ang. "minimal distance"). + + + +```glsl + ... + vec2 diff = neighbor + point - f_st; + + // Odległość do punktu + float dist = length(diff); + + // Zachowaj mniejszą odległość + m_dist = min(m_dist, dist); + ... +``` + + + +Powyższy kod jest inspirowany [artykułem Inigo Quileza](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm), w którym zauważa, jak problemy z precyzją bitową mogą być uniknięte poprzez przejście do stosowanej już przez nas przestrzeni kafelkowej (w przeciwieństwie do robienia obliczeń w domyślnych współrzędnych, niepodzielonych na części całkowite i ułamkowe): + + + + +Podsumowując: dzielimy przestrzeń na kafelki; każdy piksel liczy odległość do punktu w swoim własnym kafelku i odległość do punktów z otaczających go 8 kafelków; przechowuje najbliższą odległość. Wynikiem jest pole odległości, które wygląda jak w poniższym przykładzie: + + + +
+ +Eksploruj tę ideę dalej: + +- Przeskaluj przestrzeń o różne wartości. +- Czy możesz wymyślić inne sposoby animacji punktów? +- Co jeśli chcemy obliczyć dodatkowy punkt z pozycji myszy? +- Jakie inne sposoby konstruowania tego pola odległości możesz sobie wyobrazić, poza ``m_dist = min(m_dist, dist);``? +- Jakie ciekawe wzory można stworzyć za pomocą tego pola odległości? + + + +Algorytm ten można również interpretować z perspektywy punktów, a nie bieżących pikseli. W takim przypadku można go opisać jako: każdy punkt rośnie, dopóki nie znajdzie rosnącego obszaru innego punktu. Odzwierciedla to niektóre z zasad wzrostu w naturze. Żywe formy kształtowane są przez napięcie między wewnętrzną siłą do rozszerzania się i wzrostu oraz zewnętrznymi siłami ograniczającymi. Klasyczny algorytm symulujący to zachowanie nazwany został za [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy). + + + +![](monokot_root.jpg) + +### Algorytm Voronoi + +Konstruowanie diagramów Voronoi z szumu komórkowego jest mniej trudne niż mogłoby się wydawać. Musimy tylko *zachować* pewną dodatkową informację o punkcie, który jest najbliżej bieżącego piksela. Do tego celu użyjemy ``vec2`` o nazwie ``m_point`` (z ang. "minimal point"). Przechowując wektor od bieżącego piksela do najbliższego punktu (zamiast samej odległości) będziemy "przechowywać" "unikalny" identyfikator tego punktu. + + + +```glsl + ... + if( dist < m_dist ) { + m_dist = dist; + m_point = point; + } + ... +``` + +Zauważ, że w poniższym kodzie nie używamy już ``min`` do obliczania najbliższej odległości, ale zwykłegpo warunku ``if``. Dlaczego? Ponieważ chcemy zrobić coś więcej za każdym razem, gdy pojawi się nowy bliższy punkt, a mianowicie zapisać jego pozycję (linie 32 do 37). + + + +
+ +Zauważ, jak kolor ruchomej komórki (związanej z pozycją myszy) zmienia kolor w zależności od jej położenia. To dlatego, że kolor jest przypisywany przy użyciu wartości (pozycji) najbliższego punktu. + +Podnieśmy poprzeczkę, przechodząc na podejście z [artykułu Stevena Worleya](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Spróbuj zaimplementować to samodzielnie. Możesz skorzystać z pomocy poniższego przykładu, klikając na niego. Zauważ, że oryginalne podejście Stevena Worleya używa zmiennej liczby punktów dla każdego kafla, więcej niż jeden w większości kafli. W tej jego nie-shaderowej implementacji (bo w C, a nie w GLSL) pomaga to przyspieszyć pętlę poprzez wczesne jej opuszczanie. Pętle GLSL nie pozwalają na zmienną liczbę iteracji, więc prawdopodobnie chcesz trzymać się jednego punktu na kafelek. + + + + + +Gdy już rozgryziesz ten algorytm, pomyśl o ciekawych i kreatywnych jego zastosowaniach. + + + +![Extended Voronoi - Leo Solaas (2011)](solas.png) + +![Cloud Cities - Tomás Saraceno (2011)](saraceno.jpg) + +![Accretion Disc Series - Clint Fulkerson](accretion.jpg) + +![Vonoroi Puzzle - Reza Ali (2015)](reza.png) + +### Ulepszenie Voronoi + +W 2011 roku [Stefan Gustavson zoptymalizował algorytm Stevena Worleya](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) pod GPU, iterując tylko przez macierz 2x2 zamiast 3x3. To znacznie zmniejsza ilość pracy, ale może tworzyć artefakty w postaci nieciągłości na krawędziach między kafelkami. Przyjrzyj się poniższym przykładom. + + + +
+ +Później w 2012 roku [Inigo Quilez napisał artykuł o tym, jak zrobić Voronoi z ostrymi granicami](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm). + + + + + +Eksperymenty Inigo z Voronoi nie skończyły się na tym. W 2014 roku napisał artykuł o tym, co nazywa [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm). Jest to funkcja, która pozwala na stopniowe interpolowanie między zwykłym szumem a Voronoi. Jego słowami: + +*"Pomimo tego podobieństwa, faktem jest, że sposób użycia kafelkowania w obu metodach jest inny. Szum interpoluje/uśrednia wartości losowe (jak w Value Noise) lub gradienty (jak w Gradient Noise), podczas gdy Voronoi oblicza odległość do najbliższego punktu w kafelku. Interpolacja dwuliniowa* (ang. "bilinear") *i wartość minimalna to dwie bardzo różne operacje, ale czy na pewno? Czy można je połączyć w bardziej ogólną metrykę? Gdyby tak było, to zarówno szum jak i Voronoi mogłyby być postrzegane jako szczególne przypadki bardziej ogólnego generatora wzorów kafelkowych?"*. + + + + + +Teraz nadszedł czas, abyś przyjrzał się bliżej rzeczom, zainspirował się naturą i znalazł swoje własne ujęcie tej techniki! + + + +![Deyrolle glass film - 1831](DeyrolleFilm.png) + +
diff --git a/13/README-pl.md b/13/README-pl.md new file mode 100644 index 0000000..a5cc970 --- /dev/null +++ b/13/README-pl.md @@ -0,0 +1,155 @@ +![Due East over Shadequarter Mountain - Matthew Rangel (2005) ](rangel.jpg) + +## Fractal Brownian Motion (pol. "fraktalne ruchy Browna") + +Szum zwykle oznacza różne rzeczy dla różnych ludzi. Muzycy będą myśleć o nim w kategoriach przeszkadzających dźwięków, komunikatorzy jako o zakłóceniach, a astrofizycy jako o kosmicznym mikrofalowym promieniowaniu tła. Te koncepcje sprowadzają nas z powrotem do fizycznych przyczyn losowości w otaczającym nas świecie. Zacznijmy jednak od czegoś bardziej podstawowego i prostszego: od fal i ich właściwości. Fala jest fluktuacją w czasie jakiejś właściwości. Fale dźwiękowe to fluktuacje ciśnienia powietrza, fale elektromagnetyczne to fluktuacje pola elektrycznego i magnetycznego. Dwie ważne cechy fali to jej amplituda i częstotliwość. Równanie dla prostej liniowej (jednowymiarowej) fali wygląda tak: + + + +
+ +* Spróbuj zmienić wartości częstotliwości i amplitudy, aby zrozumieć, jak się zachowują. +* Używając shaping functions, spróbuj zmienić amplitudę w czasie. +* Używając shaping functions, spróbuj zmienić częstotliwość w czasie. + + + +Wykonując dwa ostatnie ćwiczenia udało Ci się "zmodulować" sinusoidę i właśnie stworzyłeś fale AM (modulowane amplitudą, ang. "amplitude modulated") i FM (modulowane częstotliwością, ang. "frequency modulated"). Gratulacje!!! + +Inną ciekawą właściwością fal jest ich zdolność do sumowania się, co formalnie nazywa się superpozycją. Skomentuj/odkomentuj i zmodyfikuj poniższe linijki. Zwróć uwagę, jak zmienia się ogólny wygląd wykresu, gdy dodajemy do siebie fale o różnych amplitudach i częstotliwościach. + + + +
+ +* Eksperymentuj, zmieniając częstotliwość i amplitudę dla dodatkowych fal. +* Czy jest możliwe, aby dwie fale wzajemnie się zniosły? Jak to będzie wyglądało? +* Czy można dodać fale w taki sposób, że będą się one wzajemnie wzmacniać? + +W muzyce każda nuta jest związana z określoną częstotliwością. Układ częstotliwości tych nut nazywamy skalą, gdzie podwojenie lub zmniejszenie częstotliwości o połowę odpowiada skokowi o jedną oktawę. + + + +Teraz użyjmy szumu Perlina zamiast sinusoidy! Szum Perlina w swojej podstawowej formie wygląda podobnie do sinusoidy. Jego amplituda i częstotliwość różnią się nieco, ale amplituda pozostaje w miarę stała, a częstotliwość jest ograniczona do dość wąskiego zakresu wokół częstotliwości środkowej. Szum nie jest jednak tak regularny jak sinusoida, tym bardziej, gdy zsumujemy jego kilka przeskalowanych wersji. Można sprawić, że suma fal sinusoidalnych również będzie wyglądać na przypadkową, ale potrzeba wielu różnych fal, aby ukryć ich okresową, regularną naturę. + +Poprzez dodanie różnych iteracji szumu (*octaves*, pol. "oktawy"), gdzie kolejno zwiększamy częstotliwości w regularnych krokach (*lacunarity*, pol. "lakunarność") i zmniejszamy amplitudę (*gain*, pol. "wzmocnienie"), otrzymamy szum bardziej granularny, zawierający więcej detali. Technikę tę nazwywamy "fractal Brownian Motion" (*fBM*) lub, po prostu "fractal noise" (pol. "szum fraktalny"). W swojej najprostszej postaci, możemy go stworzyć w następujący sposób: + + + +
+ +* Stopniowo zmieniaj liczbę oktaw z 1 do 2, 4, 8 i 10. Zobacz, co się stanie. +* Gdy masz więcej niż 4 oktawy, spróbuj zmienić wartość `lacunarity`. +* Również przy >4 oktawach zmień wartość `gain` i zobacz, co się stanie. + + + +Zauważ, że z każdą dodatkową oktawą krzywa wydaje się być bardziej szczegółowa. Zauważ też, że w miarę dodawania kolejnych oktaw występuje efekt samopodobieństwa - jeśli powiększysz krzywą, powiększona część wygląda mniej więcej tak samo jak całość, a każda powiększona część wygląda mniej więcej tak samo jak każda inna. Jest to ważna właściwość fraktali matematycznych, a my symulujemy tę właściwość w naszej pętli. Nie tworzymy *prawdziwego* fraktala, ponieważ zatrzymujemy sumowanie po kilku iteracjach, ale teoretycznie rzecz biorąc, uzyskalibyśmy prawdziwy fraktal matematyczny, gdybyśmy pozwolili pętli trwać w nieskończoność i dodawali nieskończoną liczbę składowych szumu. W grafice komputerowej zawsze mamy limit najmniejszych szczegółów, które możemy wyrenderować, gdyż obiekty stają się mniejsze niż piksel, więc nie ma potrzeby wykonywania nieskończonych sum, aby stworzyć wygląd fraktala. Czasami może być potrzebna duża ilość iteracji, ale nigdy nieskończona liczba. + + + +Poniższy kod jest przykładem tego, jak fBm może być zaimplementowany w dwóch wymiarach, aby stworzyć wzór wyglądający jak fraktal: + + + +
+ +* Zmniejsz liczbę oktaw poprzez zmianę wartości w linii 37 +* Zmodyfikuj `lacunarity` fBm w linii 47 +* Eksploruj zmianę `gain` na linii 48 + + + +Ta technika jest powszechnie używana do konstruowania proceduralnych krajobrazów. Samopodobieństwo fBm jest idealne dla gór, ponieważ procesy erozji, które tworzą góry, działają w sposób, który daje ten rodzaj samopodobieństwa w dużym zakresie skal. Jeśli jesteś zainteresowany tym zastosowaniem, powinieneś koniecznie przeczytać [ten świetny artykuł Inigo Quilesa o zaawansowanym szumie](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm). + + + +![Blackout - Dan Holdsworth (2010)](holdsworth.jpg) + +Używając mniej więcej tej samej techniki, możliwe jest również uzyskanie innych efektów, takich jak **turbulencja**. Jest to w zasadzie fBm, ale skonstruowane z wartości bezwzględnej szumu (wariantu zwracającego również ujemne wartości), aby stworzyć ostre doliny w funkcji. + + + +```glsl +for (int i = 0; i < OCTAVES; i++) { + value += amplitude * abs(snoise(st)); + st *= 2.; + amplitude *= .5; +} +``` + + + +Innym członkiem tej rodziny algorytmów jest **ridge** (pol. "grzbiet"), w którym ostre doliny są odwrócone do góry nogami, tworząc zamiast nich ostre grzbiety: + + + +```glsl + n = abs(n); // Stwórz doliny + n = offset - n; // Odwróć doliny, aby powstały grzbiety + n = n * n; // Zaostrz grzbiety +``` + + + +Innym użytecznym wariantem jest mnożenie składowych szumu zamiast ich dodawania. Interesujące jest również skalowanie kolejnych funkcji szumu za pomocą czegoś, co zależy od poprzednich terminów w pętli. Kiedy robimy takie rzeczy, odchodzimy od ścisłej definicji fraktala i wchodzimy w stosunkowo nieznaną dziedzinę "multifraktali". Multifraktale nie są tak ściśle zdefiniowane matematycznie, ale to nie czyni ich mniej użytecznymi dla grafiki. W rzeczywistości symulacje multifraktalne są bardzo powszechne we współczesnym komercyjnym oprogramowaniu do generowania terenu. Aby przeczytać więcej, możesz przeczytać rozdział 16 książki "Texturing and Modeling: a Procedural Approach" (3. edycja), autorstwa Kentona Musgrave. Niestety, książka ta jest już od kilku lat niedostępna w druku, ale wciąż można ją znaleźć w bibliotekach i na rynku wtórnym. (Istnieje wersja PDF pierwszego wydania dostępna do kupienia online, ale nie kupuj jej - to strata pieniędzy. Jest z 1994 roku i nie zawiera żadnych rzeczy związanych z modelowaniem terenu z 3. edycji). + + + +### Warping (pol. "zakrzywianie") + +[Inigo Quiles napisał też inny fascynujący artykuł](http://www.iquilezles.org/www/articles/warp/warp.htm) o tym jak można użyć fBm do zakrzywienia przestrzeni fBm. Zdumiewające, prawda? To jak sen wewnątrz snu o Incepcji. + + + +![ f(p) = fbm( p + fbm( p + fbm( p ) ) ) - Inigo Quiles (2002)](quiles.jpg) + +Mniej ekstremalnym przykładem tej techniki jest następujący kod, w którym zakrzywienie jest używane do wytworzenia tekstury przypominającej chmury. Zauważ, że właściwość samopodobieństwa jest nadal obecna. + + + +
+ +Zakrzywianie współrzędnych tekstury za pomocą szumu może być bardzo użyteczne, daje dużo frajdy, ale jest diabelnie trudne do opanowania. Jest to potężne narzędzie, ale potrzeba sporo doświadczenia, aby dobrze je wykorzystać. Przydatnym wariantem jest też przemieszczanie współrzędnych za pomocą pochodnej (gradientu) szumu. [Na tym pomyśle opiera się słynny artykuł Kena Perlina i Fabrice'a Neyreta o nazwie "flow noise"](http://evasion.imag.fr/Publications/2001/PN01/). Niektóre nowoczesne implementacje szumu Perlina zawierają wariant, który oblicza zarówno funkcję, jak i jej gradient. Jeśli gradient nie istnieje, zawsze możesz obliczyć skończone różnice (różnica między sąsiadującymi pikselami), aby go przybliżyć, chociaż jest to mniej dokładne i wymaga więcej pracy. + + diff --git a/README-pl.md b/README-pl.md new file mode 100644 index 0000000..2918580 --- /dev/null +++ b/README-pl.md @@ -0,0 +1,121 @@ + + +# The Book of Shaders +*autorstwa [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) i [Jen Lowe](http://jenlowe.net/)* + +Łagodny, krok po kroku przewodnik przez abstrakcyjny i złożony świat Fragment Shaderów. + +
+ +
+ +## Spis treści + +* [O książce](00/) + +* Wprowadzenie + * [Czym jest shader?](01/) + * ["Witaj świecie!"](02/) + * [Uniformy](03/) + * [Uruchomienie shaderu](04/) + +* Rysowanie algorytmiczne + * [Shaping functions](05/) + * [Kolory](06/) + * [Kształty](07/) + * [Macierze](08/) + * [Wzorce](09/) + +* Design generatywny + * [Random](10/) + * [Noise](11/) + * [Cellular noise](12/) + * [Fractal Brownian Motion](13/) + * Fraktale + +* Image processing + * Textures + * Image operations + * Kernel convolutions + * Filters + * Others effects + +* Simulation + * Pingpong + * Conway + * Ripples + * Water color + * Reaction diffusion + +* 3D graphics + * Lights + * Normal-maps + * Bump-maps + * Ray marching + * Environmental-maps (spherical and cube) + * Reflect and refract + +* [Dodatek:](appendix/) Inne sposoby korzystania z tej książki + * [Jak mogę korzystać z tej książki offline?](appendix/00/) + * [Jak uruchomić przykłady na Raspberry Pi?](appendix/01/) + * [Jak wydrukować tę książkę?](appendix/02/) + * [Jak mogę pomóc?](appendix/03/) + * [Wprowadzenie dla biegłych w JavaScript](appendix/04/) by [Nicolas Barradeau](http://www.barradeau.com/) + +* [Galeria przykładów](examples/) + +* [Glosariusz](glossary/) + +## O autorach + +[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentyna) jest nowojorskim artystą i developerem. Bada granice między organicznym a syntetycznym, analogowym a cyfrowym, indywidualnym i kolektywnym. W swojej pracy używa kodu jako ekspresywnego języka, z intencją rozwijania współpracy międzyludzkiej. + +Patricio studiował i praktykował psychoterapię oraz arteterapię. Otrzymał tytuł magistra sztuk pięknych w Design & Technology od Parsons The New School, gdzie aktualnie uczy. Obecnie pracuje jako inżynier graficzny w Mapzen, gdzie tworzy opensource'owe narzędzia do kartografii komputerowej. + +
www - Twitter - GitHub - Vimeo - Flickr
+ +[Jen Lowe](http://jenlowe.net/) jest niezależną data scientist i komunikatorką danych w Datatelling, gdzie łączy ludzi + liczby + słowa. Uczy w ramach programu Design for Social Innovation na SVA, współzałożyła School for Poetic Computation, uczyła matematyki dla artystów w NYU ITP, była badaczką w Spatial Information Design Lab na Uniwersytecie Columbia oraz zgłaszała swoje pomysły do Office of Science and Technology Policy Białego Domu. Przemawiała na SXSW i w Eyeo. Jej pracę opisywały The New York Times i Fast Company. Jej działalność badawcza, pisarska i mównicza eksplorują obietnice oraz implikacje danych i technologii dla społeczeństwa. Obroniła tytuły licencjata matematyki stosowanej oraz magistra informatyki. Często opozycyjna, ale zawsze po stronie miłości. + +
www - Twitter - GitHub
+ +## Podziękowania + +Podziękowania dla [Scott Murray](http://alignedleft.com/) za porady i inspriację. + +Podziękowania dla [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) za wsparcie, dobre pomysły i kod. + +Podziękowania dla [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) i [Sawako](https://twitter.com/sawakohome) za japońskie [tłumaczenie (日本語訳)](?lan=jp) + +Podziękowania dla [Tong Li](https://www.facebook.com/tong.lee.9484) i [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) za chińskie [tłumaczenie (中文版)](?lan=ch) + +Podziękowania dla [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) i [June Kim](https://github.com/rlawns324) za koreańskie [tłumaczenie (한국어)](?lan=kr) + +Podziękowania dla Nahuel Coppero (Necsoft) za hiszpańskie [tłumaczenie (español)](?lan=es) + +Podziękowania dla [Raphaela Protásio](https://github.com/Rawphs) i [Lucas Mendonça](https://github.com/luuchowl) za portugalskie [tłumaczenie (portugues)](?lan=pt) + +Podziękowania dla [Nicolas Barradeau](https://twitter.com/nicoptere) i [Karim Naaji](http://karim.naaji.fr/) za francuskie [tłumaczenie (français)](?lan=fr) + +Podziękowania dla [Andrea Rovescalli](https://www.earove.info) za włoskie [tłumaczenie (italiano)](?lan=it) + +Podziękowania dla [Michael Tischer](http://www.mitinet.de) za niemieckie [tłumaczenie (deutsch)](?lan=de) + +Podziękowania dla [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) za rosyjskie [tłumaczenie (russian)](?lan=ru) + +Podziękowania dla [Vu Phuong Hoang](https://www.facebook.com/vuphuonghoang88) za wietnamskie [tłumaczenie (Tiếng Việt)](?lan=vi) + +Podziękowania dla [Andy Stanton](https://andy.stanton.is/) za naprawę i usprawnienie funkcji [eksportu pdf/epub ](https://thebookofshaders.com/appendix/02/) + +Podziękowania dla każdego, kto [współtworzy](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ten projekt poprzez swoje rady, korekty lub finansowe wsparcie. + +## Zdobądź nowe rozdziały + +Zapisz się do newslettera lub obserwuj na [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) + +
+ diff --git a/appendix/00/README-pl.md b/appendix/00/README-pl.md new file mode 100644 index 0000000..0e67325 --- /dev/null +++ b/appendix/00/README-pl.md @@ -0,0 +1,41 @@ +## Jak mogę korzystać z tej książki offline? + +Powiedzmy, że masz przed sobą długą podróż i chcesz ją wykorzystać do nauczenia się kilku shaderów. W takim przypadku możesz zrobić lokalną kopię tej książki na swoim komputerze i uruchomić lokalny serwer. + +Do tego potrzebujesz tylko PHP, Pythona 3 i Git'a. Na komputerach z systemem macOS i Raspberry Pi Python jest zainstalowany domyślnie, ale musisz jeszcze zainstalować PHP i klienta Git. W tym celu: + + + +Na **MacOSX** musisz mieć zainstalowane [homebrew](http://brew.sh/) by następnie w terminalu uruchomić: + +```bash +brew update +brew upgrade +brew install git php +``` + +Na **Raspberry Pi** potrzebujesz [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), opartej na Debianie dystrybucji Linuxa, by następnie uruchomić: + +```bash +sudo apt-get update +sudo apt-get upgrade +sudo apt-get install git-core glslviewer php +``` + +Gdy masz już wszystko zainstalowane wystarczy uruchomić: + + + +```bash +cd ~ +git clone --recursive https://github.com/patriciogonzalezvivo/thebookofshaders.git +cd thebookofshaders +git submodule foreach git submodule init && git submodule update +php -S localhost:8000 +``` + +Następnie otwórz swoją przeglądarkę na [`http://localhost:8000/`](http://localhost:8000/) diff --git a/appendix/01/README-pl.md b/appendix/01/README-pl.md new file mode 100644 index 0000000..fbd7475 --- /dev/null +++ b/appendix/01/README-pl.md @@ -0,0 +1,28 @@ +## Jak uruchomić przykłady na Raspberry Pi? + +Jeszcze kilka lat temu założenie, że każdy ma komputer z procesorem graficznym było dalekie od prawdy. Teraz większość komputerów ma GPU, ale to wciąż wysoka poprzeczka. + +Dzięki [Fundacji Raspberry Pi](http://www.raspberrypi.org/) nowy typ małych i tanich komputerów nowej generacji (około 35 dolarów za sztukę) trafił do sal lekcyjnych. Co ważniejsze dla celów tej książki, [Raspberry Pi](http://www.raspberrypi.org/) jest wyposażone w przyzwoity procesor graficzny Broadcom, do którego można uzyskać dostęp bezpośrednio z konsoli. Stworzyłem [elastyczne narzędzie do kodowania GLSL na żywo o nazwie **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer), które uruchamia wszystkie przykłady zawarte w tej książce. Program ten automatycznie się odswieża, gdy użytkownik zapisze zmiany w swoim kodzie. Co to oznacza? Możesz edytować shader i za każdym razem, gdy go zapiszesz, shader zostanie ponownie skompilowany i wyrenderowany za Ciebie. + + + +Robiąc lokalną kopię repozytorium tej książki (zobacz poprzedni rozdział) i mając [zainstalowany `glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer), użytkownicy mogą uruchamiać przykłady za pomocą `glslviewer`. Dodając flagę `-l` mogą oni renderować przykład w rogu ekranu, podczas gdy modyfikują go za pomocą dowolnego edytora tekstu (jak `nano`, `pico`, `vi`, `vim` lub `emacs`). Działa to również przy połączeniu przez ssh/sftp. + +Aby zainstalować i skonfigurować to wszystko na Raspberry Pi, po zainstalowaniu [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) (dystrybucja Linuksa oparta na Debianie, stworzona dla Raspberry Pi) i zalogowaniu się, wpisz następujące polecenia: + + + +```bash +sudo apt-get update +sudo apt-get upgrade +sudo apt-get install git-core glslviewer +cd ~ +git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git +cd thebookofshaders +``` diff --git a/appendix/02/README-pl.md b/appendix/02/README-pl.md new file mode 100644 index 0000000..6ac38a8 --- /dev/null +++ b/appendix/02/README-pl.md @@ -0,0 +1,107 @@ +## Jak wydrukować tę książkę? + +Powiedzmy, że nie chcesz nawigować ani wchodzić w interakcje z przykładami i chcesz po prostu mieć starą dobrą książkę tekstową, którą możesz czytać na plaży lub podczas dojazdu do miasta. W takim przypadku możesz wydrukować tę książkę. + + +#### Instalacja programu glslViewer + +Aby wydrukować tę książkę, musisz najpierw ją przetworzyć. W tym celu będziesz potrzebował [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) - konsolowego narzędzia do shaderów, które skompiluje i przekształci przykłady shaderów w obrazy. + + + +W **MacOSX** upewnij się, że masz zainstalowany [homebrew](http://brew.sh/), a następnie w terminalu wykonaj: + + + +```bash +brew install glslviewer +``` + +Na **Raspberry Pi** należy pobrać [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), dystrybucję Linuksa opartą na Debianie, stworzoną dla Raspberry Pi, a następnie wykonać: + + + +```bash +sudo apt-get update +sudo apt-get upgrade +sudo apt-get install git-core glslviewer +``` + +#### Instalacja Pythona 3, silnika Latex i Pandoc + +Do parsowania Markdowna do Latexa, a następnie do pliku PDF użyjemy Xetex Latex Engine i Pandoc. + +W **MacOSX**: + +Pobierz i zainstalluj MacTeX: + + + +```bash +brew cask install mactex-no-gui +``` + +a następnie zainstalowuj [Pandoc](http://johnmacfarlane.net/pandoc/) i Python 3 przez: + + + +```bash +brew install pandoc python +``` + +Na **Raspberry Pi** (Raspbian): + +```bash +sudo apt-get install texlive-xetex pandoc python2.7 +``` + +#### Skompiluj książkę do pdf i wydrukuj ją + +Teraz, gdy masz już wszystko, czego potrzebujesz, nadszedł czas na sklonowanie [repozytorium tej książki](https://github.com/patriciogonzalezvivo/thebookofshaders) i skompilowanie książki. + +W tym celu otwórz jeszcze raz swój terminal i wpisz: + + + +```bash +cd ~ +git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git +cd thebookofshaders +make clean pdf +``` + +Jeśli wszystko pójdzie dobrze, zobaczysz plik `book.pdf`, który możesz przeczytać na swoim ulubionym urządzeniu lub wydrukować. + +#### Skompiluj książkę do postaci epub, aby użyć jej w e-czytniku. + + + +```bash +cd ~ +git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git +cd thebookofshaders +make clean epub +``` + +Wygenerowany `book.epub` może być użyty bezpośrednio, lub przekonwertowany, za pomomocą, na przykład, Calibre, na plik `.mobi` do użytku z Kindle. + + diff --git a/appendix/03/README-pl.md b/appendix/03/README-pl.md new file mode 100644 index 0000000..c0bb318 --- /dev/null +++ b/appendix/03/README-pl.md @@ -0,0 +1,113 @@ +## Jak mogę pomóc? + +Dziękujemy za chęć współpracy! Jest wiele sposobów pomocy: + +- Tłumaczenie treści +- Poprawianie [sekcji ```glosariusz/```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary) +- Edytowanie zawartości +- Dzielenie się swoimi przykładami shaderów poprzez [edytor on-line](http://editor.thebookofshaders.com/) + + + +### Tłumaczenie treści + +Ta książka jest napisana w [języku Markdown](https://daringfireball.net/projects/markdown/syntax), więc bardzo łatwo jest ją edytować i pracować nad nią. + +1. Zacznij od przejścia do [repozytorium github pod adresem ``github.com/patriciogonzalezvivo/thebookofshaders``](https://github.com/patriciogonzalezvivo/thebookofshaders). Przyjrzyj się znajdującym się w nim plikom i folderom. Zauważysz, że treść znajduje się w pliku ``README.md`` oraz innych plikach z dużymi literami jak: ``TITLE.md``, ``SUMMARY.md``, itd. Zauważ również, że tłumaczenia są hostowane w plikach z nazwami kończącymi się na dwie litery reprezentujące język tłumaczenia, na przykład: ``README-jp.md``, ``README-es.md``, itd. + + + +2. Forkuj repozytorium i sklonuj je w swoim komputerze. + +3. Zduplikuj zawartość plików, które chcesz przetłumaczyć. Pamiętaj, aby do plików, nad którymi będziesz pracował, dodać dwie litery nawiązujące do języka, który tłumaczysz. + +4. Przetłumacz treść linijka po linijce (patrz **Uwagi dotyczące tłumaczenia**). + +5. Przetestuj ją (patrz **Testy**). + +6. Pushuj na własny fork githuba, aby następnie zrobić [Pull Request](https://help.github.com/articles/using-pull-requests/) + + + +#### Uwagi dotyczące tłumaczenia + +Nie wymazuj ani nie modyfikuj rzeczy w osadzonych przykładach, wyglądających tak: + + + +```html +
+``` + +lub + +```html +
+``` + +#### Testowanie + +Rozpocznij uruchamianie lokalnego serwera PHP wewnątrz lokalnego folderu repozytorium: + + + +```bash +php -S localhost:8000 +``` + +Następnie w przeglądarce wyszukaj ``localhost:8000``, przejdź do rozdziału, który tłumaczysz i dodaj ``?lan=``, a następnie dwie litery, których użyłeś do oznaczenia języka, na który tłumaczysz. + +Na przykład, jeśli tłumaczysz rozdział ``03`` na język francuski pracowałeś z plikiem ``03/README-fr.md``, to możesz go przetestować wchodząc na: ``http://localhost:8000/03/?lan=fr`` + + + +### Ulepszanie glosariusza + +Glosariusz jest w trakcie rozwoju. Chętnie wysłuchamy Twoich pomysłów, jak uczynić ją przyjaznym narzędziem dla wszystkich. Wyślij nam wiadomość na adres [@bookofshaders](https://twitter.com/bookofshaders). + +### Edycja treści + +Wszyscy jesteśmy ludźmi. Jeśli widzisz błąd, daj znać i zrób Pull Request lub otwórz Issue. Dzięki! + + + +### Dzielenie się przykładami shaderów + +Zobaczysz wiele linków do [edytora on-line](http://editor.thebookofshaders.com/) i jego osadzonych instancji. +Gdy zakodujesz coś, co sprawi, że będziesz dumny, kliknij "Export" (lub ikonę ``⇪``), a następnie skopiuj "URL to code...". Wyślij go do [@bookofshaders](https://twitter.com/bookofshaders) lub [@kyndinfo](https://twitter.com/kyndinfo). Czekamy na nie i dodamy je do [działu galeria przykładów](https://thebookofshaders.com/examples/). + + diff --git a/appendix/README-pl.md b/appendix/README-pl.md new file mode 100644 index 0000000..5f0c4e0 --- /dev/null +++ b/appendix/README-pl.md @@ -0,0 +1,32 @@ +# Dodatek + +1. [Jak mogę nawigować po tej książce w trybie off-line?](00/) + +2. [Jak uruchomić przykłady na Raspberry Pi?](01/) + +3. [Jak wydrukować tę książkę?](02/) + +4. [Jak współpracować przy tworzeniu tej książki?](03/) + +5. [Wprowadzenie dla osób pochodzących z JS](04/) autorstwa [Nicolas Barradeau](http://www.barradeau.com/) + +6. [Wprowadzenie dla wektorów](05/) autorstwa ... + +7. [Wprowadzenie do interpolacji](06) przez ... + + +