Premultiplied alpha
Внимание! Этот документ ещё не опубликован.
Автор: FordPerfect
Статья находится в работе.
Статья посвящена premultiplied alpha. Этот метод композиции изображений (блендинга) обладает рядом значимых преимуществ и почти лишён недостатков. Однако (несмотря на то, что метод был введён в 1984 году), он недостаточно хорошо известен - и осознаваем - среди графических программистов. Помочь исправить данную ситуацию и призвана эта статья.
Что такое premultiplied alpha
Свойства
Фильтрация
Ассоциативность
Единое выражение для альфа- и аддитивного блендинга
Переход от обычного блендинга
Исходные изображения
Режим блендинга
Изменение цвета
Когда "обычная" альфа предпочтительнее
Гамма-корректность
Ссылки
Что такое premultiplied alpha
Premultiplied alpha (PMA) - это способ интерпретации компонент RGBA. Он естественным образом задаёт и логику операций над цветами в этом представлении. Способ был предложен в 1984 г. в статье "Compositing Digital Images", T. Porter & T. Duff (да, это тот самый Том Дафф, автор Duff's device, изобретённого, кстати, примерно в то же время - в 1983 г.). Можно отметить, что статья уделяла не много внимания преимуществам premultiplied alpha, и рассматривала её в основном как оптимизацию.
Обычно в компьютерной графике цвет задаётся 3-мя компонентами RGB (интерпретация самих RGB - отдельная большая тема, которой эта статья касается лишь ограниченно).
Для задания полупрозрачности добавляется 4-я компонента, А. Она также называется альфой (α), и задаёт степень непрозрачности (англ. opacity) цвета.
Наиболее распространённый способ интерпретации цвета с полупрозрачностью, у которого, в виду его повсеместности, и названия толком нет (в английском встречается термин straight alpha; в статье далее по тексту он называется "обычным") состоит в следующем. RGB означают цвет, как и раньше, а альфа задаёт степень непрозрачности. Этот способ довольно интуитивен, но подобрать ему физическую модель несколько нетривиально. Можно представить стеклянную пластинку, на которую напылён тонкий слой краски заданного оттенка. RGB соответствует цвету краски, альфа - толщине (точнее непрозрачности) слоя.
Premultiplied alpha использует несколько более непосредственную модель. RGB обозначают вклад данного цвета, т. е., грубо говоря, количество энергии (точнее мощности в данном спектральном диапазоне (R, G или B)), которое данный объект добавляет изображению. Альфа задаёт степень непрозрачности, т. е. долю света заслонённых объектов, которую объект поглощает (так же, как и в предыдущем способе).
Соответственно, если у нас есть цвет, компоненты которого в "обычном" представлении заданы RGBA, то соответствующий ему цвет в premultiplied alpha, rgba, будет иметь вид
[r, g, b, a]=[R·A, G·A, B·A, A]
Примечание: значения компонент здесь принимаются вещественными, линейными, и (для alpha) - в диапазоне [0; 1]. Вопросам представления (кодирования) цвета посвящён раздел Гамма-корректность.
Видим, что RGB были домножены на альфу, чем и вызвано название ("premultiplied alpha" = "пре-домноженная альфа").
Рассмотрим, как в этих представлениях происходит композиция (блендинг) , т. е. получение из фонового (dst) цвета и цвета объекта (src), окончательного цвета (final)?
"Обычный" блендинг:
Cf=Cs·As+Cd·(1−As)
Af=As+Ad·(1−As)
Premultiplied alpha:
Cf=Cs+Cd·(1−As)
Af=As+Ad·(1−As)
Здесь и далее в статье C обозначает цветовые компоненты (R, G и B), если формулы для них совпадают по форме.
Свойства
Рассмотрим свойства premultiplied alpha блендинга, и то как они отличают его от "обычного" блендинга.
Фильтрация
Часто возникающая задача - это фильтрация изображения, т. е. получение цвета по значениям нескольких соседних пикселей. Очевидными примерами являются изменение размера изображения (resize) и билинейная интерполяция текстур. Другим примером фильтрации является размытие (blur).
Рис. 1
Рис. 2
Для наглядности рассмотрим следующий пример. Нужно получить билинейно интерполированное значение цвета в позиции между 4 текселями.
Прямолинейный подход - воспользоваться формулами ниже:
Cf=C00·(1−u)·(1−v)+C01·(1−u)·v+C10·u·(1−v)+C11·u·v
Af=A00·(1−u)·(1−v)+A01·(1−u)·v+A10·u·(1−v)+A11·u·v
Здесь u, v - интерполяционные коэффициенты. В частности, для u=v=0.5 выражения превращаются в средне арифметическое.
Именно так тексели интерполирует видеокарта.
Если вспомнить определение premultiplied alpha, то видно, что для неё эти формулы дают правильный результат - энергию и затенение интерполированного участка. Их можно понимать как параметры однотексельного квадратика с центром в данной точке (столь наглядная интерпретация справедлива для билинейной интерполяции, но не обязательно для других фильтров).
Легко видеть, что для "обычного" блендинга результат, вычисленный по данным формулам, будет неправильным. Как минимум очевидно, что цвет полностью прозрачного текселя будет влиять на результирующий цвет.
Зная, что результат для premultiplied alpha правильный, можно выразить формулы для "обычного" блендинга, переводом туда и обратно:
Cf=(C00·A00·(1−u)·(1−v)+C01·A01·(1−u)·v+C10·A10·A11·u·(1−v)+C11·u·v)/(A00·(1−u)·(1−v)+A01·(1−u)·v+A10·u·(1−v)+A11·u·v)
Af=A00·(1−u)·(1−v)+A01·(1−u)·v+A10·u·(1−v)+A11·u·v
Формулы довольно громоздкие, и более того, не соответствуют тому, как работает видеокарта.
На практике использование фильтров с "обычным" блендингом зачастую приводит к визуальным ошибкам, вроде чёрных контуров вокруг спрайтов. С этим обычно борются добавлением вокруг изображения бордюра цвета ближайшего пикселя, но этот хак лишь частично исправляет ситуацию. Кроме того он приводит к дополнительным проблемам: некоторые редакторы любят выставлять цвет прозрачных пикселей в чёрный; и также чёрный цвет для таких пикселей устанавливают некоторые форматы, например DXT1.
Ассоциативность
Что такое ассоциативность? Оператор (назовём его #) ассоциативен, если (a # b) # c = a # (b # c). Примеры ассоциативных операций: сложение вещественных чисел, умножение матриц (эта операция ассоциативна хотя и не коммутативна).
Блендинг изображения src поверх фона dst можно понимать как функцию от двух аргументов color=blend(src,dst), что можно также записывать в инфиксной форме: color=src BLEND dst. Соответственно блендинг ассоциативен, если (a BLEND b) BLEND c = a BLEND (b BLEND c) другими словами (в функциональной форме): blend(blend(a,b),c)=blend(a,blend(b,c)).
Чем нам ценна ассоциативность блендинга? Нередко возникают задачи, в которых есть желание сблендить несколько изображений в промежуточный буфер, а уже его - на экран. Очевидные примеры: кеширование GUI, некоторые методы отрисовки полупрозрачной геометрии (напр. depth peeling). При этом, обычно, хочется, чтобы результат был тем же, что и у непосредственного блендинга на экран.
Легко проверить прямым вычислением, что premultiplied alpha blending ассоциативен, а "обычный" блендинг - нет.
Ниже приводятся выкладки: