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


NASA / WMAP science team

Шум

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

Ми відчуваємо повітря на нашій шкірі, сонце на обличчі. Світ такий яскравий та насичений. Кольори, текстури, звуки. На прогулянці ми не можемо не помітити поверхню доріг, каменів, дерев та хмар.

Непередбачуваність цих текстур можна назвати "випадковою", але вони не схожі на той рандом, з якими ми грали раніше. "Реальний світ" — це дуже багате й складне місце! Як ми можемо апроксимувати цю варіативність за допомогою обчислень?

Це питання Кен Перлін намагався вирішити на початку 1980-х років, коли йому доручили створити більш реалістичні текстури для фільму "Трон". У результаті він придумав елегантний алгоритм для генерації шуму за який потім отримав своєрідний Оскар. Нічого особливого)

Disney - Tron (1982)

Нижче наведено не класичний алгоритм шуму Перліна, але це хороша відправна точка для розуміння того, як генерувати шум.

У цих рядках ми робимо щось подібне до того, що робили в попередньому розділі. Ми ділимо безперервне число з рухомою крапкою (x) на цілу (i) і дробову (f) складові. Для отримання цілої частини "i" ми використовуємо floor(), а для дробової частини "f" — fract(). Потім ми застосовуємо rand() до цілої частини "x", що дає унікальне випадкове значення для кожного цілого числа.

Також ви бачите два закоментовані рядки. Перший інтерполює кожне випадкове значення лінійним чином.

y = mix(rand(i), rand(i + 1.0), f);

Розкоментуйте цей рядок, щоб побачити його роботу. Ми використовуємо дробове значення f, отримане після fract(), щоб за допомогою mix() зміксувати два випадкових значення.

Ми вже знаємо, що можемо використати краще рішення, ніж лінійна інтерполяція, чи не так? Розкоментуйте наступний рядок, щоб застосувати інтерполяцію smoothstep().

y = mix(rand(i), rand(i + 1.0), smoothstep(0., 1. ,f));

Зверніть увагу на те, як перехід між вершинами стає плавним. У деяких реалізаціях шуму програмісти віддають перевагу створенню власних кубічних кривих (наприклад, наступна формула) замість використання smoothstep().

float u = f * f * (3.0 - 2.0 * f ); // варіант кубічної кривої
y = mix(rand(i), rand(i + 1.0), u); // використання її в інтерполяції

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

Robert Hodgin - Written Images (2010)

Тепер настала ваша черга:

Двомірний шум

Тепер, коли ми знаємо, як створити одномірний шум (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.)).

Так само, якщо ми хочемо отримати тривимірний шум, то потрібно інтерполювати між вісьмома кутами куба. Ця техніка пов'язана з інтерполяцією випадкових значень, тому її називають value noise (шумом значення).

Як і з одномірним прикладом, ця інтерполяція не лінійна, а кубічна, яка плавно інтерполює будь-які точки всередині нашої квадратної сітки.

Погляньте на наступну функцію шуму:

Ми починаємо з масштабування простору у 5 разів (рядок 45), щоб побачити інтерполяцію між квадратами сітки. Потім у функції шуму ми ділимо простір на комірки. Дробову частину координати ми зберігаємо для використання всередині клітини, а цілу частину — як координату самої клітини. Ми використовуємо цілочисельне значення позиції, щоб обчислити координати чотирьох кутів комірки та отримати випадкове значення для кожного з них (рядки 23-26). Нарешті, у рядку 35 ми інтерполюємо між 4 випадковими значеннями кутів, використовуючи дробові позиції, які ми зберегли раніше.

Тепер ваша черга. Спробуйте наступні вправи:

Mark Rothko - Three (1950)

Використання шуму в генеративному дизайні

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

Inigo Quilez - Value Noise

Як ви виявили в попередніх вправах, значення шуму має тенденцію виглядати "блоковим". Щоб зменшити цей блоковий ефект, у 1985 році Кен Перлін розробив іншу реалізацію алгоритму під назвою градієнтний шум. Кен зрозумів як інтерполювати випадкові градієнти замість значень. Ці градієнти були результатом двомірної випадкової функції, яка повертає напрямки (у вигляді vec2) замість окремих значень типу float. Клацніть на наступне зображення, щоб побачити код та як він працює.

Inigo Quilez - Gradient Noise

Знайдіть хвилинку, щоб переглянути ці два приклади, за авторства Inigo Quilez, та зверніть увагу на відмінності між шумом значень та градієнтним шумом.

