Я админю группу по Blender много лет, и бывает отвечаю на вопросы. Вопросы бывают разные, на какие‑то просто ответить одним словом, фразой или предложением, а на какие‑то просто так не ответишь — нужно писать целую статью.
Вот, к примеру, кто‑то жалуется, у него свечение не сохранилось в PNG. Или это не свечение а полу‑прозрачный шейдер или огонь - не важно. В Blender есть, а в PNG нет — баг какой‑то. И как тут ответить одним сообщением? Тут и про разные типы альфа‑канала надо рассказать, и почему они нужны и для чего используются, и какие‑то способы проблему обойти нужно дать, потому что теория теорией, а что делать‑то?

Два формата альфы
Начнём сначала. То что на свете существует два типа альфа‑канала люди в основном узнают либо когда сталкиваются с этой проблемой, либо никогда. Серьёзно. Ты можешь в совершенстве владеть 3д программой и даже запаковывать в альфа‑канал, например, roughness для HDRP, но при этом даже не догадываться, что альфа‑канал может быть в разных форматах. Обычно разные альфы не вызывают проблем — они автоматически конвертируются, правда не всегда удачно. Либо проблемы не замечаются.
Мне нравится как рассказывает об этих форматах Алан Меликджанян, если у вас хорошо с английским, рекомендую посмотреть. Начинает он так. Раньше, в аналоговые времена, когда фильмы снимали на плёнку, чтобы сделать коллаж из нескольких видео, нужно было один кадр проэкспонировать с маской, а второй кадр с этой же маской, но инвертированной. Полученные изображения нужно проявить на одну плёнку. Прошло время, люди перешли на цифру, но по сути ничего не поменялось, только вместо плёнки теперь нули и единицы, а вместо света, используемого при экспонировании — математика. Так в цифровом мире первый этап заменили умножением (MULTIPLY), а второй сложением (ADD). Почему? Удобно с точки зрения математики.

А еще с приходом цифры люди догадались, что можно сохранить альфа‑канал вместе с самим изображением, так появились форматы GIF и PNG. С гиф всё просто — пиксель либо прозрачный, либо нет. Но для любого формата сложнее GIF возникает «серая зона» — промежуточная область — где пиксель полупрозрачный. Серые значения в альфе дают антиалайзинг по краям, и вот тут‑то обычно и начинается путаница с premultiplication.
Straight alpha
Во многих 2D‑редакторах и в вебе используется так называемый straight alpha (он же unassociated). Он миксует верхний слой со слоями снизу в пропорции, указанной в альфа‑канале. Всё просто: указано 50 процентов — берём половину верхнего слоя и половину нижнего. Как смеситель в ванной мешает горячую и холодную воду:

Математически это можно выразить так: чтобы получить результат смешивания, нужно цвета верхнего слоя умножить на альфа‑канал, а цвета нижнего слоя (или результат смешивания всех нижних) умножить на его инвертированное значение. Мы это уже видели в виде схемы сверху, можем продублировать формулой:
2D‑редакторам проще работать с таким форматом: ластик меняет только альфа‑канал, а картинка остаётся без изменений. При желании можно взять анти‑ластик и вернуть картинку обратно, ничего не потеряв. А ИИшкам можно кодировать секретные меседжи в прозрачных частях изображений
Premultiplied (associated) — формат композа и 3D
В рендере и композе при установке альфа‑канала на 50 процентов мы не получим 50 процентов графической прозрачности: на поверхности может быть блик — он перекроет изображение снизу, хотя прозрачность всё равно останется на уровне 50 процентов.

Как это работает? Здесь используется другой тип альфа‑канала — premultiplied (associated). Помните первый этап, когда пиксели исходного изображения умножаются на альфа‑канал? В отличие от straight, считается что умножение уже выполнено перед сохранением файла, и еще раз умножать не нужно. Отсюда и название pre + multiplied — предварительно умноженный.
На визуальном уровне premultiplied alpha показывает не в какой пропорции брать слои, а сколько света, идущего снизу, блокируется слоем. Там, где у straight альфа‑канал на нуле, картинка всегда полностью прозрачна, а у premultiplied — не всегда: в этом месте цвета добавляются, и могут формироваться свечение или блики.

И зачем такое городить, скажете вы? Неужели нельзя обойтись обычным альфа каналом?
Чтобы сделать такое в 2D‑редакторе с straight alpha, вам нужно два слоя: один обычный, второй со свечением в режиме смешивания Add. Тогда как premultiplied alpha может иметь полупрозрачные и светящиеся области одновременно в одном слое.


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

Обратите внимание, что у straight alpha пиксель с краев яркий пока альфа канал хотя бы чуть‑чуть больше нуля. Уже потом, на этапе композитинга, альфа канал будет умножен на цвет и цвета с краев перестанут быть резкими. А вот композитинг premultiplied alpha должен исключать второй этап, изображение идет сразу на этап сложения, поэтому у premultiplied пиксели по краям сразу темные.

И вот если случайно изображение с premultiplied alpha попадет в обычный композитинг, пиксели по краям «затемнятся» 2 раза — один раз на этапе сохранения, а второй раз в композе, и вокруг объектов появится черная кайма:

