GrabDuck

У прозрачных пикселей тоже есть чувства или артефакты png'шек с прозрачностью

:

Поговорим о 2D-играх. Независимо от платформы, на которой они разрабатываются — почти всегда они будут использовать 3D-акселлераторы для вывода 2D-спрайтов (iOS, Android, PC… даже Flash уже это учится делать).

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

Вы попытаетесь наложить тайлы внахлест, но швы все равно останутся… И вы начнете ломать голову.

А дело все в злосчастных прозрачных пикселях! Оказывается, у них тоже есть цвет.

Для того, чтобы понять, почему это происходит, вы должны понять, каким образом GPU масштабирует текстуры. Он это делает не совсем так, как это делают графредакторы. И дело тут касается прозрачности.

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

О прозрачности и PNG.


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

Это изображение состоит из двух каналов — канал цвета (RGB) и альфа-канал (прозрачность). Вся загвоздка в том, что полностью прозрачные пиксели все равно имеют какое-то значение в канале цвета. И какое именно это будет значение — известно только софтине, которая сжимала PNG. По сути, эти цвета могут быть любыми.

В ситуации с изображением выше запросто может получиться такая картина:

Т.е. прозрачные пиксели будут иметь белый цвет. Но т.к. они полностью прозрачны — мы этого никогда не увидим и все будет ок.

Прозрачность, GPU и масштабирование.


Теперь давайте посмотрим, как видеокарта масштабирует текстуры с прозрачностью.

Для упрощения этого дела, она масштабирует отдельно канал цвета и отдельно — альфа-канал. Например, при масштабировании вышеупомянутой текстуры на 80% (баг проявится при любом скейле), мы получим такую картину:

Видите?

GPU смешал пограничные синие пиксели с теми, что за границей прозрачности (т.к. он скейлил канал цвета отдельно от альфы и ему было все равно, прозрачные они или нет). В результате пограничные пиксели смешались с белым цветом и приобрели совсем непонятный цвет.

Очевидно, если попытаться затайлить такой спрайт, мы явно увидим швы.

И, думаю, очевидно, почему от таких артефактов избавлены спрайты, граница которых постепенно сходит в прозрачность, а не резко скачет с 1 до 0.

Как бороться?


Теперь, когда мы знаем в чем дело, мы знаем, как с этим бороться. Нам нужно, чтобы прозрачные пиксели, прилегающие к границам, имели цвет, схожий с пограничными. При чем, если мы будем уменьшать мастштаб спрайта более чем в 2 раза, то нужно позаботиться об «окантовке» изображения шириной в несколько пикселей. Но как это сделать?

Самый простой способ, который я нашел — это создать второй слой в фотошопе, положить его под основной, размыть его blur'ом и выставить прозрачность в 1%. В результате, пиксели вокруг нашего изображения будут почти невидимыми (1% прозрачности), но гарантировано иметь цвет, схожий с пограничными. Конечно, эффект блюра подойдет не для каждого спрайта. Где-то можно создать 4 таких (1%) слоя, но не блюрить их, а просто сдвинуть в разные стороны…

В общем, надеюсь, кому-то эта информация окажется полезной.