Advertisement
  1. Game Development

 Посібник для початківців для кодування графічних шейдерів

Scroll to top
Read Time: 10 min
This post is part of a series called A Beginner's Guide to Coding Graphics Shaders.
A Beginner's Guide to Coding Graphics Shaders: Part 2

() translation by (you can also view the original English article)

 Вчимося писати графічні шейдери-це навчитися використовувати міць GPU, з тисячами ядер все працює паралельно. Це вид програмування, який вимагає іншого мислення, але розкривши його потенціал, і варто початковому неприємностей.

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

 Сцена в Minecraft, до і після застосування шейдерів.

Мета даного посібника

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

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

 Так що ж таке Шейдер?

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

Шейдери пишуться в спеціальному затінення мову. Не хвилюйтеся, вам не доведеться виходити на вулицю і вивчати абсолютно новий мову; ми будемо з використанням glsl (OpenGL для мови для заливки), який є с-подібною мовою.  (Є купа затінення мовами там для різних платформ, але так як всі вони адаптовані для виконання на GPU, вони всі дуже схожі)

Давайте стрибати!

 Ми будемо використовувати ShaderToy для цього підручника.  Це дозволяє почати програмування шейдерів прямо в браузері, без необхідності що-небудь налаштовувати!  (Він використовує webgl для візуалізації, тому вам знадобиться браузер, який може підтримувати це.) Створення облікового запису необов'язково, але зручно для збереження коду.

 Примітка: ShaderToy знаходиться в бета-версії на момент написання цієї статті.  Деякі малі UI/деталі синтаксис може трохи відрізнятися.

Після натискання кнопки Новий Шейдер, що ви повинні побачити щось на зразок цього:

Ваш інтерфейс може виглядати дещо інакше, якщо Ви не ввійшли в систему.

 Ваш інтерфейс може виглядати дещо інакше, якщо Ви не ввійшли в систему.

Маленьку чорну стрілку внизу, що натиснути, щоб скомпілювати код.Що відбувається?

Я хотіла пояснити, як шейдери працюють в одному реченні. Чи готові ви? Тут йде!

 Єдиною метою шейдер-повернення чотирьох чисел: Р, Р, Б,А.

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

Маючи це на увазі, давайте спробуємо повертаючи екран червоним кольором. У rgba (червоний, зелений, синій, і "Альфа", який визначає прозорість) значення від 0 до 1, тому все, що нам потрібно зробити, це повернути Р,Г,Б,А = 1,0,0,1. ShaderToy очікує остаточного кольору пікселя, який буде зберігатися в fragColor.

1
void mainImage( out vec4 fragColor, in vec2 fragCoord )
2
{
3
    fragColor = vec4(1.0,0.0,0.0,1.0);
4
}

 Мої вітання!  Це ваш перший працюючий шейдер!

 Завдання: ви можете змінити його колір на сірий?

 vec4-це просто тип даних, тому ми можемо оголосили наш колір в якості змінної, ось так:

1
void mainImage( out vec4 fragColor, in vec2 fragCoord )
2
{
3
    vec4 solidRed = vec4(1.0,0.0,0.0,1.0);
4
    fragColor = solidRed;
5
}

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

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

 Шейдер Входи

Піксельний шейдер кілька змінних для використання.  Найбільш корисним для нас є fragCoord, який тримає піксель по X і Y і Z, якщо ви працюєте в 3D) координат.  Давайте спробуємо зафарбувати всі пікселі на ліву половину екрану чорне, і всі, хто на праву половину червоний:

1
void mainImage( out vec4 fragColor, in vec2 fragCoord )
2
{
3
    vec2 xy = fragCoord.xy; //We obtain our coordinates for the current pixel

4
    vec4 solidRed = vec4(0,0.0,0.0,1.0);//This is actually black right now

5
    if(xy.x > 300.0){//Arbitrary number, we don't know how big our screen is!

6
        solidRed.r = 1.0;//Set its red component to 1.0

7
    }
8
    fragColor = solidRed;
9
}

 Примітка: для будь-якого vec4, ви можете отримати доступ до його компонентів і obj.х, кадриров.р, кадриров.З І obj.W або через об'єкт.р, кадриров.р, кадриров.б, кадриров.а.  Вони еквівалентні; це просто зручний спосіб іменування їх, щоб зробити ваш код більш читабельним, так що коли інші бачать в obj.р, вони розуміють, що obj являє собою колір.

 Ви бачите проблеми з вище код? Спробуйте натиснути на кнопку Go fullscreen в правому нижньому куті вікна попереднього перегляду.

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

 Якщо щось не вбудований в змінної, ви можете відправити цю інформацію від центрального процесора (основної програми) для ДП (шейдер).  ShaderToy ручки, що для нас.  Ви можете побачити всі змінні, які передаються в шейдер Шейдер вкладці "параметри".  Змінні, які передаються в цьому випадку з CPU на GPU називається однорідним в glsl.

Давайте покращимо наш код вище, щоб правильно отримати центрі екрану.  Нам потрібно використовувати шейдер введення iResolution:

