Патерни
Шейдерні програми виконуються попіксельно, тому незалежно від того скільки ви повторюєте якусь фігуру, кількість обчислень залишається незмінною. Це означає, що фрагментні шейдери добре підходять для створення патернів — візерунків, що повторюються.
У цьому розділі ми збираємося застосувати дещо з попереднього матеріалу, щоб продублювати його кілька разів на полотні. Як і в попередніх розділах, наша стратегія базуватиметься на перемноженні просторових координат з діапазоном від 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 помножуються на однакове значення, то співвідношення сторін простору не змінюється. Відповідно форми також не матимуть викривлень та будуть такими, як очікувалося.
Для глибшого розуміння, спробуйте виконати деякі з наведених нижче вправ:
-
Помножте просторові координати на різні числа. Спробуйте різні значення з рухомою крапкою, а також різні значення для x та y.
-
Зробіть, для цього трюку з плиткою, функцію для повторного використання.
- Розділіть простір на 3 рядки та 3 стовпці. Знайдіть спосіб дізнатися, у якому стовпці та рядку знаходиться потік, і в залежності від цього змінити фігуру, що буде малюватися. Спробуйте зробити композицію з гри у хрестики-нулики.
Застосування матриць всередині патернів
Оскільки кожен підрозділ або комірка є зменшеною версією нормалізованої системи координат, яку ми використовували раніше, ми можемо застосувати до них такі ж самі матричні перетворення для переміщення, обертання та масштабування.
-
Подумайте про цікаві способи анімації цього візерунка. Подумайте про анімацію кольорів, форм і рухів. Зробіть три різні анімації.
- Відтворіть складніші візерунки, компонуючи різні форми.
- Комбінуйте різні шари патернів, щоб створити власні орнаменти шотландського тартану.
Патерни зі зміщенням
Припустимо, ми хочемо імітувати цегляну стіну. Розглядаючи стіну, ви можете побачити, що кожен другий її ряд зміщений на півцеглини по вісі 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, ви зможете побачити, як виглядає система координат, відображена у червоний та зелений кольори.
-
Спробуйте анімувати цей приклад, змінюючи зміщення відповідно до часу.
-
Зробіть ще одну анімацію, у якій парні ряди рухаються ліворуч, а непарні — праворуч.
-
Чи можете ви повторити цей ефект, але зі стовпцями?
- Спробуйте скомбінувати зсуви на вісі
x
таy
, щоб отримати щось на зразок наступного:
Плитка Труше
Тепер, коли ми навчилися визначати, чи знаходиться наша комірка в парному чи непарному рядку чи стовпці, можна повторно використовувати один елемент дизайну залежно від його положення. Розглянемо випадок плитки Труше, де один елемент дизайну може бути представлено чотирма різними способами:
Змінюючи малюнок у плитках, можна побудувати нескінченний набір складних зображень.
Зверніть увагу на функцію rotateTilePattern()
, яка розбиває простір на чотири комірки та призначає кожній кут повороту.
-
Закоментуйте, розкоментуйте та продублюйте рядки з 69 по 72, щоб скомпонувати нові зображення.
-
Змініть чорно-білий трикутник на інший елемент, наприклад: півколо, повернуті квадрати або лінії.
-
Запрограмуйте інші патерни, де елементи обернені відповідно до їхнього положення.
-
Створіть патерн, який змінює інші свої властивості відповідно до положення елементів.
- Подумайте про щось інше, не обов'язково про патерни, де ви можете застосувати принципи з цього розділу. Наприклад, гексаграми "I Ching":
Створення власних правил
Створення процедурних патернів — це розумова вправа з пошуку мінімальної кількості елементів для багаторазово використання в просторі. Ця давня практика. Ми, як біологічний вид, використовуємо сітки та візерунки для декорування текстилю, підлоги та границь об'єктів протягом тривалого часу: від візерунків декоративних звивистих ліній (меандрів) стародавньої Греції до китайських решітчастих патернів. Насолода від повторення та варіацій захоплює нашу уяву. Знайдіть час, щоб переглянути декоративні візерунки та подивитися як художники з дизайнерами балансуються між передбачуваністю порядку й несподіваністю варіацій та хаосу. Від арабських геометричних візерунків до розкішних африканських зображень на тканинах пролягає цілий всесвіт візерунків для натхнення та пізнання.
Цією главою ми закінчуємо розділ про алгоритмічне малювання. У наступних розділах ми дізнаємося, як привносити у наші шейдери трохи ентропії та створювати генеративні дизайни.