Альфа канал
Концепция альфа канала очень проста. Вместо того, чтобы просто записывать знрачения RGB, мы будем
записывать RGBA:
// Выходные данные. Теперь это vec4
// Выходные данные. Теперь это vec4
out vec4 color;
Первые три компонента как были xyz так и остаются ими, а вот четвертый – а:
Первые три компонента как были xyz так и остаются ими, а вот четвертый – а:
color.a = 0.3;
Основная непонятность – альфа=непрозрачность. То есть альфа
= 1 – предмет польность непрозрачный, а альфа = 0 – полностью прозрачный.
Тут мы просто захардкодили значение альфа канала в шейдере в
значение 0.3, но обычно это значение берут из RGBA текстуры
(формат TGA поддерживает альфа канал, а библиотека GLFV поддерживает
формат TGA).
А вот и результат. Не забудьте выключить отсечение обратных
поверхностей(glDisable(GL_CULL_FACE). Так как теперь мы можем смотреть сквозь предмет,
и поэтому должны видеть обратную сторону.
Порядок имеет значение!
На предыдущем скриншоте все, вроде бы как неплохо, но это
просто потому, что нам повезло.
Проблема
Давайте нарисуем два квадрата с 50% прозрачностью, один
зеленый, и один красный. Как вы видите, результирующий цвет зависит от того,
какой из квадратов находится сзади.
Как оказывается, это достаточно сложная проблема. Вот почему
в играх не часто можно видеть множество прозрачных объектов.
Простое решение
Самым простым решением будет отсортировать все прозрачные
треугольники. Да, ВСЕ прозрачные треугольники.
- Сначала рисуем непрозрачные объекты, чтобы потом Z буфер мог автоматом отсечь все невидимые прозрачные треугольники.
- Сортируем прозрачные треугольники от самого дальнего до ближнего.
- Рисуем прозрачные треугольники.
Вы можете сортировать все что угодно с помощью функций qsort
в С, или std::sort в С++. Я тут не буду вдаваться в подробности, так как…
Проблема
- Мы можем напороться на ограничение пропускной способности. Каждый фрагмент будет перезаписываться 10, 20 раз, а может быть и больше. А это уж слишком для несчастной шины памяти. Обычно Z буфер отсекает достаточно далекие фрагменты, но тут мы вручную отсортировали треугольники, поэтому Z буфер уже непригоден.
- Это придется повторять каждый раз для каждого пикселя(так как мы используем 4xMSAA) если только не применять какие-нибудь хитрые оптимизации.
- Сортировка занимает время.
- Если вам необходимо будет сменять текстуры, или еще хуже – шейдер, то будут вообще дикие тормоза. Не делайте этого.
Хорошей практикой будет:
- Ограничить количество прозрачных полигонов.
- Использовать один и тот же шейдер и одну и ту же текстуру для всех треугольников.
- Если они должны выглядеть по-разному, все равно пользуйтесь одной текстурой, можно даже и большой.
- Если вы можете избежать сортировки, а результат приемлемый, то считайте, что вам повезло.
Порядконезависимая прозрачность
Существуют другие техники которые стоит почитать, если в
вашем приложении нужно действительно много прозрачностей:
- The original 2001 Depth Peeling paper: очень точная, но не быстрая.
- Dual Depth Peeling : немного улучшенный алгоритм.
- Несколько работ с сортировкой. Используется массив фрагментов который сортируется прямо в шейдере
- ATI’s Mecha Demo : хороший и быстрый алгоритм, но достаточно сложный для реализации. Требует современного железа. Использует связанный список фрагментов.
- Cyril Crassin’s variation on the ATI’s technique : еще более запутанный алгоритм.
Однако попробуйте обратить внимание, что даже в современных
играх редко когда используется больше одного уровня прозрачности.
Функция блендинга
Для того, чтобы предыдущий код заработал нам нужно настроить
функцию блендинга.
// Включаем блендинг
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
что означает:
Новый цвет во фреймбуфере
=
Текущий альфа во фреймбуфере * текущий цвет во фреймбуфере+ (1-текущая альфа во фреймбуфере)*результирующий цвет шейдера
Текущий альфа во фреймбуфере * текущий цвет во фреймбуфере+ (1-текущая альфа во фреймбуфере)*результирующий цвет шейдера
Комментариев нет:
Отправить комментарий