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

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

#version 130

out vec4 flatColor;

void main(void)
{
    flatColor = vec4(0.0,1.0,0.0,0.5);
}

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

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


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

#version 330

in vec2 TexCoord0;

uniform sampler2D TexSampler;

out vec4 x;
out vec4 y;

void main()
{
    y = texture2D(TexSampler, TexCoord0.xy);
}

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


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

Ответ 1

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

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

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

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

layout(location = 2) in color;

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

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

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

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

layout(location = 1) out secColor;

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

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

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

Ответ 2

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

§4.4.2

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