Темный ореол вокруг частично прозрачных частей изображений в opengl

Я обычно нахожу с OpenGL, когда я пытаюсь нарисовать что-то на текстуру, а затем на другую поверхность, используя glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)Я неизменно получаю цветное ореол (обычно полоса темного цвета) в полупрозрачных частях моего исходного изображения вблизи его краев. Это очевидно вызвано проблемами с созданием того, что по существу является предварительно умноженной альфа, вызванным этим стилем смешивания. Для трехмерных сцен я обычно использую алгоритм рисования, а для рендеринга двумерного контента я предпочитаю сначала рисовать крайние объекты и накладывать на них дополнительные объекты. Стоит отметить, что при выполнении 2-мерного рисования я, как правило, не могу полагаться на такие функции, как z-буфер, как в 3D, поэтому для рендеринга таких вещей, как графический интерфейс, больше проблем, чем для трехмерных графов сцены.

Я думаю, что стоит отметить, что вышеприведенный стиль смешивания на самом деле идеален, когда целевой буфер уже оказывается полностью непрозрачным, но если целевой объект прозрачен, то в данном случае действительно нужно glBlendFunc(GL_SRC,GL_ZERO)... поскольку любые полностью белые пиксели, которые частично прозрачны в источнике, например, должны оставаться такими же полностью насыщенными цветом, а не "смешиваться" с фоном, который на самом деле еще не существует, потому что при использовании glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) на самом деле будет отображать частично прозрачный и полностью белый пиксель как смесь между передним планом и фоном, чего я и хочу, но не в той степени, в которой альфа-информация теряется, ни в той степени, в которой цвета фактически изменяются.

Мне приходит в голову, поэтому, вид смешивающей функции, которая, вероятно, была бы идеальной, был бы той, которая фактически смешивается с тем, что иначе вызвано glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) и что в противном случае вызвано glBlendFunc(GL_SRC,GL_ZERO) в зависимости от стоимости DST_ALPHA сам.

Таким образом, в идеале:

Cr = Cs * (1 - Ad) + (Cs * As + Cd * (1 - As)) * Ad
Ar = As * (1 - Ad) + Ad * Ad

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

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

Единственный обходной путь, который я нашел до сих пор, - это изменять порядок рисования всякий раз, когда я рисую текстуру, которую я позже буду рисовать в другом месте, и использовать glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA),

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

Наконец, хотя изменение порядка рисования всей сцены не обязательно совершенно невозможно, требуется, чтобы полный список объектов, которые будут отображаться в каждом кадре графики, был определен до того, как будет нарисован даже первый объект. Основная проблема, с которой я столкнулся, заключается в том, что, хотя это может быть устойчивым при рендеринге 3D-сцен, при рисовании таких объектов, как 2d gui, само разнообразие нарисованных объектов и способ их рисования просто настолько велики, что способ обобщить их в единый список объектов, который всегда можно просмотреть в обратном порядке позже. Мне кажется, что это потребовало бы столь радикально другого взгляда на то, как построить 2-мерные сцены в этом "обратном" порядке из того, к чему я привык, что в настоящее время я просто не в состоянии даже найти приемлемое решение.

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

Редактировать:

Если существует какое-либо общедоступное расширение для OpenGL, разработанное NVIDIA или другим способом, которое допускает смешанный режим, который может сделать это:

Cr = Cs * (1 - Ad) + (Cs * As + Cd * (1 - As)) * Ad
Ar = As * (1 - Ad) + Ad * Ad

(Где Cs и Cd - исходные и целевые цвета, As и Ad - исходные и целевые альфа-значения, а Cr и Ar - результирующие цвета и альфа-значения), мне бы очень хотелось узнать, как называется расширение и как использовать его... до тех пор, пока он может быть произведен на потребительском оборудовании.

1 ответ

Я написал разные вещи, сочетающие полупрозрачные 2D-оверлеи с полупрозрачным 3D-контентом, и никогда не чувствовал, что OpenGL упускает что-то решающее в области glBlendFunc / glBlendFuncSeparate (по крайней мере, пока вы не начнете беспокоиться о гамма-коррекции композитинга контента sRGB и кадровых буферов в любом случае).

Я в основном с подозрением отношусь к вашему использованию glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) очевидно, с предварительно умноженной альфой (извините, хотя ваш вопрос длинный, на самом деле я не нахожу его настолько ясным; некоторые изображения простых тестовых случаев могут помочь). Для композитинга предварительно умноженного альфа-контента я бы ожидал увидеть GL_ONE как один из glBlendFunc аргументы (который зависит от того, выполняете ли вы операции над / под операцией).

Здесь очень хорошая слайд-колода по смешиванию / компоновке (включая правильное использование предварительно умноженных и "прямых" цветов) здесь (слайды 20-35 соответствующего материала).

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

Другие вопросы по тегам