Можно ли добиться смешивания MAX (As, Ad) openGL?

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

Я не могу просто отобразить их в спрайт png, иначе тени будут перекрывать соседние спрайты.

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

Эти спрайты анимированы, поэтому их массовое рендеринг невозможно.

По сути, я хочу, чтобы тени спрайтов смешивались вместе, чтобы они были максимальными при установленной непрозрачности. Пример:

введите описание изображения здесь

Я считаю, что это эквивалентно смешиванию openGL (Rs, Gs, Bs, Max (As, Ds)), где меня не волнуют R, G и B, так как они всегда будут одного и того же цвета в src и дст.

Однако это недопустимый режим наложения openGL. Есть ли простой способ сделать это, особенно в cocos2d-iphone?

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


person Jeff B    schedule 27.01.2010    source источник


Ответы (1)


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

Во-первых, есть способ сделать смешивание Max Alpha openGL, и это использование glBlendEquations. Для этого вам нужно будет изменить метод рисования (и создать новый атрибут для textureNode, чтобы переключаться между этими методами) и использовать любой из них:

 glBlendEquationOES( GL_MAX_EXT );
 glBlendEquationSeparateOES( GL_FUNC_ADD_OES, GL_MAX_EXT );

Первый использует max() для RGBA, а второй использует стандартное сложение для RGB и max() для альфа-канала.

Теперь проблема в том, что каждый спрайт и его потомки в z-порядке рисуются на экране. Это означает, что после отрисовки первой тени она становится частью буфера основного экрана. Другими словами, ее непрозрачность изменилась, и при смешивании max() и стандартном непрозрачном фоне она теперь нарисована на фоне, поэтому, когда вы рисуете следующую тень, она сделает max(As, 1), что равно 1, потому что фон непрозрачный. Так что я не достигаю смешивания, которое я хочу. Это «работало бы», если бы мой фон был прозрачным, но тогда я не мог бы применить какой-либо фон «позади», мы можем только добавить его в буфер.

Я мог бы сначала нарисовать тени, используя смесь max(), а затем сделать {ONE_MINUS_DST_ALPHA, DST_ALPHA} glBlend. Это нормальное обходное решение, но у меня есть другие проблемы, которые усложняют его.

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

Обновление:

Хорошо, теперь у меня есть рабочее решение.

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

  1. Сначала нарисуйте 0% черный альфа-канал png на весь экран. (Я не знаю, нужно ли это. Я не знаю, какая альфа экрана по умолчанию).

  2. Нарисуйте тени на экране, используя glEquationSeperateOES( GL_ADD, GL_MAX_ENT) и glBlend( GL_ONE, GL_ONE ). Это соединит все тени вместе, как описано, взяв max() альфы.

    • Поскольку вы компонуете в черный цвет, это эквивалентно использованию glBlendEquationOES( GL_MAX_ENT ). (Х+0 == макс(Х,0))

    • glBlend( GL_ZERO, GL_ONE ) устранит необходимость шага 1 или, по крайней мере, требование, чтобы этот слой был 0% черным. GL_ZERO по существу заставляет его быть 0% черным.

  3. Нарисуйте пол, который будет над тенями, но используйте glBlend( ONE_MINUS_DST_ALPHA, DST_ALPHA ). Это приводит к точно таким же результатам, как если бы вы добавили тени к полу с помощью glBlend( SRC_ALPHA, ONE_MINUS_SRC_ALPHA ), однако, если бы вы сделали это таким образом, вы не смогли бы смешать тени вместе (читайте почему в начале ответа).

  4. Вы сделали! Преимущество этого метода в том, что спрайты теней можно анимировать как обычно, без необходимости вызывать "visit" для отдельной текстуры рендеринга.

Остальное:

Я также модифицировал CocosNode, чтобы добавить тень к слою, который ссылается на другой CocosNode. Таким образом, тень визуализируется как дочерний элемент пола (или спрайт с черным фоном 0% для смешивания теней), но связана с другим CocosNode. Когда спрайт движется, если у него есть тень, он также обновляет положение тени. Это позволяет мне иметь все тени под всеми объектами на экране, и тени автоматически следуют за объектом.

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

person Jeff B    schedule 27.01.2010
comment
Спасибо за продолжение вашего вопроса с информативным ответом! - person Sophie Alpert; 13.06.2011
comment
Спасибо также! Этой информации практически нет нигде. :) - person Chris Burt-Brown; 18.01.2012