«Нормальный» режим смешивания с проблемой OpenGL

8

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

Изображения для смешивания

Тестовые изображения

Это то, что я ожидаю (и что происходит в paint.net):

ожидаемый результат

Paint.Net Image Test

Очевидно, что функция смешивания opengl по умолчанию выглядит так (очень неправильно):

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

OpenGL Normal Blending Test

После тонны тестирования это самое близкое к созданию «хорошей» функции наложения:

glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

OpenGL Custom Blend Test

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

Кто-нибудь знает решение этой проблемы? Я использовал предварительно умноженную альфу в исходных кодах (хотя я не хочу этого делать, потому что это требует дополнительной работы, чтобы преобразовать каждый цвет, который я использую в моей игре, в предварительное умножение или просто написать некоторые вещи в каждом шейдере) и сделать это так. :

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (без предварительного умножения)

OpenGL Custom Blend Test

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

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (предварительно умноженные входы)

OpenGL Custom Blend Test

Единственная проблема в том, как мне избавиться от предварительного умножения, чтобы отобразить его на экране? Вероятно, потребуется дополнительный цикл рендеринга для каждой вещи, которую я смешиваю, и это кажется слишком сложным для этой проблемы, поэтому я все еще ищу ответ (интересно, что я ничего не могу найти по этому вопросу, потому что OpenGL настолько широко используется, что Я представляю, кто-то другой столкнулся с этой проблемой).

Источники:

Онлайн-тестирование функции смешивания - http://www.andersriggelsen.dk/glblendfunc.php
Изображение нижнего слоя - http://i.stack.imgur.com/XjLNW.png
Изображение верхнего слоя - http: //i.stack.imgur .com / 9CN6w.png

Лимонный леденец
источник
Все скриншоты были взяты из интерактивного инструмента Visual glBlendFunc + glBlendEquation Андерса Риггельсена . В будущем подобные вещи было бы полезно упомянуть при обращении за помощью.
Тревор Пауэлл
@TrevorPowell Dang Я знал, что забыл что-то сказать (я действительно планировал поместить это внизу). В любом случае это просто то, что я использовал для простого тестирования режимов наложения, это должно быть стандартным для любого другого вида OpenGL (даже если я вижу других людей, желающих его использовать).
Лимонная капля

Ответы:

5

В первом примере ( glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)) вы говорите смешивать цвета на основе альфа-изображения изображения, которое рисуется сверху («переднего плана»). Поэтому, когда вы смешиваете 50% между цветом переднего плана и цветом (38,50,168)фона (38,50,168)в левом нижнем углу изображения, неудивительно, что вы получаете точно такой же цвет (38,50,168). Потому что именно это смешивание - именно то, что вы сказали OpenGL.

Судя по вашему «ожидаемому» изображению, вы не хотите делать перекрестное смешение между двумя цветами - вы хотите наложить цвет переднего плана поверх полноцветного цвета фона, а не смешивать между ними.

Чтобы сделать это, вы хотите использовать glBlendFuncSeparate (так как вы обрабатываете цвет фона иначе, чем его альфа), и указать, что во время операции наложения значение альфа фонового значения должно рассматриваться как 100%.

за работой

Для облегчения просмотра вот вывод окончательных значений RGB: RGB

И вот окончательные значения прозрачности выводятся. альфа

(Эта область прозрачности «100%» на самом деле должна быть помечена как прозрачная на 99,7%, а нижняя правая область «50%» должна быть помечена как прозрачная на 49,7%, оба из-за красного цвета на правой стороне первого изображения). Кроме того, извините за перечисление номеров с использованием «прозрачности», а не непрозрачности, возможно, немного запутывает.)

Если есть конкретные проблемы, укажите область RGB или альфа-изображения, которые выдают неправильные значения.

Тревор Пауэлл
источник
Разве исходный коэффициент альфа не должен быть GL_ONEтаким же? В противном случае уравнение альфа выглядит следующим образомdest_alpha = src_alpha * src_alpha + 1 * dest_alpha
bcrist
Что ж, если вы посмотрите на то, что средняя левая часть все еще намного темнее, чем должна быть, при переворачивании слоев это выглядит так: i.imgur.com/rigBNz6.png (этот едва видимый красный цвет используется для проверки на такие вещи, как Это
Лимон Дроп
Вы смешиваете это на 50% против (0,0,0). Из Конечно , это темнее , чем когда вы смешиваете его на 50% против (255,255,255).
Тревор Пауэлл
@TrevorPowell Разве это не имеет значения, если альфа равна 0? Как уравнения я собираюсь за похоже: finalAlpha = srcAlpha + destAlpha * (1 - srcAlpha)и бит в расчете цвета может быть сделано в шейдерах путем вывода предварительно умноженных значений, но Тереза нет способа разделить на finalAlpha , чтобы избавиться от premultiplication. (Взято отсюда )finalColor = ((srcColor * srcAlpha) + (destColor * destAlpha * (1 - srcAlpha))) / finalAlphaColor * Alpha
Lemon Drop
0

У меня была точно такая же проблема, когда я хотел визуализировать набор перекрывающихся объектов кадрового буфера, таких как слои. Проблема заключается в том, что функции смешивания Open GL являются линейными, и они работают, когда фон назначения является непрозрачным. Но фактическое уравнение смешивания для смешивания двух прозрачных слоев не является линейным уравнением и содержит разделительную часть.

out_color = {src_color * src_alpha + dest_color * dest_alpha * (1-src_alpha)} / out_alpha

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

Супун Готама
источник
Да, я просто предварительно умножил альфа на текстурах, а не делал обходные пути, это легко сделать с некоторыми библиотеками (они будут просто предварительно умножать текстуры при загрузке)
Lemon Drop