top of page
Поиск
Фото автораРостислав Кейван

Опасайтесь прозрачных пикселей

Обновлено: 17 июн. 2023 г.

В этом топике мы разберемся что такое пиксель его прозрачность и как он играет важную роль в отображении на экране.

Пиксель — сокращение от piсtures element, которое в свою очередь сокращается до pix element, это минимальный и неделимый элемент (точка), из которого состоит изображение на экране монитора.

Если собрать все пиксели вместе, то получим изображение, которые мы видим. Чем больше пикселей находится на единицу площади, тем более качественным будет изображение.



Альфа-канал - также известный как маска-канал, — это просто способ объединить переходную прозрачность с изображением.



Формат GIF поддерживает простую бинарную

прозрачность (когда любой пиксель может быть либо полностью прозрачным, либо абсолютно непрозрачным). Формат PNG позволяет использовать 254 или 65534 уровня частичной прозрачности.


Все три типа PNG-изображений («TrueColor», «GrayScale» и индексированная палитра) могут содержать альфа-информацию, хотя обычно она применяется лишь с «TrueColor» изображениями. Вместо того, чтобы сохранять три байта для каждого пикселя (красный, зелёный и синий, RGB), сохраняются четыре: красный, зелёный, синий и альфа, таким образом получается RGBA.


Если вы используете в своей игре спрайты с прозрачностью (а обычно так и бывает, как минимум для UI), то вам, вероятно, стоит уделить внимание к полностью прозрачным пикселям текстур (или «текселам»).



Даже если значение альфа-канала равно 0, с пикселем всё равно связано значение цвета. Этот цвет ни на что не влияет, так ведь? В конце концов, пиксель полностью прозрачен, кому есть дело до его цвета…


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


Пример искажений


Время для реального примера! Вот XMB моей PS3 (главное меню), просматриваются некоторые установленные демоверсии игр.

Сначала выбирается Limbo , я просто нажимаю «Вверх», чтобы переместить фокус на The Unfinished Swan


Начало.

Нажимаю «вниз». Limbo спускается вниз.

Фон становится белым.

Артефакты.

Видите, что произошло с областью логотипа Limbo?


Фон сменился на белый фон The Unfinished Swan и в результате «абсолютно белый» логотип Limbo отрисован поверх фона, который тоже полностью белый. Эта область должна быть полностью белой, тогда откуда взялись эти странные серые пиксели?


Вероятнее всего, искажение возникло из-за того, что текстура Limbo использует для полностью прозрачных пикселей неправильные цвета RGB.

Фильтрация текстур


Артефакты на самом деле возникают из-за того, как видеопроцессор фильтрует текстуру при рендеринге спрайта на экране. Давайте рассмотрим его работу на простом примере.


Вот небольшая пиксельная текстура с красным крестом размером 12x12

А вот его увеличенное изображение, шахматная клетка просто показывает, что это полностью прозрачная область со значением альфа-канала 0.

Можно использовать этот спрайт как значок для отображения в UI здоровья или как текстуру для игровой модели аптечки. (Хотя нет! На самом деле этого делать не стоит!)


Давайте создадим три версии этого спрайта, просто изменив значение цвета пикселей с нулевой альфа-прозрачностью.


Прозрачная область: зеленый


Прозрачная область: синяя


Прозрачная область: красная


Эти три спрайта выглядят на экране совершенно одинаково, правда? Это логично: мы всего лишь изменили значение цвета прозрачных пикселей, которые всё равно будут невидимыми.


Но давайте посмотрим, что происходит, когда эти спрайты находятся в движении. Вот увеличенное изображение, чтобы лучше видеть экранные пиксели:




Мы видим тут искажения! Коричневый оттенок у первого спрайта и фиолетовый у второго. У третьего всё правильно, именно так он должен выглядеть. Давайте рассмотрим синюю версию:


Как видите, проблема возникает, когда текстура не идеально выровнена по пикселям с пикселями экрана. Это можно объяснить билинейной фильтрацией, которую GPU выполняет при рендеринге спрайта на экране: при выборке текстуры GPU усредняет значения цвета ближайших соседей запрашиваемых координат как в вертикальном, так и в горизонтальном направлении.


Итак, если мы рассмотрим случай, когда спрайт смещен ровно на половину пикселя:


