diff --git a/06/README-pl.md b/06/README-pl.md index 95bd0467..908493bd 100644 --- a/06/README-pl.md +++ b/06/README-pl.md @@ -216,4 +216,4 @@ int newFunction(in vec4 aVec4, // read-only Może w to nie uwierzysz, ale mamy wszystkie składniki potrzbne do tworzenia fajnych rysunków. W następnym rozdziale nauczymy się jak połączyć wszystkie poznane tricki, by stworzyć geometryczne formy przez *blendowanie* przestrzeni. Dobrze słyszysz... *blendowanie* przestrzeni. -You may not believe it but now we have all the elements to make cool drawings. In the next chapter we will learn how to combine all our tricks to make geometric forms by *blending* the space. Yep... *blending* the space. + diff --git a/07/README-pl.md b/07/README-pl.md new file mode 100644 index 00000000..401dbf7f --- /dev/null +++ b/07/README-pl.md @@ -0,0 +1,293 @@ +![Alice Hubbard, Providence, USA, ca. 1892. Zdjęcie: Zindman/Freemont.](froebel.jpg) + +## Kształty + +Nareszcie! Czekaliśmy na ten moment! Poznałeś większość podstaw GLSL, jego typów i funkcji. Ćwiczyłeś również wykorzystanie funkcji kształtujących. Teraz nadszedł czas, aby połączyć to wszystko w całość. Jesteś w stanie sprostać temu wyzwaniu! W tym rozdziale dowiesz się, jak procedrualnie i równolegle rysować proste kształty. + + + +### Prostokąt + +Wyobraźmy sobie, że mamy papier w kratkę, taki jaki używaliśmy na lekcjach matematyki i naszym zadaniem domowym jest narysowanie kwadratu. Rozmiar papieru to 10x10, a kwadrat ma mieć wymiary 8x8. Co zrobisz? + + + +![](grid_paper.jpg) + +Zamalowałbyś wszystko poza pierwszym i ostatnim rzędem oraz pierwszą i ostatnią kolumną, tak? + + + +Jak to się ma do shaderów? Każdy mały kwadracik naszego papieru siatkowego to wątek (piksel). Każdy mały kwadrat zna swoje położenie, podobne do współrzędnych na szachownicy. W poprzednich rozdziałach zmapowaliśmy *x* i *y* na kanały kolorów *czerwony* i *zielony* oraz nauczyliśmy się korzystać z ciasnego dwuwymiarowego terytorium pomiędzy 0.0 a 1.0. Jak możemy tę wiedzę wykorzystać, aby narysować wyśrodkowany kwadrat na środku naszej kanwy? + + + +Zacznijmy od naszkicowania pseudokodu, który używa `if`ów na współrzędnych kanwy. Zasady, aby to zrobić, są nadzwyczaj podobne do tego, jak myślimy o sytuacji z papieram w kratke. + + + +```glsl +if ( (X WIĘKSZE NIŻ 1) ORAZ (Y WIĘKSZE NIŻ 1) ) + pomaluj na biało +else + pomaluj na czarno +``` + +Teraz, gdy mamy lepsze wyobrażenie o tym, jak to będzie działać, zastąpmy `if`a funkcją [`step()`](../glossary/?search=step), a zamiast używać współrzędnych 10x10 użyjmy znormalizowanych odpowiedników pomiędzy 0.0 a 1.0: + + + +```glsl +uniform vec2 u_resolution; + +void main(){ + vec2 st = gl_FragCoord.xy/u_resolution.xy; + vec3 color = vec3(0.0); + + // Obie linijki zwracają 1.0 (biały) lub 0.0 (czarny). + float left = step(0.1,st.x); // Równoważnie: (X WIĘKSZE NIŻ 0.1) + float bottom = step(0.1,st.y); // Równoważnie: (Y WIĘKSZE NIŻ 0.1) + + // Mnożenie left*bottom jest podobne do logicznego AND. + color = vec3( left * bottom ); + + gl_FragColor = vec4(color,1.0); +} +``` + +Funkcja [`step()`](../glossary/?search=step) "pomaluje" każdy piksel poniżej 0.1 na czarno (`vec3(0.0)`) a resztę na biało (`vec3(1.0)`). Mnożenie pomiędzy `left` i `bottom` działa jak logiczna operacja `AND`, gdzie obie muszą być 1.0 aby zwrócić 1.0, a gdy przynajmniej jedna jest 0.0, to obie są 0.0. W efekcie otrzymujemy dwie czarne linie, jedną na dole, a drugą po lewej stronie kanwy. + + + +![](rect-01.jpg) + +W poprzednim kodzie powtarzamy funkcję [`step()`](../glossary/?search=step) dla każdej osi (lewej i dolnej). Możemy zaoszczędzić kilka linii kodu, przekazując obie wartości razem zamiast pojedynczo. Wygląda to następująco: + + + +```glsl +vec2 borders = step(vec2(0.1),st); +float pct = borders.x * borders.y; +``` + +Do tej pory narysowaliśmy tylko dwie krawędzie (dolna-lewa) naszego prostokąta. Dorysujmy teraz dwie pozostałe (górna-prawa). Sprawdź następujący kod: + + + +
+ +Odkomentuj *linijki 21-22* i zobacz jak odwracamy współrzędne `st` - w ten sposób `vec2(0,0,0)` znajdzie się w prawym górnym rogu. Otrzymaliśmy odbicie lustrzane. Teraz wystarczy przekazać te odwrócone współrzędne do [`step()`](../glossary/?search=step). + + + +![](rect-02.jpg) + +Zwróć uwagę, że w *linijkach 18 i 22* wszystkie boki są mnożone przez siebie. Jest to równoznaczne z napisaniem: + + + +```glsl +vec2 bl = step(vec2(0.1),st); // bottom-left +vec2 tr = step(vec2(0.1),1.0-st); // top-right +color = vec3(bl.x * bl.y * tr.x * tr.y); +``` + +Ciekawe, prawda? W tej technice chodzi o wykorzystanie [`step()`](../glossary/?search=step), przerzucania współrzędnych oraz mnożenia (do operacji logicznych). + + + +Zanim przejdziesz dalej, spróbuj wykonać następujące ćwiczenia: + +* Zmień rozmiar i proporcje prostokąta. + +* Użyj [`smoothstep()`](../glossary/?search=smoothstep) zamiast [`step()`](../glossary/?search=step). Zauważ, że zmieniając wartości, możesz przejść od rozmytych krawędzi do eleganckich gładkich granic. + +* Zaimplementuj to samo, ale za pomocą [`floor()`](../glossary/?search=floor)(+ mnożenia i dzielenia). + +* Wybierz implementację, którą najbardziej lubisz i zrób z niej funkcję, którą możesz ponownie wykorzystać w przyszłości. Spraw, aby twoja funkcja była elastyczna i wydajna. + +* Zrób inną funkcję, która po prostu rysuje kontur prostokąta. + +* Jak myślisz, jak można narysować różne prostokąty na tej samej kanwie? Jeśli wymyślisz jak, pochwal się swoimi umiejętnościami, tworząc kompozycję z prostokątów i kolorów, która przypomina obraz [Pieta Mondriana](http://en.wikipedia.org/wiki/Piet_Mondrian). + + + +![Piet Mondrian - Tableau (1921)](mondrian.jpg) + +### Koła + +Łatwo jest rysować kwadraty na papierze w kratkę i prostokąty na współrzędnych kartezjańskich, ale okręgi wymagają innego podejścia, zwłaszcza że potrzebujemy algorytmu działającego na każdym pikselu z osobna. Jednym z rozwiązań jest *zmapowanie* współrzędnych tak, abyśmy mogli użyć funkcji [`step()`](../glossary/?search=step) do narysowania okręgu. + +Jak to zrobić? Przypomnijmy sobie lekcje matematyki, gdzie rozpościeraliśmy ramiona cyrkla na promień okręgu, wciskaliśmy jedno ramię cyrkla w środek okręgu, a następnie obrysowywaliśmy krawędź okręgu obracając drugie ramię. + + + +![](compass.jpg) + +Przełożenie tego na shader, w którym każdy piksel jast jak kratka na papierze, implikuje *zadawanie* każdemu pikselowi (wątkowi) pytania, czy znajduje się wewnątrz obszaru koła. Robimy to poprzez obliczenie odległości od danego piksela do środka okręgu. + + + +![](circle.jpg) + +Istnieje kilka sposobów na obliczenie tej odległości. Najprostszy z nich wykorzystuje funkcję [`distance()`](../glossary/?search=distance), która oblicza [`length()`](../glossary/?search=length) różnicy pomiędzy dwoma punktami (w naszym przypadku współrzędną piksela i środkiem kanwy). Funkcja `length()` to nic innego jak przekształcone twierdzenie Pitagorasa: + + + +![](hypotenuse.png) + +Możesz użyć [`distance()`](../glossary/?search=distance), [`length()`](../glossary/?search=length) lub [`sqrt()`](../glossary/?search=sqrt) aby obliczyć odległość do centrum kanwy. Poniższy kod zawiera te trzy funkcje i nie zaskakuje fakt, że każda z nich zwraca dokładnie taki sam wynik. + + + +Komentuj i odkomentuj linijki, aby wypróbować różne sposoby uzyskania tego samego wyniku. + + + + + +W powyższym przykładzie mapujemy odległość do centrum kanwy na jasność piksela. Im bliżej centrum znajduje się piksel, tym niższą (ciemniejszą) ma wartość. Zauważ, że wartości nie są zbyt wysokie, ponieważ od centrum ( `vec2(0.5, 0.5)` ) maksymalna odległość ledwo przekracza 0.5. Pokontempluj nad dokonanym mapowaniem i pomyśl: + + + +* Co można z niego wywnioskować? + +* Jak możemy je użyć do narysowania koła? + +* Zmodyfikuj powyższy kod, aby zawrzeć cały gradient wewnątrz kanwy. (Wskazówka: użyj mnożenia) + + + +### Distance field + +Możemy również myśleć o powyższym przykładzie jako o mapie wysokości, gdzie ciemniejszy kolor oznacza wyższy. Gradient pokazuje nam coś podobnego do wzoru tworzonego przez stożek. Wyobraź sobie, że jesteś na szczycie tego stożka. Pozioma odległość do krawędzi stożka wynosi 0,5. Będzie ona stała we wszystkich kierunkach. Wybierając miejsce "przecięcia" stożka otrzymamy większą lub mniejszą powierzchnię kołową. + + + +![](distance-field.jpg) + +Basically we are using a re-interpretation of the space (based on the distance to the center) to make shapes. This technique is known as a “distance field” and is used in different ways from font outlines to 3D graphics. + +Try the following exercises: + +* Use [`step()`](../glossary/?search=step) to turn everything above 0.5 to white and everything below to 0.0. + +* Inverse the colors of the background and foreground. + +* Using [`smoothstep()`](../glossary/?search=smoothstep), experiment with different values to get nice smooth borders on your circle. + +* Once you are happy with an implementation, make a function of it that you can reuse in the future. + +* Add color to the circle. + +* Can you animate your circle to grow and shrink, simulating a beating heart? (You can get some inspiration from the animation in the previous chapter.) + +* What about moving this circle? Can you move it and place different circles in a single billboard? + +* What happens if you combine distances fields together using different functions and operations? + +```glsl +pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6)); +pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6)); +pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6))); +``` + +* Make three compositions using this technique. If they are animated, even better! + +#### For your tool box + +In terms of computational power the [`sqrt()`](../glossary/?search=sqrt) function - and all the functions that depend on it - can be expensive. Here is another way to create a circular distance field by using [`dot()`](../glossary/?search=dot) product. + + + +### Useful properties of a Distance Field + +![Zen garden](zen-garden.jpg) + +Distance fields can be used to draw almost everything. Obviously the more complex a shape is, the more complicated its equation will be, but once you have the formula to make distance fields of a particular shape it is very easy to combine and/or apply effects to it, like smooth edges and multiple outlines. Because of this, distance fields are popular in font rendering, like [Mapbox GL Labels](https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817), [Matt DesLauriers](https://twitter.com/mattdesl) [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu) and [as is described on Chapter 7 of iPhone 3D Programming, O’Reilly](http://chimera.labs.oreilly.com/books/1234000001814/ch07.html#ch07_id36000921). + +Take a look at the following code. + + + +We start by moving the coordinate system to the center and shrinking it in half in order to remap the position values between -1 and 1. Also on *line 24* we are visualizing the distance field values using a [`fract()`](../glossary/?search=fract) function making it easy to see the pattern they create. The distance field pattern repeats over and over like rings in a Zen garden. + +Let’s take a look at the distance field formula on *line 19*. There we are calculating the distance to the position on `(.3,.3)` or `vec3(.3)` in all four quadrants (that’s what [`abs()`](../glossary/?search=abs) is doing there). + +If you uncomment *line 20*, you will note that we are combining the distances to these four points using the [`min()`](../glossary/?search=min) to zero. The result produces an interesting new pattern. + +Now try uncommenting *line 21*; we are doing the same but using the [`max()`](../glossary/?search=max) function. The result is a rectangle with rounded corners. Note how the rings of the distance field get smoother the further away they get from the center. + +Finish uncommenting *lines 27 to 29* one by one to understand the different uses of a distance field pattern. + +### Polar shapes + +![Robert Mangold - Untitled (2008)](mangold.jpg) + +In the chapter about color we map the cartesian coordinates to polar coordinates by calculating the *radius* and *angles* of each pixel with the following formula: + +```glsl +vec2 pos = vec2(0.5)-st; +float r = length(pos)*2.0; +float a = atan(pos.y,pos.x); +``` + +We use part of this formula at the beginning of the chapter to draw a circle. We calculated the distance to the center using [`length()`](../glossary/?search=length). Now that we know about distance fields we can learn another way of drawing shapes using polar coordinates. + +This technique is a little restrictive but very simple. It consists of changing the radius of a circle depending on the angle to achieve different shapes. How does the modulation work? Yes, using shaping functions! + +Below you will find the same functions in the cartesian graph and in a polar coordinates shader example (between *lines 21 and 25*). Uncomment the functions one-by-one, paying attention the relationship between one coordinate system and the other. + + + + + +Try to: + +* Animate these shapes. +* Combine different shaping functions to *cut holes* in the shape to make flowers, snowflakes and gears. +* Use the `plot()` function we were using in the *Shaping Functions Chapter* to draw just the contour. + +### Combining powers + +Now that we've learned how to modulate the radius of a circle according to the angle using the [`atan()`](../glossary/?search=atan) to draw different shapes, we can learn how use `atan()` with distance fields and apply all the tricks and effects possible with distance fields. + +The trick will use the number of edges of a polygon to construct the distance field using polar coordinates. Check out [the following code](http://thndl.com/square-shaped-shaders.html) from [Andrew Baldwin](https://twitter.com/baldand). + + + +* Using this example, make a function that inputs the position and number of corners of a desired shape and returns a distance field value. + +* Mix distance fields together using [`min()`](../glossary/?search=min) and [`max()`](../glossary/?search=max). + +* Choose a geometric logo to replicate using distance fields. + +Congratulations! You have made it through the rough part! Take a break and let these concepts settle - drawing simple shapes in Processing is easy but not here. In shader-land drawing shapes is twisted, and it can be exhausting to adapt to this new paradigm of coding. + +Down at the end of this chapter you will find a link to [PixelSpirit Deck](https://patriciogonzalezvivo.github.io/PixelSpiritDeck/) this deck of cards will help you learn new SDF functions, compose them into your designs and use on your shaders. The deck has a progressive learning curve, so taking one card a day and working on it will push and challenge your skills for months. + +Now that you know how to draw shapes I'm sure new ideas will pop into your mind. In the following chapter you will learn how to move, rotate and scale shapes. This will allow you to make compositions!