Merge pull request #389 from WojtekPachowiak/master
Polish translation of The Book of Shaderspull/395/head
commit
9518ea2ff2
@ -0,0 +1,50 @@
|
||||
# Wprowadzenie
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="cmyk-halftone.frag" data-textures="vangogh.jpg" width="700px" height="320px"></canvas>
|
||||
|
||||
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.
|
||||
|
@ -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.
|
||||
|
||||
<!-- Usually the "Hello world!" example is the first step to learning a new language. It's a simple one-line program that outputs an enthusiastic welcoming message and declares opportunities ahead. -->
|
||||
|
||||
W świecie GPU renderowanie tekstu jest jednak zbyt skomplikowanym zadaniem dla żółtodzioba. Zamiast tego wybierzemy jasny, serdeczny kolor by wykrzyczeć naszą ekscytację!
|
||||
|
||||
<!-- In GPU-land rendering text is an overcomplicated task for a first step, instead we'll choose a bright welcoming color to shout our enthusiasm! -->
|
||||
|
||||
<div class="codeAndCanvas" data="hello_world.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- If you are reading this book in a browser the previous block of code is interactive. That means you can click and change any part of the code you want to explore. Changes will be updated immediately thanks to the GPU architecture that compiles and replaces shaders *on the fly*. Give it a try by changing the values on line 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).
|
||||
|
||||
<!-- Although these simple lines of code don't look like a lot, we can infer substantial knowledge from them:
|
||||
|
||||
1. Shader Language has a single `main` function that returns a color at the end. This is similar to C.
|
||||
|
||||
2. The final pixel color is assigned to the reserved global variable `gl_FragColor`.
|
||||
|
||||
3. This C-flavored language has built in *variables* (like `gl_FragColor`), *functions* and *types*. In this case we've just been introduced to `vec4` that stands for a four dimensional vector of floating point precision. Later we will see more types like `vec3` and `vec2` together with the popular: `float`, `int` and `bool`.
|
||||
|
||||
4. If we look closely to the `vec4` type we can infer that the four arguments respond to the RED, GREEN, BLUE and ALPHA channels. Also we can see that these values are *normalized*, which means they go from `0.0` to `1.0`. Later, we will learn how normalizing values makes it easier to *map* values between variables.
|
||||
|
||||
5. Another important *C feature* we can see in this example is the presence of preprocessor macros. Macros are part of a pre-compilation step. With them it is possible to `#define` global variables and do some basic conditional operation (with `#ifdef` and `#endif`). All the macro commands begin with a hashtag (`#`). Pre-compilation happens right before compiling and copies all the calls to `#defines` and check `#ifdef` (is defined) and `#ifndef` (is not defined) conditionals. In our "hello world!" example above, we only insert the line 2 if `GL_ES` is defined, which mostly happens when the code is compiled on mobile devices and browsers. -->
|
||||
|
||||
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).
|
@ -0,0 +1,165 @@
|
||||
## Macierze 2D
|
||||
|
||||
<canvas id="custom" class="canvas" data-fragment-url="matrix.frag" width="700px" height="200px"></canvas>
|
||||
|
||||
### 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.
|
||||
|
||||
<!-- In the previous chapter we learned how to make some shapes - the trick to moving those shapes is to move the coordinate system itself. We can achieve that by simply adding a vector to the ```st``` variable that contains the location of each fragment. This causes the whole space coordinate system to move. -->
|
||||
|
||||
![](translate.jpg)
|
||||
|
||||
Łatwiej jest to zobaczyć niż wytłumaczyć, zatem:
|
||||
|
||||
*Odkomentuj linijkę 35 poniższego kodu, by zobaczyć jak przestrzeń się przesuwa.
|
||||
|
||||
<!-- This is easier to see than to explain, so to see for yourself:
|
||||
|
||||
* Uncomment line 35 of the code below to see how the space itself moves around. -->
|
||||
|
||||
<div class="codeAndCanvas" data="cross-translate.frag"></div>
|
||||
|
||||
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:
|
||||
|
||||
<!-- Now try the following exercise:
|
||||
|
||||
* Using ```u_time``` together with the shaping functions move the small cross around in an interesting way. Search for a specific quality of motion you are interested in and try to make the cross move in the same way. Recording something from the "real world" first might be useful - it could be the coming and going of waves, a pendulum movement, a bouncing ball, a car accelerating, a bicycle stopping.
|
||||
|
||||
### Rotations
|
||||
|
||||
To rotate objects we also need to move the entire space system. For that we are going to use a [matrix](http://en.wikipedia.org/wiki/Matrix_%28mathematics%29). A matrix is an organized set of numbers in columns and rows. Vectors are multiplied by matrices following a precise set of rules in order to modify the values of the vector in a particular way.
|
||||
|
||||
[![Wikipedia entry for Matrix (mathematics) ](matrixes.png)](https://en.wikipedia.org/wiki/Matrix)
|
||||
|
||||
GLSL has native support for two, three and four dimensional matrices: [```mat2```](../glossary/?search=mat2) (2x2), [```mat3```](../glossary/?search=mat3) (3x3) and [```mat4```](../glossary/?search=mat4) (4x4). GLSL also supports matrix multiplication (```*```) and a matrix specific function ([```matrixCompMult()```](../glossary/?search=matrixCompMult)).
|
||||
|
||||
Based on how matrices behave it's possible to construct matrices to produce specific behaviors. For example we can use a matrix to translate a vector: -->
|
||||
|
||||
![](3dtransmat.png)
|
||||
|
||||
Co ciekawsze, możemy użyć macierzy do obrócenia całego układu współrzędnych
|
||||
|
||||
<!-- More interestingly, we can use a matrix to rotate the coordinate system: -->
|
||||
|
||||
![](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)``.
|
||||
|
||||
<!-- Take a look at the following code for a function that constructs a 2D rotation matrix. This function follows the above [formula](http://en.wikipedia.org/wiki/Rotation_matrix) for two dimensional vectors to rotate the coordinates around the ```vec2(0.0)``` point. -->
|
||||
|
||||
```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.
|
||||
|
||||
<!-- According to the way we've been drawing shapes, this is not exactly what we want. Our cross shape is drawn in the center of the canvas which corresponds to the position ```vec2(0.5)```. So, before we rotate the space we need to move shape from the `center` to the ```vec2(0.0)``` coordinate, rotate the space, then finally move it back to the original place. -->
|
||||
|
||||
![](rotate.jpg)
|
||||
|
||||
Co odpowiada ponizszemu kodowi:
|
||||
|
||||
<!-- That looks like the following code: -->
|
||||
|
||||
<div class="codeAndCanvas" data="cross-rotate.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Try the following exercises:
|
||||
|
||||
* Uncomment line 45 of above code and pay attention to what happens.
|
||||
|
||||
* Comment the translations before and after the rotation, on lines 37 and 39, and observe the consequences.
|
||||
|
||||
* Use rotations to improve the animation you simulated in the translation exercise.
|
||||
|
||||
### Scale
|
||||
|
||||
We've seen how matrices are used to translate and rotate objects in space. (Or more precisely to transform the coordinate system to rotate and move the objects.) If you've used 3D modeling software or the push and pop matrix functions in Processing, you will know that matrices can also be used to scale the size of an object. -->
|
||||
|
||||
![](scale.png)
|
||||
|
||||
Na podstawie powyższego wzoru, możemy stworzyć 2D macierz skalowania w GLSL:
|
||||
|
||||
<!-- Following the previous formula, we can figure out how to make a 2D scaling matrix: -->
|
||||
|
||||
```glsl
|
||||
mat2 scale(vec2 _scale){
|
||||
return mat2(_scale.x,0.0,
|
||||
0.0,_scale.y);
|
||||
}
|
||||
```
|
||||
|
||||
<div class="codeAndCanvas" data="cross-scale.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Try the following exercises to understand more deeply how this works.
|
||||
|
||||
* Uncomment line 42 of above code to see the space coordinate being scaled.
|
||||
|
||||
* See what happens when you comment the translations before and after the scaling on lines 37 and 39.
|
||||
|
||||
* Try combining a rotation matrix together with a scale matrix. Be aware that the order matters. Multiply by the matrix first and then multiply the vectors.
|
||||
|
||||
* Now that you know how to draw different shapes, and move, rotate and scale them, it's time to make a nice composition. Design and construct a [fake UI or HUD (heads up display)](https://www.pinterest.com/patriciogonzv/huds/). Use the following ShaderToy example by [Ndel](https://www.shadertoy.com/user/ndel) for inspiration and reference. -->
|
||||
|
||||
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/4s2SRt?gui=true&t=10&paused=true" allowfullscreen></iframe>
|
||||
|
||||
### 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.
|
||||
|
||||
<div class="codeAndCanvas" data="yuv.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- ### Other uses for matrices: YUV color
|
||||
|
||||
[YUV](http://en.wikipedia.org/wiki/YUV) is a color space used for analog encoding of photos and videos that takes into account the range of human perception to reduce the bandwidth of chrominance components.
|
||||
|
||||
The following code is an interesting opportunity to use matrix operations in GLSL to transform colors from one mode to another.
|
||||
|
||||
<div class="codeAndCanvas" data="yuv.frag"></div>
|
||||
|
||||
As you can see we are treating colors as vectors by multiplying them with matrices. In that way we “move” the values around.
|
||||
|
||||
In this chapter we've learned how to use matrix transformations to move, rotate and scale vectors. These transformations will be essential for making compositions out of the shapes we learned about in the previous chapter. In the next chapter we'll apply all we've learned to make beautiful procedural patterns. You will find that coding repetition and variation can be an exciting practice. -->
|
@ -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:
|
||||
|
||||
<!-- ## Patterns
|
||||
|
||||
Since shader programs are executed by pixel-by-pixel no matter how much you repeat a shape the number of calculations stays constant. This means that fragment shaders are particulary suitable for tile patterns.
|
||||
|
||||
[ ![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag)
|
||||
|
||||
In this chapter we are going to apply what we've learned so far and repeat it along a canvas. Like in previous chapters, our strategy will be based on multiplying the space coordinates (between 0.0 and 1.0), so that the shapes we draw between the values 0.0 and 1.0 will be repeated to make a grid.
|
||||
|
||||
*"The grid provides a framework within which human intuition and invention can operate and that it can subvert. Within the chaos of nature patterns provide a constrast and promise of order. From early patterns on pottery to geometric mosaics in Roman baths, people have long used grids to enhance their lives with decoration."* [*10 PRINT*, Mit Press, (2013)](http://10print.org/)
|
||||
|
||||
First let's remember the [```fract()```](../glossary/?search=fract) function. It returns the fractional part of a number, making ```fract()``` in essence the modulo of one ([```mod(x,1.0)```](../glossary/?search=mod)). In other words, [```fract()```](../glossary/?search=fract) returns the number after the floating point. Our normalized coordinate system variable (```st```) already goes from 0.0 to 1.0 so it doesn't make sense to do something like: -->
|
||||
|
||||
```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.
|
||||
|
||||
<!-- But if we scale the normalized coordinate system up - let's say by three - we will get three sequences of linear interpolations between 0-1: the first one between 0-1, the second one for the floating points between 1-2 and the third one for the floating points between 2-3. -->
|
||||
|
||||
<div class="codeAndCanvas" data="grid-making.frag"></div>
|
||||
|
||||
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:
|
||||
|
||||
<!-- Now it's time to draw something in each subspace, by uncommenting line 27. (Because we are multiplying equally in x and y the aspect ratio of the space doesn't change and shapes will be as expected.)
|
||||
|
||||
Try some of the following exercises to get a deeper understanding: -->
|
||||
|
||||
* 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
|
||||
|
||||
<!-- * Multiply the space by different numbers. Try with floating point values and also with different values for x and y.
|
||||
|
||||
* Make a reusable function of this tiling trick.
|
||||
|
||||
* Divide the space into 3 rows and 3 columns. Find a way to know in which column and row the thread is and use that to change the shape that is displaying. Try to compose a tic-tac-toe match. -->
|
||||
|
||||
### 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.
|
||||
|
||||
<!-- ### Apply matrices inside patterns
|
||||
|
||||
Since each subdivision or cell is a smaller version of the normalized coordinate system we have already been using, we can apply a matrix transformation to it in order to translate, rotate or scale the space inside. -->
|
||||
|
||||
<div class="codeAndCanvas" data="checks.frag"></div>
|
||||
|
||||
* 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.
|
||||
|
||||
<!-- * Think of interesting ways of animating this pattern. Consider animating color, shapes and motion. Make three different animations.
|
||||
|
||||
* Recreate more complicated patterns by composing different shapes. -->
|
||||
|
||||
|
||||
[![](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).
|
||||
|
||||
<!-- * Combine different layers of patterns to compose your own [Scottish Tartan Patterns](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.
|
||||
|
||||
<!-- ### Offset patterns
|
||||
|
||||
So let's say we want to imitate a brick wall. Looking at the wall, you can see a half brick offset on x in every other row. How we can do that?
|
||||
|
||||
![](brick.jpg)
|
||||
|
||||
As a first step we need to know if the row of our thread is an even or odd number, because we can use that to determine if we need to offset the x in that row.
|
||||
|
||||
____we have to fix these next two paragraphs together____
|
||||
|
||||
To determine if our thread is in an odd or even row, we are going to use [```mod()```](../glossary/?search=mod) of ```2.0``` and then see if the result is under ```1.0``` or not. Take a look at the following formula and uncomment the two last lines. -->
|
||||
|
||||
<div class="simpleFunction" data="y = mod(x,2.0);
|
||||
// y = mod(x,2.0) < 1.0 ? 0. : 1. ;
|
||||
// y = step(1.0,mod(x,2.0));"></div>
|
||||
|
||||
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``.
|
||||
|
||||
<!-- As you can see we can use a [ternary operator](https://en.wikipedia.org/wiki/%3F:) to check if the [```mod()```](../glossary/?search=mod) of ```2.0``` is under ```1.0``` (second line) or similarly we can use a [```step()```](../glossary/?search=step) function which does the same operation, but faster. Why? Although is hard to know how each graphic card optimizes and compiles the code, it is safe to assume that built-in functions are faster than non-built-in ones. Everytime you can use a built-in function, use it!
|
||||
|
||||
So now that we have our odd number formula we can apply an offset to the odd rows to give a *brick* effect to our tiles. Line 14 of the following code is where we are using the function to "detect" odd rows and give them a half-unit offset on ```x```. Note that for even rows, the result of our function is ```0.0```, and multiplying ```0.0``` by the offset of ```0.5``` gives an offset of ```0.0```. But on odd rows we multiply the result of our function, ```1.0```, by the offset of ```0.5```, which moves the ```x``` axis of the coordinate system by ```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.
|
||||
|
||||
<!-- Now try uncommenting line 32 - this stretches the aspect ratio of the coordinate system to mimic the aspect of a "modern brick". By uncommenting line 40 you can see how the coordinate system looks mapped to red and green. -->
|
||||
|
||||
<div class="codeAndCanvas" data="bricks.frag"></div>
|
||||
|
||||
* 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:
|
||||
|
||||
<!-- * Try animating this by moving the offset according to time.
|
||||
|
||||
* Make another animation where even rows move to the left and odd rows move to the right.
|
||||
|
||||
* Can you repeat this effect but with columns?
|
||||
|
||||
* Try combining an offset on ```x``` and ```y``` axis to get something like this: -->
|
||||
|
||||
<a href="../edit.php#09/marching_dots.frag"><canvas id="custom" class="canvas" data-fragment-url="marching_dots.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
## 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 Tiles
|
||||
|
||||
Now that we've learned how to tell if our cell is in an even or odd row or column, it's possible to reuse a single design element depending on its position. Consider the case of the [Truchet Tiles](http://en.wikipedia.org/wiki/Truchet_tiles) where a single design element can be presented in four different ways: -->
|
||||
|
||||
![](truchet-00.png)
|
||||
|
||||
Zmieniając wzór na kafelkach, można zbudować nieskończony zestaw skomplikowanych wzorów.
|
||||
|
||||
<!-- By changing the pattern across tiles, it's possible to construct an infinite set of complex designs. -->
|
||||
|
||||
![](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.
|
||||
|
||||
<!-- Pay close attention to the function ```rotateTilePattern()```, which subdivides the space into four cells and assigns an angle of rotation to each one. -->
|
||||
|
||||
<div class="codeAndCanvas" data="truchet.frag"></div>
|
||||
|
||||
* 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)
|
||||
|
||||
<!-- * Comment, uncomment and duplicate lines 69 to 72 to compose new designs.
|
||||
|
||||
* Change the black and white triangle for another element like: half circles, rotated squares or lines.
|
||||
|
||||
* Code other patterns where the elements are rotated according to their position.
|
||||
|
||||
* Make a pattern that changes other properties according to the position of the elements.
|
||||
|
||||
* Think of something else that is not necessarily a pattern where you can apply the principles from this section. (Ex: I Ching hexagrams) -->
|
||||
|
||||
<a href="../edit.php#09/iching-01.frag"><canvas id="custom" class="canvas" data-fragment-url="iching-01.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
## 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ć.
|
||||
|
||||
<!-- ## Making your own rules
|
||||
|
||||
Making procedural patterns is a mental exercise in finding minimal reusable elements. This practice is old; we as a species have been using grids and patterns to decorate textiles, floors and borders of objects for a long time: from meanders patterns in ancient Greece, to Chinese lattice design, the pleasure of repetition and variation catches our imagination. Take some time to look at [decorative](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) [patterns](https://www.pinterest.com/patriciogonzv/paterns/) and see how artists and designers have a long history of navigating the fine edge between the predictability of order and the surprise of variation and chaos. From Arabic geometrical patterns, to gorgeous African fabric designs, there is an entire universe of patterns to learn from. -->
|
||||
|
||||
![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.
|
||||
|
||||
<!-- With this chapter we end the section on Algorithmic Drawing. In the following chapters we will learn how to bring some entropy to our shaders and produce generative designs. -->
|
@ -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:
|
||||
|
||||
<!-- Randomness is a maximal expression of entropy. How can we generate randomness inside the seemingly predictable and rigid code environment?
|
||||
|
||||
Let's start by analyzing the following function: -->
|
||||
|
||||
<div class="simpleFunction" data="y = fract(sin(x)*1.0);"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Above we are extracting the fractional content of a sine wave. The [```sin()```](../glossary/?search=sin) values that fluctuate between ```-1.0``` and ```1.0``` have been chopped behind the floating point, returning all positive values between ```0.0``` and ```1.0```. We can use this effect to get some pseudo-random values by "breaking" this sine wave into smaller pieces. How? By multiplying the resultant of [```sin(x)```](../glossary/?search=sin) by larger numbers. Go ahead and click on the function above and start adding some zeros.
|
||||
|
||||
By the time you get to ```100000.0``` ( and the equation looks like this: ```y = fract(sin(x)*100000.0)``` ) you aren't able to distinguish the sine wave any more. The granularity of the fractional part has corrupted the flow of the sine wave into pseudo-random 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.
|
||||
|
||||
<!-- ## Controlling chaos
|
||||
|
||||
Using random can be hard; it is both too chaotic and sometimes not random enough. Take a look at the following graph. To make it, we are using a ```rand()``` function which is implemented exactly like we describe above.
|
||||
|
||||
Taking a closer look, you can see the [```sin()```](../glossary/?search=sin) wave crest at ```-1.5707``` and ```1.5707```. I bet you now understand why - it's where the maximum and minimum of the sine wave happens.
|
||||
|
||||
If look closely at the random distribution, you will note that the there is some concentration around the middle compared to the edges. -->
|
||||
|
||||
<div class="simpleFunction" data="y = rand(x);
|
||||
//y = rand(x)*rand(x);
|
||||
//y = sqrt(rand(x));
|
||||
//y = pow(rand(x),5.);"></div>
|
||||
|
||||
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ść.
|
||||
|
||||
<!-- A while ago [Pixelero](https://pixelero.wordpress.com) published an [interesting article about random distribution](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/). I've added some of the functions he uses in the previous graph for you to play with and see how the distribution can be changed. Uncomment the functions and see what happens.
|
||||
|
||||
If you read [Pixelero's article](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/), it is important to keep in mind that our ```rand()``` function is a deterministic random, also known as pseudo-random. Which means for example ```rand(1.)``` is always going to return the same value. [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) makes reference to the ActionScript function ```Math.random()``` which is non-deterministic; every call will return a different value. -->
|
||||
|
||||
## 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.
|
||||
|
||||
<!-- Now that we have a better understanding of randomness, it's time to apply it in two dimensions, to both the ```x``` and ```y``` axis. For that we need a way to transform a two dimensional vector into a one dimensional floating point value. There are different ways to do this, but the [```dot()```](../glossary/?search=dot) function is particulary helpful in this case. It returns a single float value between ```0.0``` and ```1.0``` depending on the alignment of two vectors. -->
|
||||
|
||||
<div class="codeAndCanvas" data="2d-random.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Take a look at lines 13 to 15 and notice how we are comparing the ```vec2 st``` with another two dimensional vector ( ```vec2(12.9898,78.233)```).
|
||||
|
||||
* Try changing the values on lines 14 and 15. See how the random pattern changes and think about what we can learn from this.
|
||||
|
||||
* Hook this random function to the mouse interaction (```u_mouse```) and time (```u_time```) to understand better how it works. -->
|
||||
|
||||
## 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.
|
||||
|
||||
<!-- ## Using the chaos
|
||||
|
||||
Random in two dimensions looks a lot like TV noise, right? It's a hard raw material to use to compose images. Let's learn how to make use of it.
|
||||
|
||||
Our first step is to apply a grid to it; using the [```floor()```](../glossary/?search=floor) function we will generate an integer table of cells. Take a look at the following code, especially lines 22 and 23. -->
|
||||
|
||||
<div class="codeAndCanvas" data="2d-random-mosaic.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- After scaling the space by 10 (on line 21), we separate the integers of the coordinates from the fractional part. We are familiar with this last operation because we have been using it to subdivide a space into smaller cells that go from ```0.0``` to ```1.0```. By obtaining the integer of the coordinate we isolate a common value for a region of pixels, which will look like a single cell. Then we can use that common integer to obtain a random value for that area. Because our random function is deterministic, the random value returned will be constant for all the pixels in that cell.
|
||||
|
||||
Uncomment line 29 to see that we preserve the floating part of the coordinate, so we can still use that as a coordinate system to draw things inside each cell. -->
|
||||
|
||||
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``.
|
||||
|
||||
<!-- Combining these two values - the integer part and the fractional part of the coordinate - will allow you to mix variation and order.
|
||||
|
||||
Take a look at this GLSL port of the famous ```10 PRINT CHR$(205.5+RND(1)); : GOTO 10``` maze generator. -->
|
||||
|
||||
<div class="codeAndCanvas" data="2d-random-truchet.frag"></div>
|
||||
|
||||
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ę.
|
||||
|
||||
<!-- Here I'm using the random values of the cells to draw a line in one direction or the other using the ```truchetPattern()``` function from the previous chapter (lines 41 to 47).
|
||||
|
||||
You can get another interesting pattern by uncommenting the block of lines between 50 to 53, or animate the pattern by uncommenting lines 35 and 36. -->
|
||||
|
||||
## 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.
|
||||
|
||||
<!-- [Ryoji Ikeda](http://www.ryojiikeda.com/), Japanese electronic composer and visual artist, has mastered the use of random; it is hard not to be touched and mesmerized by his work. His use of randomness in audio and visual mediums is forged in such a way that it is not annoying chaos but a mirror of the complexity of our technological culture. -->
|
||||
|
||||
<iframe src="https://player.vimeo.com/video/76813693?title=0&byline=0&portrait=0" width="800" height="450" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Take a look at [Ikeda](http://www.ryojiikeda.com/)'s work and try the following exercises:
|
||||
|
||||
* Make rows of moving cells (in opposite directions) with random values. Only display the cells with brighter values. Make the velocity of the rows fluctuate over time. -->
|
||||
|
||||
<a href="../edit.php#10/ikeda-00.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-00.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
* 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.
|
||||
|
||||
<!-- * Similarly make several rows but each one with a different speed and direction. Hook the position of the mouse to the threshold of which cells to show. -->
|
||||
|
||||
<a href="../edit.php#10/ikeda-03.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-03.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
* Stwórz inne ciekawe efekty.
|
||||
|
||||
<!-- * Create other interesting effects. -->
|
||||
|
||||
<a href="../edit.php#10/ikeda-04.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-04.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Using random aesthetically can be problematic, especially if you want to make natural-looking simulations. Random is simply too chaotic and very few things look ```random()``` in real life. If you look at a rain pattern or a stock chart, which are both quite random, they are nothing like the random pattern we made at the begining of this chapter. The reason? Well, random values have no correlation between them what so ever, but most natural patterns have some memory of the previous state.
|
||||
|
||||
In the next chapter we will learn about noise, the smooth and *natural looking* way of creating computational chaos. -->
|
@ -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.
|
||||
|
||||
<!-- ## Noise
|
||||
|
||||
It's time for a break! We've been playing with random functions that look like TV white noise, our head is still spinning thinking about shaders, and our eyes are tired. Time to go out for a walk!
|
||||
|
||||
We feel the air on our skin, the sun in our face. The world is such a vivid and rich place. Colors, textures, sounds. While we walk we can't avoid noticing the surface of the roads, rocks, trees and clouds. -->
|
||||
|
||||
![](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.
|
||||
|
||||
<!-- The unpredictability of these textures could be called "random," but they don't look like the random we were playing with before. The “real world” is such a rich and complex place! How can we approximate this variety computationally?
|
||||
|
||||
This was the question [Ken Perlin](https://mrl.nyu.edu/~perlin/) was trying to solve in the early 1980s when he was commissioned to generate more realistic textures for the movie "Tron." In response to that, he came up with an elegant *Oscar winning* noise algorithm. (No biggie.) -->
|
||||
|
||||
![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.
|
||||
|
||||
<!-- The following is not the classic Perlin noise algorithm, but it is a good starting point to understand how to generate noise. -->
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
float i = floor(x); // cz. całkowita
|
||||
float f = fract(x); // cz. ułamkowa
|
||||
y = rand(i); //funkcja rand() opisana jest w poprzednim rozdziale
|
||||
//y = mix(rand(i), rand(i + 1.0), f);
|
||||
//y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f));
|
||||
"></div>
|
||||
|
||||
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ą.
|
||||
|
||||
|
||||
<!-- In these lines we are doing something similar to what we did in the previous chapter. We are subdividing a continuous floating number (```x```) into its integer (```i```) and fractional (```f```) components. We use [```floor()```](../glossary/?search=floor) to obtain ```i``` and [```fract()```](../glossary/?search=fract) to obtain ```f```. Then we apply ```rand()``` to the integer part of ```x```, which gives a unique random value for each integer.
|
||||
|
||||
After that you see two commented lines. The first one interpolates each random value linearly. -->
|
||||
|
||||
```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.
|
||||
|
||||
<!-- Go ahead and uncomment this line to see how this looks. We use the [```fract()```](../glossary/?search=fract) value store in `f` to [```mix()```](../glossary/?search=mix) the two random values.
|
||||
|
||||
At this point in the book, we've learned that we can do better than a linear interpolation, right?
|
||||
Now try uncommenting the following line, which uses a [```smoothstep()```](../glossary/?search=smoothstep) interpolation instead of a linear one. -->
|
||||
|
||||
```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).
|
||||
|
||||
<!-- After uncommenting it, notice how the transition between the peaks gets smooth. In some noise implementations you will find that programmers prefer to code their own cubic curves (like the following formula) instead of using the [```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.
|
||||
|
||||
<!--
|
||||
This *smooth randomness* is a game changer for graphical engineers or artists - it provides the ability to generate images and geometries with an organic feeling. Perlin's Noise Algorithm has been implemented over and over in different languages and dimensions to make mesmerizing pieces for all sorts of creative uses. -->
|
||||
|
||||
![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.
|
||||
|
||||
<!-- Now it's your turn:
|
||||
|
||||
* Make your own ```float noise(float x)``` function.
|
||||
|
||||
* Use your noise function to animate a shape by moving it, rotating it or scaling it.
|
||||
|
||||
* Make an animated composition of several shapes 'dancing' together using noise.
|
||||
|
||||
* Construct "organic-looking" shapes using the noise function.
|
||||
|
||||
* Once you have your "creature," try to develop it further into a character by assigning it a particular movement. -->
|
||||
|
||||
## 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.)``).
|
||||
|
||||
<!-- Now that we know how to do noise in 1D, it's time to move on to 2D. In 2D, instead of interpolating between two points of a line (```fract(x)``` and ```fract(x)+1.0```), we are going to interpolate between the four corners of the square area of a plane (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` and ```fract(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**.
|
||||
|
||||
<!-- Similarly, if we want to obtain 3D noise we need to interpolate between the eight corners of a cube. This technique is all about interpolating random values, which is why it's called **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.
|
||||
|
||||
<!-- Like the 1D example, this interpolation is not linear but cubic, which smoothly interpolates any points inside our square grid. -->
|
||||
|
||||
![](05.jpg)
|
||||
|
||||
Przyjrzyj się następującej funkcji szumu.
|
||||
|
||||
<!-- Take a look at the following noise function. -->
|
||||
|
||||
<div class="codeAndCanvas" data="2d-noise.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- We start by scaling the space by 5 (line 45) in order to see the interpolation between the squares of the grid. Then inside the noise function we subdivide the space into cells. We store the integer position of the cell along with the fractional positions inside the cell. We use the integer position to calculate the four corners' coordinates and obtain a random value for each one (lines 23-26). Finally, in line 35 we interpolate between the 4 random values of the corners using the fractional positions we stored before. -->
|
||||
|
||||
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).
|
||||
|
||||
<!-- Now it's your turn. Try the following exercises:
|
||||
|
||||
* Change the multiplier of line 45. Try to animate it.
|
||||
|
||||
* At what level of zoom does the noise start looking like random again?
|
||||
|
||||
* At what zoom level is the noise is imperceptible?
|
||||
|
||||
* Try to hook up this noise function to the mouse coordinates.
|
||||
|
||||
* What if we treat the gradient of the noise as a distance field? Make something interesting with it.
|
||||
|
||||
* Now that you've achieved some control over order and chaos, it's time to use that knowledge. Make a composition of rectangles, colors and noise that resembles some of the complexity of a [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko) painting. -->
|
||||
|
||||
![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...
|
||||
|
||||
<!-- Noise algorithms were originally designed to give a natural *je ne sais quoi* to digital textures. The 1D and 2D implementations we've seen so far were interpolations between random *values*, which is why they're called **Value Noise**, but there are more ways to obtain noise... -->
|
||||
|
||||
[ ![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.
|
||||
|
||||
<!-- As you discovered in the previous exercises, value noise tends to look "blocky." To diminish this blocky effect, in 1985 [Ken Perlin](https://mrl.nyu.edu/~perlin/) developed another implementation of the algorithm called **Gradient Noise**. Ken figured out how to interpolate random *gradients* instead of values. These gradients were the result of a 2D random function that returns directions (represented by a ```vec2```) instead of single values (```float```). Click on the following image to see the code and how it works. -->
|
||||
|
||||
[ ![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.
|
||||
|
||||
<!-- Take a minute to look at these two examples by [Inigo Quilez](http://www.iquilezles.org/) and pay attention to the differences between [value noise](https://www.shadertoy.com/view/lsf3WH) and [gradient noise](https://www.shadertoy.com/view/XdXGW8).
|
||||
|
||||
Like a painter who understands how the pigments of their paints work, the more we know about noise implementations the better we will be able to use them. For example, if we use a two dimensional noise implementation to rotate the space where straight lines are rendered, we can produce the following swirly effect that looks like wood. Again you can click on the image to see what the code looks like. -->
|
||||
|
||||
[ ![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/).
|
||||
|
||||
<!-- Another way to get interesting patterns from noise is to treat it like a distance field and apply some of the tricks described in the [Shapes chapter](../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/).
|
||||
|
||||
<!-- A third way of using the noise function is to modulate a shape. This also requires some of the techniques we learned in the [chapter about shapes](../07/). -->
|
||||
|
||||
<a href="../edit.php#11/circleWave-noise.frag"><canvas id="custom" class="canvas" data-fragment-url="circleWave-noise.frag" width="300px" height="300"></canvas></a>
|
||||
|
||||
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.
|
||||
|
||||
<!-- For you to practice:
|
||||
|
||||
* What other generative pattern can you make? What about granite? marble? magma? water? Find three pictures of textures you are interested in and implement them algorithmically using noise.
|
||||
* Use noise to modulate a shape.
|
||||
* What about using noise for motion? Go back to the [Matrix chapter](../08/). Use the translation example that moves the "+" around, and apply some *random* and *noise* movements to it.
|
||||
* Make a generative Jackson Pollock. -->
|
||||
|
||||
![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)).
|
||||
|
||||
<!-- An improvement by Perlin to his original non-simplex noise **Simplex Noise**, is the replacement of the cubic Hermite curve ( _f(x) = 3x^2-2x^3_ , which is identical to the [```smoothstep()```](../glossary/?search=smoothstep) function) with a quintic interpolation curve ( _f(x) = 6x^5-15x^4+10x^3_ ). This makes both ends of the curve more "flat" so each border gracefully stitches with the next one. In other words, you get a more continuous transition between the cells. You can see this by uncommenting the second formula in the following graph example (or see the [two equations side by side here](https://www.desmos.com/calculator/2xvlk5xp8b)). -->
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
// Cubic Hermite Curve. Same as SmoothStep()
|
||||
y = x*x*(3.0-2.0*x);
|
||||
// Quintic interpolation curve
|
||||
//y = x*x*x*(x*(x*6.-15.)+10.);
|
||||
"></div>
|
||||
|
||||
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).
|
||||
|
||||
<!-- Note how the ends of the curve change. You can read more about this in [Ken's own words](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.
|
||||
|
||||
<!-- For Ken Perlin the success of his algorithm wasn't enough. He thought it could perform better. At Siggraph 2001 he presented the "simplex noise" in which he achieved the following improvements over the previous algorithm:
|
||||
|
||||
* An algorithm with lower computational complexity and fewer multiplications.
|
||||
* A noise that scales to higher dimensions with less computational cost.
|
||||
* A noise without directional artifacts.
|
||||
* A noise with well-defined and continuous gradients that can be computed quite cheaply.
|
||||
* An algorithm that is easy to implement in hardware. -->
|
||||
|
||||
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ą*).
|
||||
|
||||
<!-- I know what you are thinking... "Who is this man?" Yes, his work is fantastic! But seriously, how did he improve the algorithm? Well, we saw how for two dimensions he was interpolating 4 points (corners of a square); so we can correctly guess that for [three (see an implementation here)](../edit.php#11/3d-noise.frag) and four dimensions we need to interpolate 8 and 16 points. Right? In other words for N dimensions you need to smoothly interpolate 2 to the N points (2^N). But Ken smartly noticed that although the obvious choice for a space-filling shape is a square, the simplest shape in 2D is the equilateral triangle. So he started by replacing the squared grid (we just learned how to use) for a simplex grid of equilateral triangles. -->
|
||||
|
||||
![](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.
|
||||
|
||||
<!-- The simplex shape for N dimensions is a shape with N + 1 corners. In other words one fewer corner to compute in 2D, 4 fewer corners in 3D and 11 fewer corners in 4D! That's a huge improvement!
|
||||
|
||||
In two dimensions the interpolation happens similarly to regular noise, by interpolating the values of the corners of a section. But in this case, by using a simplex grid, we only need to interpolate the sum of 3 corners. -->
|
||||
|
||||
![](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).
|
||||
|
||||
<!-- How is the simplex grid made? In another brilliant and elegant move, the simplex grid can be obtained by subdividing the cells of a regular 4 cornered grid into two isosceles triangles and then skewing it until each triangle is equilateral. -->
|
||||
|
||||
![](simplex-grid-02.png)
|
||||
|
||||
<!-- Then, as [Stefan Gustavson describes in this paper](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _"...by looking at the integer parts of the transformed coordinates (x,y) for the point we want to evaluate, we can quickly determine which cell of two simplices that contains the point. By also comparing the magnitudes of x and y, we can determine whether the point is in the upper or the lower simplex, and traverse the correct three corner points."_
|
||||
|
||||
In the following code you can uncomment line 44 to see how the grid is skewed, and then uncomment line 47 to see how a simplex grid can be constructed. Note how on line 22 we are subdividing the skewed square into two equilateral triangles just by detecting if ```x > y``` ("lower" triangle) or ```y > x``` ("upper" triangle). -->
|
||||
|
||||
|
||||
<!-- [Stefan Gustavson w tej pracy](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf) opisuje : _"...patrząc na części całkowite przekształconych współrzędnych (x,y) możemy szybko określić, który kafelek dwóch prostopadłościanów zawiera ten punkt. Porównując również wielkości x i y, możemy określić, czy punkt znajduje się w górnej czy dolnej prostej i przemierzyć właściwe trzy punkty narożne."_. -->
|
||||
|
||||
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).
|
||||
|
||||
<div class="codeAndCanvas" data="simplex-grid.frag"></div>
|
||||
|
||||
<!-- All these improvements result in an algorithmic masterpiece known as **Simplex Noise**. The following is a GLSL implementation of this algorithm made by Ian McEwan and Stefan Gustavson (and presented in [this paper](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) which is overcomplicated for educational purposes, but you will be happy to click on it and see that it is less cryptic than you might expect, and the code is short and fast. -->
|
||||
|
||||
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.
|
||||
|
||||
<!-- Well... enough technicalities, it's time for you to use this resource in your own expressive way:
|
||||
|
||||
* Contemplate how each noise implementation looks. Imagine them as a raw material, like a marble rock for a sculptor. What can you say about about the "feeling" that each one has? Squinch your eyes to trigger your imagination, like when you want to find shapes in a cloud. What do you see? What are you reminded of? What do you imagine each noise implementation could be made into? Following your guts and try to make it happen in code.
|
||||
|
||||
* Make a shader that projects the illusion of flow. Like a lava lamp, ink drops, water, etc. -->
|
||||
|
||||
<a href="../edit.php#11/lava-lamp.frag"><canvas id="custom" class="canvas" data-fragment-url="lava-lamp.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
* Użyj Simplex Noise, aby dodać trochę tekstury do pracy, którą już wykonałeś.
|
||||
|
||||
<!-- * Use Simplex Noise to add some texture to a work you've already made. -->
|
||||
|
||||
<a href="../edit.php#11/iching-03.frag"><canvas id="custom" class="canvas" data-fragment-url="iching-03.frag" width="520px" height="520px"></canvas></a>
|
||||
|
||||
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!
|
||||
|
||||
<!-- In this chapter we have introduced some control over the chaos. It was not an easy job! Becoming a noise-bender-master takes time and effort.
|
||||
|
||||
In the following chapters we will see some well known techniques to perfect your skills and get more out of your noise to design quality generative content with shaders. Until then enjoy some time outside contemplating nature and its intricate patterns. Your ability to observe needs equal (or probably more) dedication than your making skills. Go outside and enjoy the rest of the day! -->
|
||||
|
||||
<p style="text-align:center; font-style: italic;">"Talk to the tree, make friends with it." Bob Ross
|
||||
</p>
|
@ -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.
|
||||
|
||||
<!-- In 1996, sixteen years after Perlin's original Noise and five years before his Simplex Noise, [Steven Worley wrote a paper called “A Cellular Texture Basis Function”](http://www.rhythmiccanvas.com/research/papers/worley.pdf). In it, he describes a procedural texturing technique now extensively used by the graphics community.
|
||||
|
||||
To understand the principles behind it we need to start thinking in terms of **iterations**. Probably you know what that means: yes, start using ```for``` loops. There is only one catch with ```for``` loops in GLSL: the number we are checking against must be a constant (```const```). So, no dynamic loops - the number of iterations must be fixed.
|
||||
|
||||
Let's take a look at an example. -->
|
||||
|
||||
### 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.
|
||||
|
||||
<!-- Cellular Noise is based on distance fields, the distance to the closest one of a set of feature points. Let's say we want to make a distance field of 4 points. What do we need to do? Well, **for each pixel we want to calculate the distance to the closest point**. That means that we need to iterate through all the points, compute their distances to the current pixel and store the value for the one that is closest. -->
|
||||
|
||||
```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));
|
||||
```
|
||||
|
||||
<!-- ```glsl
|
||||
float min_dist = 100.; // A variable to store the closest distance to a point
|
||||
|
||||
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``.
|
||||
|
||||
<!-- This is not very elegant, but it does the trick. Now let's re-implement it using an array and a ```for``` loop. -->
|
||||
|
||||
```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:
|
||||
|
||||
<!-- Note how we use a ```for``` loop to iterate through an array of points and keep track of the minimum distance using a [```min()```](../glossary/?search=min) function. Here's a brief working implementation of this idea: -->
|
||||
|
||||
<div class="codeAndCanvas" data="cellnoise-00.frag"></div>
|
||||
|
||||
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?
|
||||
|
||||
<!-- In the above code, one of the points is assigned to the mouse position. Play with it so you can get an intuitive idea of how this code behaves. Then try this:
|
||||
|
||||
- How can you animate the rest of the points?
|
||||
- After reading [the chapter about shapes](../07/), imagine interesting ways to use this distance field!
|
||||
- What if you want to add more points to this distance field? What if we want to dynamically add/subtract points? -->
|
||||
|
||||
### 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.
|
||||
|
||||
<!-- You probably notice that ```for``` loops and *arrays* are not very good friends with GLSL. Like we said before, loops don't accept dynamic limits on their exit condition. Also, iterating through a lot of instances reduces the performance of your shader significantly. That means we can't use this direct approach for large amounts of points. We need to find another strategy, one that takes advantage of the parallel processing architecture of the 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ą.
|
||||
|
||||
<!-- One way to approach this problem is to divide the space into tiles. Not every pixel needs to check the distance to every single point, right? Given the fact that each pixel runs in its own thread, we can subdivide the space into cells, each one with one unique point to watch. Also, to avoid aberrations at the edges between cells we need to check for the distances to the points on the neighboring cells. That's the main brillant idea of [Steven Worley's paper](http://www.rhythmiccanvas.com/research/papers/worley.pdf). At the end, each pixel needs to check only nine positions: their own cell's point and the points in the 8 cells around it. We already subdivide the space into cells in the chapters about: [patterns](../09/), [random](../10/) and [noise](../11/), so hopefully you are familiar with this technique by now. -->
|
||||
|
||||
```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.
|
||||
|
||||
<!-- So, what's the plan? We will use the tile coordinates (stored in the integer coordinate, ```i_st```) to construct a random position of a point. The ```random2f``` function we will use receives a ```vec2``` and gives us a ```vec2``` with a random position. So, for each tile we will have one feature point in a random position within the tile. -->
|
||||
|
||||
```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.
|
||||
|
||||
<!-- Each pixel inside that tile (stored in the float coordinate, ```f_st```) will check their distance to that random point. -->
|
||||
|
||||
```glsl
|
||||
vec2 diff = point - f_st;
|
||||
float dist = length(diff);
|
||||
```
|
||||
|
||||
Wynik będzie wyglądał tak:
|
||||
|
||||
<!-- The result will look like this: -->
|
||||
|
||||
<a href="../edit.php#12/cellnoise-01.frag"><img src="cellnoise.png" width="520px" height="200px"></img></a>
|
||||
|
||||
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:
|
||||
|
||||
<!-- We still need to check the distances to the points in the surrounding tiles, not just the one in the current tile. For that we need to **iterate** through the neighbor tiles. Not all tiles, just the ones immediately around the current one. That means from ```-1``` (left) to ```1``` (right) tile in ```x``` axis and ```-1``` (bottom) to ```1``` (top) in ```y``` axis. A 3x3 region of 9 tiles can be iterated through using a double ```for``` loop like this one: -->
|
||||
|
||||
```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``).
|
||||
|
||||
<!-- Now, we can compute the position of the points on each one of the neighbors in our double ```for``` loop by adding the neighbor tile offset to the current tile coordinate. -->
|
||||
|
||||
```glsl
|
||||
...
|
||||
// Losowe położenie punktu wewnątrz sąsiedniego kafelka
|
||||
vec2 point = random2(i_st + neighbor);
|
||||
...
|
||||
```
|
||||
|
||||
<!-- ```glsl
|
||||
...
|
||||
// Random position from current + neighbor place in the grid
|
||||
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").
|
||||
|
||||
<!-- The rest is all about calculating the distance to that point and storing the closest one in a variable called ```m_dist``` (for minimum 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);
|
||||
...
|
||||
```
|
||||
|
||||
<!-- ```glsl
|
||||
...
|
||||
vec2 diff = neighbor + point - f_st;
|
||||
|
||||
// Distance to the point
|
||||
float dist = length(diff);
|
||||
|
||||
// Keep the closer distance
|
||||
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):
|
||||
|
||||
|
||||
<!-- The above code is inspired by [this article by Inigo's Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) where he said:
|
||||
|
||||
*"... it might be worth noting that there's a nice trick in this code above. Most implementations out there suffer from precision issues, because they generate their random points in "domain" space (like "world" or "object" space), which can be arbitrarily far from the origin. One can solve the issue moving all the code to higher precision data types, or by being a bit clever. My implementation does not generate the points in "domain" space, but in "cell" space: once the integer and fractional parts of the shading point are extracted and therefore the cell in which we are working identified, all we care about is what happens around this cell, meaning we can drop all the integer part of our coordinates away all together, saving many precision bits. In fact, in a regular voronoi implementation the integer parts of the point coordinates simply cancel out when the random per cell feature points are subtracted from the shading point. In the implementation above, we don't even let that cancelation happen, cause we are moving all the computations to "cell" space. This trick also allows one to handle the case where you want to voronoi-shade a whole planet - one could simply replace the input to be double precision, perform the floor() and fract() computations, and go floating point with the rest of the computations without paying the cost of changing the whole implementation to double precision. Of course, same trick applies to Perlin Noise patterns (but i've never seen it implemented nor documented anywhere)."* -->
|
||||
|
||||
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:
|
||||
|
||||
<!-- Recapping: we subdivide the space into tiles; each pixel will calculate the distance to the point in their own tile and the surrounding 8 tiles; store the closest distance. The result is a distance field that looks like the following example: -->
|
||||
|
||||
<div class="codeAndCanvas" data="cellnoise-02.frag"></div>
|
||||
|
||||
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?
|
||||
|
||||
<!-- Explore this further by:
|
||||
|
||||
- Scaling the space by different values.
|
||||
- Can you think of other ways to animate the points?
|
||||
- What if we want to compute an extra point with the mouse position?
|
||||
- What other ways of constructing this distance field can you imagine, besides ```m_dist = min(m_dist, dist);```?
|
||||
- What interesting patterns can you make with this distance field? -->
|
||||
|
||||
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).
|
||||
|
||||
<!-- This algorithm can also be interpreted from the perspective of the points and not the pixels. In that case it can be described as: each point grows until it finds the growing area from another point. This mirrors some of the growth rules in nature. Living forms are shaped by this tension between an inner force to expand and grow, and limitations by outside forces. The classic algorithm that simulates this behavior is named after [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.
|
||||
|
||||
<!-- Constructing Voronoi diagrams from cellular noise is less hard than what it might seem. We just need to *keep* some extra information about the precise point which is closest to the pixel. For that we are going to use a ```vec2``` called ```m_point```. By storing the vector direction to the center of the closest point, instead of just the distance, we will be "keeping" a "unique" identifier of that point. -->
|
||||
|
||||
```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).
|
||||
|
||||
<!-- Note that in the following code that we are no longer using ```min``` to calculate the closest distance, but a regular ```if``` statement. Why? Because we actually want to do something more every time a new closer point appears, namely store its position (lines 32 to 37). -->
|
||||
|
||||
<div class="codeAndCanvas" data="vorono-00.frag"></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Note how the color of the moving cell (bound to the mouse position) changes color according to its position. That's because the color is assigned using the value (position) of the closest point.
|
||||
|
||||
Like we did before, now is the time to scale this up, switching to [Steven Worley's paper's approach](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Try implementing it yourself. You can use the help of the following example by clicking on it. Note that Steven Worley's original approach uses a variable number of feature points for each tile, more than one in most tiles. In his software implementation in C, this is used to speed up the loop by making early exits. GLSL loops don't allow variable number of iterations, so you probably want to stick to one feature point per tile. -->
|
||||
|
||||
<a href="../edit.php#12/vorono-01.frag"><canvas id="custom" class="canvas" data-fragment-url="vorono-01.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
Gdy już rozgryziesz ten algorytm, pomyśl o ciekawych i kreatywnych jego zastosowaniach.
|
||||
|
||||
<!-- Once you figure out this algorithm, think of interesting and creative uses for it. -->
|
||||
|
||||
![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.
|
||||
|
||||
<!-- In 2011, [Stefan Gustavson optimized Steven Worley's algorithm to GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) by only iterating through a 2x2 matrix instead of 3x3. This reduces the amount of work significantly, but it can create artifacts in the form of discontinuities at the edges between the tiles. Take a look to the following examples. -->
|
||||
|
||||
<div class="glslGallery" data="12/2d-cnoise-2x2,12/2d-cnoise-2x2x2,12/2d-cnoise,12/3d-cnoise" data-properties="clickRun:editor,openFrameIcon:false"></div>
|
||||
|
||||
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).
|
||||
|
||||
<!-- Later in 2012 [Inigo Quilez wrote an article on how to make precise Voronoi borders](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm). -->
|
||||
|
||||
<a href="../edit.php#12/2d-voronoi.frag"><img src="2d-voronoi.gif" width="520px" height="200px"></img></a>
|
||||
|
||||
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?"*.
|
||||
|
||||
<!-- Inigo's experiments with Voronoi didn't stop there. In 2014 he wrote this nice article about what he calls [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), a function that allows a gradual blend between regular noise and voronoi. In his words:
|
||||
|
||||
*"Despite this similarity, the fact is that the way the grid is used in both patterns is different. Noise interpolates/averages random values (as in value noise) or gradients (as in gradient noise), while Voronoi computes the distance to the closest feature point. Now, smooth-bilinear interpolation and minimum evaluation are two very different operations, or... are they? Can they perhaps be combined in a more general metric? If that was so, then both Noise and Voronoi patterns could be seen as particular cases of a more general grid-based pattern generator?"* -->
|
||||
|
||||
<a href="../edit.php#12/2d-voronoise.frag"><canvas id="custom" class="canvas" data-fragment-url="2d-voronoise.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
Teraz nadszedł czas, abyś przyjrzał się bliżej rzeczom, zainspirował się naturą i znalazł swoje własne ujęcie tej techniki!
|
||||
|
||||
<!-- Now it's time for you to look closely at things, be inspired by nature and find your own take on this technique! -->
|
||||
|
||||
![Deyrolle glass film - 1831](DeyrolleFilm.png)
|
||||
|
||||
<div class="glslGallery" data="12/metaballs,12/stippling,12/cell,12/tissue,12/cracks,160504143842" data-properties="clickRun:editor,openFrameIcon:false"></div>
|
@ -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:
|
||||
|
||||
<!-- Noise tends to mean different things to different people. Musicians will think of it in terms of disturbing sounds, communicators as interference and astrophysicists as cosmic microwave background radiation. These concepts bring us back to the physical reasons behind randomness in the world around us. However, let's start with something more fundamental, and more simple: waves and their properties. A wave is a fluctuation over time of some property. Audio waves are fluctuations in air pressure, electromagnetical waves are fluctuations in electrical and magnetic fields. Two important characteristics of a wave are its amplitude and frequency. The equation for a simple linear (one-dimensional) wave looks like this: -->
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
float amplitude = 1.;
|
||||
float frequency = 1.;
|
||||
y = amplitude * sin(x * frequency);
|
||||
"></div>
|
||||
|
||||
* 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.
|
||||
|
||||
<!-- * Try changing the values of the frequency and amplitude to understand how they behave.
|
||||
* Using shaping functions, try changing the amplitude over time.
|
||||
* Using shaping functions, try changing the frequency over time. -->
|
||||
|
||||
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.
|
||||
|
||||
<!-- By doing the last two exercises you have managed to "modulate" a sine wave, and you just created AM (amplitude modulated) and FM (frequency modulated) waves. Congratulations!
|
||||
|
||||
Another interesting property of waves is their ability to add up, which is formally called superposition. Comment/uncomment and tweak the following lines. Pay attention to how the overall appearance changes as we add waves of different amplitudes and frequencies together. -->
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
float amplitude = 1.;
|
||||
float frequency = 1.;
|
||||
y = sin(x * frequency);
|
||||
float t = 0.01*(-u_time*130.0);
|
||||
y += sin(x*frequency*2.1 + t)*4.5;
|
||||
y += sin(x*frequency*1.72 + t*1.121)*4.0;
|
||||
y += sin(x*frequency*2.221 + t*0.437)*5.0;
|
||||
y += sin(x*frequency*3.1122+ t*4.269)*2.5;
|
||||
y *= amplitude*0.06;
|
||||
"></div>
|
||||
|
||||
* 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ę.
|
||||
|
||||
<!-- * Experiment by changing the frequency and amplitude for the additional waves.
|
||||
* Is it possible to make two waves cancel each other out? What will that look like?
|
||||
* Is it possible to add waves in such a way that they will amplify each other?
|
||||
|
||||
In music, each note is associated with a specific frequency. The frequencies for these notes follow a pattern which we call a scale, where a doubling or halving of the frequency corresponds to a jump of one octave. -->
|
||||
|
||||
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:
|
||||
|
||||
<!-- By adding different iterations of noise (*octaves*), where we successively increment the frequencies in regular steps (*lacunarity*) and decrease the amplitude (*gain*,) of the **noise** we can obtain a finer granularity in the noise and get more fine detail. This technique is called "fractal Brownian Motion" (*fBM*), or simply "fractal noise", and in its simplest form it can be created by the following code: -->
|
||||
|
||||
<div class="simpleFunction" data="// Properties
|
||||
const int octaves = 1;
|
||||
float lacunarity = 2.0;
|
||||
float gain = 0.5;
|
||||
//
|
||||
// Początkowe wartości
|
||||
float amplitude = 0.5;
|
||||
float frequency = 1.;
|
||||
//
|
||||
// Pętla po oktawach
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
	y += amplitude * noise(frequency*x);
|
||||
	frequency *= lacunarity;
|
||||
	amplitude *= gain;
|
||||
}"></div>
|
||||
|
||||
* 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.
|
||||
|
||||
<!-- * Progressively change the number of octaves to iterate from 1 to 2, 4, 8 and 10. See what happens.
|
||||
* When you have more than 4 octaves, try changing the lacunarity value.
|
||||
* Also with >4 octaves, change the gain value and see what happens. -->
|
||||
|
||||
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.
|
||||
|
||||
<!-- Note how with each additional octave, the curve seems to get more detail. Also note the self-similarity while more octaves are added. If you zoom in on the curve, a smaller part looks about the same as the whole thing, and each section looks more or less the same as any other section. This is an important property of mathematical fractals, and we are simulating that property in our loop. We are not creating a *true* fractal, because we stop the summation after a few iterations, but theoretically speaking, we would get a true mathematical fractal if we allowed the loop to continue forever and add an infinite number of noise components. In computer graphics, we always have a limit to the smallest details we can resolve, for example when objects become smaller than a pixel, so there is no need to make infinite sums to create the appearance of a fractal. A lot of terms may be needed sometimes, but never an infinite number. -->
|
||||
|
||||
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:
|
||||
|
||||
<!-- The following code is an example of how fBm could be implemented in two dimensions to create a fractal-looking pattern: -->
|
||||
|
||||
<div class='codeAndCanvas' data='2d-fbm.frag'></div>
|
||||
|
||||
* Zmniejsz liczbę oktaw poprzez zmianę wartości w linii 37
|
||||
* Zmodyfikuj `lacunarity` fBm w linii 47
|
||||
* Eksploruj zmianę `gain` na linii 48
|
||||
|
||||
<!-- * Reduce the number of octaves by changing the value on line 37
|
||||
* Modify the lacunarity of the fBm on line 47
|
||||
* Explore by changing the gain on line 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).
|
||||
|
||||
<!-- This technique is commonly used to construct procedural landscapes. The self-similarity of the fBm is perfect for mountains, because the erosion processes that create mountains work in a manner that yields this kind of self-similarity across a large range of scales. If you are interested in this use, you should definitely read [this great article by Inigo Quiles about advanced noise](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.
|
||||
|
||||
<!-- Using more or less the same technique, it's also possible to obtain other effects like what is known as **turbulence**. It's essentially an fBm, but constructed from the absolute value of a signed noise to create sharp valleys in the function. -->
|
||||
|
||||
```glsl
|
||||
for (int i = 0; i < OCTAVES; i++) {
|
||||
value += amplitude * abs(snoise(st));
|
||||
st *= 2.;
|
||||
amplitude *= .5;
|
||||
}
|
||||
```
|
||||
|
||||
<a href="../edit.php#13/turbulence.frag"><img src="turbulence-long.png" width="520px" height="200px"></img></a>
|
||||
|
||||
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:
|
||||
|
||||
<!-- Another member of this family of algorithms is the **ridge**, where the sharp valleys are turned upside down to create sharp ridges instead: -->
|
||||
|
||||
```glsl
|
||||
n = abs(n); // Stwórz doliny
|
||||
n = offset - n; // Odwróć doliny, aby powstały grzbiety
|
||||
n = n * n; // Zaostrz grzbiety
|
||||
```
|
||||
|
||||
<a href="../edit.php#13/ridge.frag"><img src="ridge-long.png" width="520px" height="200px"></img></a>
|
||||
|
||||
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).
|
||||
|
||||
<!-- Another variant which can create useful variations is to multiply the noise components together instead of adding them. It's also interesting to scale subsequent noise functions with something that depends on the previous terms in the loop. When we do things like that, we are moving away from the strict definition of a fractal and into the relatively unknown field of "multifractals". Multifractals are not as strictly defined mathematically, but that doesn't make them less useful for graphics. In fact, multifractal simulations are very common in modern commercial software for terrain generation. For further reading, you could read chapter 16 of the book "Texturing and Modeling: a Procedural Approach" (3rd edition), by Kenton Musgrave. Sadly, that book is out of print since a few years back, but you can still find it in libraries and on the second hand market. (There's a PDF version of the 1st edition available for purchase online, but don't buy that - it's a waste of money. It's from 1994, and it doesn't contain any of the terrain modeling stuff from the 3rd edition.) -->
|
||||
|
||||
### 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.
|
||||
|
||||
<!-- [Inigo Quiles wrote this other fascinating article](http://www.iquilezles.org/www/articles/warp/warp.htm) about how it's possible to use fBm to warp a space of a fBm. Mind blowing, Right? It's like the dream inside the dream of Inception. -->
|
||||
|
||||
![ 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.
|
||||
|
||||
<!-- A less extreme example of this technique is the following code where the wrap is used to produce this clouds-like texture. Note how the self-similarity property is still present in the result. -->
|
||||
|
||||
<div class='codeAndCanvas' data='clouds.frag'></div>
|
||||
|
||||
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.
|
||||
|
||||
<!-- Warping the texture coordinates with noise in this manner can be very useful, a lot of fun, and fiendishly difficult to master. It's a powerful tool, but it takes quite a bit of experience to use it well. A useful tool for this is to displace the coordinates with the derivative (gradient) of the noise. [A famous article by Ken Perlin and Fabrice Neyret called "flow noise"](http://evasion.imag.fr/Publications/2001/PN01/) is based on this idea. Some modern implementations of Perlin noise include a variant that computes both the function and its analytical gradient. If the "true" gradient is not available for a procedural function, you can always compute finite differences to approximate it, although this is less accurate and involves more work. -->
|
@ -0,0 +1,121 @@
|
||||
<canvas id="custom" class="canvas" data-fragment-url="src/moon/moon.frag" data-textures="src/moon/moon.jpg" width="350px" height="350px"></canvas>
|
||||
|
||||
# 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.
|
||||
|
||||
<div class="header">
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=B5FSVSHGEATCG" style="float: right;"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" alt=""></a>
|
||||
</div>
|
||||
|
||||
## 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.
|
||||
|
||||
<div class="header"> <a href="http://patriciogonzalezvivo.com/" target="_blank">www</a> - <a href="https://twitter.com/patriciogv" target="_blank">Twitter</a> - <a href="https://github.com/patriciogonzalezvivo" target="_blank">GitHub</a> - <a href="https://vimeo.com/patriciogv" target="_blank">Vimeo</a> - <a href="https://www.flickr.com/photos/106950246@N06/" target="_blank"> Flickr</a></div>
|
||||
|
||||
[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.
|
||||
|
||||
<div class="header"> <a href="http://jenlowe.net/" target="_blank">www</a> - <a href="https://twitter.com/datatelling" target="_blank">Twitter</a> - <a href="https://github.com/datatelling" target="_blank">GitHub</a></div>
|
||||
|
||||
## 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) / <a rel="me" href="https://mastodon.gamedev.place/@bookofshaders">Mastodon</a> / [Discord](shader.zone)
|
||||
|
||||
<div id="fd-form-623359074e5181d777e479f9"></div>
|
||||
<script>
|
||||
window.fd('form', {
|
||||
formId: '623359074e5181d777e479f9',
|
||||
containerEl: '#fd-form-623359074e5181d777e479f9'
|
||||
});
|
||||
</script>
|
@ -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.
|
||||
|
||||
<!-- ## How to run the examples on a Raspberry Pi?
|
||||
|
||||
A few years ago, assuming that everybody has a computer with a graphical processing unit was a long shot. Now, most computers have a GPU, but it's still a high bar for a requirement in a workshop or class, for example.
|
||||
|
||||
Thanks to the [Raspberry Pi Foundation](http://www.raspberrypi.org/) a new type of small and cheap generation of computers (around $35 each) has found its way into classrooms. More importantly for the purposes of this book, the [Raspberry Pi](http://www.raspberrypi.org/) comes with a decent Broadcom GPU that can be accessed directly from the console. I made a [flexible GLSL live coding tool call **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer) that runs all the examples in this book. This program also has the ability to update automatically when the user saves a change to their code. What does this mean? You can edit the shader and every time you save it, the shader will be re-compile and render for you. -->
|
||||
|
||||
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:
|
||||
|
||||
<!-- By making a local copy of the repository of this book (see the above section) and having [`glslViewer` installed](https://github.com/patriciogonzalezvivo/glslViewer), users can run the examples with `glslviewer`. Also by using the `-l` flag they can render the example in a corner of the screen while they modify it with any text editor (like `nano`, `pico`, `vi`, `vim` or `emacs`). This also works if the user is connected through ssh/sftp.
|
||||
|
||||
To install and set this all up on the Raspberry Pi after installing [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), a Debian-based Linux distribution made for Raspberry Pi, and logging in, type the following commands: -->
|
||||
|
||||
```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
|
||||
```
|
@ -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/)
|
||||
|
||||
<!-- ## How can I collaborate with this book?
|
||||
|
||||
Thanks for being willing to collaborate! There are plenty of ways you can:
|
||||
|
||||
- Translating content
|
||||
- Improving the [```glossary/``` section](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
|
||||
- Editing content
|
||||
- Sharing your shaders examples through [the on-line editor](http://editor.thebookofshaders.com/) to -->
|
||||
|
||||
### 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.
|
||||
|
||||
<!-- ### Translating content
|
||||
|
||||
This book is written in [Markdown language](https://daringfireball.net/projects/markdown/syntax) so it's very easy to edit and work on it.
|
||||
|
||||
1. Start by going to [github's repository at ```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Take a look at the files and folders inside it. You will note that the content is in the ```README.md``` and other files with capital letters like: ```TITLE.md```, ```SUMMARY.md```, etc. Also note that translations are hosted in files with names ending in two letters referencing the language they are for, ex.: ```README-jp.md```, ```README-es.md```, etc. -->
|
||||
|
||||
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/)
|
||||
|
||||
<!-- 2. Fork the repository and clone it in your computer.
|
||||
|
||||
3. Duplicate the content of the files want to translate. Remember to add to the two letters that makes reference to the language you are translating to the files you will work on.
|
||||
|
||||
4. Translate the content line by line (see **Translation notes**).
|
||||
|
||||
5. Test it (see **Testing**).
|
||||
|
||||
6. Push to your own github fork to then make a [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:
|
||||
|
||||
<!-- #### Translating notes
|
||||
|
||||
Do not erase or modify things the embedded examples, that looks like this: -->
|
||||
|
||||
```html
|
||||
<div class="codeAndCanvas" data="grid-making.frag"></div>
|
||||
```
|
||||
|
||||
lub
|
||||
|
||||
```html
|
||||
<div class="simpleFunction" data="y = mod(x,2.0);"></div>
|
||||
```
|
||||
|
||||
#### Testowanie
|
||||
|
||||
Rozpocznij uruchamianie lokalnego serwera PHP wewnątrz lokalnego folderu repozytorium:
|
||||
|
||||
<!-- #### Testing
|
||||
|
||||
Start running a local PHP server inside the local repository folder: -->
|
||||
|
||||
```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``
|
||||
|
||||
<!-- Then in your browser search for ```localhost:8000``` go to the chapter you are translating and add ```?lan=``` followed by the two letters you used to mark the language you are translating to.
|
||||
|
||||
For example, if you are translating the chapter ```03``` to french you had been working with the file ```03/README-fr.md``` and you can test it by going to: ```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!
|
||||
|
||||
<!-- ### Improving the glossary section
|
||||
|
||||
This section is under development. We are happy to listen to your ideas on how to make it a friendly tool for all. Send us a message to [@bookofshaders](https://twitter.com/bookofshaders).
|
||||
|
||||
### Editing content
|
||||
|
||||
We are all humans. If you see something say something and make a Pull Request or open an issue. Thanks! -->
|
||||
|
||||
### 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/).
|
||||
|
||||
<!-- ### Sharing your shaders examples
|
||||
|
||||
You will see a lot of links to [the on-line editor](http://editor.thebookofshaders.com/) and embedded instances of it.
|
||||
Once you code something that makes you proud, click the "Export" (or the ```⇪``` icon) and then copy the "URL to code...". Send it to [@bookofshaders](https://twitter.com/bookofshaders) or [@kyndinfo](https://twitter.com/kyndinfo). We are looking forward to see it and add it to [the example gallery section](https://thebookofshaders.com/examples/). -->
|
@ -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 ...
|
||||
|
||||
|
||||
<!-- # Appendix
|
||||
|
||||
1. [How can I navigate this book off-line?](00/)
|
||||
|
||||
2. [How to run the examples on a Raspberry Pi?](01/)
|
||||
|
||||
3. [How to print this book?](02/)
|
||||
|
||||
4. [How can I collaborate with this book?](03/)
|
||||
|
||||
5. [An introduction for those coming from JS](04/) by [Nicolas Barradeau](http://www.barradeau.com/)
|
||||
|
||||
6. [An introduction for vectors](05/) by ...
|
||||
|
||||
7. [An introduction to interpolation](06) by ... -->
|
Loading…
Reference in New Issue