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


83

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

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

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


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

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


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

Ответы:


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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.