2015-02-04 2 views
1

Я действительно не понимаю, как работает фрагментарный шейдер.Как шейдеры вершин и фрагментов взаимодействуют в OpenGL?

Я знаю, что

  • вершинный шейдер выполняется один раз в вершинах
  • пиксельный шейдер выполняется один раз в фрагменте

Поскольку пиксельный шейдер не работает на вершине, но на фрагменте как он может передавать данные к фрагментному шейдеру? Количество вершин и количество фрагментов не равны.

Как определить, какой фрагмент принадлежит к какой вершине?

ответ

5

Чтобы понять это, вам нужно рассмотреть весь рендеринг. Выходы вершинного шейдера (кроме специального выхода gl_Position) передаются как «связанные данные» вершины на следующие этапы в конвейере.

Хотя вершинный шейдер работает только по одной вершине за раз, не заботясь о примитивах, дальнейшие этапы конвейера учитывают примитивный тип (и информацию о связности вершин). Это то, что обычно называют «примитивной сборкой». Теперь у нас все еще есть единственные вершины с соответствующими данными, создаваемыми VS, но мы также знаем, какие вершины сгруппированы вместе, чтобы определить базовый примитив, такой как точка (1 вершина), строка (2 вершины) или треугольник (3 вершины).

Во время растеризации фрагменты генерируются для каждого пиксельного местоположения в растровом пикселе выходного изображения, который принадлежит примитиву. При этом соответствующие данные вершин, определяющих примитив, могут быть интерполированы по всему примитиву. В строке это довольно просто: выполняется линейная интерполяция. Назовем конечные точки A и B с каждым ассоциированным выходным вектором v, так что мы имеем v_A и v_B. По всей линии мы получаем интерполированное значение для v как v (x) = (1-x) * v_A + x * v_B в каждой конечной точке, где x находится в диапазоне от 0 (в точке A) до 1 (в точке Б). Для треугольника используется барицентрическая интерполяция между данными всех трех вершин. Таким образом, пока нет сопоставления 1: 1 между вершинами и фрагментами, выходы VS по-прежнему определяют значения входного сигнала FS, а не прямо, но косвенно путем интерполяции по используемому примитивному типу.

conceptual data shader flow in the GL

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

Вы можете отключить коррекцию перспективы, используя квалификатор noperspective для переменных in/out в GLSL. Затем линейная/барицентрическая интерполяция используется, как я ее описал.

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

+0

Так что, я думаю, мы можем применить эту формулу и по координатам uv для текстурирования. –

+0

Ну. Основной принцип применяется ко всем выходным переменным, а uv-коорды - всего лишь один пример. Я продлил свой ответ, чтобы рассмотреть перспективную коррекцию интерполяции. – derhass

1

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

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

Смежные вопросы