# Алгоритмічне малювання
## Формотворчі функції або функції формування

Цей розділ можна було б назвати "Урок з парканом від містера Міягі". Раніше ми зіставляли нормалізоване положення координат *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/) — бібліотека шейдерів із функцій, які можна легко включити та використати у ваших проєктах. Бібліотека дуже атомарна, створена для зручного перевикористання, продуктивності й гнучкості. Може бути легко додана до будь-яких проєктів та фреймворків.
