Использование нескольких шейдеров

53

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

http://www.youtube.com/watch?v=1ogg4ZfdBqU

Другой - применение шейдера Блума в сцене и шейдера размытия в движении. Как добиться этих эффектов, когда у вас может быть только один вершинный шейдер и один фрагментный шейдер? Есть ли какая-нибудь хитрость, такая как использование более одной шейдерной программы?

ibrabeicker
источник
Хорошие ответы Ре Натана и Дэвида, вот почему вы видите термин « проход» или « шейдер» ; Есть несколько проходов, необходимых для составления окончательного изображения / кадра. Одна из причин, почему обработка на GPU стала настолько чертовски параллельной и, следовательно, такой быстрой, заключается в необходимости нескольких проходов на кадр. Вернитесь к программным средствам рендеринга Quake II или Half Life, чтобы напомнить себе, сколько проходов любовного шейдера добавляют ко всему опыту трехмерной графики.
Инженер

Ответы:

59

Ответ прост: вы меняете их между каждым вызовом розыгрыша. Установите шейдер, нарисуйте чайник, установите другой шейдер, нарисуйте другой чайник.

Для более сложных вещей, где вам нужно применить несколько шейдеров только к одному объекту, например размытие, свечение и так далее. Вы в основном все визуализируете в текстуру (ы). Затем вы визуализируете квад по всему экрану с этой текстурой, примененной во время использования другого шейдера.

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

Существует еще один метод, называемый отложенным затенением, при котором вы визуализируете сцену без освещения и применяете ее позже в пространстве экрана. Основная цель состоит в том, чтобы уменьшить затраты на пиксельное освещение.

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

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

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

С более современным OpenGL (3.0+) вы используете объект Framebuffer с прикрепленными объектами Renderbuffers. С рендерингами буфера можно обращаться как с текстурой. Вы можете сделать что-то вроде рендеринга 1 шейдера для нескольких различных буферов рендеринга (так что вам не нужно рендерить текстуру, а не нормали, а затем компоненты свечения), но основная практика остается той же.

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

Дэвид С. Бишоп
источник
16

Вы просто связываете один шейдер, визуализируете все объекты с помощью этого шейдера, затем связываете следующий шейдер, визуализируете объекты с помощью этого и т. Д.

Вы можете иметь столько шейдерных объектов (шейдеров, загруженных в память и скомпилированных), сколько захотите; только один может быть связан (активен) одновременно.

Натан Рид
источник
5
С точки зрения реализации, в каждом кадре я использую glUseProgram (1) и glUseProgram (2), чтобы изменить шейдеры? Насколько это дорого для производительности?
Ибрабикер
4
Это нетривиальная стоимость (хотя на последних графических процессорах она меньше, чем на ранних). Вот почему большинство людей сортируют свои объекты по материалам, объединяя все объекты из одного материала. Но вы, конечно, можете позволить себе менять программы от десятков до сотен раз за кадр, если не больше.
Натан Рид
9

Использование более одного шейдера в сцене довольно просто; измените шейдер, установите для него значения, а затем визуализируйте объект.

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

Первый и, как правило, самый желательный метод - это добавить функциональность для всех ваших методов шейдера только к одному шейдеру и использовать условия, которые вы задали для рендеринга каждого объекта по-разному с одним и тем же шейдером. Я не знаю о шейдерах OpenGL и GLSL, но с шейдерами HLSL и DirectX их можно сгруппировать как «технику», и вы можете установить технику вместо смены шейдера. Это позволяет вам фактически иметь несколько разных пиксельных и вершинных шейдеров в одном файле.

Второй способ уменьшить влияние на производительность - установить шейдер, отобразить каждый объект, использующий этот шейдер, и повторить. Другими словами, пакетный рендеринг.

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

OriginalDaemon
источник
7

Я обнаружил еще один способ сделать это с помощью подпрограмм glsl, где каждый тип шейдера определен в одной функции, а в приложении OpenGL мы можем определить текущую подпрограмму, нарисовать вершину буфера, изменить подпрограмму и рендеринг другого буфера

ibrabeicker
источник
4
Для этого требуется оборудование с поддержкой GL 4.x, которое является оборудованием класса DX11.
Николь Болас