Режимы наложения OpenGL и Shader Blending

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

В чем причины выбора первого или последнего? Есть ли узкие места в производительности, выбирая один за другим? Или это только вопрос личных предпочтений?

Ответ 1

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

В настоящее время вы можете проходить только по цвету и выбирать один из ограниченного набора режимов смешивания (glBlendFunc/glBlendEquation), который будет применяться растеризатором графического процессора до записи в фреймбуфер.

Ответ 2

Когда шейдер читает текстуру, а одновременно отображает ту же текстуру, результаты undefined. Вот почему полезно использовать "традиционное" или фиксированное функциональное сочетание с glBlendFunc и glBlendEquation.

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

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

На современном оборудовании разница между двумя методами имеет тенденцию быть небольшим.

Ответ 3

Можно смоделировать смешивание OpenGL из шейдера в трех обстоятельствах, о которых я знаю:

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

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

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

Ответ 4

Это можно осуществить с помощью расширения gl 3.0 с использованием функции текстурного барьера:

http://www.opengl.org/registry/specs/NV/texture_barrier.txt

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