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

83

Я вижу много разных шейдеров фрагментов,

И все они используют разные переменные для «цвета выхода» (в данном случае flatColor). Итак, как OpenGL узнает, что вы пытаетесь сделать?

Я предполагаю, что это работает, потому что flatColorэто единственная переменная, определенная как out, но вам разрешено добавлять больше outпеременных, не так ли? Или это просто вылетит?


Собственно, в качестве теста я просто запустил это:

Он работал нормально, использовал ли я xили y.


Кроме того, у нас есть предопределенный gl_FragColor. В чем разница и почему люди обычно настаивают на использовании собственных переменных?

mpen
источник

Ответы:

143

Кроме того, у нас есть предопределенный gl_FragColor.

Начнем с этого. Нет, у вас нет предопределенного gl_FragColor. Это было удалено из ядра OpenGL 3.1 и выше. Если вы не используете совместимость (в этом случае шейдеры 3.30 должны указывать #version 330 compatibilityвверху), вам никогда не следует ее использовать.

Теперь вернемся к пользовательским выводам фрагментного шейдера. Но сначала небольшая аналогия.

Помните, как в вершинных шейдерах у вас есть входы? И эти входы представляют собой вершину индексов атрибутов, число Проходите glVertexAttribPointerи glEnableVertexAttribArrayтак далее? Вы устанавливаете, какой вход будет извлекаться из какого атрибута. В GLSL 3.30 вы используете этот синтаксис:

Это устанавливает, что colorввод вершинного шейдера будет поступать из местоположения атрибута 2. До 3.30 (или без ARB_explicit_attrib_location) вам нужно было бы явно установить это с помощью glBindAttrbLocationперед связыванием или запросить программу для индекса атрибута с glGetAttribLocation. Если вы явно не укажете местоположение атрибута, GLSL назначит местоположение произвольно (то есть: способом, определяемым реализацией).

Установка его в шейдере почти всегда лучший вариант.

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

Этот процесс начинается со значения местоположения вывода фрагмента. Это очень похоже на расположение входных данных вершинного шейдера:

Также существуют функции API glBindFragDataLocationи glGetFragDataLocation, аналогичные glBindAttribLocationи glGetAttribLocation.

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

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

Николь Болас
источник
4
Хотел бы я дать больше +1. Эффектный ответ. Мне было интересно, как работают места вывода фрагментов. :)
kevintodisco
Ааа .. так они gl_FragColorотказались от рекомендаций в пользу предоставления вам большей гибкости в выборе буфера для записи? Имеет смысл. Еще раз спасибо!
mpen
3
@Mark: «Устарело» означает, что «вы все еще можете использовать его, но он может быть удален в более поздних версиях». «Удалено» означает удалено . Есть разница. То, что было помечено как устаревшее в GL 3.0, было удалено в 3.1 (за исключением нескольких вещей).
Никол Болас
3
@NicolBolas: «GL 3.3 и выше (это изменение по сравнению с предыдущими версиями) назначит их всем местоположению 0». Интересно, где это гарантируется спецификацией. 3.3 говорит: «Когда программа связана, любые изменяющиеся переменные без привязки, указанной [...] или явно установленной в тексте шейдера, будут автоматически привязаны к цветам и индексам фрагментов GL. Все такие назначения будут использовать индексы цвета нуль.". Последнее предложение отсутствует в 3.2. Однако индекс не относится к номеру цвета, а только к индексу смешивания двойного источника (который был добавлен в 3.3).
derhass
1
Спасибо @NicolBolas, отличный ответ! Так что я еще не до конца понял это и просто хочу сделать это «без вопросов». В наших шейдерах мы всегда указываем layout (location = 0) out vec4 outColorпри рисовании к чему-то привязанному (чаще всего «экран», а не FBO). Итак, по умолчанию, если мы не связали FBO (или другой буфер) с помощью glDrawBuffers и укажем location = 0, он всегда будет правильно отображаться на экране?
AzP
9

Я хотел бы указать это для OpenGLES 3.1, который использует ссылку GLSL_ES_3.10 :

§4.4.2

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

Лоренцо Белли
источник