Подібно до художника, який розуміється на роботі пігментних фарб, чим більше ми знаємо про імплементацію шуму, тим краще ми можемо їх використовувати. Наприклад, якщо за допомогою значень двомірного шуму обертати простір зображення з прямими лініями, то можна створити наступний ефект закручування, схожий на текстуру деревини. Клацніть на зображення, щоб побачити код:

Wood texture

    pos = rotate2d(noise(pos)) * pos; // обертання простору
    pattern = lines(pos, .5); // малювання лінії

Ще один спосіб отримати цікаві візерунки за допомогою шуму – це розглядати його як поле відстаней та застосувати деякі трюки, описані в розділі про фігури.

Splatter texture

    color += smoothstep(.15, .2, noise(st * 10.)); // чорні бризки
    color -= smoothstep(.35, .4, noise(st * 10.)); // дірки на бризках

Третій спосіб використання функції шуму – це модуляція фігур. Для цього також потрібні певні трюки з розділу про фігури.

Для вашої практики:

Jackson Pollock - Number 14 gray (1948)

Покращений шум

Кен Перлін удосконалив свій оригінальний шум та зробив симплексний шум, що полягає в заміні кубічної кривої Ерміта ( f(x) = 3x^2-2x^3, яка є ідентичною до функції smoothstep()) на квінтичну інтерполяційну криву (криву п'ятого ступеня) ( f(x) = 6x^5 - 15x^4 + 10x^3 ). Це робить обидва кінці кривої більш "пласкими", тому кожна межа з'єднується з наступною плавніше. Іншими словами, ви отримуєте більш безперервний перехід між осередками. Ви можете побачити це, розкоментувавши другу формулу в наступному прикладі графіка (або перегляньте обидва рівняння тут).

Зверніть увагу на те, як змінюються кінці кривої. Ви можете прочитати більше про це у поясненнях самого Кена.

Симплексний шум

Кен Перлін не задовольнився успіхом свого алгоритму. Він гадав, що зможе досягти для нього більшої продуктивності. На Siggraph 2001 він представив "симплексний шум", у якому досяг наступних покращень у порівнянні з попередньою версією:

Я знаю про що ви думаєте... "Хто цей чоловік?" Так, його робота фантастична! Але серйозно, як він покращив алгоритм? Розберімось. Для двох вимірів він інтерполював 4 точки (кути квадрата), для трьох (див. реалізацію) та чотирьох вимірів нам потрібно інтерполювати вже 8 і 16 точок відповідно. Правильно? Іншими словами, для N вимірів вам потрібно плавно інтерполювати 2 у степені N точок (2^N). Але Кен розумно помітив, що хоча очевидним вибором форми, що заповнює простір, є квадрат, найпростішою фігурою у двомірному просторі є рівносторонній трикутник. Тому він почав із заміни квадратної сітки (яку ми щойно навчилися використовувати) на симплексну сітку рівносторонніх трикутників.

Симплексна форма для N-розмірності – це багатокутник з N + 1 кутами. Іншими словами, у двомірному просторі можна буде обчислювати на один кут менше, у тримірному – на 4 кути менше, а у чотиримірному – на 11 кутів менше! Це величезне покращення!

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

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

Далі, як описав Stefan Gustavson у статті "Simplex noise demystified": "...розглянувши цілі частини трансформованої координати (x, y) для точки, яку ми хочемо визначити, можна швидко визначити, яка саме клітинка з двох симплексів її вміщує. Порівнявши абсолютні величини x і y, ми можемо визначити, чи точка знаходиться у верхньому чи нижньому симплексі та обійти через три кутові точки."

У наступному коді ви можете розкоментувати рядок 44, щоб побачити перекіс сітки, а потім розкоментувати рядок 47, щоб побачити побудову симплексної сітки. Зверніть увагу, як у рядку 22 ми ділимо скошений квадрат на два рівносторонні трикутники, просто визначаючи, чи x > y ("нижній" трикутник) чи y > x ("верхній" трикутник).

Результатом усіх цих удосконалень є алгоритмічний шедевр, відомий як Симплексний шум. Нижче наведено GLSL-реалізацію цього алгоритму, розроблену за участі Ian McEwan та Stefan Gustavson (представлена у роботі "Efficient computational noise in GLSL"), яка занадто складна для простих освітніх цілей, але ви із задоволенням побачите, що вона менш загадкова, ніж можна було очікувати, а код короткий та швидкий.

Ian McEwan of Ashima Arts - Simplex Noise

Що ж... досить технічних нюансів, настав ваш час для використання цього ресурсу у якості нового засобу виразності:

У цьому розділі ми навчилися певного контролю над хаосом. Це була нелегка робота! Для того, щоб стати майстром з використання шуму, потрібні час та зусилля.

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

"Поговори з деревом, подружися з ним." Bob Ross