Магія текстур і кольорів. Створюємо візуальні ефекти за допомогою шейдерів



Компанія SUITSME, що входить до екосистеми бізнесів Genesis, розвиває інтерактивну платформу для всіх, кого цікавить мода. У застосунку SUITSME кожен може поекспериментувати з одягом та аксесуарами від відомих брендів і стилізувати свого аватара для участі в різноманітних івентах. Усе це побудоване на основі 2D-графіки.


Віталій Янчук, Unity-розробник і Tech Artist у SUITSME, в матеріалі для DOU розібрав базові методи розробки візуальних ефектів, теорію шейдерів, а також низку маніпуляцій із текстурами й кольором. Стаття буде корисною для VFX-художників-початківців, розробників усіх рівнів та інших спеціалістів, які цікавляться комп’ютерною графікою. Публікуємо стислий переказ матеріалу.



З чого почати. Графічний конвеєр


Маємо задачу — вдосконалити візуальний стиль продукту і створити кілька ефектів для тканин, які додали б шарму статичним речам.


Так виглядає базовий ефект для тканини:



А так — той самий ефект у готових образах:



Спочатку всі дані й текстури проходять певний шлях перед тим, як опинитися в готовому вигляді на екрані: спочатку на процесорі комп’ютера (CPU), а потім на графічному процесорі (GPU). Ці етапи називають графічним конвеєром, або ж Graphics Pipeline.



Спочатку геометрія, текстури й колір у загальному вигляді обробляються на рівні застосунку в CPU, за інструкціями, написаними C++ чи будь-якою іншою мовою. А далі — потрапляють до графічного процесора. Там спочатку обробляються вершини усіх геометричних фігур, а потім ця геометрія растеризується, тобто попіксельно зафарбовується. Растеризація та обробка геометрії відбуваються за шейдерним кодом, який зазвичай написаний на HLSL або Cg.

GPU не дає змоги ефективно проводити складні логічні операції, проте здатний робити масивні паралельні розрахунки.



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



Текстурні координати. Створюємо форми та розташування


Кожен піксель на текстурі має свої координати в UV-просторі (аналогічно до XY-координат) від 0 до 1 з кожної з координат в UnityEngine, починаючи з нижнього лівого кута.



Додавання векторної константи до UV відповідає за зміщення текстури. Якщо додати до U-координати UV-простору величину, що дорівнює 0.5, текстура зміститься на половину своєї довжини вправо. Прив’язавши це до таймера, отримуємо латеральний рух текстури.



Множення UV відповідає за масштабування текстури. Якщо помножити V на 2, текстура звузиться вдвічі по вертикалі й у той самий квадрат вміститься вже дві такі текстури.


Додавання відповідає за зсув текстури, а множення — за деформацію.

Розглянемо процес на прикладі ефекту, що імітує рефракцію від гарячого повітря.

Він складається з двох шарів:

  • зсув текстури шуму (додаємо векторну константу до UV-координат текстури шуму за таймером, у нас це вектор U=1 V=0 (1, 0), помножений на час одного кадру. Це означає, що текстура зміститься вправо на один період за одну секунду ігрового часу);

  • додавання отриманого результату до UV-координат іншої текстури.

Це має такий вигляд:



Використана текстура не зовсім проста. Це процедурно згенерований градієнтний шум, тому при анімації чи зміщенні він не повторює себе й водночас не має швів.

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



Для розтягнення застосовуємо множення UV-координат. Ефект для тканини майже готовий, але треба подбати про деталі. Тканина — складний матеріал, і при утворенні на ній хвиль змінюється її освітленість.


Кольорові координати


Фрагментні шейдери також допомагають контролювати колір кожного пікселю, що видно на екрані.

Майже кожен монітор комп’ютера показує колір у RGB-форматі — як комбінацію червоного, зеленого та синього різної яскравості. Тому й на графічному процесорі кожен піксель описується комбінацією трьох кольорів з яскравістю від 0 до 1.

Базово додавання цих кольорів один до одного працює таким чином:



В графіці використовуються різні режими змішування шарів, або ж Blend modes. Їх багато, проте всі вони містять хоча б одну з чотирьох базових операцій:

  • додавання кольорів (режим змішування Add або Linear Dodge) ARGB+BRGB — корисне для засвітлення без змін контрасту;

  • віднімання кольорів (режим змішування Subtract) ARGB-BRGB — корисне для затемнення з контрастом;

  • множення кольорів (режим змішування Multiply) ARGB*BRGB — корисне для затемнення без змін контрасту та маскування зображень;

  • ділення кольорів (режим змішування Divide) ARGB/BRGB — корисне для засвітлення з контрастом.

Кілька прикладів однієї й тієї ж маски в різних режимах:



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

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


Ось що відбудеться, якщо застосувати анімовану маску до текстури із зірочками в режимі Multiply:



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



Повернемося до нашого ефекту розвіювання тканини:

  • засвітимо ділянки на вершині хвилі;

  • затемнимо ділянки внизу хвилі.

Це допоможе спрощено передати світло і тінь. Для більш коректного зображення варто змінювати освітленість не від висоти хвилі, а від кута нахилу поверхні хвилі. А якщо мова про кут нахилу, то це — математична похідна. Тож якщо ми продиференціюємо текстуру за координатою U (ddx), то отримаємо більш фізично коректну картину зміни освітленості поверхні.



Згори — маска для засвітлення, знизу — маска для затемнення. Потрібно намагатись робити ефект так, щоб він не виходив з контексту, відповідав стилю і був доцільним.

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

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

Підписуйся на нашу розсилку та отримуй корисні матеріали першим!

Надаючи вашу електронну адресу, ви погоджуєтесь з нашою Політикою приватності.

Дякуємо, що підписалися.

image-from-rawpixel-id-5996033-png.png