Каждый пиксель экрана будет сэмплировать текстуру спрайта прямо посередине между двумя текселами. Вот что происходит с пикселем, который вы видите слева: он извлекает текстуру спрайта посередине между сплошным красным текселем и прозрачным синим текселем. Усредненный цвет:




А это частично прозрачный фиолетовый, примерно такой:


Этот цвет, возвращённый сэмплером текстур, теперь будет примешан к альфа-каналу результату рендеринга (сплошному белому цвету).


Уравнение смешивания имеет вид:


Поэтому конечный цвет пикселя на экране будет примерно таким:




Это не то, что мы хотели.

Правильный результат, который получается, когда прозрачные пиксели красные, будет следующим:


Это билинейно интерполированное значение, которое затем смешивается и получается


Как же нам избежать этих неприятных артефактов?


Как избежать этой проблемы

Если вы художник: пусть всё просочится!

Если вы отвечаете за создание графических ресурсов, то обезопасьте свою работу и не доверяйте программистам и движку. Велика вероятность, что на каком-то этапе конвейера цвета прозрачных пикселей «просочатся» на окружающую их графику. Мы уже видели, как это бывает при билинейной фильтрации текстур, но так может произойти и при генерировании MIP-текстур…


Можно бороться с таким просачиванием цветов…

дополнительным просачиванием!


Исходный спрайт
















Только RGB












Под этим я подразумеваю то, что перед экспортом графики, нужно сначала сделать так, чтобы все непрозрачные пиксели «просочились» в значения RGB соседних прозрачных пикселей (это также называется заливкой (flood-filling) или контурной заливкой (edge-padding)). В этом случае когда прозрачные пиксели в процессе выполнения игры просочатся к своим непрозрачным соседям, то они хотя бы протекут с правильным цветом. На изображениях выше показан пример из реального мира: атлас спрайтов растительности, извлечённый из GTA V аматорами найденый мною на просторах интернета, с альфа-каналом и без него. Заметьте границу вокруг пикселей с ненулевой прозрачностью: прозрачные пиксели заимствуют цвета своих ближайших видимых соседей. Rockstar не случайно проделала всю эту работу. В этом процессе нам могут помочь инструменты: у Photoshop есть плагин Solidify, для Gimp тоже существует плагин Также будьте внимательны при экспорте значений RGB прозрачных пикселей, например, при сохранении PNG: многие программы по умолчанию отбрасывают данные RGB прозрачных пикселей и заменяют их при экспорте сплошным цветом (белым или чёрным), чтобы улучшить сжатие.

Джон Кармак также поддерживает этот подход :

Убедитесь, что цвета остаются одинаковыми на всем пути к краю, даже если альфа-канал равен 0. Очень часто можно увидеть смешанную графику с темной окантовкой вокруг них, потому что текстура переходит в (0 0 0 0) прямо на контуре. а не просто вырезает его в альфа-канале.

Как программист: используйте Premultiplied Alpha!

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

У вас может быть какой-нибудь инструмент для автоматизации цветового блефа, о котором мы говорили ранее, он будет запускаться во время импорта ассета. Но у вас есть гораздо лучшее и более надежное решение: альфа с предварительным умножением.


Подводим итог Итак, вернёмся к первоначальной теме: была ли проблема с логотипом Limbo действительно вызвана «мусором» в RGB прозрачных пикселей? Есть только один способ узнать это, поэтому я извлёк файл PNG из пакета демо /PS3_GAME/ICON0.PNG. На первый взгляд, изображение выглядит отлично, но давайте удалим альфа-канал, чтобы визуализировать полные значения RGB:


Оригинал

Что ж, вот оно: вместо какого-то сплошного белого везде отверстия «B» и «O» заполнены каким-то неправильным RGB, который затем просачивается и вызывает сбой, который мы видели ранее.


Проблема с этими артефактами заключается в том, что их трудно обнаружить. Я не замечал ничего плохого в логотипе Limbo , пока он не был отрисован поверх белого фона.

Не все знают о проблеме с самого начала, поэтому повышение осведомленности по этой теме не помешает.


Если вы художник, вы первая линия защиты, обратите внимание на то, какой цвет вы помещаете внутрь прозрачных пикселей. Если вы программист, подумайте о предварительно умноженном альфа-канале.


Обновление: для более глубокого анализа этой проблемы очень рекомендую пост Эрика Хейнса: «GPU предпочитают предварительное умножение» .


_________________________________________________________________________________


19 просмотров0 комментариев

Недавние посты

Смотреть все

Comments


bottom of page