Альфа канал

Концепція альфа каналу досить проста. Замість використання RGB, ви використовуєте RGBA :

// Вихідні дані : тепер це vec4
out vec4 color;

перші три компоненти все ще доступні за допомогою оператора .xyz, а о прозорість - .a :

color.a = 0.3;

Не зовсім очевидно, та альфа це “непрозорість”, тому альфа = 1 - повна непрозорість, альфа = 0 - повна прозорість.

Тут ми просто використовуємо альфа канал рівний 0.3, та ви можете захотіти щось своє чи прочитати з RGBA текстури (TGA підтримує альфа канал, GLFW підтримує TGA).

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

Порядок має значення !

Попереднє зображення виглядає непогано, але це тому, що нам пощастило.

Проблема

Тепер у нас намальовано два квадрата с прозорістю 50%, зелений та червоний. Тепер повинно бути видно, что порядок має значення, вихідний колір дає певні підказки для очей для правильного сприйняття.

Цей феномен також видно і в нашій сцені. Давайте змінимо трішки позицію перегляду :

Тепер видно, що це може бути серйозною проблемою. Ви ніколи не бачили скільки прозорості в іграх, чи не так?

Просте рішення

Просте рішення в тому, що би відсортувати всі прозорі трикутники. Так, всі прозорі трикутники.

  • Намалювати всі непрозорі складові світу і буфер глибини зможе відкинути всі сховані прозорі трикутники
  • Відсортувати всі прозорі трикутники від дальніх до ближніх
  • Намалювати прозорі трикутники

Ви можете використати qsort (в C) чи std::sort (в C++). Я не буду заглиблюватись в деталі, тому що…

Застереження

Так буде працювати (більше про це в наступній секції), але:

  • Швидкість заповнення обмежена. Кожний фрагмент буде записаний 10, 20 раз, можливо більше. Це погано для повільної шини пам’яті. Зазвичай буфер глибини дозволяє відкинути достатньо “далекі” фрагменти, але зараз, Ви самі сортуєте їх і буфер глибини не потрібен.
  • Ви будете робити це 4 рази на піксель (ми використовуємо 4xMSAA), якщо тільки не використовувати більш якісні оптимізації.
  • Сортування всіх прозорих трикутників - це досить довго
  • Якщо Вам потрібно перемикати текстури чи, що ще гірше, шейдери на кожний трикутник, то у Вас будуть серйозні проблеми з продуктивністю (швидкістю виконання). Не робіть так.

Більш краще рішення зазвичай є:

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

Прозорість, що не залежить від порядку

Варто вивчити ряд сучасних технік, якщо ваш рушій дійсно потребує надсучасної прозорості:

  • The original 2001 Depth Peeling paper: результати з точністью до пікселя, проте повільно.
  • Dual Depth Peeling : невеличке покращення
  • Деякі статті по сортування методом комірок. Використовується масив фрагментів, сортування за глибиною в шейдері.
  • ATI’s Mecha Demo : гарний та швидкий, але з складний в реалізації, потребує сучасного заліза. Використовує зв’язаний список фрагментів.
  • Cyril Crassin’s variation on the ATI’s technique : ще складніша реалізація

Зверніть увагу, що навіть сучасні ігри (наприклад, Little Big Planet), що запускаються на потужних консолях, використовують тільки один шар прозорості.

Функція змішування (blend)

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

// Дозволити змішування (blending)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Що значить :


New color in framebuffer =
           current alpha in framebuffer * current color in framebuffer +
           (1 - current alpha in framebuffer) * shader's output color

Приклад для зображення вище, з червоним на верху:

new color = 0.5*(0,1,0) + (1-0.5)*(1,0.5,0.5); // (червоний був змішаний з білим фоном)
new color = (1, 0.75, 0.25) = the same orange