Мне иногда писали, но ведь в Blender, у меня картинка с прозрачностью, я же её вижу. А в PNG — ее нет.
На что я отвечаю, нет, в Blender вы не видите картинку с прозрачностью — вы видите результат композитинга этой картинки на серый фон с квадратиками.
В Blender используется premultiplied композитинг, в PNG — straight alpha. Мы уже знаем, что чтобы получить из straight alpha формат premultiplied, нужно цвета изображения перемножить с альфа каналом. А чтобы сохранить в PNG, нужно сделать наоборот, то есть на этот альфа канал разделить. Это, естественно, не вызовет никаких проблем до тех пор пока не придется делить на ноль.
И пока математики не придумали как нам делить на ноль, давайте разберем конкретный пример — свечение вокруг объекта. Blender делает его легко и просто: добавляет размытое изображение поверх того что есть, оставляя альфа‑канал нетронутым. И если мы проверим область свечения вокруг объекта — она действительно полностью прозрачна:

При сохранении в PNG альфу нужно привести к straight — если вы этого не сделаете, как вы помните, получится черная кайма. Но что делать с фоном? Как вы помните, нужно разделить цвет фона на 0 (полная прозрачность).
Тут вы скажете: да ладно тебе заливать, что за ерунда. Сделай цвет белым, а яркость пикселя переведи в альфа канал — и PNG все будет прекрасно!
Сама модель straight умеет только миксовать слой и фон, а не добавлять свет поверх. Даже если руками нарисовать альфу вокруг объектов, а цвет сделать ярким, вместо добавления получится смешивание — да, это сработает с белым цветом, но все цвета кроме белого будут блеклыми.
Так что‑же с этим делать?
Неужели нет способа сохранить свечение? Есть несколько способов, но они не идеальны.
EXR - для композа
Вы можете использовать EXR — там premultiplied alpha, если изображения нужны для композа, это идеальный вариант. Минус — Blender сохраняет EXR без цветовой трансформации. Еще он тяжелее PNG и хуже открывается в бытовых просмотрщиках.
Для 2D-программ - два слоя
Как перенести свечение в 2D‑программу, которая знает только straight alpha?
Сохраните изображение без альфа‑канала — только RGB. Альфа‑канал инвертируйте и сохраните отдельно — это holdout для фона. В графическом редакторе: инвертированной альфой через Multiply затемняете/маскируете фон, сверху RGB в режиме Add. Картинка будет идентична тому, как она выглядит после рендера.



Но что если всё‑таки нужен формат PNG?
Честного перевода, как мы уже поняли, нет — но приближение иногда лучше, чем ничего. Давайте попробуем это сделать.
Давайте возьмём для примера этот рендер обезьянок с эффектом свечения.

В первую очередь возьмём ноду Alpha Convert и переведём её в режим Premultiplied. При сохранении в PNG Blender будет переводить изображение в straight alpha, и нам нужно нивелировать этот эффект.

Распределим цвет на составляющие HSV. Поскольку правки нужны только в прозрачной области, выделим эту часть с помощью ноды ColorRamp. В зависимости от задачи вы можете взять больше полупрозрачных областей. Hue и Saturation оставляем без изменений.

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

Степень свечения у нас регулируется альфа‑каналом. Однако мы подрегулируем её с помощью кривых — отредактируйте её на свой вкус. Чем выше середина кривой, тем сильнее будет виден эффект свечения.

В результате должно получиться что‑то такое:


Этот способ не заменит вам настоящего premultiplied: свечение не такое чистое и ровное, местами меняется цвет, блики сиреют. Как видите, способ не идеальный и всё равно приводит к потере цветовой информации. К тому же на границах непрозрачных объектов может возникнуть ореол. Однако, такой способ всё же лучше, чем ничего.
Что еще посмотреть — почитать:
Главный баг репорт по этой проблеме
Ранее я делал видео на эту тему на YouTube.
Упоминаемое видео от Алана Меликджаняна (Captain Disillusion) на английском
Моя телега, где я рассказываю про свой мультфильм и аддоны для Blender
nin-jin
В правой картинке, очевидно, зашит чёрный фон, так что на любом другом фоне она будет выглядеть криво - с тёмной окантовкой. Зачем такой формат "прозрачности" хоть кому-то нужен остаётся загадкой.
Mixail_Soluyanov Автор
Да, если смотреть только на RGB, кажется, будто справа «зашит чёрный фон». На самом деле это не фон, а уже выполненное умножение цвета на альфу.
Такую картинку нельзя просто положить на другой фон как обычный PNG. Её композят так:
Тогда тёмная кайма не появляется: поскольку изображение сверху добавляется через ADD. Напомню ADD это операция когда цвета становятся ярче, но никак не темнее. Кайма возникает, когда premultiplied принимают за straight и умножают на альфу второй раз — об этом как раз абзац про чёрный контур вокруг огня.
Зачем так хранить:
в одном слое можно держать (и, главное, рендерить) и полупрозрачность, и свечение (огонь, glare, блик), это я указал в статье
при мипмапинге и фильтрации такая альфа ведёт себя лучше;
рендер, Nuke, Fusion, работают именно с таким типом альфы. Это - стандарт композа.