Проблема наложения WebGL при рисовании полупрозрачного спрайта на не-черном фоне (cocos2d html5)

Я экспериментирую с фреймворком Cocos2d HTML5, но считаю, что это стандартная проблема WebGL, которую я не могу точно определить, так как у меня нет хороших знаний по этой теме. Если у меня есть стандартное изображение PNG с полупрозрачными пикселями, такими как мягкие края, и если фон (холст или другой элемент позади RenderTexture) заполнен не черным цветом, спрайт при рисовании в RenderTexture в конечном итоге впитывается в фон, даже если этого не должно быть. Например, если рисунок, который я рисую, красный и я использую зеленый фон, полупрозрачные пиксели в конечном итоге трансформируются в желтый. См. Эти изображения для иллюстрации:

Внешний вид на сплошном черном фоне - это то, что я хочу Внешний вид на сплошном черном фоне, это то, что я желаю

Появление на не черном фоне, с просачиванием bg насквозь Появление на не черном фоне, с просачиванием bg насквозь

Все, что находится на заднем плане, будет видно, когда я размещу любое изображение, отличное от 100% непрозрачности.

Полный код класса RenderTexture на основе JavaScript можно увидеть в репозитории cocos2d-html5 Github в разделе cocos2d / misc_nodes / CCRenderTexture.js. Это преобразование из Cocos2d-x C ++ / Objective C (которое не демонстрирует этой проблемы). Несколько лет назад в системе отслеживания проблем cocosd-iphone была обнаружена проблема №937, описывающая ту же проблему для версии, отличной от HTML. С тех пор это было решено, но я не могу определить, какое было разрешение или как его можно было преобразовать в формат WebGL. Я уверен, что это проблема наложения, но я безуспешно пытался изменить режимы наложения (с GL_ONE, GL_ONE_MINUS_SRC_ALPHA на GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).

Мы будем очень благодарны за любую помощь экспертов OpenGL / WebGL. Если я использую стандартные «спрайты» в Cocos2d вне этого RenderTexture, проблемы не существует. Кроме того, функция MotionStreak, похоже, тоже работает без сбоев, но мне требуется RenderTexture для создания динамических текстур для дальнейшего использования.


person Sam J    schedule 30.10.2013    source источник


Ответы (1)


По умолчанию WebGL имеет то же значение, что и изображения и холст 2D, а именно он ожидает, что содержимое холста будет RGBA, он ожидает, что RGB будет предварительно умножен на альфа (другими словами, если альфа равна нулю, RGB также должен быть нулевым, поскольку что-либо умножить на ноль равно нулю). И, наконец, сочетается с тем, что стоит за ним, с GL_ONE_MINUS_SOURCE_ALPHA.

Если вы хотите, чтобы это было по-другому, у вас есть 2 варианта

  1. Скажите WebGL, чтобы у него не было альфа

    Вы делаете это, создавая контекст без альфы.

    gl = canvas.getContext("experimental-webgl", { alpha: false });
    

    Вероятно, это лучший вариант для вашего случая. Поскольку альфа-канала не будет, смешение не требуется, что быстрее, чем смешение с фоном, что обычно и делает браузер.

  2. Сообщите WebGL, что ваши значения RGB не умножаются предварительно

    gl = canvas.getContext ("экспериментальный-webgl", {premultipledAlpha: false});

    Это означает, что браузер по-прежнему будет смешивать ваш холст WebGL с фоном, вместо этого он будет делать это с GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA. Вы по-прежнему будете видеть зеленый цвет позади.

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

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

    ...render scene...
    
    gl.colorMask(false, false, false, true);
    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    

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

  2. Если вы не хотите видеть вещи за холстом, задайте фон холсту цвет.

    <canvas style="background-color: green;"></cavnas>
    

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

person gman    schedule 31.10.2013
comment
Спасибо за подробное объяснение и за то, что дали мне области для исследования. Мне все еще не везет, но я полагаю, что это связано с чем-то более глубоким в движке Cocos2d. Мне нужен прозрачный контекст, чтобы то, что в нем нарисовано, могло действовать как наложение на другие элементы на сайте, такие как цвет холста. Когда альфа-канал имеет значение true в генерации контекста, зеленый фон тела и clearColor (0,0,0,0) в контексте, похоже, та же проблема сохраняется (т. Е. Красная текстура, нарисованная для контекста, в конечном итоге выглядит желтой из-за зеленый цвет bg). Но я продолжу расследование. - person Sam J; 31.10.2013
comment
Вы хотите установить альфу на false, чтобы не было смешивания. По умолчанию true. Я немного запутался. Вы говорите, что хотите, чтобы он сливался с фоном. У вас зеленый фон, а вы рисуете красным. Вы видите желтый. Это именно то, что вы получите при смешивании. Так в чем опять проблема? - person gman; 01.11.2013
comment
Прости. Я пытаюсь создать своего рода многоуровневый интерфейс. Итак, мне ДЕЙСТВИТЕЛЬНО нужна прозрачность на уровне (-ах) WebGL, чтобы то, что находится за ним, могло быть видно сквозь, но я НЕ хочу, чтобы на то, что я рисую в данном контексте / слое, влияло то, что находится за ним (т. Е. задний план). См., Например, эту иллюстрацию; фон радуги будет соответствовать текстуре холста или тела. Красные / белые / зеленые линии - это то, что я хочу нарисовать на слое GL без воздействия на них bg. Как слои Photoshop. В моих тестах (C2D) они затронуты. - person Sam J; 01.11.2013
comment
Я думаю, что вы хотите сделать, либо # 2 выше, либо вручную предварительно умножить альфа. В приведенных выше примерах изображений вам нужно будет использовать предварительно умноженную альфа. Если ваши текстуры уже умножены до умножения, вы ничего не сделаете. В противном случае вы можете попробовать, например, gl_FragColor = vec4(color.rgb * color.a, color.a);. К сожалению, это не так просто. Чтобы использовать предварительно умноженную альфу в целом, вам нужно либо (а) сделать все ваши данные, шейдеры и смешивание предварительно умноженными, либо (б) выполнить рендеринг в текстуру, а затем обработать ее в предварительно умноженное изображение. Вариант (2) сделает это за вас. - person gman; 03.11.2013
comment
Вот скрипт, показывающий предварительно примененные данные и настройки холста jsfiddle.net/greggman/pWPPC - person gman; 03.11.2013