The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe

Bahasa Indonesia - Tiếng Việt - 日本語 - 中文版 - 한국어 - Español - Portugues - Français - Italiano - Deutsch - Русский - Polski - English


Патерни

Шейдерні програми виконуються попіксельно, тому незалежно від того скільки ви повторюєте якусь фігуру, кількість обчислень залишається незмінною. Це означає, що фрагментні шейдери добре підходять для створення патернів — візерунків, що повторюються.

Nina Warmerdam - The IMPRINT Project (2013)

У цьому розділі ми збираємося застосувати дещо з попереднього матеріалу, щоб продублювати його кілька разів на полотні. Як і в попередніх розділах, наша стратегія базуватиметься на перемноженні просторових координат з діапазоном від 0.0 до 1.0, так щоб фігури, які ми малюватимемо між значеннями 0.0 та 1.0, повторювалися, утворюючи сітку.

"Сітка забезпечує структуру, в межах якої людській інтуїції та винахідливості зручно орієнтуватись. У хаосі природи візерунки створюють контраст і обіцяють порядок. Від ранніх візерунків на кераміці до геометричної мозаїки в римських лазнях люди давно використовують сітки, щоб прикрасити своє життя за допомогою декору." 10 PRINT, Mit Press, (2013)

Спочатку згадаймо функцію fract(). Вона повертає дробову частину числа, роблячи fract() модулем одиниці (mod(x,1.0)). Іншими словами, fract() повертає число після коми з рухомою крапкою. Наша змінна з нормалізованою системою координат (st) уже змінюється в межах діапазону від 0.0 до 1.0, тому немає сенсу робити щось на наступний зразок:

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.

Настав час намалювати щось у кожному підпросторі, розкоментувавши рядок 27. Оскільки обидві вісі x та y помножуються на однакове значення, то співвідношення сторін простору не змінюється. Відповідно форми також не матимуть викривлень та будуть такими, як очікувалося.

Для глибшого розуміння, спробуйте виконати деякі з наведених нижче вправ:

Застосування матриць всередині патернів

Оскільки кожен підрозділ або комірка є зменшеною версією нормалізованої системи координат, яку ми використовували раніше, ми можемо застосувати до них такі ж самі матричні перетворення для переміщення, обертання та масштабування.

Векторний візерунок шотландського тартану від Kavalenkava

Патерни зі зміщенням

Припустимо, ми хочемо імітувати цегляну стіну. Розглядаючи стіну, ви можете побачити, що кожен другий її ряд зміщений на півцеглини по вісі x. Як можна це зробити?

Першим кроком потрібно визначити, чи є потік поточного рядка парним чи непарним, що дасть нам розуміння чи потрібно робити зміщення у цьому рядку. Для цього ми використаємо функцію модуля mod() зі значенням 2.0 для другого параметру, а потім перевіримо, чи результат буде меншим від 1.0 чи ні. Подивіться на наступну формулу та розкоментуйте два останні рядки.

Як бачите, ми можемо використати тернарний оператор, щоб перевірити, чи остача від ділення по модулю mod() на 2.0 менше за 1.0, що означатиме другий рядок. Або ми можемо аналогічно використати функцію step(), яка виконає ту саму операцію, але швидше. Чому? Хоча важко напевно знати, як кожна графічна карта оптимізує та компілює код, але можна з упевненістю припустити, що вбудовані функції працюють швидше. За кожної можливості надавайте перевагу використанню вбудованих функцій!

Тепер, маючи формулу визначення непарних чисел, ми можемо застосувати зміщення до непарних рядків, щоб надати нашим плиткам ефект цегли. У рядку 14 наступного коду ми використовуємо функцію для "виявлення" непарних рядків та зсуваємо їх на половину одиниці по вісі x. Зауважте, що для парних рядків результатом нашої функції буде 0.0, що при множенні на значення для зміщення в 0.5 залишається тим самим 0.0. Але в непарних рядках ми отримуємо результат нашої функції як 1.0, що при множенні на зсув 0.5, переміщує вісь x системи координат на 0.5.

Тепер спробуйте розкоментувати рядок 32 — це розтягне співвідношення сторін системи координат, щоб імітувати її до співвідношення "сучасної цегли". Розкоментувавши рядок 40, ви зможете побачити, як виглядає система координат, відображена у червоний та зелений кольори.

Плитка Труше

Тепер, коли ми навчилися визначати, чи знаходиться наша комірка в парному чи непарному рядку чи стовпці, можна повторно використовувати один елемент дизайну залежно від його положення. Розглянемо випадок плитки Труше, де один елемент дизайну може бути представлено чотирма різними способами:

Змінюючи малюнок у плитках, можна побудувати нескінченний набір складних зображень.

Зверніть увагу на функцію rotateTilePattern(), яка розбиває простір на чотири комірки та призначає кожній кут повороту.

Створення власних правил

Створення процедурних патернів — це розумова вправа з пошуку мінімальної кількості елементів для багаторазово використання в просторі. Ця давня практика. Ми, як біологічний вид, використовуємо сітки та візерунки для декорування текстилю, підлоги та границь об'єктів протягом тривалого часу: від візерунків декоративних звивистих ліній (меандрів) стародавньої Греції до китайських решітчастих патернів. Насолода від повторення та варіацій захоплює нашу уяву. Знайдіть час, щоб переглянути декоративні візерунки та подивитися як художники з дизайнерами балансуються між передбачуваністю порядку й несподіваністю варіацій та хаосу. Від арабських геометричних візерунків до розкішних африканських зображень на тканинах пролягає цілий всесвіт візерунків для натхнення та пізнання.

Franz Sales Meyer - A handbook of ornament (1920)

Цією главою ми закінчуємо розділ про алгоритмічне малювання. У наступних розділах ми дізнаємося, як привносити у наші шейдери трохи ентропії та створювати генеративні дизайни.