Merge branch 'master' into fix-iphone-book-url

This commit is contained in:
Patricio Gonzalez Vivo 2025-03-04 09:16:03 -08:00 committed by GitHub
commit 7b975805b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
241 changed files with 6054 additions and 277 deletions

View File

@ -42,10 +42,10 @@ Fragment shaders片段着色器可以让你控制像素在屏幕上的快
此外,基于你有的条件或需求你可以:
* [制作一个离线版的本书](https://thebookofshaders.com/appendix/)
* [制作一个离线版的本书](https://thebookofshaders.com/appendix/00/?lan=ch)
* [树莓派而不是浏览器来运行书中示例](https://thebookofshaders.com/appendix/)
* [不带浏览器的树莓派来运行书中示例](https://thebookofshaders.com/appendix/01/?lan=ch)
* [做一个PDF版的书用于打印](https://thebookofshaders.com/appendix/)
* [做一个PDF版的书用于打印](https://thebookofshaders.com/appendix/02/?lan=ch)
* 用[github仓库](https://github.com/patriciogonzalezvivo/thebookofshaders)来帮助解决问题和分享代码

View File

@ -2,35 +2,35 @@
<canvas id="custom" class="canvas" data-fragment-url="cmyk-halftone.frag" data-textures="vangogh.jpg" width="700px" height="320px"></canvas>
Die oben abgebildeten Grafiken wurden auf ganz unterschiedliche Weise erstellt. Die linke Abbildung stammt aus den Händen des Malers Van Gogh, der die Farben in stundenlanger Arbeit Schicht für Schicht mit einem Pinsel aufgetragen hat. Die rechte Abbildung wurde dagegen innerhalb von Sekundenbruchteilen mit Hilfe von vier Punktmatrizen erzeugt: eine für Cyan, eine für Magenta, eine für Gelb und eine für Schwarz. Der entscheidende Unterschied: Das zweite Bild wurde nicht seriell erstellt, d.h. Strich für Strich, sondern parallel, alle Punkte zur gleichen Zeit.
Die oben abgebildeten Grafiken wurden auf verschiedene Weise erstellt. Die linke Abbildung stammt aus den Händen des Malers Van Gogh, der die Farben in stundenlanger Arbeit Schicht für Schicht mit einem Pinsel aufgetragen hat. Die rechte Abbildung wurde dagegen innerhalb von wenigen Sekunden mit Hilfe von vier Pixelmatrizen erzeugt: eine für cyan, eine für magenta, eine für gelb und eine für schwarz. Der entscheidende Unterschied ist, dass das zweite Bild nicht seriell erstellt wurde, also nicht Schritt für Schritt, sondern parallel, alle Punkte zur gleichen Zeit.
Dieses Buch handelt von einer Computertechnik mit Namen *Fragment Shader*, die die digitale Erzeugung von Bildern revolutioniert und zu neuen Höhen geführt hat. Man kann ihre Erfindung ein wenig vergleichen mit dem Schritt von der manuellen Vervielfältigung einzelner Grafiken und Dokumente hin zur massenhaften Replikation durch Gutenbergs Druckerpresse.
Dieses Buch handelt von der Rechentechnik mit dem Namen *Fragment-Shader*, die die digitale Erzeugung von Bildern revolutioniert und zu neuen Höhen geführt hat. Man kann ihre Erfindung ein wenig vergleichen mit dem Schritt von der manuellen Vervielfältigung einzelner Grafiken und Dokumente hin zur massenhaften Replikation durch Gutenbergs Druckerpresse.
![Gutenbergs Druckerpresse](gutenpress.jpg)
Fragment-Shader ermöglichen die vollständige Kontrolle über alle Bildpunkte, die als Grafik auf dem Bildschirm erscheinen. Und das mit ungeheurer Geschwindigkeit. Deshalb wird diese Technik mittlerweile in vielen Bereichen der Computergrafik angewandt, von Videofiltern auf Smartphones bis hin zu den neuesten fotorealistisch wirkenden 3D-Videospielen.
Fragment-Shader ermöglichen die vollständige Kontrolle über alle Bildpunkte, die als Grafik auf dem Bildschirm erscheinen. Und das mit ungeheurer Geschwindigkeit. Deshalb wird diese Technik mittlerweile in vielen Bereichen der Computergrafik angewandt, von Videofiltern auf Smartphones bis hin zu beeindruckenden 3D-Videospielen.
![Grafik aus dem Spiel „Journey“ von That Game Company](journey.jpg)
Die folgenden Kapitel wollen Dir zeigen, wie unglaublich schnell und leistungsfähig diese Technik ist, und wie Du sie im Rahmen von privaten und beruflichen Projekten einsetzen kannst.
Die folgenden Kapitel zeigen Dir, wie unglaublich schnell und leistungsfähig diese Technik ist und wie Du sie im Rahmen von privaten und beruflichen Projekten einsetzen kannst.
## Für wen ist dieses Buch geeignet?
Dieses Buch wendet sich an kreative Programmierer, Spieleentwickler und Ingenieure, die bereits über eine gewisse Programmiererfahrung, sowie grundlegende Kenntnisse aus den Bereichen der linearen Algebra und der Trigonometrie verfügen. (Falls Du erst noch Programmieren lernen möchtest, empfehle ich Dir, mit [Processing](https://processing.org/) zu beginnen und anschließend mit diesem Buch fortzufahren.)
Dieses Buch wendet sich an kreative Programmierer, Spieleentwickler und Ingenieure, die bereits Programmiererfahrung und grundlegende Kenntnisse in den Bereichen linearen Algebra und Trigonometrie haben. (Falls Du erst noch programmieren lernen möchtest, empfehle ich Dir, mit [Processing](https://processing.org/) zu beginnen und anschließend mit diesem Buch fortzufahren.)
Die folgenden Kapitel werden Dir zeigen, wie Du Shader in Deinen Projekten einsetzen kannst, um die Qualität und die Geschwindigkeit bei der Erzeugung von Grafiken zu verbessern. GLSL-Shader (GLSL steht für „OpenGL Shading Language“) lassen sich auf einer Vielzahl von Hardwareplattformen und Betriebssystemen kompilieren und ausführen. Dadurch kannst Du das erlernte Wissen in jeder Umgebung einsetzen, die OpenGL, OpenGL ES oder WebGL unterstützt.
Dieses Buch zeigt Dir, wie Du Shader in Deinen Projekten einsetzen kannst und wie Du die Qualität und die Geschwindigkeit von Shadern verbesserst. GLSL-Shader (GLSL steht für „OpenGL Shading Language“) lassen sich auf einer Vielzahl von Hardwareplattformen und Betriebssystemen kompilieren und ausführen. Dadurch kannst Du das erlernte Wissen in jeder Umgebung einsetzen, die OpenGL, OpenGL ES oder WebGL benutzt.
In anderen Worten, Du kannst Dein Know-how u.a. beim Malen mit [Processing](https://processing.org/), bei Anwendungen für [openFrameworks](http://openframeworks.cc/), interaktiven Installationen mit [Cinder](http://libcinder.org/), Webseiten mit [Three.js](http://threejs.org/) oder bei Spielen für iOS/Android nutzen.
In anderen Worten, Du kannst Dein Know-how u.a. beim Malen mit [Processing](https://processing.org/), bei Anwendungen für [openFrameworks](http://openframeworks.cc/), interaktiven Installationen mit [Cinder](http://libcinder.org/), Webseiten mit [Three.js](http://threejs.org/) oder bei Spielen für iOS und Android nutzen.
## Welchen Aspekten widmet sich dieses Buch?
Dieses Buch konzentriert sich auf den Einsatz von GLSL-Pixel-Shadern. Zunächst erklären wir, was Shader sind, dann wenden wir uns der algorithmischen Erzeugung von Formen, Mustern, Texturen und Animationen zu. Du lernst die Grundlagen der Programmiersprache für OpenGL-Shader kennen und erfährst, wie man sie für konkrete Zwecke nutzt. Dazu zählt die Bildbearbeitung (Bildmanipulationen, Matrizenoperationen, Farbfilter und weitere Effekte), sowie Simulationen (Conways Game of Life, Reaktion und Diffusion von Chemikalien nach Gray-Scott, Erzeugung von Wasserwellen, die Nachbildung des Malens mit Wasserfarben, Erzeugung von Voronoi-Zellen und mehr). Zum Ende des Buches hin lernst Du fortschrittliche Techniken kennen, bei denen etwa mit Hilfe des sogenannten „Ray Marchings“ beeindruckende 2D-Grafiken aus 3D-Daten generiert werden.
Dieses Buch behandelt hauptsächlich den Umgang mit GLSL-Pixel-Shadern. Zunächst erklären wir, was Shader sind, dann wenden wir uns der algorithmischen Erzeugung von Formen, Mustern, Texturen und Animationen zu. Du lernst die Grundlagen der Programmiersprache für OpenGL-Shader kennen und erfährst, wie man sie für konkrete Zwecke nutzt. Dazu zählt die Bildbearbeitung (Bildmanipulationen, Matrizenoperationen, Blurfilter, Farbfilter und weitere Effekte), sowie Simulationen (Conways Game of Life, Reaktion und Diffusion von Chemikalien nach Gray-Scott, Erzeugung von Wasserwellen, die Nachbildung des Malens mit Wasserfarben, Erzeugung von Voronoi-Zellen und mehr). Gegen Ende vom Buch lernst Du mehrere fortgeschrittene Techniken kennen, die mithilfe einer Technik namens *Ray-Marching* beeindruckende 2D-Grafiken aus 3D-Daten generiert werden.
*In jedem Kapitel gibt es interaktive Beispiele, mit denen Du vieles ausprobieren kannst.* Sobald du etwas am Programmcode änderst, erscheinen die daraus resultierenden Veränderungen an der erzeugten Grafik sofort auf dem Bildschirm. Die vorgestellten Konzepte sind teilweise abstrakt und auf den ersten Blick vielleicht ein wenig verwirrend. Aber mit Hilfe der interaktiven Beispiele kannst Du den Lernstoff leicht nachvollziehen. Je mehr Du ausprobierst, desto einfacher wird Dir das Lernen fallen.
*In jedem Kapitel gibt es interaktive Beispiele, mit denen Du vieles ausprobieren kannst.* Sobald du etwas am Programmcode änderst, erscheinen die daraus resultierenden Veränderungen an der erzeugten Grafik sofort. Die vorgestellten Konzepte sind teilweise abstrakt und auf den ersten Blick vielleicht ein wenig verwirrend. Aber mithilfe der interaktiven Beispiele kannst Du den Lernstoff leicht nachvollziehen. Je mehr Du ausprobierst, desto einfacher wird Dir das Lernen fallen.
Was dieses Buch nicht behandelt:
* Dies *ist kein * Buch über openGL oder webGL. OpenGL/webGL ist ein umfassenderes Thema als GLSL- oder Fragment-Shader. Wenn Du mehr über openGL/webGL lernen möchtest, empfehle ich Dir die folgenden Materialien: [OpenGL Einführung (Englisch)](https://open.gl/introduction), [Die achte Ausgabe des „OpenGL Programming Guide“ (Englisch)](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) (auch bekannt als das „Red Book“) oder [„WebGL: Up and Running“ (Englisch)](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)
* Dies *ist kein* Buch über OpenGL oder WebGL. OpenGL und WebGL sind ein umfassenderes Thema als GLSL- oder Fragment-Shader. Wenn Du mehr über OpenGL oder WebGL lernen möchtest, empfehle ich Dir die folgenden Materialien: [OpenGL Einführung (Englisch)](https://open.gl/introduction), [Die achte Ausgabe des „OpenGL Programming Guide“ (Englisch)](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) (auch bekannt als das „Red Book“) oder [„WebGL: Up and Running“ (Englisch)](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)
* Das vorliegende Werk *ist außerdem kein* Mathematik-Buch. Obwohl wir bei vielen Techniken und Algorithmen auf Algebra und Trigonometrie zurückgreifen, werden die mathematischen Grundlagen nicht an jeder Stelle vollständig in allen Details erklärt. Bei Fragen dazu empfehle ich Dir eines der folgenden Bücher: [Dritte Ausgabe von „Mathematics for 3D Game Programming and Computer Graphics“ (Englisch)](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) oder [Zweite Ausgabe von „Essential Mathematics for Games and Interactive Applications“ (Englisch)](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).
@ -40,10 +40,10 @@ Nicht viel! Wenn Du auf Deinem Rechner, Smartphone oder Tablet einen modernen We
Alternativ kannst Du auch:
- [Eine Offline-Fassung dieses Buches erstellen](https://thebookofshaders.com/appendix/?lan=de)
- [Eine Offline-Fassung von diesem Buch erstellen](https://thebookofshaders.com/appendix/?lan=de)
- [Die Beispielprogramme aus diesem Buch direkt auf einem RaspberryPi ausführen (ohne Internet-Browser)](https://thebookofshaders.com/appendix/?lan=de)
- [Eine PDF-Datei mit diesem Buch erzeugen, um es auszudrucken](https://thebookofshaders.com/appendix/?lan=de)
- [Eine druckbare PDF-Datei mit diesem Buch erzeugen](https://thebookofshaders.com/appendix/?lan=de)
- Die [Online-Ablage dieses Buches](https://github.com/patriciogonzalezvivo/thebookofshaders) bei GitHub nutzen, um Fehler zu melden und Programmcode mit anderen Lesern zu teilen.
- Die [Github-Seite von diesem Buch](https://github.com/patriciogonzalezvivo/thebookofshaders) nutzen, um Fehler zu melden und Programmcode mit anderen Lesern zu teilen.

View File

@ -2,14 +2,14 @@
<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).
Powyższe obrazy zostały stworzone na różne sposoby. Pierwszy z nich stworzył Van Gogh, aplikując farbę warstwa po warstwie. Zajęło mu to godziny. Drugi stworzono poprzez połączenie czterech macierzy pikseli odpowiadających kolorom: cyjan, magenta, żółty i czarny. Kluczową różnicę stanowi fakt, że drugi obraz stworzony 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.
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 trójwymiarowych gier wideo.
![Journey by That Game Company](journey.jpg)
@ -17,21 +17,21 @@ W następujących rozdziałach odkryjesz jak niewiarygodnie szybkie i potężne
## 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 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 graficznych 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.
Ta książka skupia się na użyciu fragment shaderów GLSL. Najpierw 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.
*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 interaktywne 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:
* To *nie jest* książka do nauki matematyki. Choć opisane są w niej algorytmy i techniki, które opierają się na 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ąć?
@ -40,11 +40,11 @@ Niewiele! Jeśli masz współczesną przeglądarkę, która obsługuje WebGL (ja
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)
- [Stworzyć wersję offline 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)
- [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.
- Sprawdź [repozytorium GitHub](https://github.com/patriciogonzalezvivo/thebookofshaders) tej książki, by pomóc w rozwiązywaniu problemów (issues) i podzielić się swoim kodem.

View File

@ -34,7 +34,7 @@ O que esse livro não cobre:
## O que você precisa para começar?
Não muito! Se você tem um browser modernos que possa rodar WebGL (como Chrome, Firefox ou Safari) e uma conexão à internet, clique no botão para o próximo capítulo no fim desta página para começar.
Não muito! Se você tem um browser moderno que possa rodar WebGL (como Chrome, Firefox ou Safari) e uma conexão à internet, clique no botão para o próximo capítulo no fim desta página para começar.
Alternativamente, baseado no que você tem, ou no que você precisa deste livro você pode:

47
00/README-ua.md Normal file
View File

@ -0,0 +1,47 @@
# Вступ
<canvas id="custom" class="canvas" data-fragment-url="cmyk-halftone.frag" data-textures="vangogh.jpg" width="700px" height="320px"></canvas>
Наведені вище зображення були зроблені різними способами. Перше намальовано рукою Ван Гога з поступовим нанесенням фарби шар за шаром. Це зайняло в нього години. Друге було створено миттєво за допомоги комбінації чотирьох матриць пікселів різних кольорів: ціанового, пурпурового, жовтого та чорного. Ключова відмінність полягає в тому, що друге зображення отримано не послідовним чином, тобто не поступово крок за кроком, а усе одночасно.
Ця книга про революційну техніку обчислювання - *фрагментні шейдери* - яка виводить генерацію цифрових зображень на новий рівень. Ви можете думати про це як про своєрідний еквівалент преса Гутенберга для графіки.
![Gutenberg's press](gutenpress.jpg)
Фрагментні шейдери дають вам повний контроль над пікселями екрану із надзвичайно високою швидкістю. Ось чому вони використовуються у самих різних випадках, від відеофільтрів на мобільних телефонах до неймовірних 3D-ігор.
![Journey by That Game Company](journey.jpg)
У наступних розділах ви дізнаєтесь, наскільки неймовірно швидка і потужна ця техніка та як застосувати її у своїх професійних та особистих проєктах.
## Для кого ця книга?
Книга написана для творчих програмістів, розробників ігор та інженерів, які мають досвід програмування, базові знання лінійної алгебри та тригонометрії й бажають вивести свою роботу на захопливий новий рівень графічної якості. Якщо ви тільки починаєте і хочете навчитися програмувати, я наполегливо рекомендую вам почати з [Processing](https://processing.org/) і повернутися пізніше, коли освоїтесь.
Ця книга навчить вас використовувати та інтегрувати шейдери у ваші проєкти, покращуючи їхню продуктивність і графічну якість. Оскільки GLSL (OpenGL Shading Language) шейдери компілюються і працюють на різних платформах, ви зможете застосувати отримані тут знання до будь-якого середовища, яке використовує OpenGL, OpenGL ES або WebGL. Іншими словами, ви зможете застосовувати та використовувати свої знання у [Processing](https://processing.org/)-скетчах, [openFrameworks](http://openframeworks.cc/) програмах, інтерактивних інсталяціях [Cinder](http ://libcinder.org/), веб-сайтах з [Three.js](http://threejs.org/) або iOS/Android іграх.
## Про що йдеться в цій книзі?
Ця книга буде присвячена використанню піксельних GLSL шейдерів. Спочатку ми визначимо, що таке шейдери, а потім навчимося створювати за їх допомогою процедурні форми, візерунки, текстури та анімацію. Ви вивчите основи мови шейдерів та застосуєте її до більш корисних задач, таких як: обробка зображень (різні операції із зображеннями, згортання матриці, розмиття, кольорові фільтри, таблиці пошуку та інші ефекти) і симуляції ("гра життя" Конвея, реакційно-дифузійна модель Грея-Скотта, брижі води, акварельні ефекти, комірки Вороного тощо). Ближче до кінця книги ми побачимо набір передових технік, заснованих на Ray Marching (алгоритми трасування променів).
*У кожному розділі є інтерактивні приклади, з кодом яких можна взаємодіяти.* При редагуванні коду ви одразу побачите відповідні зміни. Описані поняття можуть бути абстрактними та незрозумілими, тому інтерактивні приклади будуть корисними при вивченні матеріалу. Чим швидше ви побачите концепції в дії, тим легшим буде процес навчання.
Що не розглядається в цій книзі:
* Це *не* книга з openGL або webGL. OpenGL/webGL є більш обширною темою, ніж GLSL або фрагментні шейдери. Щоб дізнатися більше про openGL/webGL, я рекомендую переглянути: [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) (також відома як червона книга) або [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)
* Це *не* підручник з математики. Хоча ми розглянемо низку алгоритмів і методів, які спираються на розуміння алгебри та тригонометрії, ми не будемо пояснювати їх докладно. Якщо у вас виникнуть запитання щодо математики, я рекомендую тримати під рукою одну з таких книг як: [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) або [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).
## Що потрібно для початку?
Не багато! Якщо у вас є сучасний браузер, який підтримує WebGL (наприклад, Chrome, Firefox або Safari) і підключення до Інтернету, просто натисніть кнопку «Next» в кінці цієї сторінки.
Окрім того, в залежності від вашого бажання, ви можете:
- [Зробити офлайн-версію книги](https://thebookofshaders.com/appendix/00/?lan=ua)
- [Запустити приклади на Raspberry Pi без браузера](https://thebookofshaders.com/appendix/01/?lan=ua)
- [Зібрати PDF-версію книги для друку](https://thebookofshaders.com/appendix/02/?lan=ua)
- Переглянути [GitHub-репозиторій книги](https://github.com/patriciogonzalezvivo/thebookofshaders) для виправлення помилок або поділитися своїми прикладами коду.

View File

@ -18,7 +18,7 @@ In the following chapters you will discover how incredibly fast and powerful thi
This book is written for creative coders, game developers and engineers who have coding experience, a basic knowledge of linear algebra and trigonometry, and who want to take their work to an exciting new level of graphical quality. (If you want to learn how to code, I highly recommend you start with [Processing](https://processing.org/) and come back later when you are comfortable with it.)
This book will teach you how to use and integrate shaders into your projects, improving their performance and graphical quality. Because GLSL (OpenGL Shading Language) shaders compile and run on a variety of platforms, you will be able to apply what you learn here to any enviroment that uses OpenGL, OpenGL ES or WebGL. In other words, you will be able to apply and use your knowledge with [Processing](https://processing.org/) sketches, [openFrameworks](http://openframeworks.cc/) applications, [Cinder](http://libcinder.org/) interactive installations, [Three.js](http://threejs.org/) websites or iOS/Android games.
This book will teach you how to use and integrate shaders into your projects, improving their performance and graphical quality. Because GLSL (OpenGL Shading Language) shaders compile and run on a variety of platforms, you will be able to apply what you learn here to any environment that uses OpenGL, OpenGL ES or WebGL. In other words, you will be able to apply and use your knowledge with [Processing](https://processing.org/) sketches, [openFrameworks](http://openframeworks.cc/) applications, [Cinder](http://libcinder.org/) interactive installations, [Three.js](http://threejs.org/) websites or iOS/Android games.
## What does this book cover?
@ -28,7 +28,7 @@ This book will focus on the use of GLSL pixel shaders. First we'll define what s
What this book doesn't cover:
* This *is not* an openGL or webGL book. OpenGL/webGL is a bigger subject than GLSL or fragment shaders. To learn more about openGL/webGL I recommend taking a look at: [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) (also known as the red book) or [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)
* This *is not* an OpenGL or webGL book. OpenGL/webGL is a bigger subject than GLSL or fragment shaders. To learn more about OpenGL/webGL I recommend taking a look at: [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) (also known as the red book) or [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)
* This *is not* a math book. Although we will cover a number of algorithms and techniques that rely on an understanding of algebra and trigonometry, we will not explain them in detail. For questions regarding the math I recommend keeping one of the following books nearby: [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) or [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).

View File

@ -1,13 +1,14 @@
# Einstieg
## Was ist ein Fragment-Shader?
Im vorangegangenen Kapitel haben wir Fragment-Shader als eine Art Gutenbergsche Druckerpresse für Grafiken beschrieben. Nun, wie kommen wir darauf? Und vor allem: Was genau soll das sein, ein „Shader“?
Im vorangegangenen Kapitel haben wir Fragment-Shader als eine Art Gutenbergsche Druckerpresse für Computergrafiken beschrieben. Nun, wie kommen wir darauf? Und was genau soll ein Shader sein?
![Von Brief-für-Brief zu Seite-für-Seite. Rechts: William Blades (1891), links Rolt-Wheeler (1920).](print.png)
Falls Du schon Erfahrung mit der Erstellung von Computergrafiken gesammelt hast, kennst Du bestimmt die folgende Vorgehensweise: Man malt per Programmbefehl Kreise, Rechtecke, Dreiecke und Linien, damit auf dem Bildschirm nach und nach die gewünschte Grafik entsteht. Dieser Prozess erinnert stark an das Verfassen eines Dokuments per Hand, indem man einzelne Zeichen-Operationen Schritt für Schritt abarbeitet.
Falls Du schon Erfahrung mit der Erstellung von Computergrafiken gesammelt hast, kennst Du bestimmt die folgende Vorgehensweise: Man malt per Programmbefehl Kreise, Rechtecke, Dreiecke und Linien, damit auf dem Bildschirm nach und nach die gewünschte Grafik entsteht. Dieser Vorgang ähnelt von Hand einen Brief oder Buch zu verfassen. Es handelt sich um eine Folge von Anweisungen (den Zeichenoperationen), die Schritt für Schritt abgearbeiet werden müssen.
Auch Shader verkörpern eine Abfolge von Operationen, doch hier werden diese Operationen gleichzeitig für jeden Bildpunkt (Pixel) auf der Zeichenfläche ausgeführt. Das hat zur Folge, dass der Programmcode des Shaders in Abhängigkeit von der Lage des jeweils bearbeiteten Bildpunktes unterschiedlich agieren muss. Der Shader arbeitet dabei als eine Funktion, die die Koordinaten des jeweiligen Bildpunktes erhält und als Ergebnis die Farbe für diesen Bildpunkt zurückliefert. Ist der Shader einmal kompiliert, läuft dieser Prozess unglaublich schnell und für sehr viele Bildpunkte gleichzeitig ab.
Auch Shader sind nur eine Abfolge von Anweisungen, doch werden diese Anweisungen alle gleichzeitig für jeden Bildpunkt (Pixel) in der Grafik ausgeführt. Das bedeutet also, dass das von Dir geschriebene Shader-Programm die Grafik abhängig von der sich ändernden Position eines einzelnen Bildpunkts beschreiben muss. Der Shader arbeitet dabei als eine Funktion, die die Koordinaten des jeweiligen Bildpunktes erhält und als Ergebnis die Farbe für diesen Bildpunkt zurückliefert. Ist der Shader einmal kompiliert, läuft dieser Prozess unglaublich schnell und für sehr viele Bildpunkte gleichzeitig ab.
![Verschiebbare Lettern mit Chinesischen Symbolen](typepress.jpg)

View File

@ -28,7 +28,7 @@ Wyobraź sobie procesor twojego komputera jako potok przetwarzania (ang. "pipeli
![CPU](00.jpeg)
Gry video i inne aplikacje graficzne wymagają zdecydowanie więcej mocy obliczeniowej niż większość programów, gdyż muszą wykonywać ogromne ilości operacji piksel po pikselu. Nie dość, że każdy pojedynczy piksel musi być obliczony, to w wypadku gier 3D dochodzą do tego obliczenia geometryczne i obliczenie perspektywy.
Gry wideo i inne aplikacje graficzne wymagają zdecydowanie więcej mocy obliczeniowej niż większość programów, gdyż muszą wykonywać ogromne ilości operacji piksel po pikselu. Nie dość, że każdy pojedynczy piksel musi być obliczony, to w przypadku gier 3D dochodzą do tego obliczenia geometryczne i obliczenie perspektywy.
<!-- Video games and other graphic applications require a lot more processing power than other programs. Because of their graphic content they have to do huge numbers of pixel-by-pixel operations. Every single pixel on the screen needs to be computed, and in 3D games geometries and perspectives need to be calculated as well. -->
@ -44,7 +44,7 @@ Z pomocą przychodzi przetwarzanie równoległe. Zamiast kilku dużych, potężn
![GPU](04.jpeg)
Wyobraź sobie mały mikroprocesor jako tablicę rur (spójrz na obrazek powyżej), a dane jako piłeczki ping pongowe. 14.400.000 piłeczek ping pongowych na sekundę może zablokować prawie każdą pojedynczą rurę. Ale tabela 800x600 malutkich rur przyjmująca co sekundę 30 fal po 480.000 piłeczek poradzi sobie z nimi bez problemu. Tak samo działa to na wyższych rozdzielczościach - im więcej równolegle pracującego hardware'u, tym większy potok, z którymi GPU sobie poradzi.
Wyobraź sobie mały mikroprocesor jako tablicę rur (spójrz na obrazek powyżej), a dane jako piłeczki ping pongowe. 14.400.000 piłeczek ping pongowych na sekundę może zablokować prawie każdą pojedynczą rurę. Ale tabela 800x600 malutkich rur przyjmująca co sekundę 30 fal po 480.000 piłeczek poradzi sobie z nimi bez problemu. Tak samo działa to na wyższych rozdzielczościach - im więcej równolegle pracującego hardware'u, tym większy potok, z którym GPU sobie poradzi.
<!-- Picture the tiny microprocessors as a table of pipes, and the data of each pixel as a ping pong ball. 14,400,000 ping pong balls a second can obstruct almost any pipe. But a table of 800x600 tiny pipes receiving 30 waves of 480,000 pixels a second can be handled smoothly. This works the same at higher resolutions - the more parallel hardware you have, the bigger the stream it can manage. -->
@ -64,7 +64,7 @@ Jak to mówią: "with great power comes great responsibility". Stosuje się to r
<!-- As Uncle Ben said “with great power comes great responsibility,” and parallel computation follows this rule; the powerful architectural design of the GPU comes with its own constraints and restrictions. -->
Aby wątki mogły działać równolegle, muszą być od siebie niezależne. Mówimy, że wątki są *ślepe* na to, co robi reszta wątków. Ograniczenie to implikuje, że dane muszą "płynąć w ten samą stronę" - nie jest możliwe sprawdzić dane wyjściowe innego wątku, zmodyfikować jego dane wejściowe albo przekazać dane wyjściowe jednego wątku jako dane wejściowe innego.
Aby wątki mogły działać równolegle, muszą być od siebie niezależne. Mówimy, że wątki są *ślepe* na to, co robi reszta wątków. Ograniczenie to implikuje, że dane muszą "płynąć w tę samą stronę" - nie jest możliwe sprawdzić dane wyjściowe innego wątku, zmodyfikować jego dane wejściowe albo przekazać dane wyjściowe jednego wątku jako dane wejściowe innego.
<!-- In order to run in parallel every pipe, or thread, has to be independent from every other thread. We say the threads are *blind* to what the rest of the threads are doing. This restriction implies that all data must flow in the same direction. So its impossible to check the result of another thread, modify the input data, or pass the outcome of a thread into another thread. Allowing thread-to-thread communications puts the integrity of the data at risk. -->
@ -72,6 +72,6 @@ Poza tym GPU odpowiada za to, żeby każdy wątek miał coś do roboty, i żeby
<!-- Also the GPU keeps the parallel micro-processor (the pipes) constantly busy; as soon as they get free they receive new information to process. It's impossible for a thread to know what it was doing in the previous moment. It could be drawing a button from the UI of the operating system, then rendering a portion of sky in a game, then displaying the text of an email. Each thread is not just **blind** but also **memoryless**. Besides the abstraction required to code a general function that changes the result pixel by pixel depending on its position, the blind and memoryless constraints make shaders not very popular among beginning programmers. -->
Ale nie martw się! W następnych rozdziałąch nauczymy się, krok po kroku, prostych i zaawansowanych obliczeń shadingowych. Jeżeli czytasz to we współczesnej przeglądarce, to z pewnością docenisz zabawę z interaktywnymi przykładami. Ale nie przedłużajmy! Naciśnij *Next>>* aby przejść dalej.
Ale nie martw się! W następnych rozdziałach nauczymy się, krok po kroku, prostych i zaawansowanych obliczeń shadingowych. Jeżeli czytasz to we współczesnej przeglądarce, to z pewnością docenisz zabawę z interaktywnymi przykładami. Ale nie przedłużajmy! Naciśnij *Next>>* aby przejść dalej.
<!-- Don't worry! In the following chapters, we will learn step-by-step how to go from simple to advanced shading computations. If you are reading this with a modern browser, you will appreciate playing with the interactive examples. So let's not delay the fun any longer and press *Next >>* to jump into the code! -->

48
01/README-ua.md Normal file
View File

@ -0,0 +1,48 @@
# Вступ
## Що таке фрагментний шейдер?
У попередньому розділі ми описали шейдери як еквівалент пресу Гутенберга для графіки. Чому? І що ще важливіше: що таке шейдер?
![Ліворуч: літера за літерою (монах скрипторію за роботою, William Blades, 1891). Праворуч: Сторінка за сторінкою, (печатний станок, Rolt-Wheeler, 1920.](print.png)
Якщо у вас уже є досвід малювання за допомогою комп'ютера, то ви знаєте, що в цьому процесі ви, умовно кажучи, спочатку малюєте коло, потім прямокутник, лінію, ще кілька трикутників і так далі, доки не отримаєте потрібне зображення. Цей процес дуже схожий на написання листа чи книги від руки це набір інструкцій, які послідовно виконують одне завдання за іншим.
Шейдери також є набором інструкцій, але вони виконуються одночасно для кожного пікселя на екрані. Це означає, що код, який ви пишете, має поводити себе по-різному залежно від положення пікселя на екрані. Подібно до печатного преса, ваша програма працюватиме як функція, яка отримує координати пікселя та повертає колір. Після компіляції вона працюватиме надзвичайно швидко.
![Китайський набірний шрифт](typepress.jpg)
## Чому шейдери швидкі?
Щоб відповісти на це питання, я розповім про чудеса *паралельних обчислень*.
Уявіть центральний процесор вашого комп'ютера у вигляді великої промислової труби, а кожне завдання як щось, що проходить крізь неї, як через фабричну лінію. Деякі завдання більші за інші, а це означає, що для їх вирішення потрібно більше часу та енергії. В комп'ютерному сенсі ми скажемо, що їм потрібна більша обчислювальна потужність. Через особливості архітектури комп'ютерів завдання виконуються послідовно, тобто по черзі. Сучасні комп'ютери зазвичай мають групи з кількох процесорів, які працюють як ці труби, виконуючи завдання одне за одним, щоб забезпечити безперебійну роботу. Кожна подібна труба також називається *потоком*.
![CPU](00.jpeg)
Відеоігри та інші графічні програми вимагають набагато більшої обчислювальної потужності, ніж інші програми. Через свій графічний контент їм доводиться виконувати величезну кількість попіксельних операцій. Необхідно обчислити кожен окремий піксель на екрані, а в 3D-іграх також потрібно обчислити усю геометрію і перспективу.
Повернемося до нашої метафори про труби та завдання. Кожен піксель на екрані представляє просте маленьке завдання. Окремо такі завдання не є проблемою для CPU, але проблема в тому, що кожне крихітне завдання потрібно виконати для кожного пікселя на екрані! Це означає, що на старому екрані з роздільною здатністю 800x600 потрібно обробляти 480 000 пікселів на 1 кадр оновлення, що становить близько 14 400 000 обчислень за секунду! О, так! Це достатньо велика проблема, щоб перенавантажити мікропроцесор. У сучасному дисплеї Retina 2880x1800, що оновлюється зі швидкістю 60 кадрів на секунду, ця кількість обчислень за секунду складе 311 040 000. Як інженери графічних систем розв'язують цю проблему?
![](03.jpeg)
Ось коли паралельні обчислення стають хорошим рішенням. Замість того, щоб мати пару великих і потужних мікропроцесорів, або *труб*, розумніше мати багато маленьких мікропроцесорів, що працюють паралельно. Саме так і влаштовано графічний процесор (GPU).
![GPU](04.jpeg)
Уявіть крихітні мікропроцесори у вигляді столу із труб, а дані кожного пікселя як кульку для пінг-понгу. 14 400 000 кульок для пінг-понгу за секунду можуть закупорити майже будь-яку трубу. Але стіл з крихітними трубками розміром 800x600, зможе спокійно прийняти 30 хвиль по 480 000 пікселів за секунду і працюватиме безперебійно. Те ж саме і з прикладом вищої роздільної здатності - чим більше у вас обладнання, що працює паралельно, тим більшим потоком воно зможе керувати.
Ще одна "суперздатність" графічного процесора — це спеціальні математичні функції, прискорені за допомогою апаратного забезпечення. Тож складні математичні операції вирішуються безпосередньо мікрочіпами, а не програмним забезпеченням. Це означає надшвидкі тригонометричні та матричні операції - настільки швидкі, наскільки швидко може рухатися електрика.
## Що таке GLSL?
GLSL розшифровується як OpenGL Shading Language і є спеціальним стандартом шейдерних програм, які ви побачите в наступних розділах. Залежно від апаратного забезпечення та операційної системи існують різні типи шейдерів. Ми працюватимемо зі специфікаціями OpenGL, які регулює [Khronos Group](https://www.khronos.org/opengl/). Розуміння історії OpenGL може бути корисним для розуміння більшості його дивних конвенцій. Для цього я рекомендую переглянути наступне посилання: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html)
## Чому шейдери такі болючі?
Як сказав дядько Бен, "з великою силою приходить велика відповідальність" і паралельні обчислення дотримуються цього правила. Потужний архітектурний дизайн графічного процесора має власні обмеження.
Щоб працювати паралельно, кожен канал або потік має бути незалежним від будь-якого іншого потоку. Ми кажемо, що потоки *сліпі* стосовно того, що роблять інші потоки. Це обмеження означає, що всі дані повинні рухатись в одному напрямку. Тому неможливо перевірити результат іншого потоку, змінити вхідні дані або передати результат одного потоку в інший потік. Спроба дозволу міжпотокових зв'язків ставить під загрозу цілісність даних.
Крім того, GPU підтримує свої мікропроцесори (труби) постійно зайнятими. Як тільки вони звільняються, вони отримують нову інформацію для обробки. Потоку неможливо дізнатися, що він робив у попередній момент. Це могло бути малювання кнопки інтерфейсу операційної системи, потім рендеринг частини неба із гри, а потім зображення тексту електронного листа. Кожен потік є не лише **сліпим**, а й **безпам'ятним**. Окрім абстракції, необхідної для кодування загальної функції, яка змінює результат в залежності від положення пікселя, сліпота і безпам'ятство роблять шейдери не дуже популярними серед програмістів-початківців.
Не хвилюйтесь! У наступних розділах ми крок за кроком розглянемо шейдерні обчислення від простого до складного. Якщо ви читаєте книгу в сучасному браузері, то оціните можливість взаємодії з інтерактивними прикладами. Тож давайте більше не відкладати веселощі та натискайте на посилання *Next >>*, щоб перейти до програмування!

View File

@ -35,7 +35,7 @@ Another “super power” of the GPU is special math functions accelerated via h
## What is GLSL?
GLSL stands for openGL Shading Language, which is the specific standard of shader programs you'll see in the following chapters. There are other types of shaders depending on hardware and Operating Systems. Here we will work with the openGL specs regulated by [Khronos Group](https://www.khronos.org/opengl/). Understanding the history of OpenGL can be helpful for understanding most of its weird conventions, for that I recommend taking a look at: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html)
GLSL stands for OpenGL Shading Language, which is the specific standard of shader programs you'll see in the following chapters. There are other types of shaders depending on hardware and Operating Systems. Here we will work with the OpenGL specs regulated by [Khronos Group](https://www.khronos.org/opengl/). Understanding the history of OpenGL can be helpful for understanding most of its weird conventions, for that I recommend taking a look at: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html)
## Why are Shaders famously painful?

View File

@ -1,6 +1,6 @@
## 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.
Zazwyczaj przykład "Hello world!" stanowi pierwszy krok przy nauce nowego języka. Jest to prosty jednolinijkowy program, 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. -->
@ -10,7 +10,7 @@ W świecie GPU renderowanie tekstu jest jednak zbyt skomplikowanym zadaniem dla
<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.
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. -->
@ -38,9 +38,9 @@ Choć kod jest prosty, to możemy wyciągnąć z niego ważne wnioski:
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;`).
6. Typy zmiennoprzecinkowe są kluczowe w shaderach, więc ich poziom precyzji (ang. *precision*) ma ogromne znaczenie. 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ł:
7. Ostatni i chyba najważniejszy szczegół specyfikacji GLSL: nie ma gwarancji, ż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 graficznych, 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. Przyzwyczaj 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() {
@ -54,7 +54,7 @@ Czas na ćwiczenia! Pamiętaj, że w wypadku błędu kompilacji pokaże się inf
* 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:
* Stwórz osobną funkcję, która zwraca dowolny kolor i użyj jej w `main()`. Wskazówka: poniższy kod zwraca kolor czerwony:
```glsl
vec4 red(){
@ -68,4 +68,4 @@ vec4 red(){
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).
Choć przykład ten nie jest zbyt ekscytujący, 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).

53
02/README-ua.md Normal file
View File

@ -0,0 +1,53 @@
## Hello World
Зазвичай програма "Hello world!" — це перший крок до вивчення нової мови. Це проста програма, яка виводить вітальне повідомлення та заявляє про майбутні можливості.
У GPU-світі рендеринг тексту є надскладним завданням для першого кроку. Натомість щоб висловити свій ентузіазм, ми виберемо та намалюємо яскравий колір!
<div class="codeAndCanvas" data="hello_world.frag"></div>
Якщо ви читаєте цю книгу в браузері, попередній блок коду є інтерактивним. Це означає, що ви можете змінити будь-яку частину коду, яку захочете. Зміни будуть оновлені негайно завдяки архітектурі GPU, яка компілює та замінює шейдери *на льоту*. Спробуйте змінити значення в рядку 8.
Хоча ці прості рядки коду не виглядають складними, ми можемо вивести з них суттєві знання:
1. Мова шейдерів має одну функцію `main`, яка повертає колір у кінці. Це схоже на мову C.
2. Остаточний колір пікселя записується у зарезервовану глобальну змінну `gl_FragColor`.
3. У цій C-подібній мові є вбудовані *змінні* (наприклад, `gl_FragColor`), *функції* і *типи*. У цьому випадку ми щойно познайомилися з `vec4`, який означає чотиривимірний вектор числових значень з рухомою крапкою. Пізніше ми побачимо більше типів, таких як `vec3` і `vec2` разом із популярними `float`, `int` і `bool`.
4. Якщо ми уважно подивимося на тип `vec4`, то можемо зробити висновок, що його чотири аргументи відповідають ЧЕРВОНОМУ, ЗЕЛЕНОМУ, СИНЬОМУ та АЛЬФА-каналам. Також ми бачимо, що ці значення *нормалізовані* - це означає, що вони знаходяться в діапазоні від `0.0` до `1.0`. Пізніше ми дізнаємося, як нормалізація полегшує *зіставлення* значень між змінними.
5. Інша важлива *C-особливість*, яку ми можемо побачити в цьому прикладі, вказує на наявність макросів препроцесора. Макроси є частиною етапу попередньої компіляції. З їх допомогою можна визначити (`#define`) глобальні змінні та виконати деякі базові умовні операції, використовуючи `#ifdef` і `#endif`. Усі макрокоманди починаються з символу решітки `#`. Пре-компіляція відбувається безпосередньо перед компіляцією, підставляє всі визначення із директив `#defines` і перевіряє умови `#ifdef` (якщо визначено) і `#ifndef` (якщо не визначено). У наведеному вище прикладі "hello world!", ми вставляємо рядок 2, лише якщо визначено `GL_ES`, що здебільшого відбувається, коли код компілюється на мобільних пристроях і в браузерах.
6. Типи чисел з рухомою крапкою життєво важливі в шейдерах, тому рівень *точності* є вирішальним. Нижча точність означає швидший рендеринг, але ціною якості. Ви можете бути вибагливими та вказати точність кожної такої змінної, яку використовує. У другому рядку (`precision mediump float;`) ми встановлюємо середню точність для всіх значень з рухомою крапкою. Також можна вибрати низьку (`precision lowp float;`) або високу (`precision highp float;`) точність.
7. Остання і, мабуть, найважливіша деталь полягає в тому, що специфікації GLSL не гарантують автоматичного приведення типів. Що це означає? Виробники мають різні підходи до прискорення роботи відеокарт, але вони змушені гарантувати мінімальні вимоги. Автоматичне приведення типів не відноситься до них. У нашому прикладі `vec4` має містити число з рухомою крапкою на яке й очікує. Якщо ви хочете писати якісний узгоджений код і не витрачати години на відладку білих екранів, звикніть ставити крапку (`.`) для значень з рухомою крапкою. Бо наступний код працюватиме не завжди та не скрізь:
```glsl
void main() {
gl_FragColor = vec4(1, 0, 0, 1); // ПОМИЛКА
}
```
Тепер, коли ми описали найбільш релевантні елементи нашої програми "hello world!", настав час повернутися до блоку з кодом та почати застосовувати отримані знання. Ви помітите, що в разі помилок програма не компілюється, показуючи білий екран. Є кілька речей, які можна спробувати, наприклад:
* Спробуйте замінити числа з рухомою крапкою на цілі числа. Ваша графічна карта може підтримувати або не підтримувати таку поведінку.
* Спробуйте закоментувати рядок 8 і не призначати пікселю жодного значення.
* Спробуйте створити окрему функцію, яка повертає певний колір, і використайте її всередині `main()`. Нижче приклад функції, яка повертає червоний колір:
```glsl
vec4 red() {
return vec4(1.0, 0.0, 0.0, 1.0);
}
```
* Існує кілька способів конструювання типу `vec4`, спробуйте знайти інші способи. Ось один з них:
```glsl
vec4 color = vec4(vec3(1.0, 0.0, 1.0), 1.0);
```
Це не дуже захопливий, але найпростіший приклад - ми змінюємо всі пікселі всередині полотна на той самий однаковий колір. У наступному розділі ми побачимо, як змінити кольори пікселів за допомогою двох типів вхідних даних: просторового (положення пікселя на екрані) і часового (кількість секунд після завантаження сторінки).

View File

@ -4,7 +4,7 @@ Do tej pory widzieliśmy jak GPU zarządza wieloma równoległymi wątkami, z kt
<!-- So far we have seen how the GPU manages large numbers of parallel threads, each one responsible for assigning the color to a fraction of the total image. Although each parallel thread is blind to the others, we need to be able to send some inputs from the CPU to all the threads. Because of the architecture of the graphics card those inputs are going to be equal (*uniform*) to all the threads and necessarily set as *read only*. In other words, each thread receives the same data which it can read but cannot change. -->
Inputy te nazywamy `uniform`ami i mogę być większości wspieranych typów: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` i `samplerCube`. Uniformy definiowane są zwykle na górze shaderu zaraz po przypisaniu domyślnej precyzji float'ów.
Inputy te nazywamy `uniform`ami i mogą być większości wspieranych typów: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` i `samplerCube`. Uniformy definiowane są zwykle na górze shaderu zaraz po przypisaniu domyślnej precyzji floatów.
<!-- These inputs are called `uniform` and come in most of the supported types: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` and `samplerCube`. Uniforms are defined with the corresponding type at the top of the shader right after assigning the default floating point precision. -->
@ -18,34 +18,34 @@ uniform vec2 u_mouse; // pozycja myszy na kanwie (wyrażona w pikselach)
uniform float u_time; // czas w sekundach od załadowania shadera
```
Wyobraź sobie te uniformy jak małe mosty między CPU i GPU. Ich nazwy bywają różne, ale w tej książce używam: `u_time`, `u_resolution` i `u_mouse` (przeczytaj komentarze w kodzie, aby wiedzieć, co robią). Podążam za konwencją dodawnaia `u_` przed nazwą uniformów, aby było wiadomo, że nie są to zwykłe zmienne, ale ostatecznie jest to kwestia gustu. Przykładowo, [ShaderToy.com](https://www.shadertoy.com/) używa takich samych uniformów, ale z następującym nazewnictwem:
Wyobraź sobie te uniformy jak małe mosty między CPU i GPU. Ich nazwy bywają różne, ale w tej książce używam: `u_time`, `u_resolution` i `u_mouse` (przeczytaj komentarze w kodzie, aby wiedzieć, co robią). Podążam za konwencją dodawania `u_` przed nazwą uniformów, aby było wiadomo, że nie są to zwykłe zmienne, ale ostatecznie jest to kwestia gustu. Przykładowo, [ShaderToy.com](https://www.shadertoy.com/) używa takich samych uniformów, ale z następującym nazewnictwem:
<!-- You can picture the uniforms like little bridges between the CPU and the GPU. The names will vary from implementation to implementation but in this series of examples Im always passing: `u_time` (time in seconds since the shader started), `u_resolution` (billboard size where the shader is being drawn) and `u_mouse` (mouse position inside the billboard in pixels). Im following the convention of putting `u_` before the uniform name to be explicit about the nature of this variable but you will find all kinds of names for uniforms. For example [ShaderToy.com](https://www.shadertoy.com/) uses the same uniforms but with the following names: -->
```glsl
uniform vec3 iResolution;
uniform vec4 iMouse;
uniform float iTime;
uniform vec3 iResolution; // rozdzielczość obszaru widoku (w pikselach)
uniform vec4 iMouse; // współrzędne piksela myszy: xy bieżąca pozycja, zw kliknięcie
uniform float iTime; // czas działania shadera (w sekundach)
```
(zwróć uwagę, że `iResolution` jest typu `vec3`, a `iMouse` typu `vec4`; uniformy te zawierają po prostu dodatkowe informacje, np.: stosunek szerokości do wysokości pikseli na ekranie, czy któryś z przycisków myszy został kliknięty albo czy jest przytrzymywany)
Koniec gadania, czas zobaczyć uniformy w akcji. W pożniszym kodzie używamy `u_time` (liczby sekund od uruchomienia shadera) razem z funkcją sinus, aby stworzyć animację przejścia od koloru czerwonego do czarnego.
Koniec gadania, czas zobaczyć uniformy w akcji. W poniższym kodzie używamy `u_time` (liczby sekund od uruchomienia shadera) razem z funkcją sinus, aby stworzyć animację przejścia od koloru czerwonego do czarnego.
<!-- Enough talking, let's see the uniforms in action. In the following code we use `u_time` - the number of seconds since the shader started running - together with a sine function to animate the transition of the amount of red in the billboard. -->
<div class="codeAndCanvas" data="time.frag"></div>
Jak widać GLSL skrywa wiele niespodzianek, na przykład w postaci specjalnych, zaimplementowanych w hardware'rze, funkcji trygonometryczne czy wykładniczych. Tutaj podaję część z nich: [`sin()`](../glossary/?search=sin), [`cos()`](../glossary/?search=cos), [`tan()`](../glossary/?search=tan), [`asin()`](../glossary/?search=asin), [`acos()`](../glossary/?search=acos), [`atan()`](../glossary/?search=atan), [`pow()`](../glossary/?search=pow), [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log), [`sqrt()`](../glossary/?search=sqrt), [`abs()`](../glossary/?search=abs), [`sign()`](../glossary/?search=sign), [`floor()`](../glossary/?search=floor), [`ceil()`](../glossary/?search=ceil), [`fract()`](../glossary/?search=fract), [`mod()`](../glossary/?search=mod), [`min()`](../glossary/?search=min), [`max()`](../glossary/?search=max) i [`clamp()`](../glossary/?search=clamp).
Jak widać GLSL skrywa wiele niespodzianek, na przykład w postaci specjalnych, zaimplementowanych w hardwarze, funkcji trygonometryczne czy wykładniczych. Tutaj podaję część z nich: [`sin()`](../glossary/?search=sin), [`cos()`](../glossary/?search=cos), [`tan()`](../glossary/?search=tan), [`asin()`](../glossary/?search=asin), [`acos()`](../glossary/?search=acos), [`atan()`](../glossary/?search=atan), [`pow()`](../glossary/?search=pow), [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log), [`sqrt()`](../glossary/?search=sqrt), [`abs()`](../glossary/?search=abs), [`sign()`](../glossary/?search=sign), [`floor()`](../glossary/?search=floor), [`ceil()`](../glossary/?search=ceil), [`fract()`](../glossary/?search=fract), [`mod()`](../glossary/?search=mod), [`min()`](../glossary/?search=min), [`max()`](../glossary/?search=max) i [`clamp()`](../glossary/?search=clamp).
<!--
As you can see GLSL has more surprises. The GPU has hardware accelerated angle, trigonometric and exponential functions. Some of those functions are: [`sin()`](../glossary/?search=sin), [`cos()`](../glossary/?search=cos), [`tan()`](../glossary/?search=tan), [`asin()`](../glossary/?search=asin), [`acos()`](../glossary/?search=acos), [`atan()`](../glossary/?search=atan), [`pow()`](../glossary/?search=pow), [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log), [`sqrt()`](../glossary/?search=sqrt), [`abs()`](../glossary/?search=abs), [`sign()`](../glossary/?search=sign), [`floor()`](../glossary/?search=floor), [`ceil()`](../glossary/?search=ceil), [`fract()`](../glossary/?search=fract), [`mod()`](../glossary/?search=mod), [`min()`](../glossary/?search=min), [`max()`](../glossary/?search=max) and [`clamp()`](../glossary/?search=clamp). -->
Pobawmy się powyższym kodem:
* Zmniejsz częstotliwość tak bardzo, aby zmiany koloru stały się nie zauważalne.
* Zmniejsz częstotliwość tak bardzo, aby zmiany koloru stały się niezauważalne.
* Zwiększ częstotliwość do takiego stopnia, aby ujrzeć stały kolor bez migotania.
* Wstaw funkcje sinus o różnych częstotliowściach do pozostałych kanałów (zielonego i niebieskiego), aby uzyskać ciekawe efekty.
* Wstaw funkcje sinusoidalne o różnych częstotliwościach do pozostałych kanałów (zielonego i niebieskiego), aby uzyskać ciekawe efekty.
<!-- Now it is time again to play with the above code.
@ -63,11 +63,11 @@ GLSL daje nam nie tylko domyślny output `vec4 gl_FragColor`, ale również domy
<div class="codeAndCanvas" data="space.frag"></div>
W powyższy kodzie, *normalizujemy* współrzędne fragmentu poprzez podzielenie go przez rozdzielczość kanwy. W ten sposó otrzymujemy wartości z przedziału od `0.0` do `1.0`, co ułatwia zmapowanie współrzędnych x i y do, odpowiednio, czerwonego i zielonego kanału.
W powyższym kodzie, *normalizujemy* współrzędne fragmentu poprzez podzielenie go przez rozdzielczość kanwy. W ten sposób otrzymujemy wartości z przedziału od `0.0` do `1.0`, co ułatwia zmapowanie współrzędnych x i y do, odpowiednio, czerwonego i zielonego kanału.
<!-- In the above code we *normalize* the coordinate of the fragment by dividing it by the total resolution of the billboard. By doing this the values will go between `0.0` and `1.0`, which makes it easy to map the X and Y values to the RED and GREEN channel. -->
W świecie shaderów nie mamy zbyt dużo sposóbów debuggowania poza przypisywaniem jaskrawych kolorów do zmiennych i wyciągania wniosków o działaniu shadera, na podstawie tego, co widzimy. Odkryjesz, że programowania GLSL jest często jak wkładanie miniaturowych statków do butelki - jest to trudne, ale tez piękne i satysfakcjonujące.
W świecie shaderów nie mamy zbyt dużo sposóbów debuggowania poza przypisywaniem jaskrawych kolorów do zmiennych i wyciągania wniosków o działaniu shadera, na podstawie tego, co widzimy. Odkryjesz, że programowanie GLSL jest często jak wkładanie miniaturowych statków do butelki - jest to trudne, ale też piękne i satysfakcjonujące.
<!-- In shader-land we dont have too many resources for debugging besides assigning strong colors to variables and trying to make sense of them. You will discover that sometimes coding in GLSL is very similar to putting ships inside bottles. Is equally hard, beautiful and gratifying. -->
@ -77,13 +77,13 @@ Czas przetestować nasze rozumienie kodu:
* Czy jesteś w stanie powiedzieć, gdzie na naszej kanwie znajduje się fragment o znormalizowanych współrzędnych `(0.0, 0.0)`?
* Co z framgentami o znormalizowanych współrzędnych `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` i `(1.0, 1.0)`?
* Co z fragmentami o znormalizowanych współrzędnych `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` i `(1.0, 1.0)`?
* Czy jesteś w stanie użyć uniforma `u_mouse` wiedząc, że wartości są nieznormalizowane? Spróbuj użyć go do manipulacji kolorem za pomocą ruchów myszki.
* Czy jesteś sobie w stanie wyobrazić ciekawy sposób zmieniania koloru, łącząc współrzędne `u_mouse` z `u_time`?
Po wykonaniu tych ćwiczeń, zapewne zastanawiasz się, gdzie jeszcze można użyć twoich nowych shaderowych mocy. W następnym rozdziale zobaczymy jak stworzyć swój własny shader w three.js, Processing i openFrameworks.
Po wykonaniu tych ćwiczeń, zapewne zastanawiasz się, gdzie jeszcze można użyć twoich nowych shaderowych mocy. W następnym rozdziale zobaczymy, jak stworzyć swój własny shader w three.js, Processing i openFrameworks.
<!-- Now it is time to try and challenge our understanding of this code.

61
03/README-ua.md Normal file
View File

@ -0,0 +1,61 @@
## Uniforms
Раніше ми побачили, яким чином графічний процесор керує великою кількістю паралельних потоків, кожен з яких відповідає за призначення кольору частці загального зображення. Хоча кожен паралельний потік закритий для інших, ми повинні мати можливість надсилати деякі вхідні дані від CPU до всіх потоків. Через архітектуру відеокарти ці вхідні дані будуть однаковими (*uniform* - *уніфікованими*, *однорідними*) для всіх потоків і доступними *лише для читання*. Іншими словами, кожен потік отримує ті ж самі дані, які він може читати, але не може змінювати.
Ці вхідні дані називаються `uniform` та мають більшість підтримуваних типів: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` і `samplerCube `. Uniform-змінні визначаються з відповідним типом у верхній частині шейдера відразу після встановлення точності для float-значень.
```glsl
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution; // Розмір полотна (ширина, висота)
uniform vec2 u_mouse; // Положення курсору на екрані
uniform float u_time; // Час у секундах з моменту запуску коду
```
Ви можете уявити uniform-змінні як маленькі містки між CPU та GPU. Назви для змінних можуть відрізнятися від реалізації до реалізації, але в цій серії прикладів я завжди передаю: `u_time` (час у секундах із моменту запуску шейдера), `u_resolution` (розмір зображення де застосовується шейдер) і `u_mouse` (положення курсору всередині зображення, що вимірюється у пікселях). Я дотримуюся конвенції з префіксом `u_` перед назвою uniform-змінних, щоб чітко означити природу таких змінних, але насправді ви можете зустріти різні назви. Наприклад, [ShaderToy.com](https://www.shadertoy.com/) використовує ті ж самі змінні, але з наступними назвами:
```glsl
uniform vec3 iResolution; // роздільна здатність області зображення, у пікселях (viewport resolution)
uniform vec4 iMouse; // піксельні координати курсору. xy - поточні, zw - клік
uniform float iTime; // час роботи шейдера (у секундах)
```
Досить розмов, подивимося на уніформи в дії. У наведеному нижче коді ми використовуємо `u_time` — кількість секунд із моменту запуску шейдера — разом із синус-функцією, щоб анімувати зміни у кількості червоного кольору на екрані.
<div class="codeAndCanvas" data="time.frag"></div>
Як ви бачите, GLSL має ще багато сюрпризів. GPU має апаратне прискорення для кутових, тригонометричних та експоненціальних функцій. Ось деякі з цих функцій: [`sin()`](../glossary/?lan=ua&search=sin), [`cos()`](../glossary/?lan=ua&search=cos), [`tan()`](../glossary/?lan=ua&search=tan), [`asin()`](../glossary/?lan=ua&search=asin), [`acos()`](../glossary/?lan=ua&search=acos), [`atan()`](../glossary/?lan=ua&search=atan), [`pow()`](../glossary/?lan=ua&search=pow), [`exp()`](../glossary/?lan=ua&search=exp), [`log()`](../glossary/?lan=ua&search=log), [`sqrt()`](../glossary/?lan=ua&search=sqrt), [`abs()`](../glossary/?lan=ua&search=abs), [`sign()`](../glossary/?lan=ua&search=sign), [`floor()`](../glossary/?lan=ua&search=floor), [`ceil()`](../glossary/?lan=ua&search=ceil), [`fract()`](../glossary/?lan=ua&search=fract), [`mod()`](../glossary/?lan=ua&search=mod), [`min()`](../glossary/?lan=ua&search=min), [`max()`](../glossary/?search=max) and [`clamp()`](../glossary/?lan=ua&search=clamp).
Настав час знову пограти з наведеним вище кодом.
* Уповільнюйте частоту, щоб зміна кольору стала майже непомітною.
* Пришвидшуйте, поки не побачите один колір без мерехтіння.
* Пограйтеся із RGB-каналами та різними частотами для них, щоб отримати якусь цікаву поведінку.
## gl_FragCoord
Подібно до того як GLSL, за замовчуванням, дає нам вихідні дані `vec4 gl_FragColor`, він також дає нам вхідні дані за замовчуванням, `vec4 gl_FragCoord`, що містять екранні координати *пікселя* або *фрагменту екрана*, з якими працює активний потік. За допомогою `vec4 gl_FragCoord` ми знаємо, де саме працює поточний потік всередині зображення. У цьому випадку ми не називаємо його `uniform`, тому що він буде відрізнятися від потоку до потоку, натомість `gl_FragCoord` називається *varying* (змінливим).
<div class="codeAndCanvas" data="space.frag"></div>
У наведеному вище коді ми *нормалізуємо* координати фрагмента, розділивши їх на роздільну здатність зображення. У результаті цього отримані значення будуть змінюватися у діапазоні від `0.0` до `1.0`, що полегшує зіставлення X і Y значень з ЧЕРВОНИМ і ЗЕЛЕНИМ каналами.
У світі шейдерів ми не маємо зручних інструментів для зневаджування програми, тому інколи доводиться призначати змінним якісь яскраві кольори, щоб за їх допомогою спробувати дістати потрібну інформацію. Ви виявите, що кодування на GLSL іноді дуже схоже на розміщення корабля у пляшку. Це однаково важко, красиво і захопливо.
![](08.png)
Тепер настав час перевірити наше розуміння цього коду.
* Чи можете ви сказати, де знаходиться координата `(0.0, 0.0)` на нашому полотні?
* А як щодо `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` і `(1.0, 1.0)`?
* Чи можете ви зрозуміти, як використати змінну `u_mouse`, знаючи, що її значення вказані в пікселях і НЕ нормалізовані? Чи зможете за її допомогою і руху курсору змінювати кольори?
* Чи можете ви вигадати цікавий спосіб для зміни кольорів за допомогою координат `u_time` і `u_mouse`?
Після виконання цих вправ ви можете поставити собі питання: де ще можна спробувати можливості шейдерів. У наступному розділі ми розглянемо, як створити власні шейдерні інструменти у three.js, Processing і openFrameworks.

View File

@ -44,7 +44,7 @@ In the same way GLSL gives us a default output, `vec4 gl_FragColor`, it also giv
In the above code we *normalize* the coordinate of the fragment by dividing it by the total resolution of the billboard. By doing this the values will go between `0.0` and `1.0`, which makes it easy to map the X and Y values to the RED and GREEN channel.
In shader-land we dont have too many resources for debugging besides assigning strong colors to variables and trying to make sense of them. You will discover that sometimes coding in GLSL is very similar to putting ships inside bottles. Is equally hard, beautiful and gratifying.
In shader-land we dont have too many resources for debugging besides assigning strong colors to variables and trying to make sense of them. You will discover that sometimes coding in GLSL is very similar to putting ships inside bottles. It is equally hard, beautiful and gratifying.
![](08.png)
@ -54,7 +54,7 @@ Now it is time to try and challenge our understanding of this code.
* What about `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` and `(1.0, 1.0)`?
* Can you figure out how to use `u_mouse` knowing that the values are in pixels and NOT normalized values? Can you use it to move colors around?
* Can you figure out how to use `u_mouse`, knowing that the values are in pixels and NOT normalized values? Can you use it to move colors around?
* Can you imagine an interesting way of changing this color pattern using `u_time` and `u_mouse` coordinates?

View File

@ -208,25 +208,3 @@ void ofApp::draw(){
برای اطلاعات بیشتر در مورد استفاده از شیدر ها در openFrameworks سری به [excellent tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) ساخته شده توسط [Joshua Noble](http://thefactoryfactory.com/) بزنید.
### در **Blender**
[GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) یک افزونه است که امکان می‌دهد با برنامه نویسی و استفاده از GLSL، تکستچر تولید کنید. همچنین با بقیه محیط هم سازگار است. اینگونه کار می‌کند:
1. در سرچ بار: `F3` (یا spaceBar). تایپ کنید `GlslTexture`
![](blender/00.png)
2. طول و عرض و منبع را تغییر دهید (که میتواند مسیری به فایل خارجی باشد).
![](blender/01.png)
3. از این تصویر روی متریال خود اسفاده کنید. اسم عکس بر پایه اسم منبع تعریف می‌شود.
![](blender/02.png)
4. به Text Editor بروید (یا یک ادیتور خارجی در صورت تمایل) و شیدر را تغییر دهید. به صورت آنی(هات ریلود) تغییرات را مشاهده خواهید کرد.
![](blender/03.png)

View File

@ -210,24 +210,3 @@ void ofApp::draw(){
Για περισσότερες πληροφορίες για τους shaders σε openFrameworks δείτε αυτό το [εξαιρετικό μάθημα](http://openframeworks.cc/ofBook/chapters/shaders.html) από τον [Joshua Noble](http://thefactoryfactory.com/).
### Σε **Blender**
Το [GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) είναι ένα addon που επιτρέπει να παράξετε textures (υφές) προγραμματιστικά χρησιμοποιώντας GLSL Shaders, και είναι πλήρως συμβατό με τα υπόλοιπα απο τα sandboxes (περιβάλλοντα) αυτού του κεφαλαίου. Να πως λειτουργεί:
1. Αναζήτηση Operator: `F3``SpaceBar (διάστημα)` ανάλογα με τις επιλογές περιβάλλοντος του Blender). Γράψτε `GlslTexture`
![](blender/00.png)
2. Αλλάξτε τα μεγέθη `width` και `height` και το αρχείο `Source` (όπου μπορείτε να βάλετε το path -τοποθεσία- ενός εξωτερικού αρχείου).
![](blender/01.png)
3. Χρησιμοποιήστε την Εικόνα στα υλικά σας. Το όνομα της Εικόνας βασίζεται στο όνομα του αρχείου source (βλ. 2)
![](blender/02.png)
4. Πηγαίνετε στον Text Editor (επεξεργαστή κειμένου - ή έναν εξωτερικό επεξεργαστή κειμένου αν το source αρχείο είναι εξωτερικό) και αλλάξτε τον shader. Οι αλλαγές είναι άμεσα ορατές.
![](blender/03.png)

View File

@ -209,22 +209,4 @@ void ofApp::draw(){
Untuk informasi lebih lanjut mengenai shader dalam openFrameworks lihatlah [tutorial bagus ini](https://processing.org/tutorials/pshader/).
### Dalam **Blender**
[GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) adalah addon yang memperbolehkan menghasilkan tekstur menggunakan shader GLSL secara terprogram dan kompatibel sepenuhnya dengan sandbox lainnya di bab ini. Bagaimana itu bekerja:
1. Operator Search: `F3` (atau `SpaceBar` tergantung pada setup). Cari `GlslTexture`
![](blender/00.png)
2. Ganti ukuran `width` and `height` dan berkas sumber `Source` (dapat menggunakan path file eksternal).
![](blender/01.png)
3. Gunakan gambar pada materialmu. Nama gambar akan berdasarkan pada nama file sumber.
![](blender/02.png)
4. Pergi ke Text Editor (atau eksternal editor jika file sumbermu di luar) dan edit shadernya. Ini akan memuat ulang.
![](blender/03.png)

View File

@ -249,28 +249,3 @@ void ofApp::draw(){
Po więcej informacji na temat shaderów w openFrameworks zajrzyj do znakomitego [tutoriala](http://openframeworks.cc/ofBook/chapters/shaders.html) autorstwa [Joshua Noble](http://thefactoryfactory.com/).
<!-- For more information about shaders in openFrameworks go to this [excellent tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) made by [Joshua Noble](http://thefactoryfactory.com/). -->
### W **Blender**
[GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) to addon pozwalający programistycznie generować textury z użyciem shaderów GLSL. Jest on w pełni kompatybilny z resztą sandboxów w tym rozdziale. Jak go użyć?
<!-- [GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) is an addon that allows you to programmatically generate textures using GLSL Shaders and is fully compatible with the rest of the sandboxes on this chapter. How it works: -->
1. Operator Search: `F3` (lub `Spacja`, w zależności od twojego setupu ). Wpisz `GlslTexture`
![](blender/00.png)
2. Zmień pola `width` (szerokość), `height` (wysokość) oraz `Source` (ścieżka pliku źródłowego; może być ścieżką do zewnętrznego pliku).
![](blender/01.png)
3. Wykorzystaj węzeł Image w zakładce Materials. Nazwa węzła Image będzie taka sama jak nazwa pliku źródłowego.
<!-- 3. Use the Image on your materials. The Image name will be based on the name of the source file. -->
![](blender/02.png)
4. Idź do zakładki Scripting (lub zewnętrznego edytora, jeśli twój plik źródłowy jest zewnętrzny) i zacznij edytować shader. Będzie hot reload'owany.
<!-- 4. Go to the Text Editor (or an external editor if your source file is external) and edit the shader. It will hot reload. -->
![](blender/03.png)

212
04/README-ua.md Normal file
View File

@ -0,0 +1,212 @@
## Запуск шейдера
У процесі створення цієї книги та моєї художньої практики, я сформував екосистему інструментів для створення шейдерів, їх відображення, спільного використання та керування. Ці інструменти працюють однаково в Linux, MacOS, Windows, [Raspberry Pi](https://www.raspberrypi.org/) та браузерах без необхідності змінювати код.
## Запуск шейдерів у браузері
**Відображення**: усі інтерактивні приклади в цій книзі відображаються за допомогою [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas), що робить процес запуску автономного шейдера неймовірно простим.
```html
<canvas class="glslCanvas" data-fragment-url=“yourShader.frag" data-textures=“yourInputImage.png” width="500" height="500"></canvas>
```
Як бачите, для цього потрібен лише елемент `canvas` із відповідним класом `class="glslCanvas"` та URL-адресою вашого шейдера, заданої в атрибуті `data-fragment-url`. Дізнатися більше про це можна [тут](https://github.com/patriciogonzalezvivo/glslCanvas).
Якщо ви схожі на мене, ви, ймовірно, захочете запускати шейдери безпосередньо з консолі. У такому випадку вам допоможе [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Ця програма дозволяє вам включати шейдери у ваші `bash`-скрипти або unix-конвеєри та використовувати їх подібно до [ImageMagick](http://www.imagemagick.org/script/index.php). Також [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) є чудовим способом компіляції шейдерів на [Raspberry Pi](https://www.raspberrypi.org/), через що [openFrame.io](http://openframe.io/) використовує його для демонстрації шейдерних робіт. Дізнайтеся більше про цю програму за цим [посиланням](https://github.com/patriciogonzalezvivo/glslViewer).
```bash
glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png
```
**Створення**: щоб покращити досвід кодування шейдерів, я створив онлайн-редактор під назвою [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Цей редактор використовується в інтерактивних прикладах книги та пропонує низку зручних віджетів, що робить взаємодію з абстрактним кодом glsl більш відчутним. Ви також можете запустити його як окрему вебпрограму: [editor.thebookofshaders.com](http://editor.thebookofshaders.com/). Дізнатися більше про редактор можна [тут](https://github.com/patriciogonzalezvivo/glslEditor).
![](glslEditor-01.gif)
Якщо ви бажаєте працювати з редактором офлайн за допомогою [SublimeText](https://www.sublimetext.com/), то можете встановити цей [пакет для glslViewer](https://packagecontrol.io/packages/glslViewer). Дізнайтеся більше [тут](https://github.com/patriciogonzalezvivo/sublime-glslViewer).
![](glslViewer.gif)
**Експортування**: онлайн-редактор ([editor.thebookofshaders.com](http://editor.thebookofshaders.com/)) може поділитися вашими шейдерами! Як вбудована, так і окрема версія мають кнопку для експорту, за допомогою якої ви можете отримати унікальну URL-адресу свого шейдера. Також є можливість експортувати шейдер безпосередньо в [openFrame.io](http://openframe.io/).
![](glslEditor-00.gif)
**Керування**: експорт коду — початок для того, щоб ви ділилися своїм шейдером у якості художнього витвору! Окрім опції експорту в [openFrame.io](http://openframe.io/), я створив інструмент для керування вашими шейдерами у галереї, яку можна вбудувати у будь-який сайт — [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Детальніше [тут](https://github.com/patriciogonzalezvivo/glslGallery).
![](glslGallery.gif)
## Запуск ваших шейдерів у вашому улюбленому фреймворку
Якщо у вас уже є досвід програмування в таких фреймворках, як [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) або [SFML](https://www.sfml-dev.org/), ви, мабуть, із задоволенням спробуєте шейдери у них. Нижче наведено приклади того, як налаштувати шейдери в деяких популярних фреймворках з вказаними у книзі uniform-змінними. У [GitHub-репозиторії для цього розділу](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) ви знайдете повний вихідний код для цих трьох фреймворків.
### **Three.js**
Блискучий і дуже скромний Ricardo Cabello (він же [MrDoob](https://twitter.com/mrdoob)) з групою інших [однодумців](https://github.com/mrdoob/three.js/graphs/contributors) розробили один із найвідоміших фреймворків для WebGL під назвою [Three.js](http://threejs.org/). Там ви знайдете безліч прикладів, посібників і книг, які навчать вас, як використовувати цю JS-бібліотеку для створення класної 3D-графіки.
Нижче наведено приклад із HTML та JS, які необхідні для початку роботи з шейдерами у three.js. Зверніть увагу на скрипт з `id="fragmentShader"` куди ви можете скопіювати шейдери, знайдені в цій книзі.
```html
<body>
<div id="container"></div>
<script src="js/three.min.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4(position, 1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
gl_FragColor = vec4(st.x, st.y, 0.0, 1.0);
}
</script>
<script>
let container;
let camera, scene, renderer, clock;
let uniforms;
init();
animate();
function init() {
container = document.getElementById('container');
camera = new THREE.Camera();
camera.position.z = 1;
scene = new THREE.Scene();
clock = new THREE.Clock();
const geometry = new THREE.PlaneBufferGeometry(2, 2);
uniforms = {
u_time: { type: "f", value: 1.0 },
u_resolution: { type: "v2", value: new THREE.Vector2() },
u_mouse: { type: "v2", value: new THREE.Vector2() }
};
const material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
container.appendChild(renderer.domElement);
onWindowResize();
window.addEventListener('resize', onWindowResize, false);
document.onmousemove = function(e) {
uniforms.u_mouse.value.x = e.pageX
uniforms.u_mouse.value.y = e.pageY
}
}
function onWindowResize(event) {
renderer.setSize(window.innerWidth, window.innerHeight);
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
uniforms.u_time.value += clock.getDelta();
renderer.render(scene, camera);
}
</script>
</body>
```
### **Processing**
[Processing](https://processing.org/) започатковано у 2001 році у співпраці між [Ben Fry](http://benfry.com/) та [Casey Reas](http://reas.com/). Фреймворк є надзвичайно простим та потужним середовищем, у якому можна робити свої перші кроки в програмуванні (принаймні так було у мене). [Andres Colubri](https://codeanticode.wordpress.com/) вніс важливі оновлення в Processing для підтримки openGL і відео, що полегшило використання шейдерів GLSL у цьому дружньому середовищі, ніж будь-коли. Processing шукатиме шейдер із назвою `"shader.frag"` у теці `data` вашого скетчу. Тож вам достатньо скопіювати приклади цієї книги у файл із відповідною назвою.
```cpp
PShader shader;
void setup() {
size(640, 360, P2D);
noStroke();
shader = loadShader("shader.frag");
}
void draw() {
shader.set("u_resolution", float(width), float(height));
shader.set("u_mouse", float(mouseX), float(mouseY));
shader.set("u_time", millis() / 1000.0);
shader(shader);
rect(0,0,width,height);
}
```
Щоб шейдер працював у попередніх версіях, нижчих за 2.1, вам потрібно додати рядок `#define PROCESSING_COLOR_SHADER` на початку вашого шейдера. Це виглядатиме так:
```glsl
#ifdef GL_ES
precision mediump float;
#endif
#define PROCESSING_COLOR_SHADER
uniform vec2 u_resolution;
uniform vec3 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.st / u_resolution;
gl_FragColor = vec4(st.x, st.y, 0.0, 1.0);
}
```
Щоб дізнатися більше про шейдери у Processing, перегляньте цей [посібник](https://processing.org/tutorials/pshader/).
### **openFrameworks**
У кожного є місце, де йому комфортно, у моєму випадку таким місцем залишається [спільнота openFrameworks](http://openframeworks.cc/). Цей C++ фреймворк є обгорткою навколо OpenGL та інших бібліотек на C++ з відкритим кодом. Багато в чому він дуже схожий на Processing, але зі своїми особливостями роботи з використанням компіляторів C++. Так само як і Processing, openFrameworks шукатиме ваші файли шейдерів у теці `data`. Тому не забудьте скопіювати код прикладів, які хочете використати, у файли з розширенням `.frag` і покласти їх у згадану теку:
```cpp
void ofApp::draw() {
ofShader shader;
shader.load("", "shader.frag");
shader.begin();
shader.setUniform1f("u_time", ofGetElapsedTimef());
shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight());
ofRect(0, 0, ofGetWidth(), ofGetHeight());
shader.end();
}
```
Якщо ви хочете використовувати в OpenFrameworks повний набір уніформ, що містяться в специфікаціях GlslViewer і GlslCanvas, простішим способом, я рекомендую використовувати доповнення [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader). Воно також має підтримку кількох буферів, шейдерних матеріалів, гаряче перезавантаження та автоматизацію для OpenGL ES у Raspberry Pi. Ваш код буде таким же простим, як нижче:
```cpp
//--------------------------------------------------------------
void ofApp::setup(){
ofDisableArbTex();
sandbox.allocate(ofGetWidth(), ofGetHeight());
sandbox.load("grayscott.frag");
}
//--------------------------------------------------------------
void ofApp::draw(){
sandbox.render();
sandbox.draw(0, 0);
}
```
Щоб дізнатися більше про шейдери в openFrameworks, перегляньте цей [чудовий посібник](http://openframeworks.cc/ofBook/chapters/shaders.html), створений [Joshua Noble](http://thefactoryfactory.com/).

View File

@ -210,24 +210,3 @@ void ofApp::draw(){
Để tìm hiểu thêm về shader trong openFrameworks hãy đọc [bài hướng dẫn tuyệt vời này](http://openframeworks.cc/ofBook/chapters/shaders.html) của [Joshua Noble](http://thefactoryfactory.com/).
### Với **Blender**
[GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) là một addon giúp bạn tạo ra các texture theo công thức của GLSL và hoàn toàn tương thích với các sandbox khác trong chương này. Cách mà nó hoạt động:
1. Operator Search: `F3` (hoặc gõ phím `Space` tuỳ theo chỉnh sửa của bạn). Gõ `GlslTexture`
![](blender/00.png)
2. Đổi kích thước `width``height` và tên file shader ở `Source` (có thể là đường dẫn tới 1 file khác)
![](blender/01.png)
3. Sử dụng ảnh trong chất liệu. Tên của ảnh sẽ dựa trên tên của file shader.
![](blender/02.png)
4. Mở phần Text Editor và viết shader (hoặc sửa từ bên ngoài). Nó sẽ được cập nhật ngay lập tức.
![](blender/03.png)

View File

@ -131,7 +131,7 @@ Below is an example of the HTML and JS you need to get started with shaders in t
### In **Processing**
Started by [Ben Fry](http://benfry.com/) and [Casey Reas](http://reas.com/) in 2001, [Processing](https://processing.org/) is an extraordinarily simple and powerful environment in which to take your first steps in code (it was for me at least). [Andres Colubri](https://codeanticode.wordpress.com/) has made important updates to the openGL and video in Processing, making it easier than ever to use and play with GLSL shaders in this friendly environment. Processing will search for the shader named `"shader.frag"` in the `data` folder of the sketch. Be sure to copy the examples you find here into that folder and rename the file.
Started by [Ben Fry](http://benfry.com/) and [Casey Reas](http://reas.com/) in 2001, [Processing](https://processing.org/) is an extraordinarily simple and powerful environment in which to take your first steps in code (it was for me at least). [Andres Colubri](https://codeanticode.wordpress.com/) has made important updates to the OpenGL and video in Processing, making it easier than ever to use and play with GLSL shaders in this friendly environment. Processing will search for the shader named `"shader.frag"` in the `data` folder of the sketch. Be sure to copy the examples you find here into that folder and rename the file.
```cpp
PShader shader;
@ -190,7 +190,7 @@ void ofApp::draw(){
}
```
If you want to use the full set of uniforms contain on the specs of GlslViewer and GlslCanvas in a more simple way on OpenFrameworks I recomend using the [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) addon which will also have support for multiple buffers, material shaders, hotreload and automatic conversion for OpenGL ES in the Raspberry Pi. And your code will be as simple as doing
If you want to use the full set of uniforms contain on the specs of GlslViewer and GlslCanvas in a more simple way on OpenFrameworks I recommend using the [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) addon which will also have support for multiple buffers, material shaders, hotreload and automatic conversion for OpenGL ES in the Raspberry Pi. And your code will be as simple as doing
```cpp
//--------------------------------------------------------------
@ -210,24 +210,3 @@ void ofApp::draw(){
For more information about shaders in openFrameworks go to this [excellent tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) made by [Joshua Noble](http://thefactoryfactory.com/).
### In **Blender**
[GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) is an addon that allows you to programmatically generate textures using GLSL Shaders and is fully compatible with the rest of the sandboxes on this chapter. How it works:
1. Operator Search: `F3` (or `SpaceBar` depending on your setup). Type `GlslTexture`
![](blender/00.png)
2. Change `width` and `height` size and `Source` file (which can be a path to an external file).
![](blender/01.png)
3. Use the Image on your materials. The Image name will be based on the name of the source file.
![](blender/02.png)
4. Go to the Text Editor (or an external editor if your source file is external) and edit the shader. It will hot reload.
![](blender/03.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 KiB

134
05/README-ua.md Normal file
View File

@ -0,0 +1,134 @@
# Алгоритмічне малювання
## Формотворчі функції або функції формування
Цей розділ можна було б назвати "Урок з парканом від містера Міягі". Раніше ми зіставляли нормалізоване положення координат *x* і *y* з *червоним* і *зеленим* каналами. По суті, ми створили функцію, яка приймає двовимірний вектор (x і y) та повертає чотиривимірний вектор (r, g, b і a). Але перш ніж перейти до подальшого перетворення даних між вимірами, нам потрібно почати з простіших речей... набагато простіших. З розуміння того, як користуватись одновимірними функціями. Чим більше часу та енергії ви витратите на освоєння цього і відповідну практику, тим сильнішим буде ваше шейдерне карате.
![The Karate Kid (1984)](mr_miyagi.jpg)
Наступний приклад коду буде нашим парканом. У ньому ми візуалізуємо нормалізоване значення координати *x* (`st.x`) двома способами: один за допомогою яскравості (подивіться на гарний градієнт від чорного до білого), а інший шляхом побудови зеленої діагональної лінії зверху (у цьому випадку значення *x* присвоюється безпосередньо до *y*). Поки що не зосереджуйтеся занадто на функції `plot`. Згодом ми розберемося з нею більш детально.
<div class="codeAndCanvas" data="linear.frag"></div>
**Коротка примітка**: конструктор типу `vec3` "розуміє", що ви хочете призначити одне і те саме значення трьом каналам, тоді як `vec4` розуміє, що ви хочете побудувати чотиривимірний вектор за допомогою одного тривимірного і додаткового четвертого значення. У цьому випадку четверте значення відповідатиме за альфа-канал або непрозорість. Перегляньте ці приклади на рядках 19 і 25.
Цей код — ваш паркан. Важливо бачити його і розуміти. Ви знову і знову повертатиметеся до цього простору між *0.0* і *1.0*. Ви опануєте мистецтво змішування та формування подібних ліній.
Цей однозначний зв'язок між *x* і *y* (або яскравістю) відомий як *лінійна інтерполяція*. З цього моменту ми можемо використовувати деякі математичні функції для надання лінії певної *форми*, для її формування. Наприклад, ми можемо піднести *x* до 5 степеня, щоб отримати *криву* лінію.
<div class="codeAndCanvas" data="expo.frag"></div>
Цікаво, правда? У рядку 22 спробуйте різні показники для степеня: наприклад, 20.0, 2.0, 1.0, 0.0, 0.2 і 0.02. Розуміння цього зв'язку між значенням і експонентою буде дуже корисним. Використання подібних типів математичних функцій дасть вам виразний засіб для контролю вашого коду, свого роду акупунктуру даних, яка дозволить вам контролювати потік значень.
[`pow()`](../glossary/?lan=ua&search=pow) — одна з багатьох вбудованих функцій GLSL. Більшість із них прискорені на апаратному рівні, а це означає, що якщо вони використовуються належним чином і з обережністю, то ваш код стане швидшим.
Замініть функцію `pow` у рядку 22 на якусь іншу, наприклад: [`exp()`](../glossary/?lan=ua&search=exp), [`log()`](../glossary/?lan=ua&search=log) і [`sqrt()`](../glossary/?lan=ua&search=sqrt). Деякі з цих функцій стають цікавіші із використанням числа PI. У рядку 8 ви можете побачити, що я визначив макрос, який замінить будь-яке використання `PI` на значення `3.14159265359`.
### step і smoothstep
GLSL має деякі унікальні функції інтерполяції, які також апаратно прискорені.
Функція інтерполяції [`step()`](../glossary/?lan=ua&search=step) приймає два параметри. Перший — це межа або поріг, а другий — це значення для якого ми хочемо застосувати функцію. Будь-яке значення нижче порогу поверне `0.0`, а все, що його перевищує — `1.0`.
Спробуйте змінити у наступному коді порогове значення, що на рядку 20:
<div class="codeAndCanvas" data="step.frag"></div>
Інша унікальна функція називається [`smoothstep()`](../glossary/?lan=ua&search=smoothstep). Функція плавно інтерполює значення у вказаному діапазоні з двох чисел. Перші два параметри призначені для початку та кінця перехідного діапазону, а третій — для значення, яке потрібно інтерполювати.
<div class="codeAndCanvas" data="smoothstep.frag"></div>
У функції `plot()` на рядку 12 попереднього прикладу, ми використали smoothstep, щоб намалювати зелену лінію. Для кожної позиції вздовж вісі *x* ця функція робить *виступи* у певному значенні *y*. Яким чином? Об'єднавши результат двох функцій [`smoothstep()`](../glossary/?lan=ua&search=smoothstep) разом. Погляньте на наступну функцію, замініть нею рядок 20 вище і подумайте про неї як про вертикальний розріз. Фон схожий на лінію, чи не так?
```glsl
float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);
```
### Синус і Косинус
Коли ви хочете застосувати певну математику для анімації, або при формуванні чи змішуванні значень, немає нічого кращого, ніж товаришувати з синусом і косинусом.
Ці дві основні тригонометричні функції працюють у парі при побудові кола, що є настільки ж корисним, як і швейцарський армійський ніж. Важливо знати, як вони поводяться і як їх можна комбінувати. Коротко кажучи, задаючи їм кут у радіанах, вони повертають правильне положення координати *x* ([cos](../glossary/?lan=ua&search=cos)) і *y* ([sin](../glossary/?lan=ua&search=sin)) точки на краю кола з радіусом, рівним 1. А той факт, що вони повертають нормалізовані значення (від -1 до 1), які до того ж достатньо плавні, робить їх неймовірним інструментом.
![](sincos.gif)
Хоча важко описати всі взаємозв'язки між тригонометричними функціями та колами, наведена вище анімація чудово їх узагальнює.
<div class="simpleFunction" data="y = sin(x);"></div>
Уважно подивіться на зображену вище синусоїду. Зверніть увагу, як значення *y* плавно змінюються між +1 і -1. Як ми бачили у прикладі зі змінною для часу, що був у попередньому розділі, ви можете використовувати цю ритмічну поведінку [`sin()`](../glossary/?lan=ua&search=sin) для анімації властивостей. Якщо ви читаєте цей приклад у браузері, то можете змінити код у формулі вище, щоб побачити, як змінюється хвиля. (Примітка: не забудьте про крапку з комою в кінці рядка.)
Спробуйте виконати наступні вправи та зверніть увагу на те, що відбувається:
* Додайте час (`u_time`) до *x* перед обчисленням `sin`. Оцініть **рух** уздовж осі *x*.
* Помножте *x* на `PI` перед обчисленням `sin`. Зверніть увагу, як дві фази **скорочуються**, так що кожен цикл повторюється через кожні 2 цілих числа.
* Помножте час (`u_time`) на *x* перед обчисленням `sin`. Подивіться, як **частота** між фазами стає все більш і більш стиснутою. Зверніть увагу, що `u_time` до цього моменту може стати вже дуже великим, що ускладнить сприйняття отриманого графіка.
* Додайте 1.0 до [`sin(x)`](../glossary/?lan=ua&search=sin). Подивіться, як уся хвиля **змістилася** вгору, і тепер усі значення знаходяться між 0.0 і 2.0.
* Помножте [`sin(x)`](../glossary/?lan=ua&search=sin) на 2.0. Подивіться, як **амплітуда** збільшилася вдвічі.
* Обчисліть абсолютне значення за допомогою ([`abs()`](../glossary/?lan=ua&search=abs)) `sin(x)`. Графік стане схожим на траєкторію м'яча, що **стрибає**.
* Виділіть лише дробову частину від результату [`sin(x)`](../glossary/?lan=ua&search=sin) за допомогою [`fract()`](../glossary/?lan=ua&search=fract).
* Додайте результати [`sin(x)`](../glossary/?lan=ua&search=sin), округлені в більшу ([`ceil()`](../glossary/?lan=ua&search=ceil)) та меншу сторони ([`floor()`](../glossary/?lan=ua&search=floor)), щоб отримати цифрову хвилю зі значеннями 1 і -1.
### Деякі додаткові корисні функції
Наприкінці останньої вправи ми представили кілька нових функцій. Настав час поекспериментувати з ними. Спробуйте по черзі розкоментувати та випробувати кожну з них. Ознайомтеся з цими функціями та вивчіть, як вони поводяться. Я знаю, вам цікаво... навіщо? Швидкий пошук у Google на тему "генеративне мистецтво" підкаже вам. Майте на увазі, що ці функції є нашим парканом. Ми опановуємо рух в одному вимірі, вгору і вниз. Вже зовсім скоро настане час для двох, трьох і чотирьох вимірів!
![Anthony Mattox (2009)](anthony-mattox-ribbon.jpg)
<div class="simpleFunction" data="y = mod(x,0.5); // return x modulo of 0.5
// y = fract(x); // повертає лише дробову частину числа
// y = ceil(x); // найближче ціле число, яке більше або дорівнює x
// y = floor(x); // найближче ціле число, яке менше або дорівнює x
// y = sign(x); // отримати знак числа x
// y = abs(x); // повертає абсолютне значення x
// y = clamp(x,0.0,1.0); // обмеження значення x в діапазоні між 0.0 і 1.0
// y = min(0.0,x); // повертає менше значення із x і 0.0
// y = max(0.0,x); // повертає більше значення із x і 0.0 "></div>
### Просунуті формотворчі функції
[Golan Levin](http://www.flong.com/) має чудову документацію про складніші формотворчі функції, які є надзвичайно корисними. Перенесення їх на GLSL — це розумний крок, щоб почати створювати власний ресурс з фрагментами коду.
* Поліноміальні формотворчі функції: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/)
* Експоненціальні формотворчі функції: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/)
* Кругові та еліптичні формотворчі функції: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/)
* Безьє та інші параметричні функції: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/)
<div class="glslGallery" data="160414041542,160414041933,160414041756" data-properties="clickRun:editor,hoverPreview:false"></div>
Подібно до кухарів, які збирають спеції та екзотичні інгредієнти, цифрові художники та креативні кодери приділяють особливу увагу створенню власних формотворчих функцій.
[Iñigo Quiles](http://www.iquilezles.org/) має чудову колекцію [корисних функцій](http://www.iquilezles.org/www/articles/functions/functions.htm). Прочитавши [цю статтю](http://www.iquilezles.org/www/articles/functions/functions.htm), перегляньте на наступні реалізації цих функцій на GLSL. Зверніть увагу на невеликі зміни, які потрібно було внести. Як-от на "." (крапку) для чисел з рухомою крапкою та заміни деяких *C*-функцій на GLSL аналоги: наприклад, замість `powf()` використовується `pow()`.
<div class="glslGallery" data="05/impulse,05/cubicpulse,05/expo,05/expstep,05/parabola,05/pcurve" data-properties="clickRun:editor,hoverPreview:false"></div>
Для підтримки вашої мотивації, ось елегантний приклад опанування карате формотворчих функцій. Автор [Danguafer](https://www.shadertoy.com/user/Danguafer):
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/XsXXDn?gui=true&t=10&paused=true" allowfullscreen></iframe>
У наступному розділі ми почнемо використовувати нові карате-рухи. Спочатку почнемо зі змішування кольорів, а потім перейдемо до малювання фігур.
#### Вправа
Подивіться на наведену нижче таблицю рівнянь, створену за авторства [Kynd](http://www.kynd.info/log/). Подивіться, як він поєднує функції та їхні властивості, щоб контролювати значення між 0.0 та 1.0. Настав час потренуватися, самостійно відтворюючи ці функції. Пам'ятайте, що чим більше ви тренуєтеся, тим краще буде ваше карате.
![Kynd - www.flickr.com/photos/kynd/9546075099/ (2013)](kynd.png)
#### До вашого інструментарію
Ось кілька інструментів, які полегшать візуалізацію цих типів функцій:
* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): вже згаданий [Iñigo Quilez](http://www.iquilezles.org) створив інструмент для візуалізації GLSL-функцій у WebGL.
![Iñigo Quilez - GraphToy (2010)](graphtoy.png)
* [Бібліотека шейдерів LYGIA](https://lygia.xyz/) — бібліотека шейдерів із функцій, які можна легко включити та використати у ваших проєктах. Бібліотека дуже атомарна, створена для зручного перевикористання, продуктивності й гнучкості. Може бути легко додана до будь-яких проєктів та фреймворків.

View File

@ -125,10 +125,10 @@ Take a look at the following table of equations made by [Kynd](http://www.kynd.i
#### For your toolbox
Here are some tools that will make it easier for you to visualize these types of functions.
* [LYGIA](https://lygia.xyz/) is a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. It's divided in different sections and it have an entire one for [math operations](https://lygia.xyz/math)
* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): once again [Iñigo Quilez](http://www.iquilezles.org) made a tool to visualize GLSL functions in WebGL.
![Iñigo Quilez - GraphToy (2010)](graphtoy.png)
* [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks.

136
06/README-ua.md Normal file
View File

@ -0,0 +1,136 @@
![Paul Klee - Color Chart (1931)](klee.jpg)
## Кольори
Раніше у нас не було нагоди поговорити про векторні типи GLSL. Перш ніж рушити далі, важливо дізнатися про них більше. А тема кольорів якраз дуже підходить для цього і буде чудовим шляхом для такого знайомства.
Якщо ви знайомі з парадигмами об'єктноорієнтованого програмування, то, мабуть, помітили, що ми зверталися до даних у векторах, як до будь-якої звичайної C-подібної `структури`.
```glsl
vec3 red = vec3(1.0, 0.0, 0.0);
red.x = 1.0;
red.y = 0.0;
red.z = 0.0;
```
Визначення кольору за допомогою нотації *x*, *y* і *z* може заплутати й ввести в оману, чи не так? Ось чому існують й інші способи доступу до цієї самої інформації, але під іншими іменами. Значення `.x`, `.y` і `.z` так само можна отримати через `.r`, `.g` і `.b`, а також через `.s`, `.t` і `.p`. (`.s`, `.t` і `.p` зазвичай використовуються для роботи з просторовими координатами текстури, які ми побачимо в наступному розділі.) Крім того, ви також можете отримати доступ до елементів вектора через позицію індексу: `[0]`, `[1]` і `[2]`.
Наступні рядки показують всі способи доступу до тих самих даних:
```glsl
vec4 vector;
vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;
```
Всі ці різні способи посилання на змінні всередині вектора — лише додаткові номенклатури — розроблені позначення, щоб допомогти вам написати чіткіший код. Ця гнучкість, вбудована в мову шейдерів, дає вам можливість почати думати про просторові координати та значення кольорів як про взаємозамінні сутності.
Ще одна чудова особливість векторних типів у GLSL полягає в тому, що їх властивості можна комбінувати в будь-якому довільному порядку, що спрощує приведення та змішування значень. Ця здатність називається *змішуванням*.
```glsl
vec3 yellow, magenta, green;
// Створення жовтого кольору
yellow.rg = vec2(1.0); // Присвоєння 1.0 червоному та зеленому каналам
yellow[2] = 0.0; // Присвоєння 0.0 синьому каналу
// Створення пурпурового кольору
magenta = yellow.rbg; // Присвоєння каналів зі зміною місць зеленого і синього. rbg замість rgb
// Створення зеленого кольору
green.rgb = yellow.bgb; // Присвоєння значення синього каналу зі змінної "yellow" червоному і синьому каналам змінної "red"
```
### Змішування кольорів
Тепер, коли ви знаєте, як визначаються кольори, настав час об'єднати ці нові знання з попередніми. У GLSL є дуже корисна функція [`mix()`](../glossary/?lan=ua&search=mix), яка дозволяє змішувати два значення у відсотках. Чи можете ви здогадатися, який саме там діапазон? Так, звісно це значення від 0.0 до 1.0! Ідеально підійде для вас, особливо після довгих годин відпрацювання рухів карате з парканом настав час скористатися ними!
![](mix-f.jpg)
Перевірте наступний код у рядку 18 і подивіться, як ми використовуємо абсолютні значення синусу на основі часу, щоб змішати значення кольорів у змінних `colorA` та `colorB`.
<div class="codeAndCanvas" data="mix.frag"></div>
Покажіть свої навички:
* Зробіть експресивний перехід між кольорами. Подумайте про якусь емоцію. Який колір здається найбільш характерним для неї? Як він з'являється? Як зникає? Подумайте про іншу емоцію та відповідний їй колір. Змініть початковий і кінцевий кольори у коді вище, відповідно цим емоціям. Потім анімуйте перехід за допомогою формотворчих функцій. Robert Penner розробив серію популярних функцій для комп'ютерної анімації, відомих як [функції пом'якшення](http://easings.net/). Ви можете використати [цей приклад](../edit.php#06/easing.frag) для дослідження та натхнення, але найкращий результат ви здобудете, налаштувавши свої власні переходи.
### Гра з градієнтами
Функція [`mix()`](../glossary/?lan=ua&search=mix) може запропонувати більше. Замість одного `float` значення ми можемо передати компонентний тип змінної, однаковий для перших двох аргументів, у нашому випадку це `vec3`. Таким чином ми отримуємо контроль над відсотками змішування кожного окремого каналу кольорів: `r`, `g` і `b`.
![](mix-vec.jpg)
Розгляньте наступний приклад. Як і в прикладах попереднього розділу, ми створюємо нормалізовані координати та використовуємо *x* для візуалізації лінії. Зараз усі канали змінюються по спільному правилу.
Тепер розкоментуйте рядок 25 і подивіться, що станеться. Потім спробуйте розкоментувати рядки 26 і 27. Пам’ятайте, що лінії візуалізують вагу змішування кожного каналу змінних `colorA` та `colorB`.
<div class="codeAndCanvas" data="gradient.frag"></div>
Ви, напевно, впізнали три функції, які ми використовуємо в рядках 25-27. Пограйте з ними! Настав час дослідити та продемонструвати свої навички з попереднього розділу та створити цікаві градієнти. Спробуйте наступні вправи:
![Вільям Тернер - Останній рейс "Тімірера" (1838)](turner.jpg)
* Створіть градієнт, що нагадує захід сонця Вільяма Тернера
* Анімуйте перехід між сходом і заходом сонця за допомогою `u_time`.
* Чи можете ви зробити веселку, використовуючи отримані до цього часу знання?
* Використайте функцію `step()`, щоб створити кольоровий прапор.
### HSB
Ми не можемо говорити про колір, не згадавши про колірний простір. Як ви, напевно, знаєте, існують різні способи організації кольорів, окрім червоного, зеленого та синього каналів.
[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) означає відтінок (Hue), насиченість (Saturation) і яскравість (Brightness або Value) і є більш інтуїтивно зрозумілою організацією кольорів. Прочитайте код функцій `rgb2hsv()` і `hsv2rgb()` у наступному прикладі.
Зіставляючи `x`-координату на відтінок та `y`-координату на яскравість, ми отримуємо гарний спектр видимих кольорів. Такий просторовий розподіл кольору може бути дуже зручним. Вибір кольору з простору HSB більш інтуїтивний, ніж з RGB.
<div class="codeAndCanvas" data="hsb.frag"></div>
### HSB в полярних координатах
HSB початково розроблений для представлення в полярних координатах (на основі кута та радіуса) замість декартових координат (на основі x і y). Щоб зіставити нашу функцію HSB з полярними координатами, нам потрібно отримати кут і відстань від центру полотна до піксельної координати. Для цього ми використаємо функцію розрахунку відстані — [`length()`](../glossary/?lan=ua&search=length) і арктангенс — [`atan(y, x)`](../glossary/?lan=ua&search=atan) (GLSL-версія загальновживаної функції `atan2(y, x)`).
Під час використання векторних і тригонометричних функцій типи `vec2`, `vec3` і `vec4` розглядаються як вектори, навіть якщо вони представляють кольори. Ми почнемо обробляти кольори та вектори однаковим чином. Згодом ви побачите, що ця концептуальна гнучкість дуже розширює ваші можливості.
**Примітка:** Якщо вам цікаво, то окрім [`length`](../glossary/?lan=ua&search=length) існують й інші геометричні функції, наприклад: [`distance()`](../glossary/?lan=ua&search=distance), [`dot()`](../glossary/?lan=ua&search=dot), [`cross()`](../glossary/?lan=ua&search=cross), [`normalize()`](../glossary/?lan=ua&search=normalize), [`faceforward()`](../glossary/?lan=ua&search=faceforward), [`reflect()`](../glossary/?lan=ua&search=reflect) та [`refract()`](../glossary/?lan=ua&search=refract). Також GLSL має спеціальні векторні функції порівняння, такі як: [`lessThan()`](../glossary/?lan=ua&search=lessThan), [`lessThanEqual()`](../glossary/?lan=ua&search=lessThanEqual), [`greaterThan()`](../glossary/?lan=ua&search=greaterThan), [`greaterThanEqual()`](../glossary/?lan=ua&search=greaterThanEqual), [`equal()`](../glossary/?lan=ua&search=equal) та [`notEqual()`](../glossary/?lan=ua&search=notEqual).
Отримавши кут і довжину, нам потрібно "нормалізувати" їх значення у діапазоні від 0.0 до 1.0. У рядку 27 [`atan(y, x)`](../glossary/?lan=ua&search=atan) поверне кут у радіанах між -PI та PI (від -3.14 до 3.14). Тому нам потрібно розділити це число на подвійне PI, яке записане у макрос `TWO_PI`, що визначений у верхній частині коду. Це дозволить нам отримати значення від -0.5 до 0.5, які шляхом простого додавання до них значення 0.5 ми змінимо на бажаний діапазон від 0.0 до 1.0. Радіус поверне максимум 0.5 (оскільки ми обчислюємо відстань від центру вікна перегляду), тому нам потрібно подвоїти цей діапазон (множенням на два), щоб отримати максимум 1.0.
Як бачите, наша гра полягає в перетворенні та масштабуванні значень, які нам потрібні у діапазоні від 0.0 до 1.0.
<div class="codeAndCanvas" data="hsb-colorwheel.frag"></div>
Спробуйте наступні вправи:
* Змініть приклад з полярними координатами, щоб отримати колірне коло, що обертається, як невелике коло біля екранного курсора в режимі очікування.
* Використайте функцію формування разом із функцією перетворення кольору з HSB у RGB, щоб розширити область кола з певним відтінком та звузити решту.
![William Home Lizars - Red, blue and yellow spectra, with the solar spectrum (1834)](spectrums.jpg)
* Якщо ви уважно придивитесь на колірне коло у програмних палітрах кольорів (див. зображення нижче), ви побачите, що вони використовують інший спектр відповідно до колірного простору RYB. Наприклад, колір, напроти червоного повинен бути зеленим, але в нашому прикладі вище це блакитний. Спробуйте змінити код прикладу, щоб отримати таке саме коло, як на наступному зображенні? [Підказка: це чудовий момент для використання функцій формування.]
![](colorwheel.png)
* Прочитайте книгу [Джозефа Альберса "Взаємодія кольору"](http://www.goodreads.com/book/show/111113.Interaction_of_Color) і скористайтеся для практики наведеними нижче прикладами шейдерів.
<div class="glslGallery" data="160505191155,160505193939,160505200330,160509131554,160509131509,160509131420,160509131240" data-properties="clickRun:editor,openFrameIcon:false,showAuthor:false"></div>
#### Примітка про функції та аргументи
Перш ніж перейти до наступного розділу, зупинімось і трохи перемотаємо назад. Поверніться та погляньте на функції в попередніх прикладах. Ви можете помітити слово `in` перед типом аргументів. Це [*кваліфікатор*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier), і в цьому випадку він вказує, що змінна лише для читання. У наступних прикладах ми побачимо, що також можна визначити аргументи із кваліфікаторами `out` або `inout`. Цей останній, `inout`, концептуально подібний до передачі аргументу за посиланням, що дає нам можливість змінювати передану змінну.
```glsl
int newFunction(
in vec4 aVec4, // лише для читання
out vec3 aVec3, // лише для запису
inout int aInt // і для читання і для запису
);
```
Ви можете не повірити, але тепер у нас є всі необхідні елементи для створення крутих зображень. У наступному розділі ми навчимося комбінувати всі ці трюки, щоб створити геометричні фігури шляхом *змішування* простору. Так-так... *змішування* простору!

View File

@ -132,3 +132,8 @@ int newFunction(in vec4 aVec4, // read-only
```
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.
#### For your toolbox
* [LYGIA's color shader functions ](https://lygia.xyz/color) are set of reusable functions to manipulate colors in GLSL. It includes functions to convert between color spaces, to blend colors, to create gradients, and to apply color transformations. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.

View File

@ -64,7 +64,7 @@ le programme va devoir évaluer les 2 branches de toutes façons et cette évalu
Une stratégie pour parer à ce problème est de structurer le code de manière à éliminer les conditions, donc les branches.
En l'occurrence, se servir du résultat (0 ou 1) de `step()` et le multiplier par une autre variable (la couleur par exemple).
Si le `step()` renvoie 1, la couleur se multipliera par 1 et restera la même, si le `step()` renvoie 0, la couleur se multipliera par 0 donc elle passe au noir.
C'est une technique que voue retrouverez souvent dans les shaders.
C'est une technique que vous retrouverez souvent dans les shaders.
![](rect-01.jpg)
@ -215,12 +215,12 @@ Prenez le code suivant:
<div class="codeAndCanvas" data="rect-df.frag"></div>
On commence par déplacer le système de coordonnées au centre et à le diviser par deux pour obtenir des valeurs comprises entre -1 et 1.
A la *ligne 24*, nous visualisons le champ de distances grâce à la fonction [`fract()`](../glossary/?search=fract) ce qui nous permet de mieux voir le motif qu'il crée.
À la *ligne 24*, nous visualisons le champ de distances grâce à la fonction [`fract()`](../glossary/?search=fract) ce qui nous permet de mieux voir le motif qu'il crée.
Le motif du champ de distances se répète en cercles concentriques, à la manière d'un jardin zen.
Regardons la formule du champ de distances *ligne 19*. Nous calculons la distance entre chaque position et la coordonnée `( .3,.3 )` ( entre `st` et le vecteur `vec2(.3)`) pour chaque quadrant, c'est à ça que sert l'appel à [`abs()`](../glossary/?search=abs).
Si vous décommentez la *ligne 20*, vouz noterez que nous combinons les distances à ces 4 points en utilisant la fonction [`min()`](../glossary/?search=min) contre 0, ce qui produit un nouveau motif.
Si vous décommentez la *ligne 20*, vous noterez que nous combinons les distances à ces 4 points en utilisant la fonction [`min()`](../glossary/?search=min) contre 0, ce qui produit un nouveau motif.
L'idée est qu'il n'y a qu'un seul point, et non '4', celui en haut à droite mais il est *reflété* dans les 3 autres *quadrants* du fait qu'on a changé la taille de l'espace *ligne 16* !

233
07/README-ua.md Normal file
View File

@ -0,0 +1,233 @@
![Alice Hubbard, Providence, United States, ca. 1892. Photo: Zindman/Freemont.](froebel.jpg)
## Фігури
Нарешті! Ми розвивали попередні навички саме для цього моменту! Ви вивчили більшість основ GLSL мови, її типи та функції. Ви знову й знову практикували свої навички у формотворчих функціях та рівняннях. Настав час зібрати все разом. Ви вже готові прийняти цей виклик! У цьому розділі ви дізнаєтесь, як малювати прості фігури за допомогою паралельних обчислень.
### Прямокутник
Уявіть, що ми маємо листок паперу у клітинку, як на уроках математики, і наше домашнє завдання — намалювати квадрат. Розмір паперу 10х10, а квадрат має бути 8х8. Що ви будете робити?
![](grid_paper.jpg)
Мабуть, ви б розфарбували все, окрім першого й останнього рядків та першого й останнього стовпців, чи не так?
Як це пов'язано з шейдерами? Кожен маленький квадрат нашої сітки — це один потік (піксель). Кожен квадратик знає своє положення, наче координати на шаховій дошці. У попередніх розділах ми масштабували координати *x* та *y* у канали *червоного* та *зеленого* кольорів й навчилися використовувати вузьку двовимірну територію масштабовану між 0.0 та 1.0. Як за допомогою цього ми можемо намалювати квадрат відцентрований посередині нашого полотна?
Почнімо з псевдокоду та використання `if`-операторів для просторових координат. Ці принципи надзвичайно схожі на випадок з паперовим варіантом.
```glsl
if ((X GREATER THAN 1) AND (Y GREATER THAN 1)) // якщо (x більше 1) та (y більше 1)
paint white // фарбуємо білим
else // інакше
paint black // фарбуємо чорним
```
Тепер, коли ми маємо краще уявлення про потрібну роботу, замінімо оператор `if` на [`step()`](../glossary/?lan=ua&search=step), а замість використання листка 10x10 використаємо нормалізовані значення між 0.0 і 1.0:
```glsl
uniform vec2 u_resolution;
void main(){
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec3 color = vec3(0.0);
// кожен результат поверне 1.0 (білий) або 0.0 (чорний).
float left = step(0.1, st.x); // подібно до (X більше 0.1)
float bottom = step(0.1, st.y); // подібно до (Y більше 0.1)
// множення left на bottom спрацює як логічний оператор AND.
color = vec3(left * bottom);
gl_FragColor = vec4(color, 1.0);
}
```
Функція [`step()`](../glossary/?lan=ua&search=step) перетворить кожен піксель нижче 0.1 на чорний колір (`vec3(0.0)`), а решту — на білий (`vec3(1.0)`). Множення між `left` і `bottom` працює як логічна операція AND, де обидва значення мають бути рівні 1.0, щоб повернути 1.0. Цей код намалює дві чорні лінії: знизу та зліва.
![](rect-01.jpg)
У попередньому коді ми повторюємо одну і ту ж саму дію для обох сторін: лівої та нижньої. Ми можемо зекономити кілька рядків коду, передавши у [`step()`](../glossary/?lan=ua&search=step) одразу два значення, у вигляді вектору, замість одного:
```glsl
vec2 borders = step(vec2(0.1), st);
float pct = borders.x * borders.y;
```
Поки що ми намалювали лише дві межі нашого прямокутника: нижню та ліву. Зробімо інші дві: верхню та праву. Розгляньте наступний код:
<div class="codeAndCanvas" data="rect-making.frag"></div>
Розкомментуйте *рядки 21-22* і подивіться, як ми інвертуємо там координати `st` і повторюємо ту саму функцію [`step()`](../glossary/?lan=ua&search=step). Таким чином `vec2(0.0, 0.0)` буде у верхньому правому куті. Це цифровий еквівалент перевороту сторінки з повторенням попередньої процедури.
![](rect-02.jpg)
Зверніть увагу, що в *рядках 18 і 22* всі сторони перемножуються разом. Це еквівалентно наступному написанню:
```glsl
vec2 bl = step(vec2(0.1), st); // нижній-лівий
vec2 tr = step(vec2(0.1), 1.0 - st); // верхніх-правий
color = vec3(bl.x * bl.y * tr.x * tr.y);
```
Цікаво правда? Ця техніка базується на використанні [`step()`](../glossary/?lan=ua&search=step), множенні у якості логічної операції та перевороті координат.
Перш ніж продовжити, спробуйте виконати такі вправи:
* Змініть розмір і пропорції прямокутника.
* Поекспериментуйте з тим самим кодом, використовуючи [`smoothstep()`](../glossary/?lan=ua&search=smoothstep) замість [`step()`](../glossary/?lan=ua&search=step). Зауважте, що змінюючи значення, ви можете переходити від розмитих меж до елегантно згладжених країв.
* Виконайте іншу реалізацію, з використанням [`floor()`](../glossary/?lan=ua&search=floor).
* Виберіть реалізацію, яка вам найбільше до вподоби, та створіть для неї функцію, яку ви зможете повторно використовувати в майбутньому. Зробіть свою функцію гнучкою та ефективною.
* Створіть іншу функцію, яка малюватиме просто контур прямокутника.
* Як можна було б пересувати та розміщувати різні прямокутники на одному полотні? Якщо зрозумієте як це зробити, продемонструйте свої вміння, створивши композицію з прямокутників і кольорів, що нагадує картину [Piet Mondrian](http://en.wikipedia.org/wiki/Piet_Mondrian).
![Piet Mondrian - Tableau (1921)](mondrian.jpg)
### Кола
Легко намалювати квадрати на папері в клітинку та прямокутники за декартовими координатами, але кола вимагають іншого підходу, особливо тому, що нам потрібен "по-піксельний" алгоритм. Одне з рішень полягає в *перетворенні* просторових координат таким чином, щоб ми змогли використовувати функцію [`step()`](../glossary/?lan=ua&search=step) для малювання кола.
Як? Почнімо з того, що повернемося до уроку математики та паперу у клітинку. Розкриємо циркуль на радіус кола, поставимо його голку в центрі кола, а потім окреслимо окружність кола простим обертанням.
![](compass.jpg)
Перекладаючи це на мову шейдера, де кожен квадрат на папері є пікселем, ми маємо *спитати* кожен піксель (або потік), чи знаходиться він усередині кола. Ми робимо це, обчислюючи відстань від пікселя до центру кола.
![](circle.jpg)
Є кілька способів розрахувати цю відстань. Найпростіший використовує функцію [`distance()`](../glossary/?lan=ua&search=distance), яка всередині обчислює [`length()`](../glossary/?lan=ua&search=length)-різниці між двома точками. У нашому випадку між координатою пікселя та центром полотна. По своїй суті функція `length()` — це не що інше, як скорочення для [рівняння визначення довжини гіпотенузи](http://en.wikipedia.org/wiki/Hypotenuse), яке використовує квадратний корінь ([`sqrt()`](../glossary/?lan=ua&search=sqrt)).
![](hypotenuse.png)
Щоб обчислити відстань до центру полотна ви можете використовувати [`distance()`](../glossary/?lan=ua&search=distance), [`length()`](../glossary/?lan=ua&search=length) або [`sqrt()`](../glossary/?lan=ua&search=sqrt). Наступний код містить ці три функції та той недивний факт, що кожна з них повертає точно такий самий результат.
* Закоментуйте та розкоментуйте рядки, щоб спробувати різними способами отримати той самий результат.
<div class="codeAndCanvas" data="circle-making.frag"></div>
У попередньому прикладі ми переводимо відстань від центру полотна у яскравість кольору пікселя. Чим ближче піксель до центру, тим менше (темніше) значення він має. Зауважте, що значення не стають надто високими, оскільки максимальна відстань від центру (`vec2(0.5, 0.5)`) ледве перевищує значення 0.5. Подивіться на зображення і подумайте:
* Який висновок ви можете з цього зробити?
* Як ми можемо використати це, щоб намалювати коло?
* Змініть наведений вище код, щоб вмістити весь круговий градієнт всередині полотна.
### Поле відстаней
Наведений вище приклад можна розглянути як карту висот, де темніший колір означає вищу позицію. В такому разі цей круговий градієнт буде картою конуса. Уявіть себе на вершині цього конуса. Відстань по горизонталі до краю конуса, в будь-якому напрямку, дорівнює 0.5. Вибираючи, на якій висоті "зрізати" конус, ви отримаєте більший чи менший діаметр кругової поверхні.
![](distance-field.jpg)
По суті ми інтерпретуємо простір на основі його відстані до центру для того, щоб робити таким чином фігури. Ця техніка відома як "поле відстаней" і використовується різними шляхами, від контурів шрифтів до 3D-графіки.
Спробуйте наступні вправи:
* Використовуйте [`step()`](../glossary/?lan=ua&search=step), щоб перетворити значення більші за 0.5 у білий колір, а все, що менше 0.0 — у чорний.
* Змініть місцями кольори фону та переднього плану.
* Використовуючи [`smoothstep()`](../glossary/?lan=ua&search=smoothstep) та експериментуючи з різними значеннями, отримайте гарний плавний край для вашого кола.
* Для найбільш вдалої вашої реалізації створіть функцію, яку ви зможете повторно використовувати в майбутньому.
* Додайте колу колір.
* Чи зможете ви анімувати своє коло, щоб воно збільшувалося та зменшувалося, імітуючи серцебиття? Ви можете отримати натхнення з анімації у попередньому розділі.
* А як щодо переміщення кола? Чи зможете ви перемістити та розташувати на полотні кілька різних кіл?
* Що станеться, якщо скомбінувати поля відстаней за допомогою різних функцій та операцій?
```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)));
```
* Створіть три композиції за допомоги цієї техніки. Ще краще, якщо вони будуть анімовані!
#### Для вашого інструментарію
З точки зору обчислювальної потужності, функція [`sqrt()`](../glossary/?lan=ua&search=sqrt) і всі функції, які від неї залежать, можуть бути досить ресурсовитратними. Ось ще один спосіб для створення кругового поля відстаней за допомогою функції [`dot()`](../glossary/?lan=ua&search=dot).
<div class="codeAndCanvas" data="circle.frag"></div>
### Корисні властивості поля відстаней
![Zen garden](zen-garden.jpg)
Поля відстаней можна використовувати для малювання майже всього. Очевидно, що чим складнішою є форма, тим складнішим буде її рівняння. Але як тільки у вас є формула для створення поля відстаней певної форми, її дуже легко комбінувати та/або застосовувати до неї ефекти. Наприклад, згладження країв або численні контури. Через це поля відстаней популярні у цифровому зображенні шрифтів, наприклад [Mapbox GL Labels](https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817), [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu) (автор: [Matt DesLauriers](https://twitter.com/mattdesl)) та [iPhone 3D Programming, OReilly (див. розділ 7)](http://chimera.labs.oreilly.com/books/1234000001814/ch07.html#ch07_id36000921).
Розгляньте наступний код:
<div class="codeAndCanvas" data="rect-df.frag"></div>
Ми починаємо з переміщення відліку системи координат у центр. Звужуємо її вдвічі, щоб вона вміщувала в себе значення позиції між -1.0 та 1.0. Також у *рядку 24* ми візуалізуємо значення поля відстаней за допомогою функції [`fract()`](../glossary/?lan=ua&search=fract), що покаже малюнок форми, який воно створює. Контур поля відстаней повторюється знову і знову, як кільця в саду дзен.
Подивімось на формулу поля відстаней у *рядку 19*. Тут ми обчислюємо відстань до позиції у точці `(.3, .3)` (або `vec3(.3)`) в усіх чотирьох квадрантах (саме для цього було використано [`abs()`](../glossary/?lan=ua&search=abs)).
Якщо ви розкоментуєте *рядок 20*, то помітите, що ми об'єднуємо відстані до цих чотирьох точок за допомогою функції [`min()`](../glossary/?lan=ua&search=min) до нуля. У результаті виходить новий цікавий візерунок.
Тепер спробуйте розкоментувати *рядок 21*. Тут ми робимо те саме, але використовуємо функцію [`max()`](../glossary/?lan=ua&search=max). В результаті вийде прямокутник із закругленими кутами. Зверніть увагу, що кільця поля відстаней стають більш гладкими, чим далі вони віддаляються від центру.
Нарешті, по черзі розкоментуйте *рядки з 27 по 29*, щоб побачити та зрозуміти різні варіанти шаблонів використання поля відстаней.
### Фігури у полярних координатах
![Robert Mangold - Untitled (2008)](mangold.jpg)
У розділі про колір ми зіставляли декартові координати з полярними координатами, обчислюючи *радіус* і *кут* кожного пікселя за такою формулою:
```glsl
vec2 pos = vec2(0.5) - st;
float r = length(pos) * 2.0;
float a = atan(pos.y, pos.x);
```
На початку розділу ми використали частину цієї формули, щоб намалювати коло. Ми обчислили відстань до центру за допомогою функції [`length()`](../glossary/?lan=ua&search=length). Тепер, знаючи про поля відстаней, ми можемо навчитися малювати фігури за допомогою полярних координат іншим способом.
Ця техніка трохи обмежена, але дуже проста. Вона полягає в отримання різних форм, змінюючи радіус кола залежно від кута. Як це працює? Звісно ж за допомогою функцій формування!
Нижче ви знайдете функції для отримання значень у декартовій системі координат та зображення їх на графіку. А ще нижче інший приклад з тими ж самими функціями, але вже для полярних координат (між *рядками 21 і 25*). Розкоментуйте ці функції одну за одною та звертайте увагу на співвідношення між обома системами координат.
<div class="simpleFunction" data="y = cos(x * 3.0);
//y = abs(cos(x * 3.0));
//y = abs(cos(x * 2.5)) * 0.5 + 0.3;
//y = abs(cos(x * 12.) * sin(x * 3.0)) * .8 + .1;
//y = smoothstep(-0.5, 1.0, cos(x * 10.0)) * 0.2 + 0.5;"></div>
<div class="codeAndCanvas" data="polar.frag"></div>
Спробуйте:
* Анімувати ці форми.
* Комбінувати різні формотворчі функції, щоб *вирізати отвори* у формі й зробити подобу квітів, сніжинок та шестерень.
* Використати функцію `plot()` з розділу [Формотворчих функцій](/05/?lan=ua), щоб намалювати лише контур.
### Сила комбінацій
Ми навчилися модулювати радіус кола відповідно до кута за допомогою функції [`atan()`](../glossary/?lan=ua&search=atan) для малювання різних фігур. Тепер ми можемо навчитися використовувати `atan()` з полями відстаней та застосувати всі трюки та ефекти, можливі з цими полями.
Наступний трюк використовує кількість ребер багатокутника для побудови поля відстаней за допомогою полярних координат. Перегляньте [цей код](http://thndl.com/square-shaped-shaders.html) від [Andrew Baldwin](https://twitter.com/baldand).
<div class="codeAndCanvas" data="shapes.frag"></div>
* Використовуючи цей приклад, створіть функцію, яка приймає положення та кількість кутів потрібного багатокутника й повертає значення поля відстаней.
* Змішайте поля відстаней за допомогою функції [`min()`](../glossary/?lan=ua&search=min) та [`max()`](../glossary/?lan=ua&search=max).
* Виберіть геометричний логотип і відтворіть його за допомогою полей відстані.
Щиро вітаю! Ви пройшли через складну частину! Зробіть перерву й дайте цим концепціям засвоїтись. Так, малювати прості фігури десь у Processing легко, але не тут. У світі шейдерів малювання фігур хитромудра справа, і адаптація до цієї нової парадигми кодування може бути виснажливою.
У кінці цього розділу ви знайдете посилання на [Колоду PixelSpirit](https://patriciogonzalezvivo.github.io/PixelSpiritDeck/). Ця колода карт допоможе вам вивчити нові функції SDF, скомпонувати їх та використати у ваших шейдерах. Колода має прогресивну криву навчання. Можете брати по одній карті на день й опрацьовувати її, щоб підштовхнути та випробувати свої навички.
Тепер, коли ви знаєте, як малювати фігури, я впевнений, що у вас у голові з’являться нові ідеї. У наступному розділі ви дізнаєтесь, як переміщувати, обертати та масштабувати фігури. Це дозволить вам складати композиції!

View File

@ -90,7 +90,7 @@ Before going forward, try the following exercises:
### Circles
It's easy to draw squares on grid paper and rectangles on cartesian coordinates, but circles require another approach, especially since we need a "per-pixel" algorithm. One solution is to *re-map* the spatial coordinates so that we can use a [`step()`](../glossary/?search=step) function to draw a circle.
It's easy to draw squares on grid paper and rectangles on Cartesian coordinates, but circles require another approach, especially since we need a "per-pixel" algorithm. One solution is to *re-map* the spatial coordinates so that we can use a [`step()`](../glossary/?search=step) function to draw a circle.
How? Let's start by going back to math class and the grid paper, where we opened a compass to the radius of a circle, pressed one of the compass points at the center of the circle and then traced the edge of the circle with a simple spin.
@ -184,7 +184,7 @@ Finish uncommenting *lines 27 to 29* one by one to understand the different uses
![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:
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;
@ -196,7 +196,7 @@ We use part of this formula at the beginning of the chapter to draw a circle. We
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.
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.
<div class="simpleFunction" data="y = cos(x*3.);
//y = abs(cos(x*3.));
@ -228,6 +228,10 @@ The trick will use the number of edges of a polygon to construct the distance fi
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.
#### For your toolbox
* [LYGIA's draw functions ](https://lygia.xyz/draw) are set of reusable functions to draw 2D shapes and patterns. You can also explore [LYGIA's SDF functions folder](https://lygia.xyz/sdf) to combine more complex shapes through distance fields. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.
* 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!

View File

@ -24,8 +24,10 @@ void main(){
// Number of sides of your shape
int N = 3;
// Angle and radius from the current pixel
// Angle from the current pixel
float a = atan(st.x,st.y)+PI;
// Angular spacing between vertices of shape
float r = TWO_PI/float(N);
// Shaping function that modulate the distance

105
08/README-ua.md Normal file
View File

@ -0,0 +1,105 @@
## Двомірні матриці
<canvas id="custom" class="canvas" data-fragment-url="matrix.frag" width="700px" height="200px"></canvas>
### Переміщення
У попередньому розділі ми навчилися створювати деякі фігури — хитрість переміщення цих фігур полягає в тому, щоб перемістити саму систему координат. Ми можемо досягти цього, просто додавши вектор до змінної ```st```, яка містить розташування кожного фрагмента. Це спричиняє зміщення у просторі усієї системи координат.
![](translate.jpg)
Це легше побачити, ніж пояснити, тому дивіться самі:
* Розкоментуйте рядок 35 в коді нижче, щоб побачити, як рухається сам простір.
<div class="codeAndCanvas" data="cross-translate.frag"></div>
Тепер спробуйте наступне:
* Використовуючи змінну ```u_time``` разом із функціями формування, надайде хрестику рух у новому цікавому напрямку. Знайдіть конкретний варіант руху, яка вас цікавить, і спробуйте змусити хрест рухатися таким же чином. Спробуйте для початку щось із "реального світу" — це можуть бути хвилеподібні рухи, коливання маятника, м’яч, що підстрибує, прискорення як в автомобіля чи зупинка велосипеда.
### Обертання
Щоб обертати об'єкти, нам також потрібно рухати всю систему простору. Для цього ми будемо використовувати [матрицю](http://en.wikipedia.org/wiki/Matrix_%28mathematics%29). Матриця — це організований набір чисел у стовпцях і рядках. Вектори помножуються на матриці відповідно до певних правил, щоб змінити значення вектора визначеним чином.
[![Wikipedia entry for Matrix (mathematics) ](matrixes.png)](https://en.wikipedia.org/wiki/Matrix)
GLSL має вбудовану підтримку дво-, три- та чотиривимірних матриць: [```mat2```](../glossary/?lan=ua&search=mat2) (2x2), [```mat3```](../glossary/?lan=ua&search=mat3) (3x3) та [```mat4```](../glossary/?lan=ua&search=mat4) (4x4). GLSL також підтримує множення матриць (```*```) та специфічну для матриці функцію ([```matrixCompMult()```](../glossary/?lan=ua&search=matrixCompMult)).
Можна побудувати різні матриці для отримання певної поведінки. Наприклад, ми можемо використати матрицю для переміщення вектора:
![](3dtransmat.png)
Що ще цікавіше, ми можемо використати матрицю для обертання системи координат:
![](rotmat.png)
Подивіться на наведений нижче код функції, яка створює двовимірну матрицю обертання. Ця функція відповідає наведеній вище [формулі](http://en.wikipedia.org/wiki/Rotation_matrix) для обертання координат навколо точки ```vec2(0.0)```.
```glsl
mat2 rotate2d(float _angle) {
return mat2(
cos(_angle), -sin(_angle),
sin(_angle), cos(_angle)
);
}
```
Судячи з того, як ми малювали фігури, це не зовсім те, що нам потрібно. Наша форма хреста намальована в центрі полотна, що відповідає позиції ```vec2(0.5)```. Отже, перед тим, як обертати простір, нам потрібно перемістити фігуру із `центру` до координати ```vec2(0.0)```, повернути простір, а потім, нарешті, перемістити його назад у початкове положення.
![](rotate.jpg)
Це можна запрограмувати таким чином:
<div class="codeAndCanvas" data="cross-rotate.frag"></div>
Спробуйте наступні вправи:
* Розкоментуйте рядок 45 із коду вище та зверніть увагу на те, що відбувається.
* Закоментуйте зміщення координат до та після повороту, у рядках 38 та 42, спостерігаючи за наслідками.
* Використайте обертання, щоб покращити анімацію, яку ви моделювали під час вправи з переміщенням.
### Масштаб
Ми побачили, як матриці використовуються для переміщення та обертання об'єктів у просторі. А точніше, як змінювати системи координат для обертання та переміщення об'єктів. Якщо ви користувалися програмним забезпеченням для 3D-моделювання або функціями `push` та `pop` для матриць у Processing, то знаєте, що матриці також можна використовувати й для масштабування розміру об'єктів.
![](scale.png)
Дотримуючись попередньої формули, ми можемо створити двомірну матрицю масштабування:
```glsl
mat2 scale(vec2 _scale) {
return mat2(
_scale.x, 0.0,
0.0, _scale.y
);
}
```
<div class="codeAndCanvas" data="cross-scale.frag"></div>
Спробуйте виконати наступні вправи, щоб глибше зрозуміти, як це працює.
* Розкомментуйте рядок 42 із коду вище, щоб побачити масштабування просторових координат.
* Подивіться, що відбудеться, коли ви закоментуєте переміщення координат до та після масштабування в рядках 37 та 39.
* Спробуйте поєднати матрицю обертання разом із матрицею масштабування. Майте на увазі, що порядок має значення. Спочатку помножте на матрицю, а потім результат помножте на вектори.
* Тепер, коли ви знаєте, як малювати різні фігури, переміщувати, обертати та масштабувати їх, настав час створити гарну композицію. Спроєктуйте та створіть фейковий [UI або HUD](https://www.pinterest.com/patriciogonzv/huds/). HUD (heads up display) — мається на увазі розташування інформації на прозорих поверхнях або дисплеях. Для натхнення та довідки, можете використати наступний ShaderToy-приклад від [Ndel](https://www.shadertoy.com/user/ndel).
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/4s2SRt?gui=true&t=10&paused=true" allowfullscreen></iframe>
### Інше використання матриць: колір у просторі YUV
[YUV](http://en.wikipedia.org/wiki/YUV) — це колірний простір, який використовується для аналогового кодування фотографій та відео, яке враховує діапазон людського сприйняття для зменшення пропускної здатності компонентів колірності.
Наступний код є цікавою можливістю використовувати матричні операції в GLSL для перетворення кольорів з одного простору в інший.
<div class="codeAndCanvas" data="yuv.frag"></div>
Як бачите, ми розглядаємо кольори як вектори, перемножуючи їх на матриці. Таким чином ми "переміщуємо" значення кольорів.
У цьому розділі ми навчилися використовувати матричні перетворення для переміщення, обертання та масштабування векторів. Ці трансформації будуть корисними для створення композицій із фігур, про які ми дізналися із попереднього розділу. У наступному розділі ми застосуємо всі здобуті знання для створення красивих процедурних візерунків. Ви побачите, що програмування повторень та варіацій може бути захопливою діяльністю.

View File

@ -99,3 +99,7 @@ The following code is an interesting opportunity to use matrix operations in GLS
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.
#### For your toolbox
* [LYGIA's space functions ](https://lygia.xyz/space) are set of reusable functions to manipulate space in GLSL. It's a great resource to learn how to use matrices to manipulate space. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.

115
09/README-ua.md Normal file
View File

@ -0,0 +1,115 @@
## Патерни
Шейдерні програми виконуються попіксельно, тому незалежно від того скільки ви повторюєте якусь фігуру, кількість обчислень залишається незмінною. Це означає, що фрагментні шейдери добре підходять для створення патернів — візерунків, що повторюються.
[![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg)](../edit.php#09/dots5.frag)
У цьому розділі ми збираємося застосувати дещо з попереднього матеріалу, щоб продублювати його кілька разів на полотні. Як і в попередніх розділах, наша стратегія базуватиметься на перемноженні просторових координат з діапазоном від 0.0 до 1.0, так щоб фігури, які ми малюватимемо між значеннями 0.0 та 1.0, повторювалися, утворюючи сітку.
*"Сітка забезпечує структуру, в межах якої людській інтуїції та винахідливості зручно орієнтуватись. У хаосі природи візерунки створюють контраст і обіцяють порядок. Від ранніх візерунків на кераміці до геометричної мозаїки в римських лазнях люди давно використовують сітки, щоб прикрасити своє життя за допомогою декору."* [*10 PRINT*, Mit Press, (2013)](http://10print.org/)
Спочатку згадаймо функцію [```fract()```](../glossary/?lan=ua&search=fract). Вона повертає дробову частину числа, роблячи ```fract()``` модулем одиниці ([```mod(x,1.0)```](../glossary/?lan=ua&search=mod)). Іншими словами, [```fract()```](../glossary/?lan=ua&search=fract) повертає число після коми з рухомою крапкою. Наша змінна з нормалізованою системою координат (```st```) уже змінюється в межах діапазону від 0.0 до 1.0, тому немає сенсу робити щось на наступний зразок:
```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);
}
```
Але якщо ми збільшимо масштаб нормалізованої системи координат, скажімо, втричі до 3.0, то отримаємо три послідовності лінійної інтерполяції одиничного розміру. Перша між 0.0 та 1.0, друга між 1.0 та 2.0 й третя між 2.0 та 3.0.
<div class="codeAndCanvas" data="grid-making.frag"></div>
Настав час намалювати щось у кожному підпросторі, розкоментувавши рядок 27. Оскільки обидві вісі x та y помножуються на однакове значення, то співвідношення сторін простору не змінюється. Відповідно форми також не матимуть викривлень та будуть такими, як очікувалося.
Для глибшого розуміння, спробуйте виконати деякі з наведених нижче вправ:
* Помножте просторові координати на різні числа. Спробуйте різні значення з рухомою крапкою, а також різні значення для x та y.
* Зробіть, для цього трюку з плиткою, функцію для повторного використання.
* Розділіть простір на 3 рядки та 3 стовпці. Знайдіть спосіб дізнатися, у якому стовпці та рядку знаходиться потік, і в залежності від цього змінити фігуру, що буде малюватися. Спробуйте зробити композицію з гри у хрестики-нулики.
### Застосування матриць всередині патернів
Оскільки кожен підрозділ або комірка є зменшеною версією нормалізованої системи координат, яку ми використовували раніше, ми можемо застосувати до них такі ж самі матричні перетворення для переміщення, обертання та масштабування.
<div class="codeAndCanvas" data="checks.frag"></div>
* Подумайте про цікаві способи анімації цього візерунка. Подумайте про анімацію кольорів, форм і рухів. Зробіть три різні анімації.
* Відтворіть складніші візерунки, компонуючи різні форми.
[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag)
* Комбінуйте різні шари патернів, щоб створити власні [орнаменти шотландського тартану](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).
[![Векторний візерунок шотландського тартану від Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076)
### Патерни зі зміщенням
Припустимо, ми хочемо імітувати цегляну стіну. Розглядаючи стіну, ви можете побачити, що кожен другий її ряд зміщений на півцеглини по вісі x. Як можна це зробити?
![](brick.jpg)
Першим кроком потрібно визначити, чи є потік поточного рядка парним чи непарним, що дасть нам розуміння чи потрібно робити зміщення у цьому рядку. Для цього ми використаємо функцію модуля [```mod()```](../glossary/?lan=ua&search=mod) зі значенням ```2.0``` для другого параметру, а потім перевіримо, чи результат буде меншим від ``` 1.0``` чи ні. Подивіться на наступну формулу та розкоментуйте два останні рядки.
<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>
Як бачите, ми можемо використати [тернарний оператор](https://en.wikipedia.org/wiki/%3F:), щоб перевірити, чи остача від ділення по модулю [```mod()```](../glossary/?lan=ua&search=mod) на ```2.0``` менше за ```1.0```, що означатиме другий рядок. Або ми можемо аналогічно використати функцію [```step()```](../glossary/?lan=ua&search=step), яка виконає ту саму операцію, але швидше. Чому? Хоча важко напевно знати, як кожна графічна карта оптимізує та компілює код, але можна з упевненістю припустити, що вбудовані функції працюють швидше. За кожної можливості надавайте перевагу використанню вбудованих функцій!
Тепер, маючи формулу визначення непарних чисел, ми можемо застосувати зміщення до непарних рядків, щоб надати нашим плиткам *ефект цегли*. У рядку 14 наступного коду ми використовуємо функцію для "виявлення" непарних рядків та зсуваємо їх на половину одиниці по вісі ```x```. Зауважте, що для парних рядків результатом нашої функції буде ```0.0```, що при множенні на значення для зміщення в ```0.5``` залишається тим самим ```0.0```. Але в непарних рядках ми отримуємо результат нашої функції як ```1.0```, що при множенні на зсув ```0.5```, переміщує вісь ```x``` системи координат на ```0.5```.
Тепер спробуйте розкоментувати рядок 32 — це розтягне співвідношення сторін системи координат, щоб імітувати її до співвідношення "сучасної цегли". Розкоментувавши рядок 40, ви зможете побачити, як виглядає система координат, відображена у червоний та зелений кольори.
<div class="codeAndCanvas" data="bricks.frag"></div>
* Спробуйте анімувати цей приклад, змінюючи зміщення відповідно до часу.
* Зробіть ще одну анімацію, у якій парні ряди рухаються ліворуч, а непарні — праворуч.
* Чи можете ви повторити цей ефект, але зі стовпцями?
* Спробуйте скомбінувати зсуви на вісі ```x``` та ```y```, щоб отримати щось на зразок наступного:
<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>
## Плитка Труше
Тепер, коли ми навчилися визначати, чи знаходиться наша комірка в парному чи непарному рядку чи стовпці, можна повторно використовувати один елемент дизайну залежно від його положення. Розглянемо випадок [плитки Труше](http://en.wikipedia.org/wiki/Truchet_tiles), де один елемент дизайну може бути представлено чотирма різними способами:
![](truchet-00.png)
Змінюючи малюнок у плитках, можна побудувати нескінченний набір складних зображень.
![](truchet-01.png)
Зверніть увагу на функцію ```rotateTilePattern()```, яка розбиває простір на чотири комірки та призначає кожній кут повороту.
<div class="codeAndCanvas" data="truchet.frag"></div>
* Закоментуйте, розкоментуйте та продублюйте рядки з 69 по 72, щоб скомпонувати нові зображення.
* Змініть чорно-білий трикутник на інший елемент, наприклад: півколо, повернуті квадрати або лінії.
* Запрограмуйте інші патерни, де елементи обернені відповідно до їхнього положення.
* Створіть патерн, який змінює інші свої властивості відповідно до положення елементів.
* Подумайте про щось інше, не обов'язково про патерни, де ви можете застосувати принципи з цього розділу. Наприклад, [гексаграми "I Ching"](https://en.wikipedia.org/wiki/Hexagram_(I_Ching)):
<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>
## Створення власних правил
Створення процедурних патернів — це розумова вправа з пошуку мінімальної кількості елементів для багаторазово використання в просторі. Ця давня практика. Ми, як біологічний вид, використовуємо сітки та візерунки для декорування текстилю, підлоги та границь об'єктів протягом тривалого часу: від візерунків декоративних звивистих ліній (меандрів) стародавньої Греції до китайських решітчастих патернів. Насолода від повторення та варіацій захоплює нашу уяву. Знайдіть час, щоб переглянути [декоративні](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) [візерунки](https://www.pinterest.com/patriciogonzv/paterns/) та подивитися як художники з дизайнерами балансуються між передбачуваністю порядку й несподіваністю варіацій та хаосу. Від арабських геометричних візерунків до розкішних африканських зображень на тканинах пролягає цілий всесвіт візерунків для натхнення та пізнання.
[![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png)](https://archive.org/details/handbookoforname00meyeuoft/page/10/mode/2up)
Цією главою ми закінчуємо розділ про алгоритмічне малювання. У наступних розділах ми дізнаємося, як привносити у наші шейдери трохи ентропії та створювати генеративні дизайни.

92
10/README-ua.md Normal file
View File

@ -0,0 +1,92 @@
# Генеративний дизайн
Не дивно, що після стількох повторень наших карате-рухів і впорядкованості, автор змушений внести трохи хаосу.
## Випадковість
[![Ryoji Ikeda - тестовий патерн (2008) ](ryoji-ikeda.jpg)](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set)
Випадковість є максимальним проявом ентропії. Як ми можемо створити випадковість у, здавалося б, передбачуваному та суворому програмному середовищі?
Почнемо з аналізу наступної функції:
<div class="simpleFunction" data="y = fract(sin(x) * 1.0);"></div>
Значення [```sin()```](../glossary/?lan=ua&search=sin) коливаються між ```-1.0``` до ```1.0```. Вище ми витягуємо дробову частину цієї синусоїди, "обрізаючи" та підіймаючи діапазон її негативних значень до позитивних в межах від ```0.0``` до ```1.0```. Цей ефект можна використати, щоб отримати деякі псевдовипадкові значення, "розбивши" синусоїду на менші частини. Як? За допомогою помноження результату [```sin(x)```](../glossary/?lan=ua&search=sin) на більші числа. Поверніться до прикладу і почніть додавати нулі до цілої частини множника.
Коли дійдете до ```100000.0``` і рівняння виглядатиме як "```y = fract(sin(x) * 100000.0)```", то більше не зможете розрізнити синусоїду. Деталізація дробової частини спотворила плавний потік синусоїди, перетворивши її у псевдовипадковий хаос.
## Управління хаосом
Використання випадковості може бути важкою справою. Інколи вона буває занадто хаотичною, а часом недостатньо випадковою. Подивіться на наступний графік. В ньому ми використовуємо функцію ```rand()```, яка реалізована так само як ми описали вище.
Придивившись ближче, ви можете побачити гребні у [```sin()```](../glossary/?lan=ua&search=sin)-хвилі по x-вісі біля значень ```-1.5707``` та ```1.5707```. Б'юся об заклад, тепер ви розумієте чому — саме там відбувається максимум і мінімум синусоїди.
Якщо уважно розглянути цей розподіл псевдовипадкових значень, то ви також помітите, що навколо середини y-вісі спостерігається більша концентрація значень, аніж на її краях.
<div class="simpleFunction" data="y = rand(x);
//y = rand(x) * rand(x);
//y = sqrt(rand(x));
//y = pow(rand(x), 5.0);"></div>
Свого часу [Pixelero](https://pixelero.wordpress.com) опублікував [цікаву статтю про випадковий розподіл](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/). Я додав декілька його прикладів до попереднього графіка, щоб ви могли пограти з ними та побачити, як можна змінити розподіл значень. Розкоментуйте рядки та подивіться, що станеться.
Читаючи [статтю Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/), важливо мати на увазі, що наша функція ```rand()``` є детерміновано випадковою, інакше кажучи, псевдовипадковою. Це означає, що, наприклад, ```rand(1.)``` завжди повертатиме одне й те саме значення. [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) у своїй статті посилається на недетерміновану ActionScript-функцію ```Math.random()```, кожен виклик якої повертає різні значення.
## Двомірна випадковість
Тепер, коли ми краще розуміємо випадковість, настав час застосувати її у двомірному просторі, до осей ```x``` та ```y```. Для цього нам потрібен спосіб перетворити двовимірний вектор в одновимірне значення з рухомою крапкою. Існують різні способи зробити це, але функція [```dot()```](../glossary/?lan=ua&search=dot) особливо корисна в цьому випадку. Вона повертає єдине float-значення між ```0.0``` і ```1.0``` залежно від розташування двох векторів.
<div class="codeAndCanvas" data="2d-random.frag"></div>
Подивіться на рядки з 13 по 15 і зверніть увагу на те, як ми порівнюємо ```vec2 st``` з іншим двовимірним вектором (```vec2(12.9898, 78.233)```).
* Спробуйте змінити значення в рядках 14 і 15. Подивіться як змінюється зображення та поміркуйте, чого ми можемо з цього навчитися.
* Застосуйте цю функцію з отримання випадкових значень до взаємодії зі змінною для курсора миші (```u_mouse```) та часом (```u_time```), щоб краще зрозуміти, як вона працює.
## Використання хаосу
Випадкові значення у двовимірному зображенні дуже схожі на телевізійний шум, чи не так? Це жорсткий та занадто сирий матеріал для створення зображень. Навчімось же ним користуватися.
Першим кроком застосуємо до нього сітку. За допомогою функції [```floor()```](../glossary/?lan=ua&search=floor) ми згенеруємо таблицю з цілочисельною кількістю клітинок. Подивіться на наступний код, особливо на рядки 22 і 23:
<div class="codeAndCanvas" data="2d-random-mosaic.frag"></div>
Після збільшення простору у 10 разів (рядок 21), ми відокремлюємо цілі числа координат від дробової частини (рядок 22). Ми знайомі з цією операцією, тому що вже використовували її для поділу простору на менші комірки, що йдуть від ```0.0``` до ```1.0```. Отримавши ціле значення координати, ми виокремлюємо загальне значення кількості пікселів, необхідних для побудови одної комірки. Далі ми можемо використовувати це ціле число, щоб отримати випадкове значення для цієї області. Оскільки наша випадкова функція є детермінованою, то випадкове значення, що повертається, буде постійним для всіх пікселів у цій клітинці.
Розкомментуйте рядок 29, щоб побачити, що ми зберігаємо дробову частину координати (рядок 23), тому ми все ще можемо використовувати її як нормовану систему координат для кожної окремої клітинки.
Поєднання цілої та дробової частин координати дозволить змішувати варіацію та порядок.
Подивіться на наступну GLSL-версію відомого генератора лабіринтів [```10 PRINT CHR$(205.5 + RND(1)); : GOTO 10```](https://10print.org/).
<div class="codeAndCanvas" data="2d-random-truchet.frag"></div>
Тут я використовую випадкові значення комірок для малювання лінії в одному чи іншому напрямку за допомогою функції ```truchetPattern()``` із попереднього розділу (рядки 41-47).
Розкоментувавши блок рядків з 50 по 53, ви можете отримати інший цікавий патерн, або анімувати його, розкоментувавши рядки 35 і 36.
## Майстер випадковості
[Ryoji Ikeda](http://www.ryojiikeda.com/) — японський електронний композитор і візуальний художник, який опанував використання випадковості. Важко залишитись байдужим та не стати загіпнозованим його роботами. При використанні випадковості у своїх аудіо- та візуальних середовищах він не перетинає межу дратівливого хаосу та відзеркалює складність нашої технологічної культури.
<iframe src="https://player.vimeo.com/video/76813693?title=0&byline=0&portrait=0" width="800" height="450" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
Перегляньте роботу [Ikeda](http://www.ryojiikeda.com/) і спробуйте виконати такі вправи:
* Створіть ряди рухомих у протилежних напрямках комірок із випадковими значеннями. Показуйте лише клітинки найбільш яскравими значеннями. Зробіть так, щоб швидкість рядків з часом змінювалася:
<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>
* Так само зробіть кілька рядів, але кожен з різною швидкістю та напрямком. Зробіть, щоб кількість видимих клітинок залежали від положення вказівника миші:
<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>
* Створіть інші цікаві ефекти:
<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>
Використовування випадковості для отримання естетичних результатів може бути проблематичним, особливо якщо ви хочете зробити симуляції, що виглядатимуть природно. Випадковість занадто хаотична й дуже мало речей виглядають **`рандомно`** у реальному житті. Якщо поглянути на патерн дощу або біржову діаграму, які є досить випадковими, то вони зовсім не схожі на ту модель випадковості, яку ми створили на початку цього розділу. В чому причина? Ну що ж, просто ці випадкові значення не мають ніякої кореляції між собою, а більшість природних шаблонів мають певну "пам'ять" про свій попередній стан.
У наступному розділі ми дізнаємося про шум, плавний і *природний* спосіб створення обчислювального хаосу.

View File

@ -90,3 +90,7 @@ Take a look at [Ikeda](http://www.ryojiikeda.com/)'s work and try the following
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.
#### For your toolbox
* [LYGIA's generative functions ](https://lygia.xyz/generative) are a set of reusable functions to generate patterns in GLSL. It's a great resource to learn how to use randomness and noise to create generative art. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.

220
11/README-ua.md Normal file
View File

@ -0,0 +1,220 @@
![NASA / WMAP science team](mcb.jpg)
## Шум
Час взяти перерву! Ми гралися з функціями випадкових значень, що нагадують телевізійний білий шум, наші голови все ще кружляють від думок про шейдери та втомились очі. Час піти на прогулянку!
Ми відчуваємо повітря на нашій шкірі, сонце на обличчі. Світ такий яскравий та насичений. Кольори, текстури, звуки. На прогулянці ми не можемо не помітити поверхню доріг, каменів, дерев та хмар.
![](texture-00.jpg)
![](texture-01.jpg)
![](texture-02.jpg)
![](texture-03.jpg)
![](texture-04.jpg)
![](texture-05.jpg)
![](texture-06.jpg)
Непередбачуваність цих текстур можна назвати "випадковою", але вони не схожі на той рандом, з якими ми грали раніше. "Реальний світ" — це дуже багате й складне місце! Як ми можемо апроксимувати цю варіативність за допомогою обчислень?
Це питання [Кен Перлін](https://mrl.nyu.edu/~perlin/) намагався вирішити на початку 1980-х років, коли йому доручили створити більш реалістичні текстури для фільму "Трон". У результаті він придумав елегантний алгоритм для генерації шуму за який потім отримав своєрідний *Оскар*. Нічого особливого)
![Disney - Tron (1982)](tron.jpg)
Нижче наведено не класичний алгоритм шуму Перліна, але це хороша відправна точка для розуміння того, як генерувати шум.
<div class="simpleFunction" data="
float i = floor(x); // integer
float f = fract(x); // fraction
y = rand(i); //rand() is described in the previous chapter
// y = mix(rand(i), rand(i + 1.0), f);
// y = mix(rand(i), rand(i + 1.0), smoothstep(0., 1., f));
"></div>
У цих рядках ми робимо щось подібне до того, що робили в попередньому розділі. Ми ділимо безперервне число з рухомою крапкою (`x`) на цілу (`i`) і дробову (`f`) складові. Для отримання цілої частини "**`i`**" ми використовуємо [```floor()```](../glossary/lan=ua&?search=floor), а для дробової частини "**`f`**" — [```fract()```](../glossary/lan=ua&?search=fract). Потім ми застосовуємо ```rand()``` до цілої частини "**`x`**", що дає унікальне випадкове значення для кожного цілого числа.
Також ви бачите два закоментовані рядки. Перший інтерполює кожне випадкове значення лінійним чином.
```glsl
y = mix(rand(i), rand(i + 1.0), f);
```
Розкоментуйте цей рядок, щоб побачити його роботу. Ми використовуємо дробове значення **`f`**, отримане після [```fract()```](../glossary/lan=ua&?search=fract), щоб за допомогою [```mix()```](../glossary/lan=ua&?search=mix) зміксувати два випадкових значення.
Ми вже знаємо, що можемо використати краще рішення, ніж лінійна інтерполяція, чи не так?
Розкоментуйте наступний рядок, щоб застосувати інтерполяцію [```smoothstep()```](../glossary/lan=ua&?search=smoothstep).
```glsl
y = mix(rand(i), rand(i + 1.0), smoothstep(0., 1. ,f));
```
Зверніть увагу на те, як перехід між вершинами стає плавним. У деяких реалізаціях шуму програмісти віддають перевагу створенню власних кубічних кривих (наприклад, наступна формула) замість використання [```smoothstep()```](../glossary/lan=ua&?search=smoothstep).
```glsl
float u = f * f * (3.0 - 2.0 * f ); // варіант кубічної кривої
y = mix(rand(i), rand(i + 1.0), u); // використання її в інтерполяції
```
Ця *плавна випадковість* змінює правила гри для графічних інженерів і художників. Вона надає можливість генерувати зображення та геометрію, що виглядатимуть органічно. Алгоритм шуму Перліна реалізовано на різних мовах та для різних вимірів, що дозволяє створювати захопливі витвори мистецтва для різноманітних творчих цілей.
![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg)
Тепер настала ваша черга:
* Створіть власну функцію типу "```float noise(float x)```".
* Використайте функцію шуму для анімації фігури, переміщуючи її, обертаючи або змінюючи масштаб.
* Використовуючи шум, створіть анімаційну композицію з кількох рухомих фігур.
* Сконструюйте за допомогою шуму "органічні" форми.
* Розвиньте отриману "істоту" у персонаж, задавши їй певний рух.
## Двомірний шум
![](02.png)
Тепер, коли ми знаємо, як створити одномірний шум (1D - one dimention), настав час перейти до 2D. У 2D, замість інтерполяції між двома точками лінії (```rand(x)``` та ```rand(x) + 1.0```), ми будемо інтерполювати між чотирма кутами квадратної площини (```rand(st)```, ```rand(st) + vec2(1., 0.)```, ```rand(st) + vec2(0., 1.)``` та ```rand(st) + vec2(1., 1.)```).
![](01.png)
Так само, якщо ми хочемо отримати тривимірний шум, то потрібно інтерполювати між вісьмома кутами куба. Ця техніка пов'язана з інтерполяцією випадкових значень, тому її називають **value noise (шумом значення)**.
![](04.jpg)
Як і з одномірним прикладом, ця інтерполяція не лінійна, а кубічна, яка плавно інтерполює будь-які точки всередині нашої квадратної сітки.
![](05.jpg)
Погляньте на наступну функцію шуму:
<div class="codeAndCanvas" data="2d-noise.frag"></div>
Ми починаємо з масштабування простору у 5 разів (рядок 45), щоб побачити інтерполяцію між квадратами сітки. Потім у функції шуму ми ділимо простір на комірки. Дробову частину координати ми зберігаємо для використання всередині клітини, а цілу частину — як координату самої клітини. Ми використовуємо цілочисельне значення позиції, щоб обчислити координати чотирьох кутів комірки та отримати випадкове значення для кожного з них (рядки 23-26). Нарешті, у рядку 35 ми інтерполюємо між 4 випадковими значеннями кутів, використовуючи дробові позиції, які ми зберегли раніше.
Тепер ваша черга. Спробуйте наступні вправи:
* Змініть множник у рядку 45. Спробуйте анімувати його.
* На якому рівні масштабування шум знову починає виглядати випадковим?
* На якому рівні масштабування шум непомітний?
* Спробуйте зробити функцію шуму залежною від координат курсору.
* Що, якщо розглядати градієнт шуму як поле відстаней? Зробіть з ним щось цікаве.
* Тепер, коли ви досягли певного контролю над порядком та хаосом, настав час використати ці знання. Створіть композицію з прямокутниками, кольорами й шумом, яка нагадувала б комплексність картини [Марка Ротко](http://en.wikipedia.org/wiki/Mark_Rothko).
![Mark Rothko - Three (1950)](rothko.jpg)
## Використання шуму в генеративному дизайні
Алгоритми шуму початково були розроблені, щоб надати цифровим текстурам певної природної якості. Одномірна та двомірна реалізації, які ми бачили до цього часу, були інтерполяцією між випадковими *значеннями*, тому вони називаються **шумом значень**, але існують й інші способи отримати шум...
[![Inigo Quilez - Value Noise](value-noise.png)](../edit.php#11/2d-vnoise.frag)
Як ви виявили в попередніх вправах, значення шуму має тенденцію виглядати "блоковим". Щоб зменшити цей блоковий ефект, у 1985 році [Кен Перлін](https://mrl.nyu.edu/~perlin/) розробив іншу реалізацію алгоритму під назвою **градієнтний шум**. Кен зрозумів як інтерполювати випадкові *градієнти* замість значень. Ці градієнти були результатом двомірної випадкової функції, яка повертає напрямки (у вигляді ```vec2```) замість окремих значень типу ```float```. Клацніть на наступне зображення, щоб побачити код та як він працює.
[![Inigo Quilez - Gradient Noise](gradient-noise.png)](../edit.php#11/2d-gnoise.frag)
Знайдіть хвилинку, щоб переглянути ці два приклади, за авторства [Inigo Quilez](http://www.iquilezles.org/), та зверніть увагу на відмінності між [шумом значень](https://www.shadertoy.com/view/lsf3WH) та [градієнтним шумом](https://www.shadertoy.com/view/XdXGW8).
Подібно до художника, який розуміється на роботі пігментних фарб, чим більше ми знаємо про імплементацію шуму, тим краще ми можемо їх використовувати. Наприклад, якщо за допомогою значень двомірного шуму обертати простір зображення з прямими лініями, то можна створити наступний ефект закручування, схожий на текстуру деревини. Клацніть на зображення, щоб побачити код:
[ ![Wood texture](wood-long.png) ](../edit.php#11/wood.frag)
```glsl
pos = rotate2d(noise(pos)) * pos; // обертання простору
pattern = lines(pos, .5); // малювання лінії
```
Ще один спосіб отримати цікаві візерунки за допомогою шуму це розглядати його як поле відстаней та застосувати деякі трюки, описані в [розділі про фігури](../07/?lan=ua).
[ ![Splatter texture](splatter-long.png) ](../edit.php#11/splatter.frag)
```glsl
color += smoothstep(.15, .2, noise(st * 10.)); // чорні бризки
color -= smoothstep(.35, .4, noise(st * 10.)); // дірки на бризках
```
Третій спосіб використання функції шуму це модуляція фігур. Для цього також потрібні певні трюки з [розділу про фігури](../07/?lan=ua).
<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>
Для вашої практики:
* Які ще генеративні патерни ви можете створити? Як щодо граніту? Мармуру? Магми? Води? Знайдіть три зображення текстур, які вас цікавлять та алгоритмічно реалізуйте їх, використовуючи шум.
* Використайте шум для модуляції форми.
* Як щодо використання шуму для руху? Поверніться до [розділу про матриці](../08/?lan=ua), використайте приклад з переміщенням хреста та застосуйте до його рухів трохи *випадковості* та *шуму*.
* Сгенеруйте зображення подібне до картини Джексона Поллака.
![Jackson Pollock - Number 14 gray (1948)](pollock.jpg)
## Покращений шум
Кен Перлін удосконалив свій оригінальний шум та зробив **симплексний шум**, що полягає в заміні кубічної кривої Ерміта ( _f(x) = 3x^2-2x^3_, яка є ідентичною до функції [```smoothstep()```](../glossary/?lan=ua&search=smoothstep)) на квінтичну інтерполяційну криву (криву п'ятого ступеня) ( _f(x) = 6x^5 - 15x^4 + 10x^3_ ). Це робить обидва кінці кривої більш "пласкими", тому кожна межа з'єднується з наступною плавніше. Іншими словами, ви отримуєте більш безперервний перехід між осередками. Ви можете побачити це, розкоментувавши другу формулу в наступному прикладі графіка (або перегляньте обидва рівняння [тут](https://www.desmos.com/calculator/2xvlk5xp8b)).
<div class="simpleFunction" data="
// Кубічна крива Ерміта. Те саме, що smoothStep()
y = x * x * (3.0 - 2.0 * x);
// Крива п'ятого ступеня
// y = x * x * x * (x * (x * 6. - 15.) + 10.);
"></div>
Зверніть увагу на те, як змінюються кінці кривої. Ви можете прочитати більше про це у [поясненнях самого Кена](http://mrl.nyu.edu/~perlin/paper445.pdf).
## Симплексний шум
Кен Перлін не задовольнився успіхом свого алгоритму. Він гадав, що зможе досягти для нього більшої продуктивності. На Siggraph 2001 він представив "симплексний шум", у якому досяг наступних покращень у порівнянні з попередньою версією:
* Менша обчислювальна складність та менша кількість множень.
* Шум масштабується до вищих розмірностей з меншими обчислювальними витратами.
* Шум без направлених артефактів.
* Шум має чітко визначений безперервний градієнт, який обчислюється досить дешево.
* Алгоритм достатньо легко реалізувати для апаратного забезпечення.
Я знаю про що ви думаєте... "Хто цей чоловік?" Так, його робота фантастична! Але серйозно, як він покращив алгоритм? Розберімось. Для двох вимірів він інтерполював 4 точки (кути квадрата), для трьох [(див. реалізацію)](../edit.php#11/3d-noise.frag) та чотирьох вимірів нам потрібно інтерполювати вже 8 і 16 точок відповідно. Правильно? Іншими словами, для N вимірів вам потрібно плавно інтерполювати 2 у степені N точок (2^N). Але Кен розумно помітив, що хоча очевидним вибором форми, що заповнює простір, є квадрат, найпростішою фігурою у двомірному просторі є рівносторонній трикутник. Тому він почав із заміни квадратної сітки (яку ми щойно навчилися використовувати) на симплексну сітку рівносторонніх трикутників.
![](simplex-grid-00.png)
Симплексна форма для N-розмірності це багатокутник з N + 1 кутами. Іншими словами, у двомірному просторі можна буде обчислювати на один кут менше, у тримірному на 4 кути менше, а у чотиримірному на 11 кутів менше! Це величезне покращення!
У двох вимірах інтерполяція відбувається подібно до звичайного шуму, шляхом інтерполяції значень кутів ділянки. Однак у випадку з симплексною сіткою, нам потрібно інтерполювати лише 3 кути.
![](simplex-grid-01.png)
Як створюється симплексна сітка? Іншим блискучим і елегантним ходом є те, що симплексну сітку можна отримати, розділивши комірки правильної сітки з 4 кутами на два рівнобедрених трикутники, а потім трохи скосити їх, доки кожен трикутник не стане рівностороннім.
![](simplex-grid-02.png)
Далі, як описав [Stefan Gustavson у статті "Simplex noise demystified"](https://web.archive.org/web/20230310204121/https://weber.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _"...розглянувши цілі частини трансформованої координати (x, y) для точки, яку ми хочемо визначити, можна швидко визначити, яка саме клітинка з двох симплексів її вміщує. Порівнявши абсолютні величини x і y, ми можемо визначити, чи точка знаходиться у верхньому чи нижньому симплексі та обійти через три кутові точки."_
У наступному коді ви можете розкоментувати рядок 44, щоб побачити перекіс сітки, а потім розкоментувати рядок 47, щоб побачити побудову симплексної сітки. Зверніть увагу, як у рядку 22 ми ділимо скошений квадрат на два рівносторонні трикутники, просто визначаючи, чи ```x > y``` ("нижній" трикутник) чи ```y > x``` ("верхній" трикутник).
<div class="codeAndCanvas" data="simplex-grid.frag"></div>
Результатом усіх цих удосконалень є алгоритмічний шедевр, відомий як **Симплексний шум**. Нижче наведено GLSL-реалізацію цього алгоритму, розроблену за участі Ian McEwan та Stefan Gustavson (представлена у роботі ["Efficient computational noise in GLSL"](https://web.archive.org/web/20190203222422/http://weber.itn.liu.se/~stegu/jgt2012/article.pdf)), яка занадто складна для простих освітніх цілей, але ви із задоволенням побачите, що вона менш загадкова, ніж можна було очікувати, а код короткий та швидкий.
[ ![Ian McEwan of Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.php#11/2d-snoise-clear.frag)
Що ж... досить технічних нюансів, настав ваш час для використання цього ресурсу у якості нового засобу виразності:
* Поміркуйте, як виглядає кожна реалізація шуму. Уявіть їх як необроблену сировину, як мармурову скелю для скульптора. Що ви можете сказати про відчуття до кожної з них? Примружте очі для активізації уяви, наче видивляєтеся якісь фігури в хмарах. Що ви бачите? Про що це нагадує? Що підказує вам ваша уява, що можна зробити з кожною реалізацією шуму? Слідуйте за своїм чуттями та спробуйте втілити ідеї в коді.
* Створіть шейдер, який створює ілюзію потоку. Подібно до лавової лампи, крапель чорнила, води тощо.
<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>
* Використовуючи симплексний шум, додайте трохи текстурності до виконаних раніше робіт.
<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>
У цьому розділі ми навчилися певного контролю над хаосом. Це була нелегка робота! Для того, щоб стати майстром з використання шуму, потрібні час та зусилля.
У наступних розділах ми оглянемо деякі добре відомі методи для вдосконалення ваших навичок та отримаємо більше користі від шуму для розробки якісної генеративної графіки за допомогою шейдерів. А поки що трохи відпочиньте та насолодіться часом на свіжому повітрі, споглядаючи природу та її складні візерунки. Ваша здатність до спостереження потребує такої ж, або навіть більшої, уваги, ніж ваші творчі навички. Вийдіть на вулицю та насолодіться рештою дня!
<p style="text-align:center; font-style: italic;">"Поговори з деревом, подружися з ним." Bob Ross
</p>

View File

@ -202,7 +202,7 @@ All these improvements result in an algorithmic masterpiece known as **Simplex N
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.
* Contemplate how each noise implementation looks. Imagine them as a raw material, like a marble rock for a sculptor. What can you say 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.
@ -218,3 +218,7 @@ In the following chapters we will see some well known techniques to perfect your
<p style="text-align:center; font-style: italic;">"Talk to the tree, make friends with it." Bob Ross
</p>
#### For your toolbox
* [LYGIA's generative functions ](https://lygia.xyz/generative) are a set of reusable functions to generate patterns in GLSL. It's a great resource to learn how to use randomness and noise to create generative art. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.

191
12/README-ua.md Normal file
View File

@ -0,0 +1,191 @@
![](dragonfly.jpg)
## Клітинний шум
У 1996 році, через шістнадцять років після оригінального шуму Перліна та за п’ять років до його симплексного шуму, Steven Worley написав статтю під назвою [“Базова функція клітинної текстури”](http://www.rhythmiccanvas.com/research/papers/worley.pdf). У ній він описує техніку процедурного текстурування, яка зараз широко використовується графічною спільнотою.
Щоб зрозуміти принципи, що лежать в її основі, нам потрібно почати думати в термінах **ітерацій**. Напевно, ви розумієте, що це означає використання циклів ```for```. У циклах ```for``` в GLSL є лише одна заковика: число, яке використовується у перевірці лічильника, має бути константою ([```const```](../glossary/?lan=ua&search=const)). Отже, ніяких динамічних циклів — кількість ітерацій має бути фіксованою.
Давайте розглянемо приклад.
### Точки у полі відстаней
Клітинний шум базується на полях відстаней, що розташовані до найближчої точки з певного набору. Скажімо, ми хочемо створити поле відстаней з 4 точок. Що нам потрібно зробити? **Для кожного пікселя ми хочемо обчислити відстань до найближчої точки**. Це означає, що нам потрібно виконати ітерацію по всім точкам, обчислити до них відстані від поточного пікселя та зберегти значення до найближчої.
```glsl
float min_dist = 100.; // змінна для збереження відстані до найближчої точки
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)
Не дуже елегантно, але робить свою справу. Тепер реалізуємо цей підхід за допомогою масиву та циклу ```for```:
```glsl
float m_dist = 100.; // мінімальна відстань
for (int i = 0; i < TOTAL_POINTS; i++) {
float dist = distance(st, points[i]);
m_dist = min(m_dist, dist);
}
```
Зверніть увагу, як ми використовуємо цикл ```for```, щоб перебирати масив точок і відстежувати мінімальну відстань за допомогою функції [```min()```](../glossary/?lan=ua&search=min). Ось коротка робоча реалізація цієї ідеї:
<div class="codeAndCanvas" data="cellnoise-00.frag"></div>
У наведеному вище коді одна з точок прив'язана до положення курсору. Пограйте з прикладом, щоб отримати краще інтуїтивне уявлення щодо поведінки програми. Потім спробуйте наступне:
- Як анімувати решту точок?
- Прочитавши [розділ про фігури](../07/?lan=ua), уявіть цікаві способи використання з цим полем відстаней!
- Як додати більше точок до цього поля відстаней? Що можна зробити для динамічного додавання або видалення точок?
### Замощення та ітерація
Ви, мабуть, помітили, що цикли ```for``` та *масиви* не дуже дружать з GLSL. Як ми вже говорили раніше, місцеві цикли не здатні на динамічну кількість ітерацій. Крім того, велика кількість ітерацій значно знижує продуктивність вашого шейдера. Це означає, що ми не можемо використовувати цей прямолінійний підхід для великої кількості точок. Нам потрібно знайти іншу стратегію, яка буде використовувати переваги архітектури GPU з її паралельними обчисленнями.
![](cell-01.png)
Один з підходів до розв'язання цієї проблеми — це розділення простору на плитки. Кожному пікселю не обов'язково перевіряти відстань до кожної окремої точки, чи не так? Враховуючи той факт, що кожен піксель працює у власному потоці, ми можемо розділити простір на комірки, кожна з яких матиме одну унікальну точку для спостереження. Крім того, щоб уникнути аберацій на межах між комірками, нам потрібно перевірити відстань до точок лише у сусідніх клітинах. Це і є головною чудовою ідеєю у [статті Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Зрештою, кожен піксель має перевірити лише дев’ять позицій: точку своєї клітини та точки у 8 клітинах навколо неї. Ми вже поділяли простір на комірки в розділах про: [патерни](../09/?lan=ua), [випадковість](../10/?lan=ua) та [шум](../11/?lan=ua), тож, сподіваюся, ви вже знайомі з цією технікою.
```glsl
// Масштаб
st *= 3.;
// Розділ простору на плитки
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Отже, який план? Ми будемо використовувати координати клітини-плитки, збережені в цілочисельній координаті ```i_st```, щоб побудувати випадкову позицію точки. Функція ```random2f```, яку ми будемо використовувати, отримує на вхід ```vec2``` та повертає нам також ```vec2``` з випадковою для даної клітини координатою. Таким чином, для кожної плитки ми матимемо одну особливу точку у випадковому місці цієї плитки.
```glsl
vec2 point = random2(i_st);
```
Кожен піксель усередині плитки, з координатою збереженою у змінній ```f_st```, перевірятиме свою відстань до випадкової точки, про яку ми говорили раніше.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Результат буде виглядати так:
<a href="../edit.php#12/cellnoise-01.frag"><img src="cellnoise.png" width="520px" height="200px"></img></a>
Нам все ще потрібно перевірити відстані до точок у навколишніх клітинах, а не лише на поточній. Для цього нам потрібно **ітерувати** сусідні клітини. Не всі клітини, а лише ті, що знаходяться безпосередньо навколо поточної. Тобто від ```-1``` клітини ліворуч, до ```+1``` клітини праворуч по осі ```x``` та від ```-1``` клітини знизу до ```+1``` клітини зверху по осі ```y```. Цю ділянку розміром 3x3 із 9 клітин можна обійти за допомогою подвійного циклу ```for```:
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Сусідня позиція клітини у сітці
vec2 neighbor = vec2(float(x), float(y));
...
}
}
```
![](cell-02.png)
Тепер у вкладеному циклі ```for``` ми можемо обчислити положення наших випадкових точок у кожній сусідній клітині, додаючи зміщення сусідньої клітини до координат поточної.
```glsl
...
// Положення випадкової точки у сусідній плитці
vec2 point = random2(i_st + neighbor);
...
```
Решта зводиться до обчислення відстаней до цієї точки та збереження найближчої у змінну ```m_dist```.
```glsl
...
vec2 diff = neighbor + point - f_st;
// Відстань до точки
float dist = length(diff);
// Збереження ближчої дистанції
m_dist = min(m_dist, dist);
...
```
Наведений вище код створено на основі [статті Inigo's Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm), де він писав:
*"... варто зазначити, що у наведеному вище коді є гарний трюк. Більшість реалізацій страждають від проблем із точністю, оскільки вони генерують свої випадкові точки в просторі "домену" (наприклад, у "глобальному" просторі чи просторі "об'єкта"), який може бути як завгодно далеко від початку координат. Проблему можна вирішити, перемістивши весь код до типів даних з вищою точністю, або проявивши трохи кмітливості. Моя реалізація генерує точки не в просторі "домену", а в просторі "комірки": як тільки із фрагментного пікселя отримано цілу та дробову частини, а значить визначено клітину, в якій ми працюємо, нас цікавитиме лише те, що відбувається навколо цієї клітини, а не весь простір. Тобто ми можемо відкинути цілочисельну частину значення наших координат та зберегти кілька біт точності. Насправді у звичайній реалізації діаграми Вороного, цілі частини координат точки просто скасовуються, коли випадкові точки клітини віднімаються від поточної шейдерної точки. У реалізації вище ми не робимо цього, оскільки переносимо всі обчислення в простір "комірки". Цей підхід дозволяє накласти діаграму Вороного хоч на цілу планету — достатньо просто подвоїти точність для вхідних даних, виконати для них обчислення з floor() і fract(), а решту обчислень проводити вже зі звичайною точністю для float, не витрачаючи обчислювальні ресурси на зміну всієї реалізації до подвійної точності. Звісно, той самий трюк можна застосувати й до підходів з шумом Перліна, але я ніколи не бачив подібну реалізацію чи опис подібного алгоритму)."*
Підсумовуючи: розбиваємо простір на клітини. Кожен піксель обчислює відстань до точки у власній клітині та навколишніх 8 клітинах, зберігаючи найближчу відстань. В результаті маємо поле відстаней, що виглядає як на прикладі нижче:
<div class="codeAndCanvas" data="cellnoise-02.frag"></div>
Дослідіть цей приклад глибше:
- Масштабуйте простір різними значеннями.
- Вигадайте інші способи анімації точок.
- Що потрібно зробити для обчислення додаткової точки у положенні курсору?
- Які інші способи побудови цього поля відстаней ви можете собі уявити, окрім ```m_dist = min(m_dist, dist);```?
- Які цікаві візерунки можна зробити за допомогою цього поля відстаней?
Цей алгоритм також можна інтерпретувати з точки зору точок, а не пікселів. У цьому випадку його можна описати таким чином: кожна точка росте, доки не натрапить на область росту іншої точки. Ця поведінка відображає деякі правила росту в природі. Живі організми формуються через цю напругу між внутрішньою силою зростання й розширення та обмеженнями зовнішніх сил. Класичний алгоритм, який імітує таку поведінку, названий на честь [Георгія Вороного](https://en.wikipedia.org/wiki/Georgy_Voronoy).
![](monokot_root.jpg)
### Алгоритм Вороного
Побудувати діаграми Вороного з клітинного шуму не так складно, як може здатися. Нам просто потрібно *зберегти* додаткову інформацію про найближчу точку до пікселя. Для цього ми використаємо змінну ```m_point``` типу ```vec2```. Зберігаючи вектор напрямку до найближчої точки замість відстані, ми "отримаємо" "унікальний" ідентифікатор цієї точки.
```glsl
...
if ( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Зауважте, що в наступному коді, для обчислення найближчої відстані ми використовуємо звичайний оператор ```if``` замість функції ```min```. Чому? Тому що, при знаходженні нової найближчої точки, ми хочемо зробити додаткову дію і зберегти її координати (рядки 32-37).
<div class="codeAndCanvas" data="vorono-00.frag"></div>
Зверніть увагу, як колір рухомої комірки, прив'язаної до положення курсору, змінює колір відповідно до його положення. Це тому, що колір визначається залежно від позиції найближчої точки.
Як і у попередніх прикладах, настав час збільшити масштаби, скориставшись підходом зі [статті за авторства Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Спробуйте реалізувати його самостійно. Ви можете скористатися допомогою наступного прикладу, клацнувши на нього. Зауважте, що оригінальний підхід від Steven Worley використовує змінну кількість точок для кожної клітини, більш ніж одну у більшості випадків. У його програмній реалізації на мові C це використовується для прискорення циклу завдяки раннім виходам із нього. Цикли GLSL не дозволяють змінювати кількість ітерацій, тому вам, ймовірно, доведеться використовувати лише одну точку на клітину.
<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>
Розібравшись із цим алгоритмом, подумайте про цікаві та креативні способи його використання.
![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)
### Поліпшення діаграми Вороного
У 2011 році [Stefan Gustavson оптимізував алгоритм Steven Worley для GPU](https://web.archive.org/web/20220530233245/https://weber.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf), обходячи лише матрицю 2x2 замість 3x3. Це значно зменшує обсяг роботи, але може створювати артефакти у вигляді розривів на краях між клітинами. Подивіться на наступні приклади:
<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>
Пізніше у 2012 році [Inigo Quilez написав статтю про створення точних меж для комірок Вороного](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>
На цьому експерименти Inigo з Вороним не закінчилися. У 2014 році він написав чудову статтю про функцію [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), яка дозволяє поступово змішувати звичайний шум з комірками Вороного. Ось вирізка з його слів:
*"Попри схожість, сітка в обох патернах використовується по різному. Шум інтерполює/усереднює випадкові значення (як у шумі значення) або градієнти (як у градієнтному шумі), тоді як алгоритм Вороного обчислює відстань до найближчої опорної точки. Плавна білінійна інтерполяція та обчислення мінімума — дві дуже різні операції чи... ні? Чи можна їх об’єднати у більш загальну метрику? Якщо так, то шум та патерни Вороного можна розглядати як окремі випадки більш загального генератора патернів на основі регулярної сітки?»*
<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>
Настав час придивитися до навколишніх речей, надихнутися природою, знайти власну ідею та спробувати сили у цій техніці!
![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>

View File

@ -188,3 +188,7 @@ Now it's time for you to look closely at things, be inspired by nature and find
![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>
#### For your toolbox
* [LYGIA's generative functions ](https://lygia.xyz/generative) are a set of reusable functions to generate patterns in GLSL. It's a great resource to learn how to use randomness and noise to create generative art. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.

111
13/README-ua.md Normal file
View File

@ -0,0 +1,111 @@
![Due East over Shadequarter Mountain - Matthew Rangel (2005) ](rangel.jpg)
## Фрактальний броунівський рух
Для різних людей слово "шум" означає різні речі. Музиканти будуть думати про безладні звуки, інженери зв'язку — про перешкоди, а астрофізики — про космічний мікрохвильовий фон. Ці концепції повертають нас до фізичної природи випадковості в навколишньому світі. Однак почнімо з чогось більш фундаментального та простішого: хвиль та їхніх характеристик. Хвиля — це коливання певної властивості з плином часу. Аудіохвилі — це коливання тиску повітря, електромагнітні хвилі — це коливання електричного та магнітного полів. Двома важливими характеристиками хвилі є її амплітуда та частота. Рівняння для простої лінійної (одномірної) хвилі виглядає так:
<div class="simpleFunction" data="
float amplitude = 1.;
float frequency = 1.;
y = amplitude * sin(x * frequency);
"></div>
* Спробуйте змінити значення частоти та амплітуди, щоб зрозуміти їх поведінку.
* Використовуючи формотворчі функції, змінюйте амплітуду залежно від часу.
* Використовуючи формотворчі функції, змінюйте частоту залежно від часу.
Виконуючи останні дві вправи, ви "модулювали" синусоїду, створивши AM (амплітудно-модульовані) та FM (frequency modulated - частотно-модульовані) хвилі. Мої вітання!
Ще однією цікавою властивістю хвиль є здатність до їх поєднання, що формально називається суперпозицією. Закоментуйте, розкоментуйте та позмінюйте наступні рядки. Зверніть увагу на зміни загального вигляду, коли ми додаємо разом хвилі з різними амплітудами та частотами.
<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>
* Поекспериментуйте, змінюючи частоту й амплітуду додаткових хвиль.
* Чи можна зробити дві хвилі, що нейтралізуватимуть одна одну? Як це буде виглядати?
* Чи можна скласти хвилі так, щоб вони посилювали одна одну?
У музиці кожна нота асоціюється з певною частотою. Частоти для цих нот відповідають певному порядку, який ми називаємо гамою. Подвоєння або зменшення частоти вдвоє відповідає зміні ноти на одну октаву.
Тепер, замість синусоїди, використаємо шум Перліна! Шум Перліна у своїй основній формі виглядає та відчувається, як синусоїда. Його амплітуда та частота дещо мінливі, але амплітуда залишається досить однорідною, а частота обмежена досить вузьким діапазоном навколо центральної частоти. В цілому шум не такий регулярний, як синусоїда, та з його допомогою легше створити видимість випадковості, об'єднавши кілька масштабованих версій. Вигляд суми синусоїд також можна зробити більш випадковим, але для цього потрібно багато різних хвиль, щоб приховати їх періодичну та регулярну природу.
Додаючи різні ітерації шуму (*октави*), у яких ми послідовно збільшуємо частоту на регулярну величину (*лакунарність*) та зменшуємо амплітуду (*посилення*) **шуму**, можна отримати деталізованіший шум та більше дрібних деталей. Ця техніка називається "фрактальний броунівський рух" (*fBM*) або просто "фрактальний шум". У найпростішому вигляді її можна створити за допомогою наступного коду:
<div class="simpleFunction" data="// Властивості
const int octaves = 1; // октави
float lacunarity = 2.0; // лакунарність
float gain = 0.5; // посилення
//
// Початкові значення
float amplitude = 0.5;
float frequency = 1.;
//
// Цикл по октавам
for (int i = 0; i < octaves; i++) {
&#9;y += amplitude * noise(frequency * x);
&#9;frequency *= lacunarity;
&#9;amplitude *= gain;
}"></div>
* Поступово збільшуйте кількість октав від 1 до 2, 4, 8 і 10. Спостерігайте за результатом.
* Коли матимете понад чотири октави, спробуйте змінити значення лакунарності.
* Також, коли октав понад 4, змініть значення для посилення (gain) та подивіться, що станеться.
Зверніть увагу, що з кожною додатковою октавою крива стає деталізованішою. Також зверніть увагу на прояви самоподібності, зі збільшенням кількості октав. Якщо збільшити масштаб кривої, менша її частина виглядатиме приблизно так само, як і вся крива, а кожен окремий відрізок виглядає більш-менш схоже на будь-який інший. Це важлива властивість математичних фракталів, яку ми моделюємо у нашому циклі. Ми не створюємо *справжній* фрактал, оскільки зупиняємо модуляцію після кількох ітерацій, але теоретично можна отримати справжній математичний фрактал, якщо дозволити циклу тривати вічно та додавати нескінченну кількість компонентів шуму. У комп'ютерній графіці ми завжди маємо обмеження щодо найдрібніших деталей, які можемо розпізнати. Наприклад, якщо об'єкти стають меншими за піксель, немає потреби робити нескінченні обрахунки, щоб створити видимість фракталу. Іноді може знадобитися багато доданків, але ніколи не знадобиться їх нескінченна кількість.
Наступний код показує реалізацію двомірного fBm, схожого на фрактальний візерунок:
<div class="codeAndCanvas" data="2d-fbm.frag"></div>
* Знизьте кількість октав, змінивши значення в рядку 37
* Змініть значення лакунарності у рядку 47
* Дослідіть результати, змінюючи значення підсилення в рядку 48
Ця техніка зазвичай використовується для побудови процедурних ландшафтів. Самоподібність fBm ідеально підходить для створення гір, тому що процеси ерозії, які створюють реальні гори, також надають їм вигляд самоподібності в широкому діапазоні масштабів. Якщо це вас зацікавило, вам варто прочитати [цю чудову статтю Inigo Quiles про вдосконалений шум](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
![Blackout - Dan Holdsworth (2010)](holdsworth.jpg)
Використовуючи більш-менш таку саму техніку, можна також отримати й інші ефекти, такі як **турбулентність**. По суті, це fBm, але побудований з абсолютних значень шуму, що створює різкі впадини.
```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>
Іншим представником цього сімейства алгоритмів є **хребти**, де гострі долини перевернуті догори дном, щоб натомість вийшли гострі гребні:
```glsl
n = abs(n); // створюємо складки
n = offset - n; // інвертуємо складки догори дном
n = n * n; // загострюємо складки ще більше
```
<a href="../edit.php#13/ridge.frag"><img src="ridge-long.png" width="520px" height="200px"></img></a>
Ще один варіант з корисними варіаціями можна здобути за допомогою перемноження компонентів шуму замість їх додавання. Також цікаво масштабувати наступні шумові функції на основі чогось, що залежить від попередніх сум складових. Коли ми робимо подібні речі, то віддаляємося від суворого визначення фракталу та переходимо у відносно невідому область "мультифракталів". Мультифрактали поки що не мають чіткого математичного визначення, але це не робить їх менш корисними для графіки. Насправді мультифрактальне моделювання дуже поширене в сучасному комерційному програмному забезпеченні для генерації рельєфу. Детальніше про це можна прочитати у 16 розділі 3-го видання книги "Текстурування та моделювання: процедурний підхід" ("Texturing and Modeling: a Procedural Approach"), автор Kenton Musgrave. На жаль, цю книгу перестали друкувати, але її все ще можна знайти в бібліотеках та вторинному ринку. Майте на увазі, що в інтернеті продається PDF-версія 1-го видання, яку не варто купувати, оскільки воно не містить жодного матеріалу про моделювання ландшафтів.
### Викривлення домену (просторової області)
[Inigo Quiles написав ще одну захопливу статтю](http://www.iquilezles.org/www/articles/warp/warp.htm) про використання fBm для деформації простору fBm. Вибух мозку, правда? Це як сон уві сні у фільмі "Початок" (Inception).
![f(p) = fbm(p + fbm(p + fbm(p))) - Inigo Quiles (2002)](quiles.jpg)
Менш екстремальний приклад цієї техніки показано у наступному коді, де викривлення використовується для отримання текстури, схожої на хмари. Зверніть увагу, що властивість самоподібності все ще присутня у результаті:
<div class="codeAndCanvas" data="clouds.frag"></div>
Викривлення координат текстури за допомогою шуму може бути дуже корисним, дуже веселим та диявольськи складним для освоєння. Це потужний інструмент, але щоб добре його використовувати, потрібен певний досвід. Корисним підходом для подібних маніпуляцій є зміщення координат за допомогою похідної (градієнта) шуму. На цій ідеї базується відома стаття під назвою ["Шум потоку"](http://evasion.imag.fr/Publications/2001/PN01/), автори Ken Perlin та Fabrice Neyret. Деякі сучасні реалізації шуму Перліна включають обчислення як функції, так і її аналітичного градієнта.

View File

@ -109,3 +109,7 @@ A less extreme example of this technique is the following code where the wrap is
<div class='codeAndCanvas' data='clouds.frag'></div>
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.
#### For your toolbox
* [LYGIA's generative functions ](https://lygia.xyz/generative) are a set of reusable functions to generate patterns in GLSL. It's a great resource to learn how to use randomness and noise to create generative art. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.

16
14/README-ua.md Normal file
View File

@ -0,0 +1,16 @@
## Фрактали
Coming soon ...
А поки що можете подивитися приклади з фракталами на платформі [shadertoy.com](https://www.shadertoy.com/results?query=fractals):
[Basic Fractal](https://www.shadertoy.com/view/Mss3Wf)
[Mandelbrot - distance](https://www.shadertoy.com/view/lsX3W4)
[Mandelbrot - smooth](https://www.shadertoy.com/view/4df3Rn)
[Mandelbrot: Power Transitioning](https://www.shadertoy.com/view/lls3D7)
[IFS - brute force](https://www.shadertoy.com/view/lss3zs)
[Julia - Distance 1](https://www.shadertoy.com/view/Mss3R8)
[Julia - Distance 3](https://www.shadertoy.com/view/4dXGDX)
[Julia - Traps 2](https://www.shadertoy.com/view/4dfGRn)
[Fractal Wheel 2.0](https://www.shadertoy.com/view/llfGD2)
[Koch Snowflake again](https://www.shadertoy.com/view/Mlf3RX)

View File

@ -1,3 +1,16 @@
## Fractals
Comming soon ...
Coming soon ...
In the meantime, you can check out some examples with fractals on the [shadertoy.com](https://www.shadertoy.com/results?query=fractals) platform:
[Basic Fractal](https://www.shadertoy.com/view/Mss3Wf)
[Mandelbrot - distance](https://www.shadertoy.com/view/lsX3W4)
[Mandelbrot - smooth](https://www.shadertoy.com/view/4df3Rn)
[Mandelbrot: Power Transitioning](https://www.shadertoy.com/view/lls3D7)
[IFS - brute force](https://www.shadertoy.com/view/lss3zs)
[Julia - Distance 1](https://www.shadertoy.com/view/Mss3R8)
[Julia - Distance 3](https://www.shadertoy.com/view/4dXGDX)
[Julia - Traps 2](https://www.shadertoy.com/view/4dfGRn)
[Fractal Wheel 2.0](https://www.shadertoy.com/view/llfGD2)
[Koch Snowflake again](https://www.shadertoy.com/view/Mlf3RX)

81
15/README-ua.md Normal file
View File

@ -0,0 +1,81 @@
# Обробка зображень
## Текстури
![](01.jpg)
Графічні карти (GPU) мають для зображень спеціальні типи пам’яті. Зазвичай CPU зберігають зображення у вигляді масиву байтів, а GPU зберігають зображення як ```sampler2D```, що більше схоже на таблицю (або матрицю) векторів типу float. Що ще цікавіше, значення цієї *таблиці* векторів безперервні. Це означає, що значення між пікселями інтерполюються на низькому рівні.
Щоб скористатися цим функціоналом, нам спочатку потрібно *завантажити* зображення з CPU на GPU, а потім передати ```id``` текстури до відповідної [```uniform```](../05/?lan=ua)-змінної. Початкове завантаження зображення відбувається поза шейдером.
Після того, як текстуру завантажено та прив'язано до змінної через ```uniform sampler2D```, ви можете отримати конкретне значення кольору у певних координатах типу [```vec2```](../glossary/?lan=ua&search=vec2) за допомогою функції [```texture2D()```](../glossary/?lan=ua&search=texture2D) яка поверне колір типу [```vec4```](../glossary/?lan=ua&search=vec4).
```glsl
vec4 texture2D(sampler2D texture, vec2 coordinates)
```
Перегляньте наступний код, у якому ми завантажуємо зображення [Хвилі Хокусая (1830)](https://en.wikipedia.org/wiki/The_Great_Wave_off_Kanagawa) як ```uniform sampler2D u_tex0```, отримуємо та відображаємо кожен її піксель всередині полотна:
<div class="codeAndCanvas" data="texture.frag" data-textures="hokusai.jpg"></div>
Якщо ви звернете увагу, то помітите, що координати для текстури нормалізовані! Який сюрприз, правда? Координати текстур консистентні з нормалізованими координатами простору, що також знаходяться в діапазоні від 0.0 до 1.0.
Тепер, коли ви побачили, як правильно завантажувати текстуру, настав час поекспериментувати та дізнатися, що можна з нею зробити:
* Змініть масштаб текстури вдвічі.
* Поверніть текстуру на 90 градусів.
* Прив'яжіть координати до позиції курсору, щоб переміщати зображення.
Чому ви повинні бути в захваті від текстур? По-перше, забудьте про сумні 255 значень для кожного каналу. Як тільки ваше зображення перетворено на ```uniform sampler2D```, ви працюватимете у діапазоні значень від 0.0 до 1.0. Ось чому шейдери можуть створювати дійсно красиві ефекти постобробки.
По-друге, за допомогою координат [```vec2```](../glossary/?lan=ua&search=vec2) ви можете отримати значення кольору текстури навіть між пікселями. Як ми вже говорили раніше, значення текстури є континуумом. Це означає, що ви можете отримувати значення вашого зображення по всій його поверхні. Ці значення плавно змінюватимуться від пікселя до пікселя без стрибків!
Нарешті, ви можете налаштувати шейдер для повторення вашого зображення вздовж полотна. Наприклад, при використанні значень, що менше або більше від нормалізованих 0.0 та 1.0 ви можете "загорнути" їх у цей самий діапазон та знову отримати кольори в межах зображення.
Усі ці можливості роблять ваші зображення схожими на нескінченну тканину спандекс. Ви можете розтягувати та звужувати свою текстуру, не зважаючи на сітку байтів, з яких вона складалася початково. Щоб відчути це, подивіться на наступний код, де ми деформуємо текстуру за допомогою [функції шуму, з попередніх розділів](../11/?lan=ua).
<div class="codeAndCanvas" data="texture-noise.frag" data-textures="hokusai.jpg"></div>
## Роздільна здатність текстури
Наведені вище приклади добре працюють з квадратними зображеннями, де обидві сторони рівні та збігаються з нашим квадратним полотном. Але для неквадратних зображень все може бути трохи складніше. Століття художнього мистецтва та фотографії знайшли для зображень більш приємні для ока неквадратні пропорції.
![Joseph Nicéphore Niépce (1826)](nicephore.jpg)
Як ми можемо розв'язати цю проблему? Щоб дізнатися як правильно розтягнути текстуру, нам потрібно знати оригінальні пропорції зображення, що дозволить отримати його [*співвідношення сторін*](http://en.wikipedia.org/wiki/Aspect_ratio). Для цього ширина та висота текстури також передаються шейдеру через ```uniform```, який у нашому прикладі буде мати тип ```vec2```. Ми надали цій змінній таку саму назву як і для текстури, але з доповненням ```Resolution```. Отримавши цю інформацію, ми можемо отримати у шейдері співвідношення сторін, поділивши ```ширину``` на ```висоту```. Нарешті, помноживши це співвідношення на координату ```y```, ми змінимо цю вісь таким чином, щоб вона відповідала бажаним пропорціям.
Розкоментуйте рядок 21 наступного коду, щоб побачити це в дії:
<div class="codeAndCanvas" data="texture-resolution.frag" data-textures="nicephore.jpg"></div>
* Поміркуйте, що потрібно зробити, щоб відцентрувати це зображення по центру полотна?
## Цифрова оббивка
![](03.jpg)
Ви можете подумати, що все це трохи ускладнено... й, напевно, матимете рацію. Але такий спосіб роботи з зображеннями залишає достатньо місця для різних хитрощів та творчих прийомів. Спробуйте уявити, що ви робите оббивку, а натягуючи та огортаючи тканину поверх конструкції, ви можете створювати нові патерни та цікавіші результати.
![Eadweard's Muybridge study of motion](muybridge.jpg)
Подібний рівень ремісництва нагадує деякі з перших оптичних експериментів. Наприклад, в іграх дуже поширена *спрайтова анімація*, що навіває спогади про [фенакістископ](https://en.wikipedia.org/wiki/Phenakistiscope), [зоотроп](https://en.wikipedia.org/wiki/Zoetrope) та [праксиноскоп](https://en.wikipedia.org/wiki/Praxinoscope).
Виглядає просто, але можливості для зміни текстурних координат просто величезні.
<div class="codeAndCanvas" data="texture-sprite.frag" data-textures="muybridge.jpg"></div>
Тепер ваша черга:
* Спробуйте зробити калейдоскоп:
<canvas id="custom" class="canvas" data-fragment-url="texture-kaleidoscope.frag" data-textures="hokusai.jpg" width="300px" height="300px"></canvas>
* Задовго до [Oculus](https://en.wikipedia.org/wiki/Oculus_Rift) та [google cardboard](https://en.wikipedia.org/wiki/Google_Cardboard) стереоскопічна фотографія була неабиякою справою. Чи можете ви закодувати простий шейдер, щоб повторно використати ці чудові зображення?
![](texture-stereo-00.jpg)
![](texture-stereo-01.jpg)
![](texture-stereo-03.jpg)
* Які ще оптичні іграшки можна відтворити за допомогою текстур?
У наступних розділах ми побачимо як за допомогою шейдерів можна обробляти зображення, виконуючи певні операції. Зрештою шейдери не в останню чергу розроблені саме для цього.

View File

@ -8,7 +8,7 @@ Graphic cards (GPUs) have special memory types for images. Usually on CPUs image
In order to use this feature we first need to *upload* the image from the CPU to the GPU, to then pass the ```id``` of the texture to the right [```uniform```](../05). All that happens outside the shader.
Once the texture is loaded and linked to a valid ```uniform sampler2D``` you can ask for specific color value at specific coordinates (formated on a [```vec2```](index.html#vec2.md) variable) using the [```texture2D()```](index.html#texture2D.md) function which will return a color formatted on a [```vec4```](index.html#vec4.md) variable.
Once the texture is loaded and linked to a valid ```uniform sampler2D``` you can ask for specific color value at specific coordinates (formatted on a [```vec2```](index.html#vec2.md) variable) using the [```texture2D()```](index.html#texture2D.md) function which will return a color formatted on a [```vec4```](index.html#vec4.md) variable.
```glsl
vec4 texture2D(sampler2D texture, vec2 coordinates)
@ -58,7 +58,7 @@ You may be thinking that this is unnecessarily complicated... and you are probab
![Eadweard's Muybridge study of motion](muybridge.jpg)
This level of craftsmanship links back to some of the first optical experiments ever made. For example on games *sprite animations* are very common, and is inevitably to see on it reminiscence to phenakistoscope, zoetrope and praxinoscope.
This level of craftsmanship links back to some of the first optical experiments ever made. For example on games *sprite animations* are very common, and is inevitably to see on it reminiscence to [phenakistoscope](https://en.wikipedia.org/wiki/Phenakistiscope), [zoetrope](https://en.wikipedia.org/wiki/Zoetrope) and [praxinoscope](https://en.wikipedia.org/wiki/Praxinoscope).
This could seem simple but the possibilities of modifying textures coordinates are enormous. For example:
@ -68,10 +68,13 @@ Now is your turn:
* Can you make a kaleidoscope using what we have learned?
* Way before Oculus or google cardboard, stereoscopic photography was a big thing. Could you code a simple shader to re-use these beautiful images?
<canvas id="custom" class="canvas" data-fragment-url="texture-kaleidoscope.frag" data-textures="hokusai.jpg" width="300px" height="300px"></canvas>
<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>
* Way before [Oculus](https://en.wikipedia.org/wiki/Oculus_Rift) or [google cardboard](https://en.wikipedia.org/wiki/Google_Cardboard), stereoscopic photography was a big thing. Could you code a simple shader to re-use these beautiful images?
![](texture-stereo-00.jpg)
![](texture-stereo-01.jpg)
![](texture-stereo-03.jpg)
* What other optical toys can you re-create using textures?

View File

@ -1,6 +1,7 @@
<?php
$path = "..";
$subtitle = ": Textures";
$README = "README";
$language = "";

23
16/README-ua.md Normal file
View File

@ -0,0 +1,23 @@
## Операції із зображеннями
Нижче ви побачите кілька прикладів із зображеннями, де ви можете пограти зі значеннями та розкоментувати певні рядки, щоб побачити відповідний результат.
### Інвертування
Розкоментуйте рядок 18:
<div class="codeAndCanvas" data="inv.frag" data-textures="00.jpg,01.jpg"></div>
### Додавання, віднімання, множення та інші варіанти
В даному шейдері завантажено два зображення, які розташовано один над одним. По черзі розкоментовуйте рядки 22-27 та спостерігайте за результатами поєднання цих зображень залежно від операції. Перш ніж розкоментувати рядок, поміркуйте над тим який має бути результат і чому:
![](02.jpg)
<div class="codeAndCanvas" data="operations.frag" data-textures="00.jpg,01.jpg"></div>
### Режими змішування як у Photoshop
![](03.jpg)
<div class="codeAndCanvas" data="blend.frag" data-textures="04.jpg,05.jpg"></div>

View File

@ -1,18 +1,19 @@
## Image operations
Below you will see some examples with images where you can play around and uncomment some lines to see the corresponding results.
### Invert
<div class="codeAndCanvas" data="inv.frag" data-imgs="00.jpg,01.jpg"></div>
<div class="codeAndCanvas" data="inv.frag" data-textures="00.jpg,01.jpg"></div>
### Add, Substract, Multiply and others
### Add, Subtract, Multiply and others
![](02.jpg)
<div class="codeAndCanvas" data="operations.frag" data-imgs="00.jpg,01.jpg"></div>
<div class="codeAndCanvas" data="operations.frag" data-textures="00.jpg,01.jpg"></div>
### PS Blending modes
![](03.jpg)
<div class="codeAndCanvas" data="blend.frag" data-imgs="04.jpg,05.jpg"></div>
<div class="codeAndCanvas" data="blend.frag" data-textures="04.jpg,05.jpg"></div>

View File

@ -1,6 +1,7 @@
<?php
$path = "..";
$subtitle = ": Image processing";
$README = "README";
$language = "";
@ -25,8 +26,10 @@
<ul class="navigationBar" >
<li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li>
<li class="navigationBar" onclick="homePage()"> Home </li>
<li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li>
</ul>';
include($path."/footer.php");
?>
<!-- <li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li> -->

View File

@ -1,4 +1,4 @@
Copyright (c) 2015 Patricio Gonzalez Vivo - http://patriciogonzalezvivo.com/
Copyright (c) 2025 Patricio Gonzalez Vivo - http://patriciogonzalezvivo.com/
All rights reserved.
I am the sole copyright owner of this Work.

View File

@ -60,10 +60,12 @@
* 环境贴图 (spherical and cube)
* 折射和反射
* [附录:](appendix/) 其他阅读本书的方式
* [如何离线阅读此书?](appendix/?lan=ch)
* [如何在树莓派上运行示例程序?](appendix/?lan=ch)
* [如何打印这本书](appendix/?lan=ch)
* [附录:](appendix/?lan=ch) 其他阅读本书的方式
* [如何离线阅读此书?](appendix/00/?lan=ch)
* [如何在树莓派上运行示例程序?](appendix/01/?lan=ch)
* [如何打印这本书](appendix/02/?lan=ch)
* [我怎样共创这本书](appendix/03/?lan=ch)
* [给那些从JS语言过来的人的介绍](appendix/04/?lan=ch) by [Nicolas Barradeau](http://www.barradeau.com/)
* [example gallery](examples/?lan=ch)
@ -100,6 +102,8 @@ Patricio 研习和实践精神疗法psychotherapy和表达性艺术治疗
感谢 Nahuel Coppero (Necsoft) 的 [西班牙语(español)](?lan=es) 翻译。
感谢 [Manoylov Andriy](https://twitter.com/ManoylovAC) 的 [乌克兰语(українська)](?lan=ua) 翻译。
感谢 [Karim Naaji](http://karim.naaji.fr/) 在代码和想法上的支持和贡献。
感谢所有相信这个项目的人[contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) 以及大家的捐赠.

View File

@ -68,12 +68,12 @@ Dies ist eine behutsame Schritt-für-Schritt-Einführung in die komplexe und vie
## Über die Autoren
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentinien) ist ein Künstler und Entwickler, der in New York lebt. Er erforscht die Räume zwischen Organischem und Synthetischem, Analogem und Digitalem, Individuen und Kollektiven. In seinen Arbeiten nutzt er Programmcode als Ausdrucksform, um das Zusammenwirken von Menschen zu verbessern.
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentinien) ist ein Künstler und Entwickler, der in New York lebt. Er erforscht die Räume zwischen organisch und synthetisch, analog und digital, einzeln und zusammen. In seinen Arbeiten nutzt er Programmcode als Ausdrucksform, um das Zusammenwirken von Menschen zu verbessern.
Patricio hat Psychologie studiert, außerdem kunstorientiertes Handeln, die sogenannte „Expressive Arts Therapy“. Er hat einen MFA-Abschluss in „Design & Technology“ von der „Parsons The New School“, wo er auch unterrichtet. Zur Zeit arbeitet Patricio als Grafikingenieur bei der Firma Mapzen und entwickelt dort Open Source Werkzeuge für die Computer-Kartographie.
Patricio hat Psychologie studiert, außerdem kunstorientiertes Handeln (die sogenannte Expressive Arts Therapy). Er hat einen MFA-Abschluss in Design und Technologie von der Parsons New School For Design, wo er auch unterrichtet. Zur Zeit arbeitet Patricio als Grafikingenieur bei der Firma Mapzen und entwickelt dort Open-Source-Werkzeuge für die Computer-Kartographie.
<div class="header"> <a href="http://patriciogonzalezvivo.com/" target="_blank">Webseite</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/) ist eine unabhängige Datenwissenschaftlerin und Datenkommunikatorin bei der Firma Datatelling, wo sie Menschen, Zahlen und Sprache zusammenführt. Sie unterrichtet im Rahmen des „SVA Design for Social Innovation“-Programms, hat die Schule für „Poetic Computation“ mitbegründet, Mathematik für Künstler an der New Yorker ITP-Universität unterrichtet, Forschungen am „Spatial Information Design Lab“ der Columbia Universität durchgeführt und Beiträge für das „White House Office of Science and Technology“ geliefert, das den US-Präsidenten in Fragen des technischen Fortschritts berät. Als Sprecherin ist Jen auf Konferenzen wie der SXSW und der Eyeo aufgetreten. Von ihren Arbeiten hat unter anderem die New York Times, sowie das Magazin FastCompany berichtet. Ihre Forschungsarbeiten, Publikationen und Vorträge kreisen um die Versprechungen und Folgen von Daten und Technologien für die gesellschaftliche Entwicklung. Sie hat einen Bachelor of Science“-Abschluss in angewandter Mathematik und einen Master-Abschluss in Informatik. Obwohl man angesichts dieser Biographie vielleicht etwas anderes vermuten könnte, schlägt sich Jen immer auf die Seite der Liebe.
[Jen Lowe](http://jenlowe.net/) ist eine unabhängige Datenwissenschaftlerin und Datenkommunikatorin bei der Firma Datatelling, wo sie Menschen, Zahlen und Sprache zusammenführt. Sie unterrichtet an der SVA das Fach Design for Social Innovation, hat die Schule für „Poetic Computation“ mitbegründet, Mathematik für Künstler an der New Yorker ITP-Universität unterrichtet, Forschungen am „Spatial Information Design Lab“ der Columbia Universität durchgeführt und Beiträge für das „White House Office of Science and Technology“ geliefert, das den US-Präsidenten in Fragen des technischen Fortschritts berät. Als Sprecherin ist Jen auf Konferenzen wie der SXSW und der Eyeo aufgetreten. Von ihren Arbeiten hat unter anderem die New York Times, sowie das Magazin FastCompany berichtet. Ihre Forschungsarbeiten, Publikationen und Vorträge kreisen um die Versprechungen und Folgen von Daten und Technologien für die gesellschaftliche Entwicklung. Sie hat einen Bachelor in angewandter Mathematik und einen Master in Informatik. Obwohl man angesichts dieser Biographie vielleicht etwas anderes vermuten könnte, schlägt sich Jen immer auf die Seite der Liebe.
<div class="header"> <a href="http://jenlowe.net/" target="_blank">Webseite</a> - <a href="https://twitter.com/datatelling" target="_blank">Twitter</a> - <a href="https://github.com/datatelling" target="_blank">GitHub</a></div>
## Danksagungen
@ -97,6 +97,8 @@ Dank an [Andrea Rovescalli](https://www.earove.info) für die [italienische Üb
Dank an [Michael Tischer](http://www.mitinet.de) für die [deutsche Übersetzung des Textes](?lan=de)
Dank an [Manoylov Andriy](https://twitter.com/ManoylovAC) für die [ukrainische Übersetzung des Textes (українська)](?lan=ua)
Und natürlich Danke an alle, die an dieses Projekt geglaubt, dafür gespendet oder durch Hinweise und Korrekturen [daran mitgewirkt haben](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors).
## Hol Dir die neuen Kapitel

View File

@ -83,6 +83,8 @@ Gracias a [Tong Li](https://www.facebook.com/tong.lee.9484) y a [Yi Zhang](https
Gracias a [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) por la [Traducción al coreano (한국어).](?lan=kr)
Gracias a [Manoylov Andriy](https://twitter.com/ManoylovAC) por la [traducción al ucraniano (українська)](?lan=ua)
Gracias a [Karim Naaji](http://karim.naaji.fr/) por su contribución, su apoyo, su código y sus buenas ideas.
Gracias a todos los que creyeron en este proyecto y [contribuyeron con sus aportes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) o donaciones.

View File

@ -102,6 +102,8 @@
ممنون از [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) برای Russian [translation (russian)](?lan=ru)
ممنون از [Manoylov Andriy](https://twitter.com/ManoylovAC) برای Ukrainian [translation (українська)](?lan=ua)
ممنون از [Andy Stanton](https://andy.stanton.is/) برای اصلاح و بهبود [the pdf/epub export pipeline](https://thebookofshaders.com/appendix/02/)
ممنون از همه کسانی که به این پروژه ایمان داشتند و[در اصلاحات مشارکت کردند](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) و یا اهدا کردند.

View File

@ -85,6 +85,8 @@ Merci à [Tong Li](https://www.facebook.com/tong.lee.9484) et [Yi Zhang](https:/
Merci à [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) pour la [traduction (한국어)](?lan=kr) coréenne
Merci à [Manoylov Andriy](https://twitter.com/ManoylovAC) pour la [traduction (українська)](?lan=ua) l'ukrainien
Merci à [Karim Naaji](http://karim.naaji.fr/) qui a contribué par son support, ses bonnes idées et son code.
Merci à tous ceux qui ont cru en ce projet et à ceux qui ont [contributé aux corrections](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ou qui ont fait des dons.

View File

@ -106,6 +106,8 @@ Terima kasih kepada [Andy Stanton](https://andy.stanton.is/) untuk perbaikan dan
Terima kasih kepada [Naufal Adriansyah](https://www.facebook.com/naufal.adrna08) untuk terjemahan [Bahasa Indonesia](?lan=id)
Terima kasih kepada [Manoylov Andriy](https://twitter.com/ManoylovAC) untuk terjemahan [Bahasa Ukraina (українська)](?lan=ua)
Terima kasih kepada semua orang yang telah percaya pada proyek ini dan [telah berkontribusi dalam perbaikan](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) atau donasi.
## Dapatkan bagian baru

View File

@ -96,6 +96,8 @@ Grazie a [Nicolas Barradeau](https://twitter.com/nicoptere) e a [Karim Naaji](ht
Grazie a [Andrea Rovescalli](https://www.earove.info) per la [traduzione](?lan=it) italiana
Grazie a [Manoylov Andriy](https://twitter.com/ManoylovAC) per la [traduzione ucraina (українська)](?lan=ua)
Grazie a tutti coloro i quali hanno creduto in questo progetto e [contribuito con correzioni](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) o donazioni.
## Come ottenere i nuovi capitoli?

View File

@ -89,6 +89,8 @@ Patricioは心理療法psychotherapyと表現療法expressive art thera
インスピレーションとアドバイスを与えてくれた[Scott Murray](http://alignedleft.com/)、日本語訳を担当してくれた[Kynd](https://twitter.com/kyndinfo)、素晴らしいアイデアとコードで貢献してくれた[Karim Naaji](http://karim.naaji.fr/) にも感謝します。
[(українська) ウクライナ語](?lan=ua)の翻訳をしてくれた [Manoylov Andriy](https://twitter.com/ManoylovAC) にも感謝します。
そして最後に、このプロジェクトを応援し[改善の手助けをしてくれた方々](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors)、寄付をくださったすべての皆様に感謝を述べたいと思います。
## アップデートのお知らせ

View File

@ -108,6 +108,8 @@ Patricio는 심리치료 및 표현예술을 공부했다. 그는 파슨스대
러시아어 번역을 맡고 있는 [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) 에게 감사를 표합니다. [Russian translation](?lan=ru)
러시아어 번역을 맡고 있는 [Manoylov Andriy](https://twitter.com/ManoylovAC) 에게 감사를 표합니다. [Ukrainian translation (українська)](?lan=ua)
[pdf/epub 배포](https://thebookofshaders.com/appendix/02/) 수정 및 개선을 맡고 있는 [Andy Stanton](https://andy.stanton.is/) 에게 감사를 표합니다.
이 프로젝트를 격려해주시고 기부해주신 모든 분들께 감사를 드립니다. [Contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors)

View File

@ -38,7 +38,7 @@
* Image operations
* Kernel convolutions
* Filters
* Others effects
* Other effects
* Simulation
* Pingpong
@ -80,7 +80,7 @@ Patricio studiował i praktykował psychoterapię oraz arteterapię. Otrzymał t
## Podziękowania
Podziękowania dla [Scott Murray](http://alignedleft.com/) za porady i inspriację.
Podziękowania dla [Scott Murray](http://alignedleft.com/) za porady i inspirację.
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.
@ -106,6 +106,8 @@ Podziękowania dla [Vu Phuong Hoang](https://www.facebook.com/vuphuonghoang88) z
Podziękowania dla [Wojciecha Pachowiaka](https://github.com/WojtekPachowiak) za polskie [tłumaczenie (polski)](?lan=pl)
Podziękowania dla [Manoylov Andriy](https://twitter.com/ManoylovAC) za ukraińskie [tłumaczenie (українська)](?lan=ua)
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.

View File

@ -100,6 +100,8 @@ Obrigado [Michael Tischer](http://www.mitinet.de) pela [tradução em Alemão (d
Obrigado [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) pela [tradução em Russo (russian)](?lan=ru)
Obrigado [Manoylov Andriy](https://twitter.com/ManoylovAC) pela [tradução em Ucraniano (українська)](?lan=ua)
Obrigado [Andy Stanton](https://andy.stanton.is/) por corrigir e melhorar [a pipeline para exportar pdf/epub](https://thebookofshaders.com/appendix/02/)
Obrigado a todos que acreditaram neste projeto e [contribuíram com correções](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ou doações.

View File

@ -100,6 +100,8 @@
Спасибо [Сергею Карчевскому](https://www.facebook.com/sergey.karchevsky.3) за [русский перевод](?lan=ru)
Спасибо [Андрею Манойлову](https://twitter.com/ManoylovAC) за [украинский перевод](?lan=ua)
Спасибо всем кто поверил в этот проект и поддержал его [исправлениями](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) или пожертвованиями.
## Новые параграфы

130
README-ua.md Normal file
View File

@ -0,0 +1,130 @@
<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
*автори: [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) і [Jen Lowe](http://jenlowe.net/)*
Легкий покроковий провідник через абстрактний і складний всесвіт фрагментних шейдерів.
<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>
## Зміст
* [Про книгу](00/?lan=ua)
* Вступ
* [Що таке шейдер?](01/?lan=ua)
* [“Hello world!”](02/?lan=ua)
* [Uniforms](03/?lan=ua)
* [Запуск шейдера](04/?lan=ua)
* Алгоритмічне малювання
* [Формотворчі функції](05/?lan=ua)
* [Кольори](06/?lan=ua)
* [Фігури](07/?lan=ua)
* [Матриці](08/?lan=ua)
* [Патерни](09/?lan=ua)
* Генеративний дизайн
* [Випадковість](10/?lan=ua)
* [Шум](11/?lan=ua)
* [Клітинний шум](12/?lan=ua)
* [Фрактальний броунівський рух](13/?lan=ua)
* Фрактали
* Обробка зображень
* Текстури
* Операції із зображеннями
* Згортка ядра
* Фільтри
* Інші ефекти
* Симуляції
* Пінг-понг
* Conway
* Брижі води
* Акварель
* Реакційно-дифузійна система
* 3D-графіка
* Освітлення
* Карти нормалей
* Карти висот
* Ray marching
* Карти оточення (сферичні та кубічні)
* Відображення та заломлення
* [Додаток:](appendix/?lan=ua) Інші способи використання цієї книги
* [Як можна переглядати книгу офлайн?](appendix/00/?lan=ua)
* [Як запустити приклади на Raspberry Pi?](appendix/01/?lan=ua)
* [Як надрукувати книгу?](appendix/02/?lan=ua)
* [Як прийняти участь у розвитку книги?](appendix/03/?lan=ua)
* [Вступ для тих, хто прийшов із JS](appendix/04/?lan=ua) від [Nicolas Barradeau](http://www.barradeau.com/)
* [Галерея прикладів](examples/?lan=ua)
* [Глосарій](glossary/?lan=ua)
## Про авторів
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Буенос-Айрес, Аргентина) — митець і розробник із Нью-Йорка. Досліджує інтерстиціальний простір між органічним і синтетичним, аналоговим і цифровим, індивідуальним і колективним. У своїй роботі він використовує код як виразну мову з метою створення кращого разом.
Патрісіо вивчав і практикував психотерапію та арттерапію. Він здобув ступінь магістра мистецтва в галузі дизайну та технологій у Parsons The New School, де зараз і викладає. Наразі він працює як графічний інженер в компанії Mapzen, розробляючи open-source інструменти для картографування.
<div class="header"> <a href="http://patriciogonzalezvivo.com/" target="_blank">WebSite</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/) - незалежна наукова фахівчиня у галузі обробки та передачі даних в компанії Datatelling, де вона поєднує людей, числа та слова. Вона викладає у SVA Design для програми соціальних інновацій, співзасновниця School for Poetic Computation, викладала математику для художників в NYU ITP, проводила дослідження в Лабораторії просторового інформаційного дизайну у Колумбійському університеті та допомагала з ідеями в Білому домі стосовно управління науки та технологічної політики. Вона виступала на конференціях SXSW та Eyeo. Її роботи висвітлювалися в The New York Times та Fast Company. У своїх дослідженнях, публікаціях та виступах вона досліджує перспективи та наслідки використання даних і технологій у суспільстві. Має ступінь бакалавра з прикладної математики та магістра інформаційних наук. Часто займаючи опозиційну позицію, вона завжди на боці любові.
<div class="header"> <a href="http://jenlowe.net/" target="_blank">WebSite</a> - <a href="https://twitter.com/datatelling" target="_blank">Twitter</a> - <a href="https://github.com/datatelling" target="_blank">GitHub</a></div>
## Подяки
Дякую [Scott Murray](http://alignedleft.com/) за натхнення та поради.
Дякую [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) за підтримку, гарні ідеї та код.
Дякую [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) і [Sawako](https://twitter.com/sawakohome) за [японський переклад (日本語訳)](?lan=jp)
Дякую [Tong Li](https://www.facebook.com/tong.lee.9484) і [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) за [китайський переклад (中文版)](?lan=ch)
Дякую [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) і [June Kim](https://github.com/rlawns324) за [корейський переклад (한국어)](?lan=kr)
Дякую Nahuel Coppero (Necsoft) за [іспанський переклад (español)](?lan=es)
Дякую [Raphaela Protásio](https://github.com/Rawphs) і [Lucas Mendonça](https://github.com/luuchowl) за [португальський переклад (portugues)](?lan=pt)
Дякую [Nicolas Barradeau](https://twitter.com/nicoptere) і [Karim Naaji](http://karim.naaji.fr/) за [французький переклад (français)](?lan=fr)
Дякую [Andrea Rovescalli](https://www.earove.info) за [італійський переклад (italiano)](?lan=it)
Дякую [Michael Tischer](http://www.mitinet.de) за [німецький переклад (deutsch)](?lan=de)
Дякую [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) за [російський переклад](?lan=ru)
Дякую [Vu Phuong Hoang](https://www.facebook.com/vuphuonghoang88) за [в'єтнамський переклад (Tiếng Việt)](?lan=vi)
Дякую [Wojciech Pachowiak](https://github.com/WojtekPachowiak) за [польський переклад (polski)](?lan=pl)
Дякую [Манойлову Андрію](https://twitter.com/ManoylovAC) за [український переклад](?lan=ua)
Дякую [Andy Stanton](https://andy.stanton.is/) за виправлення та вдосконалення [the pdf/epub export pipeline](https://thebookofshaders.com/appendix/02/?lan=ua)
Дякую всім, хто повірив у цей проект і [підтримував його виправленнями](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) або пожертвуваннями.
## Нові розділи
Для оповіщення про нові розділи, підпишіться на поштову розсилку або на [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>
## LICENSE
Copyright (c) Patricio Gonzalez Vivo, 2015 - http://patriciogonzalezvivo.com/
All rights reserved.

View File

@ -104,6 +104,8 @@ Cảm ơn [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) vì
Cảm ơn [Vu Phuong Hoang](https://github.com/DancingPhoenix88) và [Minh-Phuc Bui](https://github.com/phucbm) vì [Bản dịch tiếng Việt](?lan=vi)
Cảm ơn [Manoylov Andriy](https://twitter.com/ManoylovAC) vì [Bản dịch tiếng Ukraina (українська)](?lan=ua)
Cảm ơn [Andy Stanton](https://andy.stanton.is/) vì đã sửa lỗi và cải tiến [cách export quyển sách ra định dạng pdf/epub](https://thebookofshaders.com/appendix/02/?lan=vi)
Cảm ơn tất cả mọi người đã tin tưởng, [cùng sửa lỗi](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) và quyên góp cho dự án này.

View File

@ -38,7 +38,7 @@ This is a gentle step-by-step guide through the abstract and complex universe of
* Image operations
* Kernel convolutions
* Filters
* Others effects
* Other effects
* Simulation
* Pingpong
@ -106,6 +106,8 @@ Thanks [Vu Phuong Hoang](https://www.facebook.com/vuphuonghoang88) for the Vietn
Thanks [Wojciech Pachowiak](https://github.com/WojtekPachowiak) for the Polish [translation (polski)](?lan=pl)
Thanks [Manoylov Andriy](https://twitter.com/ManoylovAC) for the Ukrainian [translation (український переклад)](?lan=ua)
Thanks [Andy Stanton](https://andy.stanton.is/) for fixing and improving [the pdf/epub export pipeline](https://thebookofshaders.com/appendix/02/)
Thanks to everyone who has believed in this project and [contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) or donations.

33
appendix/00/README-ua.md Normal file
View File

@ -0,0 +1,33 @@
## Як користуватись книгою офлайн?
Припустимо, у вас довга подорож і ви хочете за цей час повчити шейдери. У такому випадку ви можете скопіювати книгу на свій комп'ютер і запустити її на локальному сервері.
Для цього вам потрібні лише PHP, Python 3 і git-клієнт. На комп'ютерах MacOS і Raspberry Pi Python встановлено за замовчуванням, але потрібно ще встановити PHP і git-клієнт. Це можна зробити наступним чином:
Для **MacOSX** переконайтесь, що у вас встановлено [homebrew](http://brew.sh/), після чого в терміналі виконайте наступні команди:
```bash
brew update
brew upgrade
brew install git php
```
На **Raspberry Pi** встановіть [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), дистрибутив Linux для Raspberry Pi на основі Debian, а потім виконайте наступні команди:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Після того, як все буде встановлено, склонуйте проєкт та запустіть локальний сервер:
```bash
cd ~
git clone --recursive https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
git submodule foreach git submodule init && git submodule update
php -S localhost:8000
```
Потім відкрийте у своєму браузері адресу [`http://localhost:8000/`](http://localhost:8000/)

View File

@ -1,6 +1,7 @@
<?php
$path = "../..";
$subtitle = ": How can I navigate this book off-line?";
$README = "README";
$language = "";

18
appendix/01/README-ua.md Normal file
View File

@ -0,0 +1,18 @@
## Як запустити приклади на Raspberry Pi?
Кілька років тому, припускати, що кожен має комп'ютер із графічним процесором, було важко. Зараз більшість комп'ютерів вже мають GPU, хоча подекуди й для деяких навчальних класів це все ще не так.
Завдяки [Raspberry Pi Foundation](http://www.raspberrypi.org/) новий тип невеликих і дешевих комп'ютерів (близько 35$ за штуку) знайшов свій шлях до навчальних класів. Що ще важливіше для цілей цієї книги, [Raspberry Pi](http://www.raspberrypi.org/) постачається з гідним графічним процесором Broadcom, до якого можна отримати доступ безпосередньо з консолі. Я створив гнучкий інструмент для онлайн-кодування GLSL під назвою [**glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer), який запускає всі приклади цієї книги. Ця програма має можливість автоматично оновлювати результат, коли користувач зберігає зміни у своєму коді. Що це значить? Ви можете редагувати код шейдеру, і щоразу, коли ви його зберігаєте, він буде автоматично скомпільований з оновленням вислідного зображення.
Створивши локальну копію репозиторію книги (див. [попередній розділ](../00/?lan=ua)) і встановивши [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer), можна запускати приклади за допомогою команди `glslviewer`. Крім того, з додатковим прапорцем `-l` можна візуалізувати поточний приклад у кутку екрана під час редагування коду за допомогою будь-якого текстового редактора (наприклад, `nano`, `pico`, `vi`, `vim` або `emacs`) . Це також працює при підключенні через ssh/sftp.
Щоб встановити та налаштувати все необхідне на Raspberry Pi, після встановлення [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) і входу в систему, введіть наступні команди:
```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
```

View File

@ -1,6 +1,7 @@
<?php
$path = "../..";
$subtitle = ": How to run the examples on a Raspberry Pi?";
$README = "README";
$language = "";

72
appendix/02/README-ua.md Normal file
View File

@ -0,0 +1,72 @@
## Як надрукувати цю книгу?
Скажімо, вам не потрібна навігація по тексту чи взаємодія з інтерактивними прикладами, а просто потрібна книга, яку ви зможете читати на пляжі або під час поїздок. У такому випадку ви можете надрукувати її.
#### Встановлення glslViewer
Щоб надрукувати цю книгу, її потрібно спочатку розпарсити. Для цього вам знадобиться [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) - консольний інструмент, який компілює та перетворює приклади шейдерів у зображення.
На **MacOSX** переконайтесь, що у вас встановлено [homebrew](http://brew.sh/) і потім виконайте у терміналі наступну команду:
```bash
brew install glslviewer
```
На **Raspberry Pi** установіть [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) - дистрибутив Linux на основі Debian, створений для Raspberry Pi, а потім виконайте такі дії:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Встановлення Python 3, Latex Engine і Pandoc
Для розбору розділів Markdown-розмітки у Latex, а потім у PDF-файл, ми будемо використовувати Xetex Latex Engine і Pandoc.
На **MacOSX**:
Завантажте та встановіть MacTeX:
```bash
brew install --cask mactex-no-gui
```
а потім інсталюйте [Pandoc](http://johnmacfarlane.net/pandoc/) і Python 3 за допомогою команди:
```bash
brew install pandoc python
```
На **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Зберіть книгу у pdf-формат та роздрукуйте її
Тепер, коли у вас є все необхідне, настав час клонувати [репозиторій цієї книги](https://github.com/patriciogonzalezvivo/thebookofshaders) та скомпілювати його.
Для цього ще раз відкрийте термінал і виконайте наступні команди:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
Якщо все пройде добре, ви побачите файл `book.pdf`, який можна прочитати на своєму улюбленому пристрої або роздрукувати.
#### Зберіть книгу в epub-формат для використання з Kindle
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
Згенерований файл `book.epub` можна використовувати безпосередньо або конвертувати у формат `.mobi` для використання з Kindle за допомогою конвертера, наприклад Calibre.

View File

@ -1,6 +1,7 @@
<?php
$path = "../..";
$subtitle = ": How to print this book?";
$README = "README";
$language = "";

63
appendix/03/README-ua.md Normal file
View File

@ -0,0 +1,63 @@
## Як прийняти участь у розвитку книги?
Дякуємо за бажання співпрацювати! Для цього існує кілька способів:
- Переклад контенту
- Покращення та допрацювання [```глосарію```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Редагування контенту
- Діліться своїми прикладами шейдерів через [онлайн-редактор](http://editor.thebookofshaders.com/)
### Переклад контенту
Ця книга написана мовою розмітки [Markdown](https://daringfireball.net/projects/markdown/syntax), тому її дуже легко редагувати та працювати з нею.
1. Для початку перейдіть до github-репозиторію за адресою [```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Перегляньте в ньому файли та теки. Ви помітите, що контент знаходиться в ```README.md``` та інших файлах з назвами із великих літер, наприклад: ```TITLE.md```, ```SUMMARY.md``` тощо. Також зауважте, що переклади розміщуються у файлах, імена яких закінчуються додатковими двома літерами, що вказують на мову перекладу, наприклад: ```README-jp.md```, ```README-es.md``` тощо.
2. Зробіть відгалуження репозиторію і клонуйте його на свій комп'ютер.
3. Продублюйте вміст файлів, які потрібно перекласти. Додайте до них двобуквенний код, що буде вказувати на мову для якої ви робите переклад.
4. Перекладіть вміст файлу (див. **Примітки щодо перекладу**).
5. Протестуйте зміни (див. **Тестування**).
6. Зробіть push у ваш власний форк проєкту і створіть [pull request](https://help.github.com/articles/using-pull-requests/)
#### Примітки щодо перекладу
Не видаляйте та не змінюйте вбудовані приклади, які виглядають приблизно так:
```html
<div class="codeAndCanvas" data="grid-making.frag"></div>
```
Або так:
```html
<div class="simpleFunction" data="y = mod(x,2.0);"></div>
```
#### Тестування
Запустіть локальний PHP-сервер у теці локального репозиторію:
```bash
php -S localhost:8000
```
Тепер у вашому браузері зайдіть на адресу [```localhost:8000```](http://localhost:8000), перейдіть до розділу, який ви перекладаєте, і додайте в кінці адреси такий рядок ```?lan=```, а після нього дві літери для позначення мови перекладу.
Наприклад, якщо ви перекладаєте розділ ```03``` на французьку мову, значить ви працювали з файлом ```03/README-fr.md```, і ви можете перевірити його за адресою: ``` http://localhost:8000/03/?lan=fr```
### Покращення глосарію
Цей розділ знаходиться в розробці. Ми раді вислухати ваші ідеї щодо його покращення, щоб зробити його корисним інструментом для всіх. Надсилайте свої пропозиції на [@bookofshaders](https://twitter.com/bookofshaders).
### Редагування контенту
Ми всі люди. Якщо ви побачите помилку, то сповістіть про неї, зробіть pull-request з виправленням або відкрийте issue. Дякую!
### Діліться своїми прикладами шейдерів
Ви побачите багато посилань на [онлайн-редактор](http://editor.thebookofshaders.com/) і його вбудовані у сторінки приклади з кодом.
Коли ви закодуєте щось корисне чи цікаве, натисніть «Export» (або піктограму ```⇪```) і надішліть його на адресу [@bookofshaders](https://twitter.com/bookofshaders) або [@kyndinfo](https://twitter.com/kyndinfo). Ми будемо раді переглянути його і додати до [галереї прикладів](https://thebookofshaders.com/examples/).

View File

@ -1,6 +1,7 @@
<?php
$path = "../..";
$subtitle = ": How can I collaborate with this book?";
$README = "README";
$language = "";

448
appendix/04/README-pl.md Normal file
View File

@ -0,0 +1,448 @@
## Wprowadzenie dla osób przychodzących z JS
przez [Nicolas Barradeau](http://www.barradeau.com/)
Jeśli jesteś programistą JavaScript, prawdopodobnie nieco zaskoczy Cię treść tej książki.
Rzeczywiście, istnieje wiele różnic pomiędzy manipulowaniem wysokopoziomowym kodem JS a zagłębianiem się w świat shaderów.
Jednak w przeciwieństwie do niskopoziomowego języka asemblerowego, GLSL jest czytelny dla człowieka i jestem pewien, że po zrozumieniu jego specyfiki szybko zaczniesz go używać.
Zakładam, że masz podstawową (choć może płytką) wiedzę o JavaScript, ale także o Canvas API.
Jeśli nie, nie martw się większość tej sekcji będzie dla Ciebie zrozumiała.
Nie będę zagłębiać się zbytnio w szczegóły, a niektóre kwestie mogą być _półprawdziwe_; nie oczekuj "wyczerpującego przewodnika", ale raczej
### WIELKI UŚCISK
JavaScript świetnie nadaje się do szybkiego prototypowania; wrzucasz garść losowych, nieotypowanych zmiennych i metod, możesz dynamicznie dodawać i usuwać członków klas, odświeżać stronę i sprawdzać, czy wszystko działa,
wprowadzać zmiany, odświeżać stronę, powtarzać życie jest proste.
Możesz się więc zastanawiać, jaka jest różnica między JavaScriptem a GLSL.
W końcu oba działają w przeglądarce, oba służą do rysowania różnych efektownych rzeczy na ekranie i pod tym względem JS jest łatwiejszy w użyciu.
Główna różnica polega jednak na tym, że JavaScript jest językiem **interpretowanym**, podczas gdy GLSL jest językiem **kompilowanym**.
**Kompilowany** program jest wykonywany natywnie przez system operacyjny, jest niskopoziomowy i zazwyczaj szybki.
**Interpretowany** program wymaga [wirtualnej maszyny](https://en.wikipedia.org/wiki/Virtual_machine) (VM) do wykonania, jest wysokopoziomowy i zazwyczaj wolniejszy.
Gdy przeglądarka (czyli _JavaScriptowa **VM**_) **wykonuje** lub **interpretuje** fragment kodu JS, nie wie, jaka zmienna czym jest i jaka funkcja co robi (z wyjątkiem oczywistych przypadków, takich jak **TypedArrays**).
Dlatego nie może nic zoptymalizować _z góry_, więc potrzebuje trochę czasu, aby przeczytać Twój kod, **wywnioskować** (dedukować na podstawie użycia) typy Twoich zmiennych i metod,
a kiedy to możliwe, przekształci _część_ Twojego kodu w kod asemblerowy, który wykona się znacznie szybciej.
To powolny, mozolny i niesamowicie skomplikowany proces jeśli interesują Cię szczegóły, polecam przyjrzeć się działaniu [silnika V8 w Chrome](https://developers.google.com/v8/).
Najgorsze jest to, że każda przeglądarka optymalizuje JS na swój sposób, a cały proces jest _ukryty_ przed użytkownikiem; jesteś bezsilny.
**Kompilowany** program nie jest interpretowany; system operacyjny go uruchamia, a jeśli program jest poprawny, zostaje wykonany.
To duża zmiana; jeśli zapomnisz o średniku na końcu linii, Twój kod jest niepoprawny i nie skompiluje się: Twój kod w ogóle nie przekształci się w program.
To surowe, ale tak właśnie działa **shader**: _skompilowany program wykonywany na GPU_.
Nie bój się! **Kompilator**, czyli część programu, która dba o to, aby Twój kod był poprawny, stanie się Twoim najlepszym przyjacielem.
Przykłady z tej książki oraz [edytor towarzyszący](http://editor.thebookofshaders.com/) są bardzo przyjazne użytkownikowi.
Powiedzą Ci, gdzie i dlaczego Twój program nie skompilował się, a następnie będziesz musiał wprowadzić poprawki i za każdym razem, gdy shader będzie gotowy do kompilacji, zostanie on natychmiast wyświetlony.
To świetny sposób na naukę, ponieważ jest bardzo wizualny i tak naprawdę niczego nie możesz zepsuć.
Ostatnia uwaga: **shader** składa się z dwóch programów, **vertex shader** i **fragment shader**.
W skrócie, **vertex shader**, pierwszy program, otrzymuje geometrię jako dane wejściowe i przekształca ją w serię **pikseli** (lub *fragmentów*), które następnie przekazuje do
**fragment shader**, drugiego programu, który decyduje, jaki kolor nadać pikselom.
Ta książka koncentruje się głównie na tym drugim we wszystkich przykładach geometria to prosty czworobok pokrywający cały ekran.
Więc! Gotowy?
No to ruszamy!
### Silne typowanie
![pierwszy wynik wyszukiwania dla 'strong type' w Google Images, 20.05.2016](vector.jpg)
Dla osób przychodzących z JS lub innego języka bez typów, **typowanie** zmiennych jest obcym konceptem, co sprawia, że **typowanie** stanowi najtrudniejszy krok w kierunku nauki GLSL.
**Typowanie**, jak sama nazwa wskazuje, oznacza, że musisz przypisać **typ** każdej zmiennej (oraz funkcjom, oczywiście).
To zasadniczo oznacza, że słowo **`var`** przestaje istnieć.
Polityka myślenia GLSL wymazała je z powszechnego języka i nie jesteś w stanie go używać, ponieważ... po prostu nie istnieje.
Zamiast używać magicznego słowa **`var`**, będziesz musiał _jawnie określić typ każdej używanej zmiennej_, dzięki czemu kompilator będzie widział tylko obiekty i prymitywy, które wie, jak efektywnie obsługiwać.
Minusem braku możliwości użycia słowa **`var`** i konieczności _jawnego określania wszystkiego_ jest to, że musisz znać typ wszystkich zmiennych i dobrze je rozumieć.
Spokojnie jest ich niewiele, a do tego są dość proste (GLSL nie jest frameworkiem Java).
Może to brzmieć strasznie, ale ogólnie nie różni się to bardzo od tego, co robisz w JavaScript; jeśli zmienna jest typu `boolean`, oczekujesz, że będzie przechowywać `true` lub `false` i nic więcej.
Jeśli zmienna jest zadeklarowana jako `var uid = XXX;`, prawdopodobnie przechowasz w niej wartość całkowitą, a `var y = YYY;` _może_ odnosić się do wartości zmiennoprzecinkowej.
Co więcej, dzięki **silnemu typowaniu** nie będziesz tracił czasu na zastanawianie się, czy `X == Y` (albo czy `typeof X == typeof Y`? ... albo `typeof X !== null && Y...`... w każdym razie) po prostu będziesz tego wiedział, a jeśli nie, kompilator Cię o tym poinformuje.
Oto **typy skalarne** (**skalar** określa ilość), których możesz używać w GLSL: `bool` (Boolean), `int` (liczba całkowita), `float` (liczba zmiennoprzecinkowa).
Istnieją też inne typy, ale nie ma co się przejmować poniższy fragment pokazuje, jak deklarować **zmienne (`vars`)** (tak, użyłem zakazanego słowa) w GLSL:
```glsl
// wartość typu Boolean:
JS: var b = true; GLSL: bool b = true;
// wartość typu Integer
JS: var i = 1; GLSL: int i = 1;
// wartość typu Float (liczba)
JS: var f = 3.14159; GLSL: float f = 3.14159;
```
Nie jest to trudne, prawda? Jak wspomniałem, ułatwia to kodowanie, ponieważ nie tracisz czasu na sprawdzanie typu danej zmiennej.
W razie wątpliwości pamiętaj, że robisz to po to, aby Twój program działał o wiele szybciej niż w JS.
#### void
Istnieje typ `void`, który w przybliżeniu odpowiada `null`; jest on używany jako typ zwracany przez funkcję, która nic nie zwraca.
Nie możesz przypisać go do zmiennej.
#### boolean
Jak wiesz, wartości logiczne (Boolean) są najczęściej używane w testach warunkowych, np. `if( myBoolean == true ){}else{}`.
Choć rozgałęzianie warunkowe jest możliwe na CPU, [równoległa natura](http://thebookofshaders/01/) GLSL czyni to mniej sensownym.
Używanie instrukcji warunkowych jest często wręcz zniechęcane książka przedstawia kilka alternatywnych technik rozwiązania tego problemu.
#### rzutowanie typów
Jak powiedział [Boromir](https://pl.wikipedia.org/wiki/Boromir): "Nie łączy się po prostu otypowanych prymitywów". W przeciwieństwie do JavaScript, GLSL nie pozwala na wykonywanie operacji pomiędzy zmiennymi o różnych typach.
This for instance:
```glsl
int i = 2;
float f = 3.14159;
// próba pomnożenia liczby całkowitej przez wartość zmiennoprzecinkową:
float r = i * f;
```
nie zadziała, ponieważ próbujesz połączyć **_kota_** z **_żyrafą_**.
Rozwiązaniem jest użycie rzutowania typów; to _sprawi, że kompilator uwierzy_, że *`i`* jest typu `float`, nie zmieniając faktycznie typu *`i`*.
```glsl
// rzutowanie typu zmiennej całkowitej 'i' na float:
float r = float( i ) * f;
```
Co jest ściśle równoważne przebraniu **_kota_** w **_żyrafi_ strój** i zadziała zgodnie z oczekiwaniami (`r` będzie wynikiem `i` x `f`).
Można **rzutować** dowolny z wymienionych typów na inny; zauważ, że rzutowanie `float` na `int` działa jak `Math.floor()`, ponieważ usuwa część dziesiętną.
Rzutowanie `float` lub `int` na `bool` zwróci `true`, jeśli wartość zmiennej nie wynosi zero.
#### konstruktor
**Typy** zmiennych są również swoimi własnymi **konstruktorami klas**; w rzeczywistości zmienna typu `float` może być traktowana jako _`instancja`_ klasy _`Float`_.
Następujące deklaracje są równie poprawne:
```glsl
int i = 1;
int i = int( 1 );
int i = int( 1.9995 );
int i = int( true );
```
Może się to nie wydawać znaczące dla typów `skalarnych`, ale nie różni się to zbytnio od **rzutowania** nabierze sensu, gdy przejdziemy do sekcji dotyczącej *przeciążania*.
Ok, więc te trzy to `typy prymitywne`, rzeczy, bez których nie możesz żyć ale oczywiście GLSL ma do zaoferowania więcej.
### Wektory
![pierwszy wynik wyszukiwania dla 'vector villain' w Google Images, 05.20.2016](vector.jpg)
W JavaScript, podobnie jak w GLSL, potrzebujesz bardziej zaawansowanych sposobów obsługi danych, dlatego przydają się **wektory**.
Przypuszczam, że już napisałeś klasę `Point` w JavaScript, która przechowuje razem wartość `x` i `y`, kod wyglądałby mniej więcej tak:
```glsl
// definicja 'klasy':
var Point = function( x, y ){
this.x = x || 0;
this.y = y || 0;
}
// i instancjonowałoby się ją tak:
var p = new Point( 100,100 );
```
Jak właśnie widzieliśmy, to jest TAK niepoprawne na TYLU poziomach! Po pierwsze, użycie słowa kluczowego **`var`**, potem okropne **`this`**, a następnie znowu **nieotypowane** wartości `x` i `y`...
Nie, to nie zadziała w świecie shaderów.
Zamiast tego GLSL udostępnia wbudowane struktury danych, które służą do przechowywania danych razem, mianowicie:
* `bvec2`: 2-wymiarowy wektor Boolean, `bvec3`: 3-wymiarowy wektor Boolean, `bvec4`: 4-wymiarowy wektor Boolean
* `ivec2`: 2-wymiarowy wektor Integer, `ivec3`: 3-wymiarowy wektor Integer, `ivec4`: 4-wymiarowy wektor Integer
* `vec2`: 2-wymiarowy wektor Float, `vec3`: 3-wymiarowy wektor Float, `vec4`: 4-wymiarowy wektor Float
Natychmiast zauważyłeś, że dla każdego typu prymitywnego istnieje odpowiedni **wektor**, spryciarzu.
Z tego, co właśnie widzieliśmy, można wywnioskować, że `bvec2` przechowa dwie wartości typu `bool`, a `vec4` cztery wartości typu `float`.
Inną rzeczą wprowadzoną przez wektory jest liczba **wymiarów**; nie oznacza to, że do renderowania grafiki 2D używasz 2-wymiarowego wektora, a do 3D 3-wymiarowego.
Co by wtedy reprezentował 4-wymiarowy wektor? (właściwie nazywa się tesseraktem lub hiperkostką)
Nie, **wymiary** oznaczają liczbę oraz typ **składowych** lub **zmiennych** przechowywanych w **wektorze**:
```glsl
// stwórzmy 2-wymiarowy wektor Boolean
bvec2 b2 = bvec2 ( true, false );
// stwórzmy 3-wymiarowy wektor Integer
ivec3 i3 = ivec3( 0,0,1 );
// stwórzmy 4-wymiarowy wektor Float
vec4 v4 = vec4( 0.0, 1.0, 2.0, 1. );
```
`b2` przechowuje dwie różne wartości logiczne, `i3` przechowuje trzy różne wartości całkowite, a `v4` cztery różne wartości zmiennoprzecinkowe.
Ale jak odczytać te wartości?
w przypadku `skalarów` odpowiedź jest oczywista przy `float f = 1.2`; zmienna `f` przechowuje wartość `1.2`.
W przypadku **wektorów** jest to nieco inne i całkiem piękne.
#### akcesory
Istnieją różne sposoby dostępu do wartości
```glsl
// stwórzmy 4-wymiarowy wektor Float
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
```
Aby odczytać te 4 wartości, możesz zrobić następująco:
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
bułka z masłem; ale poniższe sposoby są równie poprawne w dostępie do Twoich danych:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
I spryciarzu, już zauważyłeś trzy rzeczy:
* `X`, `Y`, `Z` i `W` są używane w programach 3D do reprezentacji wektorów 3D
* `R`, `G`, `B` i `A` służą do kodowania kolorów oraz kanału alfa
* `[0]`, `[1]`, `[2]` i `[3]` oznaczają, że mamy dostęp do wartości w sposób losowy (tablica indeksowana)
W zależności od tego, czy manipulujesz współrzędnymi 2D czy 3D, kolorem z lub bez kanału alfa, czy też po prostu różnymi zmiennymi, możesz wybrać najbardziej odpowiedni typ i rozmiar **wektora**.
Zazwyczaj współrzędne 2D i wektory (w sensie geometrycznym) przechowywane są jako `vec2`, `vec3` lub `vec4`, kolory jako `vec3` lub `vec4` (jeśli potrzebujesz kanału alfa), ale nie ma ograniczeń co do sposobu użycia wektorów.
Na przykład, jeśli chcesz przechować tylko jedną wartość logiczną w `bvec4`, jest to możliwe, ale to marnotrawstwo pamięci.
**uwaga**: w shaderze wartości kolorów (`R`, `G`, `B` i `A`) są normalizowane, mieszczą się w przedziale od 0 do 1, a nie od 0 do 0xFF, dlatego lepiej użyć Float `vec4` niż Integer `ivec4` do ich przechowywania.
Już nieźle, ale to nie wszystko!
#### swizzle
Można zwrócić więcej niż jedną wartość jednocześnie; powiedzmy, że potrzebujesz tylko składowych `X` i `Y` z `vec4`, w JavaScript musiałbyś napisać coś takiego:
```glsl
var needles = [0, 1]; // pozycja 'x' i 'y' w naszej strukturze danych
var a = [ 0,1,2,3 ]; // nasza struktura danych 'vec4'
var b = a.filter( function( val, i, array ) {
return needles.indexOf( array.indexOf( val ) ) != -1;
});
// b = [ 0, 1 ]
// albo bardziej bezpośrednio:
var needles = [0, 1];
var a = [ 0,1,2,3 ]; // our 'vec4' data structure
var b = [ a[ needles[ 0 ] ], a[ needles[ 1 ] ] ]; // b = [ 0, 1 ]
```
Brzydko. W GLSL możesz je uzyskać w ten sposób:
```glsl
// stwrórz 4-wymiarowy wektor Float
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
// i odczytaj tylko 'x' i 'y'
vec2 xy = v4.xy; // xy = vec2( 0.0, 1.0 );
```
Co tu się stało?! Gdy **skonkatenujesz akcesory**, GLSL elegancko zwraca podzbiór wartości, o które prosiłeś, w najbardziej odpowiednim formacie **wektora**.
Rzeczywiście, wektor to struktura danych o **losowym dostępie**, podobna do tablicy w JavaScript.
Tak więc, nie tylko możesz pobrać podzbiór swoich danych, ale także określić **kolejność**, w jakiej mają być zwrócone może to odwrócić kolejność składowych wektora:
```glsl
// stwórz 4-wymiarowy wektor: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// i odczytaj go w kolejności: A,B,G,R
vec4 backwards = color.abgr; // backwards = vec4( 1.0, 0.0, 0.8, 0.2 );
```
I oczywiście, możesz zapytać o tę samą składową wielokrotnie:
```glsl
// stwórz 4-wymiarowy wektor: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// i odczytaj GAG (Green, Alpha, Green) vec3 z kanałów G i A
vec3 GAG = color.gag; // GAG = vec4( 0.8, 1.0, 0.8 );
```
Jest to niezwykle przydatne, aby łączyć części wektorów, wyodrębniać tylko kanały rgb z koloru RGBA itp.
#### przeciążaj wszystko!
W sekcji o typach wspomniałem o **konstruktorze** i tu mamy kolejną świetną cechę GLSL **przeciążanie**.
Dla tych, którzy nie wiedzą, **przeciążanie** operatora lub funkcji oznacza mniej więcej: _"zmianę zachowania danego operatora lub funkcji w zależności od operandów/argumentów"_.
Przeciążanie nie jest dozwolone w JavaScript, więc na początku może to wydawać się dziwne, ale jestem pewien, że gdy się do tego przyzwyczaisz, zastanowisz się, dlaczego nie zostało to zaimplementowane w JS (krótka odpowiedź, *typowanie*).
Najprostszy przykład przeciążania operatorów wygląda następująco:
```glsl
vec2 a = vec2( 1.0, 1.0 );
vec2 b = vec2( 1.0, 1.0 );
// przeciążone dodawanie
vec2 c = a + b; // c = vec2( 2.0, 2.0 );
```
CO? Czyli można dodawać rzeczy, które nie są liczbami?!
Tak, dokładnie. Oczywiście dotyczy to wszystkich operatorów (`+`, `-`, `*` oraz `/`), ale to dopiero początek.
Rozważ poniższy fragment:
```glsl
vec2 a = vec2( 0.0, 0.0 );
vec2 b = vec2( 1.0, 1.0 );
// przeciążony konstruktor
vec4 c = vec4( a , b ); // c = vec4( 0.0, 0.0, 1.0, 1.0 );
```
Zbudowaliśmy `vec4` z dwóch `vec2`, przy czym nowy `vec4` użył `a.x` i `a.y` jako składowych `X` i `Y` wektora `c`.
Następnie wziął `b.x` i `b.y` i użył ich jako składowych `Z` i `W`.
Tak właśnie działa przeciążony konstruktor vec4, który akceptuje różne argumenty.
Oznacza to, że wiele wersji tej samej funkcji o różnych sygnaturach może współistnieć w jednym programie, na przykład następujące deklaracje są wszystkie poprawne:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0);// x, y, z, w wszystkie są równe 1.0
vec4 a = vec4( v2, float, v4 );// vec4( v2.x, v2.y, float, v4.x );
vec4 a = vec4( v3, float );// vec4( v3.x, v3.y, v3.z, float );
etc.
```
Jedyne, na co musisz zwrócić uwagę, to dostarczenie wystarczającej liczby argumentów, aby wypełnić Twój **wektor**.
Ostatnia rzecz, możesz przeciążać wbudowane funkcje w swoim programie, aby przyjmowały argumenty, dla których nie zostały zaprojektowane (choć nie powinno się to zdarzać zbyt często).
#### inne typy
Wektory są fajne, to sedno Twojego shadera.
Istnieją inne prymitywy, takie jak macierze (Matrices) i próbki tekstur (Texture samplers), które zostaną omówione później w książce.
Możemy także używać tablic (Arrays). Oczywiście muszą być typowane, a przy tym występują pewne pułapki:
* mają ustalony rozmiar
* nie możesz używać metod push(), pop(), splice() itp., a właściwość ```length``` nie istnieje
* nie możesz od razu zainicjalizować ich wartościami
* musisz przypisywać wartości pojedynczo
to nie zadziała:
```glsl
int values[3] = [0,0,0];
```
ale to zadziała:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
To jest w porządku, gdy znasz swoje dane lub masz małe tablice wartości.
Jeśli chcesz bardziej ekspresyjnego sposobu deklaracji zmiennej,
możesz użyć również typu ```struct```. Są one jak _obiekty_ bez metod;
pozwalają przechowywać i uzyskiwać dostęp do wielu zmiennych w jednym obiekcie.
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
następnie możesz ustawiać i odczytywać wartości _kolorów_ w następujący sposób:
```glsl
// zainicjuj struct z jakimiś wartościami
ColorStruct sandy = ColorStruct( vec3(0.92,0.83,0.60),
vec3(1.,0.94,0.69),
vec3(0.95,0.86,0.69) );
// odczytaj wartość ze struct
sandy.color0 // vec3(0.92,0.83,0.60)
```
To lukier składniowy, ale może pomóc w pisaniu bardziej przejrzystego kodu, przynajmniej takiego, do którego jesteś przyzwyczajony.
#### instrukcje i warunki
Struktury danych są przydatne, ale może będziesz musiał iterować lub wykonywać testy warunkowe w pewnym momencie.
Na szczęście składnia jest bardzo zbliżona do tej w JavaScript.
Warunek wygląda tak:
```glsl
if( warunek ){
// prawda
}else{
// fałsz
}
```
Pętla for zazwyczaj wygląda tak:
```glsl
const int count = 10;
for( int i = 0; i <= count; i++){
// zrób coś
}
```
lub z iteratorem typu float:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
// zrób coś
}
```
Zauważ, że `count` musi być zdefiniowane jako stała.
Oznacza to, że poprzedzasz typ kwalifikatorem `const`, o czym opowiem za chwilę.
Mamy również instrukcje ```break``` i ```continue```:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
if( i < 5. )continue;
if( i >= 8. )break;
}
```
Miej na uwadze, że na niektórych urządzeniach instrukcja ```break``` może nie działać zgodnie z oczekiwaniami i pętla nie przerwie iteracji wcześniej.
Ogólnie rzecz biorąc, powinieneś utrzymywać liczbę iteracji na możliwie najniższym poziomie i unikać pętli oraz instrukcji warunkowych tak często, jak to możliwe.
#### kwalifikatory
Oprócz typów zmiennych, GLSL używa **kwalifikatorów**.
Krótko mówiąc, kwalifikatory pomagają kompilatorowi zrozumieć, jaka jest rola danej zmiennej.
Na przykład, niektóre dane mogą być dostarczane tylko przez CPU do GPU, nazywamy je **atrybutami** i **uniformami**.
**Atrybuty** są zarezerwowane dla vertex shaderów, a **uniformy** mogą być używane zarówno w vertex, jak i fragment shaderach.
Jest też kwalifikator ```varying```, służący do przekazywania zmiennych między vertex a fragment shaderem.
Nie będę zagłębiać się tutaj w szczegóły, ponieważ skupiamy się głównie na **fragment shaderze**, ale później w książce zobaczysz coś takiego:
```glsl
uniform vec2 u_resolution;
```
Widzisz, co zrobiliśmy? Dodaliśmy kwalifikator ```uniform``` przed typem zmiennej.
Oznacza to, że rozdzielczość kanwy, nad którą pracujemy, jest przekazywana do shadera z CPU.
Szerokość kanwy zapisana jest w komponencie x, a wysokość w komponencie y 2-wymiarowego wektora.
Gdy kompilator napotka zmienną poprzedzoną tym kwalifikatorem, upewni się, że nie możesz zmieniać tych wartości w czasie wykonywania programu.
To samo dotyczy naszej zmiennej ```count```, która była limitem w pętli ```for```:
```glsl
const float count = 10.;
for( ... )
```
Kiedy używamy kwalifikatora ```const```, kompilator upewni się, że wartość zmiennej zostanie ustawiona tylko raz, w przeciwnym razie nie jest to stała.
Istnieją trzy dodatkowe kwalifikatory używane w sygnaturach funkcji: in, out oraz inout.
W JavaScript, gdy przekazujesz prymitywne argumenty do funkcji, ich wartość jest tylko do odczytu, a jeśli zmienisz ich wartość wewnątrz funkcji,
zmiany nie mają wpływu na zmienną poza funkcją.
```glsl
function banana( a ){
a += 1;
}
var value = 0;
banana( value );
console.log( value );// > 0 ; zmiany nie są brane pod uwagę poza funkcją
```
With arguments qualifiers, you can specify the behaviour of the arguments:
* ```in``` will be read-only ( default )
* ```out``` write-only: you can't read the value of this argument but you can set it
* ```inout``` read-write: you can both get and set the value of this variable
Przepisanie funkcji banana do GLSL wyglądałoby tak:
```glsl
void banana( inout float a ){
a += 1.;
}
float A = 0.;
banana( A ); // teraz A = 1.;
```
To bardzo różni się od JS i jest również potężne, ale nie musisz jawnie określać kwalifikatorów w sygnaturze (domyślnie są one tylko do odczytu).
#### przestrzeń i współrzędne
Ostatnia uwaga: w DOM oraz w 2D Canvas jesteśmy przyzwyczajeni, że oś Y wskazuje w dół.
Ma to sens w kontekście DOM, ponieważ odpowiada sposobowi, w jaki rozwija się strona internetowa pasek nawigacyjny na górze, zawartość rozciągająca się ku dołowi.
W kanwie WebGL oś Y jest odwrócona: Y wskazuje w górę.
Oznacza to, że punkt początkowy, czyli (0,0), znajduje się w lewym dolnym rogu kontekstu WebGL, a nie w lewym górnym, jak ma to miejsce w 2D Canvas.
Współrzędne tekstur podlegają tej zasadzie, co na początku może być nieintuicyjne.
## I to wszystko!
Oczywiście moglibyśmy zagłębić się w różne koncepcje, ale jak wspomniano wcześniej, chodziło o to, aby dać WIELKI UŚCISK nowoprzybyłym.
To sporo materiału do przyswojenia, ale z cierpliwością i praktyką stanie się to coraz bardziej naturalne.
Mam nadzieję, że część z tego okaże się przydatna. A teraz, co powiesz na rozpoczęcie swojej podróży przez tę książkę?

View File

@ -325,7 +325,7 @@ for( float i = 0.0; i <= count; i+= 1.0 ){
#### квалификаторы
Помимо типов переменных в GLSL есть **квалификаторы**. Вкратце, квалификаторы сообщают компилятору какая переменная для чего предназначена. Например, некоторые данные для GPU могут приходить только со стороны CPU. Такие данные называются **атрибутами** и **юниформами**. **Атрибуты** встречаются только в вершинных шейдерах, а **юниформы** - и в вершинных, и во фрагментных. Так же есть квалификатор ```varying```, используемый для передачи переменных т вершинного шейдера ко фрагментному.
Помимо типов переменных в GLSL есть **квалификаторы**. Вкратце, квалификаторы сообщают компилятору какая переменная для чего предназначена. Например, некоторые данные для GPU могут приходить только со стороны CPU. Такие данные называются **атрибутами** и **юниформами**. **Атрибуты** встречаются только в вершинных шейдерах, а **юниформы** - и в вершинных, и во фрагментных. Так же есть квалификатор ```varying```, используемый для передачи переменных от вершинного шейдера к фрагментному.
Я не буду сильно углубляться в подробности, ибо мы в основном рассматриваем **фрагментные шейдеры*, но далее в книге вам возможно встретится что-то вроде
```glsl

449
appendix/04/README-ua.md Normal file
View File

@ -0,0 +1,449 @@
## Вступ для тих, хто прийшов із JS
автор [Nicolas Barradeau](http://www.barradeau.com/)
Якщо ви JavaScript-розробник, швидше за все, ви будете трохи спантеличені, читаючи книгу.
Дійсно, є багато відмінностей між маніпулюванням високорівневим JS і длубанням у менш високорівневих шейдерах.
Проте, на відміну від більш низькорівневої мови асемблера, GLSL є людино-зрозумілою мовою, і я впевнений, що як тільки ви розберетеся з її особливостями, то швидко запрацюєте.
Я припускаю, що ви маєте хоча б поверхневе знання про JavaScript і API Canvas.
Якщо ні, не хвилюйтеся, ви все одно зможете зрозуміти більшу частину цього розділу.
Крім того, я не буду надто вдаватися в подробиці, і деякі речі можуть бути апівправдою_, тож не розраховувайте на "вичерпний посібник", а радше на ознайомлення.
### Введення для новачків
JavaScript чудово підходить для швидкого прототипування; ви накидуєте купу різноманітних нетипізованих змінних і методів, можете динамічно додавати та видаляти члени класів, оновлювати сторінку і швидко перевіряти чи вона працює.
Потім можна внести нові зміни, оновити сторінку, повторити - легке життя.
Тож ви можете поставити собі питання, у чому різниця між JavaScript і GLSL?
Зрештою, обидва працюють у браузері, обидва використовуються для малювання купи прикольних штук на екрані, і в цьому сенсі JS легше використовувати.
Що ж, головна відмінність полягає в тому, що Javascript є **інтерпретованою** мовою, тоді як GLSL є **компільованою**.
**Скомпільована** програма виконується нативно в ОС, є низькорівневою і загалом швидкою.
**Інтерпретована** програма потребує для свого виконання [віртуальну машину](https://en.wikipedia.org/wiki/Virtual_machine) (VM), є високорівневою і відносно більш повільною.
Коли браузер (_**VM** для JavaScript_) **виконує** або **інтерпретує** фрагмент JS-коду, він ще не має уявлення про те, яка змінна чим являється і яка функція що робить (за винятком **типізованих масивів**).
Тож він не може нічого оптимізувати аперед_.
Потрібен деякий час, щоб прочитати ваш код, щоб **вивести**, на основі використання, типи ваших змінних та методів і, коли це можливо, перетворити ещо_ з вашого коду на код асемблера, який виконуватиметься набагато швидше.
Це повільний, кропіткий і шалено складний процес. Якщо вас цікавлять деталі, я рекомендую подивитися, як [працює рушій V8 у Chrome](https://developers.google.com/v8/).
Найгірше те, що кожен браузер оптимізує JS по-своєму, а процес _прихований_ від вас. В цьому плані ви безсилі.
**Компільована** програма не потребує інтерпретації. Операційна система запускає її і якщо програма валідна, вона виконується.
Це велика відмінність. Якщо ви забули крапку з комою в кінці рядка, ваш код вже не валідний та не скомпілюється, він взагалі не перетвориться на програму.
Це суворо, але це те, чим є **шейдер**: _програмою, що компілюється для виконання на GPU_.
Не бійтеся! **Компілятор** який перевіряє правильність вашого коду, стане вашим найкращим другом.
Приклади цієї книги та [редактор коду](http://editor.thebookofshaders.com/) дуже дружні до користувача.
Вони підкажуть вам де і чому не вдалося скомпілювати вашу програму.
Потім, після потрібних виправлень, коли шейдер буде готовий до компіляції, він миттєво зобразить результат своєї роботи. Це чудовий спосіб навчання, оскільки він дуже наочний і безпечний, бо насправді ви нічого не зможете зламати.
Останнє зауваження: **шейдер** складається з 2 програм: **вершинного шейдера** і **фрагментного шейдера**.
Якщо коротко, то **вершинний шейдер** це перша програма, що отримує на вхід *геометрію* та перетворює її на серію **пікселів** (або *фрагментів*).
Потім вона передає їх до **фрагментного шейдера** - другої програми, яка вирішить, яким кольором пофарбувати ці пікселі.
Дана книга здебільшого зосереджена на **фрагментних шейдерах**. У всіх прикладах геометрія є простим чотирикутником, який охоплює весь екран.
Готові?
Поїхали!
### Сильні типи
![перший результат пошуку для 'strong type' в Google Image на 20.05.2016](strong_type.jpg)
Коли ви приходите з JS або будь-якої іншої нетипізованої мови, **типізація** змінних являється для вас чужорідною концепцією, що стає найважчим кроком до GLSL.
**Типізація**, як випливає з назви, означає, що вам потрібно надавати **тип** усім своїм змінним і функціям.
Це фактично означає, що слів **`var`** або **`let`** більше не існує.
Поліція думок GLSL стерла їх із загальної мови й ви більше не можете їх використовувати, тому що, ну... їх не існує.
Замість використання чарівного слова **`var`** вам доведеться _явно вказати тип кожної змінної_, яку ви використовуєте, тоді компілятор бачитиме лише ті об'єкти та примітиви, з якими він вміє ефективно поводитися.
Мінус, що ви не можете використовувати ключове слово **`var`** і повинні _явно вказувати всі типи_, полягає в тому, що вам доведеться знати типи усіх змінних і знати їх добре.
Будьте спокійні, їх небагато і вони досить прості (GLSL це вам не Java-фреймворк).
Це може здатися страшним, але загалом це не дуже відрізняється від того, що ви робите на JavaScript. Наприклад, якщо ви маєте `boolean`-змінну, то ви очікуєте, що вона зберігатиме лише `true` або `false` і нічого більше.
Якщо змінна називається `var uid = XXX;`, то в ній вірогідно зберігається цілочисельне значення, а `var y = YYY;` оже_ бути посиланням на значення з рухомою крапкою.
Що ще краще, завдяки **сильним типам** ви не витрачатимете час на роздуми про те, чи `X == Y` (чи `typeof X == typeof Y`?, чи `typeof X !== null && Y...`). Ви просто *знаєте* це, а якщо ні, то компілятор знатиме напевно.
Ось **скалярні типи** (**скаляр** описує величину), які можна використовувати в GLSL: `bool` (булів тип), `int` (ціле число), `float` (число з рухомою крапкою).
Є й інші типи, але не будемо поспішати. Наступний фрагмент показує, як оголосити **`vars`** (так, я використав заборонене слово) у GLSL:
```glsl
// логічне значення
JS: var b = true; GLSL: bool b = true;
// цілочисельне значення
JS: var i = 1; GLSL: int i = 1;
// числове значення з рухомою крапкою
JS: var f = 3.14159; GLSL: float f = 3.14159;
```
Не дуже важко, правда? Як згадувалося вище, це навіть полегшує роботу, оскільки ви не витрачаєте час на перевірку типів даних змінних.
Якщо це здається сумнівним, то пам'ятайте, що ви робите це для того, щоб ваша програма виконувалася набагато швидше, ніж на JS.
#### void
Тип `void` приблизно відповідає `null`. Він використовується в якості типу, який має повертати метод, коли він нічого не повертає.
Ви не можете призначати його змінним.
#### boolean
Як вам відомо, логічні значення здебільшого використовуються в умовних перевірках: "`if (myBoolean == true) {...} else {...}`".
Якщо умовне розгалуження є звичайним підходом для CPU, то для [паралельної природи](http://thebookofshaders/01/?lan=ua) GLSL це твердження є менш правдивим.
Використання умовних галужень навіть не рекомендується у більшості випадків і у книзі показано кілька альтернативних методів для вирішення цього обмеження.
#### приведення типів
Як казав [Боромир](https://en.wikipedia.org/wiki/Boromir), "не можна просто взяти та скомбінувати типізовані примітиви". На відміну від JavaScript, GLSL не дозволить вам виконувати операції між змінними різних типів.
Наприклад, цей код:
```glsl
int i = 2;
float f = 3.14159;
// спроба помножити ціле число на значення з рухомою крапкою
float r = i * f;
```
не спрацює, тому що ви намагаєтеся схрестити **_кота_** і **_жирафа_**.
Проблема вирішується за допомогою **приведення типу**, що _змусить компілятор повірити_, що *`i`* має тип `float` без фактичної зміни типу *`i`*.
```glsl
// приведення типу цілочисельної змінної 'i' до float
float r = float(i) * f;
```
Це як вдягти **_кота_** у **шкіру _жирафа_** і працюватиме належним чином (змінна `r` зберігатиме результат множення `i` на `f`).
Можна **привести** будь-який зі згаданих вище типів до будь-якого іншого. Зауважте, що приведення `float` до `int` поводитиметься як `Math.floor()`, оскільки видалятиме значення після рухомої крапки.
Приведення `float` або `int` до `bool` поверне `true`, якщо змінна не дорівнює нулю.
#### конструктор
**Типи** змінних також є **конструкторами класів** для самих себе. Змінну `float` фактично можна розглядати як _`екземпляр`_ класу _`float`_.
Наступні оголошення рівнозначно валідні:
```glsl
int i = 1;
int i = int(1);
int i = int(1.9995);
int i = int(true);
```
Це може здатися не дуже схожим на `скалярні` типи та не дуже відрізняється від **приведення типів**, але у цьому з'явиться більше сенсу, коли дійдемо до розділу *перевантаження*.
Отже, ми познайомилися з трьома `примітивними типами`, без яких ви не зможете жити, але, звісно, GLSL має й інші.
### Вектори
![перший результат пошуку для 'vector villain' у Google Image на 20.05.2016](vector.jpg)
У Javascript, як і в GLSL, вам знадобляться складніші способи маніпуляції даними, ось де **`вектори`** стануть у пригоді.
Я припускаю, що вам вже доводилося писати клас `Point` на JavaScript, для утримання значень `x` і `y`, що виглядав якось так:
```glsl
// визначення класу:
var Point = function(x, y) {
this.x = x || 0;
this.y = y || 0;
}
// створення екземляру:
var p = new Point(100, 100);
```
Як ми щойно побачили, це ДУЖЕ неправильно на ДУЖЕ багатьох рівнях! По-перше, ключове слово **`var`**, далі жахливе **`this`**, потім знову **нетипізовні** значення `x` і `y`...
Ні, це не запрацює в шейдерленді.
Натомість GLSL надає вбудовані структури даних для їх групування, а саме:
* **`bvec2`**: 2D вектор для bool, **`bvec3`**: 3D вектор для bool, **`bvec4`**: 4D вектор для bool
* **`ivec2`**: 2D вектор для int, **`ivec3`**: 3D вектор для int, **`ivec4`**: 4D вектор для int
* **`vec2`**: 2D вектор для float, **`vec3`**: 3D вектор для float, **`vec4`**: 4D вектор для float
Ви відразу помітили, що для кожного примітиву є відповідний **векторний** тип.
З показаного вище, ви можете зробити висновок, що `bvec2` буде містити два значення типу `bool`, а `vec4` — чотири значення `float`.
Також вектори вводять таку річ як **вимірність** або **розмірність**. Це не означає, що 2D-вектор використовується при малюванні 2D-графіки, а 3D-вектор при малюванні 3D-сцен. Ні!
Що в такому разі буде представляти 4D-вектор? (ну насправді це називається тесерактом або гіперкубом)
**Розмірність** представляє кількість і тип **компонентів** або **змінних**, що зберігаються у **векторі**:
```glsl
// створюємо двовимірний булів вектор
bvec2 b2 = bvec2(true, false);
// створюємо тривимірний цілочисельний вектор
ivec3 i3 = ivec3(0, 0, 1);
// створюємо чотиривимірний вектор з рухомою комою
vec4 v4 = vec4(0.0, 1.0, 2.0, 1.0);
```
`b2` зберігає два різних булевих значення, `i3` - 3 різні цілочисельні значення, а `v4` - 4 різні значення з рухомою комою.
Але як звернутися до цих значень?
У випадку `скалярів` відповідь очевидна: для "`float f = 1.2;`", змінна `f` містить значення `1.2`.
З **векторами** це трохи інакше і доволі красиво.
#### аксесори - доступи до елементів
Існують різні способи доступу до значень
```glsl
// створимо чотиривимірний вектор типу float
vec4 v4 = vec4(0.0, 1.0, 2.0, 3.0);
```
отримати кожне з 4-х значень, можна наступним чином:
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
Просто і легко. Наведені нижче приклади показують інші еквівалентні способи доступу до цих даних:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
Кмітливий читач міг помітити три речі:
* `X`, `Y`, `Z`, `W` зазвичай використовуються в 3D-програмах для представлення 3D-векторів
* `R`, `G`, `B`, `A` використовуються для кодування кольорів і альфа-каналу
* `[0]`, `[1]`, `[2]`, `[3]` означає, що ми можемо звертатися до значень через індекси
Тож залежно від того, чи працюєте ви з дво- чи тривимірними координатами, кольором з альфа-каналом чи без нього, або просто з деякими довільними значеннями, ви можете вибрати найбільш відповідний тип і розмірність **вектора**.
Зазвичай двовимірні координати та вектори (в геометричному сенсі) зберігаються як `vec2`, `vec3` або `vec4`, кольори як `vec3` або `vec4`, якщо вам потрібна непрозорість. Але, в цілому, обмежень на те як використовувати вектори немає.
Наприклад, якщо ви хочете зберегти лише одне логічне значення в `bvec4`, це можливо, але буде марною витратою пам'яті.
**Примітка**: у шейдері значення кольорів (`R`, `G`, `B`, `A`) нормалізовані, тобто варіюються в діапазоні від 0 до 1, а не від 0 до 0xFF, тому для них краще використовувати тип float `vec4`, ніж цілочисельний тип `ivec4`.
Вже маємо хороший початок, але рушаймо далі!
#### змішування
З вектора можна отримати більше одного значення за раз. Скажімо, із `vec4` вам потрібні лише значення `X` і `Y`. У JavaScript вам довелося б написати щось подібне:
```glsl
var needles = [0, 1]; // розміщення 'x' і 'y' в нашій структурі даних
var a = [0, 1, 2, 3]; // наша структура даних 'vec4'
var b = a.filter(function(val, i, array) {
return needles.indexOf(array.indexOf(val)) != -1;
});
// b = [0, 1]
// або більш буквально:
var needles = [0, 1];
var a = [0, 1, 2, 3]; // структура даних 'vec4'
var b = [a[needles[0]], a[needles[1]]]; // b = [0, 1]
```
Виглядає потворно. У GLSL ви можете отримати ці дані так:
```glsl
// створюємо 4D-вектор типу float
vec4 v4 = vec4(0.0, 1.0, 2.0, 3.0);
// і одночасно отримуємо лише X та Y
vec2 xy = v4.xy; // xy = vec2(0.0, 1.0);
```
Що це щойно сталося?! Коли ви **об'єднуєте аксесори**, GLSL елегантно повертає підмножину значень, які ви запросили, у найбільш відповідному **векторному** форматі.
Тож тут вектор — це структура даних із **довільним доступом**, схожий на масив як у JavaScript.
Таким чином, ви можете не тільки отримати підмножину ваших даних, але і вказати їх **порядок**, у якому вони вам потрібні. Наступний приклад змінює порядок отримання компонентів вектора:
```glsl
// створюємо чотиривимірний вектор типу float: R,G,B,A
vec4 color = vec4(0.2, 0.8, 0.0, 1.0);
// отримуємо компоненти кольору в порядку A,B,G,R
vec4 backwards = color.abgr; // backwards = vec4(1.0, 0.0, 0.8, 0.2);
```
І, звичайно, ви можете повернути той самий компонент кілька разів:
```glsl
// створюємо чотиривимірний вектор типу float: R,G,B,A
vec4 color = vec4(0.2, 0.8, 0.0, 1.0);
// отримуємо vec3 з компонентами GAG на основі каналів G і A з початкового кольору
vec3 GAG = color.gag; // GAG = vec4(0.8, 1.0, 0.8);
```
Це надзвичайно зручно для об'єднання частин вектору, виділення лише rgb-каналів із кольору RGBA тощо.
#### перевантаження
У розділі типів я згадував про **конструктор** і можливість **перевантаження**.
Для тих, хто не знає, **перевантаження** оператора або функції означає _'зміну поведінки зазначеного оператора або функції залежно від операндів/аргументів'_.
В JavaScript немає перевантаження, тому спочатку воно може здатися трохи дивним, але я впевнений, що як тільки ви звикнете до нього, то будете дивуватися, чому це не реалізовано в JS (коротка відповідь - *типізація*).
Найпростіший приклад перевантаженого оператора виглядає так:
```glsl
vec2 a = vec2(1.0, 1.0);
vec2 b = vec2(1.0, 1.0);
// перевантажене додавання
vec2 c = a + b; // c = vec2(2.0, 2.0);
```
ЩО? Отже, можна додавати сутності, які не є числами?!
Саме так. Також це стосується всіх операторів (`+`, `-`, `*` і `/`), але це тільки початок.
Розглянемо наступний фрагмент:
```glsl
vec2 a = vec2(0.0, 0.0);
vec2 b = vec2(1.0, 1.0);
// перевантажений конструктор
vec4 c = vec4(a, b); // c = vec4(0.0, 0.0, 1.0, 1.0);
```
Ми створили `vec4` з двох `vec2`. Таким чином новий `vec4` використав `a.x` і `a.y` як `X`і `Y` компоненти та `b.x` і `b.y` як `Z` і `W` компоненти для вектора `c`.
Ось що відбувається, коли **функція** перевантажується для прийняття різних аргументів, у попередньому випадку це був **конструктор** `vec4`.
Це означає, що в одній програмі може співіснувати багато **версій** одного і того самого методу з різною сигнатурою. Наприклад, усі наступні оголошення є валідними:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0); // x, y, z, w - усі дорівнюють 1.0
vec4 a = vec4(v2, float, v4); // vec4(v2.x, v2.y, float, v4.x);
vec4 a = vec4(v3, float); // vec4(v3.x, v3.y, v3.z, float);
тощо
```
Єдине про що ви повинні попіклуватися, так це про передачу достатньої кількості аргументів для заповнення **вектору**.
Нарешті, ви також можете перевантажувати вбудовані функції у вашій програмі, щоб вони могли приймати аргументи, для яких не були розроблені (хоча це не повинно траплятися занадто часто).
#### більше типів
Вектори прикольні і є основою вашого шейдера.
А ще існують інші примітиви, такі як матриці та текстурні семплери, які будуть розглянуті пізніше в книзі.
Ми також можемо використовувати масиви. Звичайно, їх потрібно типізувати й вони мають свої особливості у порівнянні з JS:
* мають фіксований розмір
* ви не можете використовувати методи push(), pop(), splice() тощо, і немає властивості ```length```
* ви не можете відразу ініціалізувати їх значеннями
* Ви повинні встановити значення індивідуально
Це не спрацює:
```glsl
int values[3] = [0, 0, 0];
```
А ось це спрацює:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
Добре, коли ви знаєте свої дані або маєте невеликі масиви значень.
Якщо вам потрібно більше виразності, то можете скористатися типом ```struct```. Це як _об'єкти_ без методів.
Вони дозволяють зберігати та отримувати доступ до кількох змінних всередині одного об'єкта:
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
Ви можете створити та отримати значення _colors_ наступним чином:
```glsl
// ініціалізуємо структуру деякими значеннями
ColorStruct sandy = ColorStruct(
vec3(0.92, 0.83, 0.60),
vec3(1., 0.94, 0.69),
vec3(0.95, 0.86, 0.69)
);
// отримуємо доступ до значень із структури
sandy.color0 // vec3(0.92, 0.83, 0.60)
```
Це синтаксичний цукор, але він може допомогти написати чистіший код, принаймні більш звичний для вас.
#### вирази та умови
Структури даних корисні, але нам оже_ знадобитися можливість для повторення дії або виконання умовних перевірок.
На щастя для нас, синтаксис дуже близький до JavaScript.
Умова виглядає так:
```glsl
if (condition) {
// true
} else {
// false
}
```
Звичайни цикл `for`:
```glsl
const int count = 10;
for (int i = 0; i <= count; i++) {
// do something
}
```
Приклад циклу з ітератором типу float:
```glsl
const float count = 10.;
for (float i = 0.0; i <= count; i += 1.0) {
// do something
}
```
Зауважте, що ```count``` потрібно визначити як ```константу```.
Це означає перед змінною потрібно додати **кваліфікатор** ```const```, який ми розглянемо трохи згодом.
Нам також доступні оператори ```break``` і ```continue```:
```glsl
const float count = 10.;
for (float i = 0.0; i <= count; i += 1.0) {
if (i < 5.) continue;
if (i >= 8.) break;
}
```
Зауважте, що на деяких типах пристроїв ```break``` не працює належним чином і завчасно не перериває виконання циклу.
Загалом, кількість ітерацій має бути якомога меншою, та і в цілому бажано уникати використання циклів і умовних галужень.
#### кваліфікатори
Окрім типів змінних, GLSL використовує **кваліфікатори**.
Коротко кажучи, кваліфікатори допомагають повідомити компілятору призначення змінних.
Наприклад, деякі дані для GPU можуть бути надані тільки від CPU і називаються **атрибутами** та **уніформами**.
**Атрибути** використовуються у вершинних шейдерах, а **уніформи** можна використовувати як у вершинних, так і у фрагментних шейдерах.
Існує також кваліфікатор ```variying```, який використовується для передачі змінних від вершинного шейдеру до фрагментного.
Я не буду вдаватися в деталі, оскільки ми зосереджені на **фрагментних шейдерах**, але далі в книзі ви побачите щось на кшталт:
```glsl
uniform vec2 u_resolution;
```
Бачите, що ми тут зробили? Ми додали кваліфікатор ```uniform``` перед типом змінної.
Це означає, що змінна, яка відповідає за роздільну здатність полотна з яким ми працюємо, передається шейдеру з CPU.
Ширина полотна зберігається в x, а висота в y-компоненті даного 2D-вектора.
Коли компілятор бачить змінну, якій передує цей кваліфікатор, він простежить, щоб ви не могли *змінити* такі значення під час рантайму.
Те саме стосується нашої змінної ```count```, яка слугувала обмеженням для циклу ```for```:
```glsl
const float count = 10.;
for ( ... )
```
Коли ми використовуємо кваліфікатор ```const```, компілятор не дає змогу перезаписувати значення такої змінної, інакше вона не була б константою.
У сигнатурах функцій можуть використовуватися 3 додаткові кваліфікатори: ```in```, ```out``` та ```inout```.
У JavaScript передані до функції значення скалярних аргументів доступні лише для читання. Якщо ви змінюєте їхні значення всередині функції, то ці зміни не застосовуються до змінної поза функцією.
```glsl
function banana(a) {
a += 1;
}
var value = 0;
banana(value);
console.log(value); // 0 - значення за межами функції не змінилося
```
За допомогою кваліфікаторів перед аргументами ви можете вказати їх поведінку:
* ```in``` - лише для читання (за замовчуванням)
* ```out``` - лише для запису: можна змінити, але не можна прочитати значення
* ```inout``` - читання і запис: можна і прочитати й встановити нове значення
Переписаний метод banana у GLSL виглядає так:
```glsl
void banana(inout float a) {
a += 1.;
}
float A = 0.;
banana(A); // тепер A = 1.;
```
Це дуже відрізняється від JS і є досить потужною можливістю, але вам не обов'язково вказувати кваліфікатори аргументів. За замовчуванням вони доступні лише для зчитування.
#### простір і координати
Останнє зауваження: у DOM і Canvas 2D ми звикли, що вісь Y спрямована 'вниз'.
Це має сенс у контексті DOM, оскільки відповідає способу розгортання вебсторінки: панель навігації вгорі, а контент прокручується донизу.
У полотні WebGL вісь Y перевернута і вказує 'вгору'.
Це означає, що початок координат, точка (0, 0), знаходиться в нижньому лівому куті контексту WebGL, а не у верхньому лівому куті, як у 2D Canvas.
Координати текстур також дотримуються цього правила, що спочатку може бути контрінтуїтивним.
## Ось і все!
Звісно, ми б могли більше заглибитися в різноманітні концепції, але, як згадувалося раніше, цей розділ написаний як просте введення для новачків.
Тут вже написано достатньо для того, щоб за деякий час переварити нові знання, але з терпінням і практикою ця мова ставатиме для вас все більш природною.
Сподіваюся, цей матеріал був корисним для вас. А тепер як щодо початку вашої подорожі основною частиною книги?

View File

@ -1,6 +1,7 @@
<?php
$path = "../..";
$subtitle = ": An introduction for those coming from JS";
$README = "README";
$language = "";

View File

@ -1,6 +1,7 @@
<?php
$path = "../..";
$subtitle = ": An introduction for vectors";
$README = "README";
$language = "";

View File

@ -1,6 +1,7 @@
<?php
$path = "../..";
$subtitle = ": An introduction to interpolation";
$README = "README";
$language = "";

15
appendix/README-ua.md Normal file
View File

@ -0,0 +1,15 @@
# Додаток
1. [Як користуватись книгою офлайн?](00/?lan=ua)
2. [Як запустити приклади на Raspberry Pi?](01/?lan=ua)
3. [Як надрукувати цю книгу?](02/?lan=ua)
4. [Як прийняти участь у розвитку книги?](03/?lan=ua)
5. [Вступ для тих, хто прийшов із JS](04/?lan=ua) від [Nicolas Barradeau](http://www.barradeau.com/)
6. [Введення до векторів](05/?lan=ua)
7. [Введення в інтерполяцію](06/?lan=ua)

View File

@ -1,6 +1,7 @@
<?php
$path = "..";
$subtitle = ": Appendix";
$README = "README";
$language = "";

View File

@ -1,6 +1,8 @@
<div class="header">
<p class="subtitle"><a href="https://thebookofshaders.com/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a> & <a href="http://jenlowe.net">Jen Lowe</a> </p>
<p> <a href="?lan=id">Bahasa Indonesia</a> - <a href="?lan=vi">Tiếng Việt</a> - <a href="?lan=jp">日本</a> - <a href="?lan=ch">中文版</a> - <a href="?lan=kr">한국어</a> - <a href="?lan=es">Español</a> - <a href="?lan=pt">Portugues</a> - <a href="?lan=fr">Français</a> - <a href="?lan=it">Italiano</a> - <a href="?lan=de">Deutsch</a> - <a href="?lan=ru">Русский</a> - <a href="?lan=pl">Polski</a> - <a href=".">English</a></p>
<?php
include("languages.php");
?>
</div>
<hr>

5
examples/README-pl.md Normal file
View File

@ -0,0 +1,5 @@
# Galeria przykładów
<p class="gallery_author">Stworzone przez <a href="https://www.kynd.info">kynd</a>(<a href="https://x.com/kyndinfo">@kyndinfo</a>) oraz Patricio Gonzalez Vivo (<a href="https://x.com/patriciogv">@patriciogv</a>)</p>
To jest zbiór przykładów wyciągniętych z rozdziałów tej książki, wraz z udostępnionymi shaderami hojnie przekazanymi przez innych czytelników korzystających z [edytora online](http://editor.thebookofshaders.com/). Zachęcamy do eksplorowania i modyfikowania ich krok po kroku. Gdy stworzysz coś, z czego będziesz dumny, kliknij "Export", a następnie skopiuj "URL do kodu...". Prześlij go do [@bookofshaders](https://x.com/bookofshaders) lub [@kyndinfo](https://x.com/kyndinfo). Nie możemy się doczekać, aby to zobaczyć!

5
examples/README-ua.md Normal file
View File

@ -0,0 +1,5 @@
# Галерея прикладів
<p class="gallery_author">Створено за участі by <a href="https://www.kynd.info">kynd</a>(<a href="https://twitter.com/kyndinfo">@kyndinfo</a>) та Patricio Gonzalez Vivo(<a href="https://twitter.com/patriciogv">@patriciogv</a>)</p>
Це колекція прикладів, взятих із розділів цієї книги разом із шейдерами, люб'язно наданими іншими читачами за допомогою [онлайн-редактора](http://editor.thebookofshaders.com/). Не соромтеся досліджувати та змінювати їх. Якщо у вас вийде приклад, яким ви пишаєтеся, зробіть експорт своїх роботи та надішліть його на адресу [@bookofshaders](https://twitter.com/bookofshaders) або [@kyndinfo](https://twitter.com/kyndinfo). Ми з нетерпінням чекатимемо!

View File

@ -3,6 +3,12 @@
<footer>
<p> Copyright 2015 <a href="http://www.patriciogonzalezvivo.com" target="_blank">Patricio Gonzalez Vivo</a> </p>
</footer>
<script type="text/javascript">
// Setting the theme immediately inside the inline script prevents flicker
document.body.dataset.theme = localStorage.getItem('theme') || 'light';
</script>
<?php
echo '
<script type="text/javascript" src="'.$path.'/src/main.js" defer></script>';

278
glossary/README-ua.md Normal file
View File

@ -0,0 +1,278 @@
# Глосарій
## За темою
* ТИПИ
[void](./?lan=ua&search=void)
[bool](./?lan=ua&search=bool)
[int](./?lan=ua&search=int)
[float](./?lan=ua&search=float)
[bvec2](./?lan=ua&search=bvec2)
[bvec3](./?lan=ua&search=bvec3)
[bvec4](./?lan=ua&search=bvec4)
[ivec2](./?lan=ua&search=ivec2)
[ivec3](./?lan=ua&search=ivec3)
[ivec4](./?lan=ua&search=ivec4)
[vec2](./?lan=ua&search=vec2)
[vec3](./?lan=ua&search=vec3)
[vec4](./?lan=ua&search=vec4)
[mat2](./?lan=ua&search=mat2)
[mat3](./?lan=ua&search=mat3)
[mat4](./?lan=ua&search=mat4)
[sampler2D](./?lan=ua&search=sampler2D)
[samplerCube](./?lan=ua&search=samplerCube)
[struct](./?lan=ua&search=struct)
* КВАЛІФІКАТОРИ
[attribute](./?lan=ua&search=attribute)
[const](./?lan=ua&search=const)
[uniform](./?lan=ua&search=uniform)
[varying](./?lan=ua&search=varying)
[precision](./?lan=ua&search=precision)
[highp](./?lan=ua&search=highp)
[mediump](./?lan=ua&search=mediump)
[lowp](./?lan=ua&search=lowp)
[in](./?lan=ua&search=in)
[out](./?lan=ua&search=out)
[inout](./?lan=ua&search=inout)
* ВБУДОВАНІ ЗМІННІ
[gl_Position](./?lan=ua&search=gl_Position)
[gl_PointSize](./?lan=ua&search=gl_PointSize)
[gl_PointCoord](./?lan=ua&gl_PointCoord)
[gl_FrontFacing](./?lan=ua&search=gl_FrontFacing)
[gl_FragCoord](./?lan=ua&search=gl_FragCoord)
[gl_FragColor](./?lan=ua&search=gl_FragColor)
* ВБУДОВАНІ КОНСТАНТИ
[gl_MaxVertexAttribs](./?lan=ua&search=gl_MaxVertexAttribs)
[gl_MaxVaryingVectors](./?lan=ua&search=gl_MaxVaryingVectors)
[gl_MaxVertexTextureImageUnits](./?lan=ua&search=gl_MaxVertexTextureImageUnits)
[gl_MaxCombinedTextureImageUnits](./?lan=ua&search=gl_MaxCombinedTextureImageUnits)
[gl_MaxTextureImageUnits](./?lan=ua&search=gl_MaxTextureImageUnits)
[gl_MaxFragmentUniformVectors](./?lan=ua&search=gl_MaxFragmentUniformVectors)
[gl_MaxDrawBuffers](./?lan=ua&search=gl_MaxDrawBuffers)
* ТРИГОНОМЕТРИЧНІ ТА КУТОВІ ФУНКЦІЇ
[radians()](./?lan=ua&search=radians)
[degrees()](./?lan=ua&search=degrees)
[sin()](./?lan=ua&search=sin)
[cos()](./?lan=ua&search=cos)
[tan()](./?lan=ua&search=tan)
[asin()](./?lan=ua&search=asin)
[acos()](./?lan=ua&search=acos)
[atan()](./?lan=ua&search=atan)
* ЕКСПОНЕНЦІАЛЬНІ ФУНКЦІЇ
[pow()](./?lan=ua&search=pow)
[exp()](./?lan=ua&search=exp)
[log()](./?lan=ua&search=log)
[exp2()](./?lan=ua&search=exp2)
[log2()](./?lan=ua&search=log2)
[sqrt()](./?lan=ua&search=sqrt)
[inversesqrt()](./?lan=ua&search=inversesqrt)
* ЗАГАЛЬНІ ФУНКЦІЇ
[abs()](./?lan=ua&search=abs)
[sign()](./?lan=ua&search=sign)
[floor()](./?lan=ua&search=floor)
[ceil()](./?lan=ua&search=ceil)
[fract()](./?lan=ua&search=fract)
[mod()](./?lan=ua&search=mod)
[min()](./?lan=ua&search=min)
[max()](./?lan=ua&search=max)
[clamp()](./?lan=ua&search=clamp)
[mix()](./?lan=ua&search=mix)
[step()](./?lan=ua&search=step)
[smoothstep()](./?lan=ua&search=smoothstep)
* ГЕОМЕТРИЧНІ ФУНКЦІЇ
[length()](./?lan=ua&search=length)
[distance()](./?lan=ua&search=distance)
[dot()](./?lan=ua&search=dot)
[cross()](./?lan=ua&search=cross)
[normalize()](./?lan=ua&search=normalize)
[facefoward()](./?lan=ua&search=facefoward)
[reflect()](./?lan=ua&search=reflect)
[refract()](./?lan=ua&search=refract)
* МАТРИЧНІ ФУНКЦІЇ
[matrixCompMult()](./?lan=ua&search=matrixCompMult)
* ФУНКЦІЇ ПОВ'ЯЗАНІ З ВЕКТОРАМИ
[lessThan()](./?lan=ua&search=lessThan)
[lessThanEqual()](./?lan=ua&search=lessThanEqual)
[greaterThan()](./?lan=ua&search=greaterThan)
[greaterThanEqual()](./?lan=ua&search=greaterThanEqual)
[equal()](./?lan=ua&search=equal)
[notEqual()](./?lan=ua&search=notEqual)
[any()](./?lan=ua&search=any)
[all()](./?lan=ua&search=all)
[not()](./?lan=ua&search=not)
* ФУНКЦІЇ ПОВ'ЯЗАНІ З ТЕКСТУРАМИ
[texture2D()](./?lan=ua&search=texture2D)
[textureCube()](./?lan=ua&search=textureCube)
## За алфавітом
* A
[abs()](./?lan=ua&search=abs)
[acos()](./?lan=ua&search=acos)
[all()](./?lan=ua&search=all)
[any()](./?lan=ua&search=any)
[asin()](./?lan=ua&search=asin)
[atan()](./?lan=ua&search=atan)
[attribute](./?lan=ua&search=attribute)
* B
[bool](./?lan=ua&search=bool)
[bvec2](./?lan=ua&search=bvec2)
[bvec3](./?lan=ua&search=bvec3)
[bvec4](./?lan=ua&search=bvec4)
* C
[ceil()](./?lan=ua&search=ceil)
[clamp()](./?lan=ua&search=clamp)
[const](./?lan=ua&search=const)
[cos()](./?lan=ua&search=cos)
[cross()](./?lan=ua&search=cross)
* D
[degrees()](./?lan=ua&search=degrees)
[dFdx()](./?lan=ua&search=dFdx)
[dFdy()](./?lan=ua&search=dFdy)
[distance()](./?lan=ua&search=distance)
[dot()](./?lan=ua&search=dot)
* E
[equal()](./?lan=ua&search=equal)
[exp()](./?lan=ua&search=exp)
[exp2()](./?lan=ua&search=exp2)
* F
[faceforward()](./?lan=ua&search=faceforward)
[float](./?lan=ua&search=float)
[floor()](./?lan=ua&search=floor)
[fract()](./?lan=ua&search=fract)
* G
[greaterThan()](./?lan=ua&search=greaterThan)
[greaterThanEqual()](./?lan=ua&search=greaterThanEqual)
[gl_FragColor](./?lan=ua&search=gl_FragColor)
[gl_FragCoord](./?lan=ua&search=gl_FragCoord)
[gl_FrontFacing](./?lan=ua&search=gl_FrontFacing)
[gl_PointCoord](./?lan=ua&gl_PointCoord)
[gl_PointSize](./?lan=ua&search=gl_PointSize)
[gl_Position](./?lan=ua&search=gl_Position)
[gl_MaxCombinedTextureImageUnits](./?lan=ua&search=gl_MaxCombinedTextureImageUnits)
[gl_MaxDrawBuffers](./?lan=ua&search=gl_MaxDrawBuffers)
[gl_MaxFragmentUniformVectors](./?lan=ua&search=gl_MaxFragmentUniformVectors)
[gl_MaxVaryingVectors](./?lan=ua&search=gl_MaxVaryingVectors)
[gl_MaxVertexAttribs](./?lan=ua&search=gl_MaxVertexAttribs)
[gl_MaxVertexTextureImageUnits](./?lan=ua&search=gl_MaxVertexTextureImageUnits)
[gl_MaxTextureImageUnits](./?lan=ua&search=gl_MaxTextureImageUnits)
* H
[highp](./?lan=ua&search=highp)
* I
[in](./?lan=ua&search=in)
[inout](./?lan=ua&search=inout)
[int](./?lan=ua&search=int)
[inversesqrt()](./?lan=ua&search=inversesqrt)
[ivec2](./?lan=ua&search=ivec2)
[ivec3](./?lan=ua&search=ivec3)
[ivec4](./?lan=ua&search=ivec4)
* L
[length()](./?lan=ua&search=length)
[lessThan()](./?lan=ua&search=lessThan)
[lessThanEqual()](./?lan=ua&search=lessThanEqual)
[log()](./?lan=ua&search=log)
[log2()](./?lan=ua&search=log2)
[lowp](./?lan=ua&search=lowp)
* M
[matrixCompMult()](./?lan=ua&search=matrixCompMult)
[mat2](./?lan=ua&search=mat2)
[mat3](./?lan=ua&search=mat3)
[mat4](./?lan=ua&search=mat4)
[max()](./?lan=ua&search=max)
[mediump](./?lan=ua&search=mediump)
[min()](./?lan=ua&search=min)
[mix()](./?lan=ua&search=mix)
[mod()](./?lan=ua&search=mod)
* N
[normalize()](./?lan=ua&search=normalize)
[not()](./?lan=ua&search=not)
[notEqual()](./?lan=ua&search=notEqual)
* O
[out](./?lan=ua&search=out)
* P
[precision](./?lan=ua&search=precision)
[pow()](./?lan=ua&search=pow)
* R
[radians()](./?lan=ua&search=radians)
[reflect()](./?lan=ua&search=reflect)
[refract()](./?lan=ua&search=refract)
[return](./?lan=ua&search=return)
* S
[sampler2D](./?lan=ua&search=sampler2D)
[samplerCube](./?lan=ua&search=samplerCube)
[sign()](./?lan=ua&search=sign)
[sin()](./?lan=ua&search=sin)
[smoothstep()](./?lan=ua&search=smoothstep)
[sqrt()](./?lan=ua&search=sqrt)
[step()](./?lan=ua&search=step)
[struct](./?lan=ua&search=struct)
* T
[tan()](./?lan=ua&search=tan)
[texture2D()](./?lan=ua&search=texture2D)
[textureCube()](./?lan=ua&search=textureCube)
* U
[uniform](./?lan=ua&search=uniform)
* V
[varying](./?lan=ua&search=varying)
[vec2](./?lan=ua&search=vec2)
[vec3](./?lan=ua&search=vec3)
[vec4](./?lan=ua&search=vec4)
[void](./?lan=ua&search=void)

View File

@ -100,7 +100,7 @@
[dot()](./?search=dot)
[cross()](./?search=cross)
[normalize()](./?search=normalize)
[facefoward()](./?search=facefoward)
[faceforward()](./?search=faceforward)
[reflect()](./?search=reflect)
[refract()](./?search=refract)

21
glossary/abs/README-pl.md Normal file
View File

@ -0,0 +1,21 @@
## abs
Zwraca wartość bezwzględną z parametru.
### Deklaracja
```glsl
float abs(float x)
vec2 abs(vec2 x)
vec3 abs(vec3 x)
vec4 abs(vec4 x)
```
### Parametry
```x``` określa wartość, z której ma zostać zwrócona wartość bezwzględna.
### Opis
```abs()``` zwraca wartość bezwzględną z x.
<div class="simpleFunction" data="y = abs(x); "></div>
### Zobacz też
[sign()](/glossary/?lan=pl&search=sign), [min()](/glossary/?lan=pl&search=min), [max()](/glossary/?lan=pl&search=max), [Rozdział 05: Shaping Functions](../05/?lan=pl)

21
glossary/abs/README-ua.md Normal file
View File

@ -0,0 +1,21 @@
## abs
Повертає абсолютне значення параметра.
### Оголошення
```glsl
float abs(float x)
vec2 abs(vec2 x)
vec3 abs(vec3 x)
vec4 abs(vec4 x)
```
### Параметри
**```x```** — значення, яке потрібно повернути в абсолют.
### Опис
**```abs()```** повертає абсолютне значення **`x`**.
<div class="simpleFunction" data="y = abs(x);"></div>
### Дивіться також
[sign()](/glossary/?lan=ua&search=sign), [min()](/glossary/?lan=ua&search=min), [max()](/glossary/?lan=ua&search=max), [Розділ 05: Формотворчі функції](/05/?lan=ua)

View File

@ -10,7 +10,7 @@ vec4 abs(vec4 x)
```
### Parameters
```x``` specify the value of which to return the absolute.
```x``` specifies the value of which to return the absolute.
### Description
```abs()``` returns the absolute value of ```x```.

View File

@ -0,0 +1,21 @@
## acos
Zwraca arcus cosinus podanego argumentu
### Deklaracja
```glsl
float acos(float x)
vec2 acos(vec2 x)
vec3 acos(vec3 x)
vec4 acos(vec4 x)
```
### Parametry
```x``` wartość, której arcus cosinus ma zostać zwrócony.
### Opis
```acos()``` zwraca kąt, którego cosinus jest równy ```x```.
<div class="simpleFunction" data="y = acos(x); "></div>
### Zobacz też
[cos()](/glossary/?lan=pl&search=cos), [sin()](/glossary/?lan=pl&search=sin), [asin()](/glossary/?lan=pl&search=asin), [tan()](/glossary/?lan=pl&search=tan), [atan()](/glossary/?lan=pl&search=atan), [Rozdział 05: Shaping Functions](/05/?lan=pl)

View File

@ -0,0 +1,21 @@
## acos
Повертає арккосинус параметра
### Оголошення
```glsl
float acos(float x)
vec2 acos(vec2 x)
vec3 acos(vec3 x)
vec4 acos(vec4 x)
```
### Параметри
**```x```** — значення, арккосинус якого потрібно повернути.
### Опис
**```acos()```** повертає кут, тригонометричний косинус якого дорівнює **`x`**.
<div class="simpleFunction" data="y = acos(x);"></div>
### Дивіться також
[cos()](/glossary/?lan=ua&search=cos), [sin()](/glossary/?lan=ua&search=sin), [asin()](/glossary/?lan=ua&search=asin), [tan()](/glossary/?lan=ua&search=tan), [atan()](/glossary/?lan=ua&search=atan), [Розділ 05: Формотворчі функції](/05/?lan=ua)

View File

@ -10,7 +10,7 @@ vec4 acos(vec4 x)
```
### Parameters
```x``` specify the value whose arccosine to return.
```x``` specifies the value whose arccosine to return.
### Description
```acos()``` returns the angle whose trigonometric cosine is ```x```.

29
glossary/all/README-pl.md Normal file
View File

@ -0,0 +1,29 @@
## all
Sprawdza, czy wszystkie elementy wektora logicznego są prawdziwe
### Deklaracja
```glsl
bool all(bvec2 x)
bool all(bvec3 x)
bool all(bvec4 x)
```
### Parametry
```x``` określa wektor, który ma zostać sprawdzony pod kątem prawdy.
### Opis
```all()``` zwraca ```true```, jeśli wszystkie elementy ```x``` są ```true``` i ```false``` w przeciwnym razie. Jest to funkcjonalnie równoważne:
```glsl
bool all(bvec x){ // bvec może być bvec2, bvec3 lub bvec4
bool result = true;
int i;
for (i = 0; i < x.length(); ++i)
{
result &= x[i];
}
return result;
}
```
### Zobacz też
[any()](/glossary/?lan=pl&search=any), [not()](/glossary/?lan=pl&search=not)

31
glossary/all/README-ua.md Normal file
View File

@ -0,0 +1,31 @@
## all
Перевіряє чи всі елементи логічного вектора істинні
### Оголошення
```glsl
bool any(bvec2 x)
bool any(bvec3 x)
bool any(bvec4 x)
```
### Параметри
**```x```** — вектор, який буде перевірено на істинність.
### Опис
**```all()```** повертає **`true`**, якщо всі елементи **`x`** мають значення **`true`**, інакше повертається **`false`**. Функціонально це еквівалентно до наступного коду:
```glsl
bool all(bvec x) { // bvec може бути bvec2, bvec3 або bvec4
bool result = true;
int i;
for (i = 0; i < x.length(); ++i) {
result &= x[i];
}
return result;
}
```
### Дивіться також
[any()](/glossary/?lan=ua&search=any), [not()](/glossary/?lan=ua&search=not)

29
glossary/any/README-pl.md Normal file
View File

@ -0,0 +1,29 @@
## any
Sprawdza, czy choć jeden element wektora logicznego jest prawdziwy
### Deklaracja
```glsl
bool all(bvec2 x)
bool all(bvec3 x)
bool all(bvec4 x)
```
### Parametry
```x``` określa wektor, który ma zostać sprawdzony pod kątem prawdy.
### Opis
```all()``` zwraca ```true```, jeśli którykolwiek element ```x``` jest ```true``` i ```false``` w przeciwnym razie. Jest to funkcjonalnie równoważne:
```glsl
bool any(bvec x) { // bvec może być bvec2, bvec3 lub bvec4
bool result = false;
int i;
for (i = 0; i < x.length(); ++i) {
result |= x[i];
}
return result;
}
```
### Zobacz też
[any()](/glossary/?lan=pl&search=any), [not()](/glossary/?lan=pl&search=not)

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