1
void mainImage( out vec4 fragColor, in vec2 fragCoord )
2
{
3
    vec2 xy = fragCoord.xy; //We obtain our coordinates for the current pixel

4
    xy.x = xy.x / iResolution.x; //We divide the coordinates by the screen size

5
    xy.y = xy.y / iResolution.y;
6
    // Now x is 0 for the leftmost pixel, and 1 for the rightmost pixel

7
    vec4 solidRed = vec4(0,0.0,0.0,1.0); //This is actually black right now

8
    if(xy.x > 0.5){
9
        solidRed.r = 1.0; //Set its red component to 1.0

10
    }
11
    fragColor = solidRed;
12
}

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

 Від роздвоєння до градієнт

 Цей градієнт повинен бути досить легким.  Колірні значення від 0 до 1, і наші координати змінюються від 0 до 1, а також.

1
void mainImage( out vec4 fragColor, in vec2 fragCoord )
2
{
3
    vec2 xy = fragCoord.xy; //We obtain our coordinates for the current pixel

4
    xy.x = xy.x / iResolution.x; //We divide the coordinates by the screen size

5
    xy.y = xy.y / iResolution.y;
6
    // Now x is 0 for the leftmost pixel, and 1 for the rightmost pixel

7
    vec4 solidRed = vec4(0,0.0,0.0,1.0); //This is actually black right now

8
     solidRed.r = xy.x; //Set its red component to the normalized x value

9
    fragColor = solidRed;
10
}

І вуаля!

 Завдання: чи зможете ви перетворити це у вертикальний градієнт? Щодо діагоналі?  А як щодо градієнта з більш ніж одним кольором?

 Якщо ви граєте навколо з цим достатньо, ви можете сказати, що верхній лівий кут має координати (0,1), а не (0,0).  Це важливо тримати в розумі.

Нанесення Зображень

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

 Якщо б ми програмували на нормальній платформі, ми повинні відправити наші зображення (або текстури) в ГПУ як єдиного, так само, як ви б відправили Дозвіл екрану.  ShaderToy піклується про те, що для нас. Є чотири вхідних каналу по дну:

Чотири вхідних каналу ShaderToy.

 Натисніть на iChannel0 і виберіть будь-текстури (зображення) Вам подобається.

 Як тільки це буде зроблено, тепер у вас є зображення, яке передається в шейдер.  Є одна проблема, однак: немає функція drawimage() функція.  Пам'ятайте, єдине, що піксельний шейдер може зробити-це змінити колір кожного пікселя.

 Так що якщо ми можемо тільки повернути колір, як ми малюємо нашу текстуру?  Нам потрібно зіставити поточний піксель шейдер для відповідного пікселя на текстуру:

 Пам'ятайте, верхній лівий піксель екрана має координати (0,1), тоді як верхній лівий піксель текстури має координати (0,0), тому ми повинні перевернути вісь Y.

 Ми можемо зробити це, використовуючи функцію texture2d(текстури,координати), який бере текстури і (х, Г) пари координат у якості вхідних даних, і повертає колір текстури в цих координатах як vec4.

 Ви можете зіставити координати на екрані будь-яким зручним для Вас способом.  Можна намалювати всю текстуру на чверть екрану (пропускаючи пікселів, зменшити її масштаб) або просто намалювати частина текстури.

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

1
void mainImage( out vec4 fragColor, in vec2 fragCoord )
2
{
3
    vec2 xy = fragCoord.xy / iResolution.xy;//Condensing this into one line

4
    xy.y = 1.0 - xy.y;
5
    vec4 texColor = texture2D(iChannel0,xy);//Get the pixel at xy from iChannel0

6
    fragColor = texColor;//Set the screen pixel to that color

7
}

 Отже, ми отримали наш перший образ!

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

 Давайте спробуємо змінити це за допомогою градієнта, аналогічного тому, що ми робили вище:

1
texColor.b = xy.x;

 Вітаємо, ви тільки що зробили ваш перший пост-обробки ефект!

 Завдання: чи Можете ви написати шейдер, який робить зображення чорно-біле?

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

 Додавши Якийсь Рух

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

1
void mainImage( out vec4 fragColor, in vec2 fragCoord )
2
{
3
    vec2 xy = fragCoord.xy / iResolution.xy; // Condensing this into one line

4
       xy.y = 1.0-xy.y; // Flipping the y

5
    vec4 texColor = texture2D(iChannel0,xy); // Get the pixel at xy from iChannel0

6
       texColor.r *= abs(sin(iGlobalTime));
7
    texColor.g *= abs(cos(iGlobalTime));
8
    texColor.b *= abs(sin(iGlobalTime) * cos(iGlobalTime));
9
    fragColor = texColor; // Set the screen pixel to that color

10
}

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

 Виклик: ви можете зробити шейдер, який змінює зображення і назад від чорно-білого до повнокольорового?

Зверніть увагу на налагодження шейдерів

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

Висновок

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

 Одна річ, я не згадав у цій статті, є вершинних шейдеров.  Вони, як і раніше, написані однією мовою, окрім вони біжать на вершину замість кожного пікселя, і вони повертають позиції, а також колір.  Вершинні шейдери, як правило, відповідає за проектування 3D-сцени на екран (те, що вбудовано в більшість графічних движків). Піксельні шейдери відповідають за багато просунуті ефекти ми бачимо, так ось чому вони знаходяться в центрі нашої уваги.

 Останній виклик: чи зможете ви написати шейдер, який знімає зеленим екраном у відео на ShaderToy і додає ще одне відео в якості фону для першого?

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

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Game Development tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.