Ответ 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 не требует такого поведения, поэтому вы также не должны зависеть от него.
Теперь, если честно, ваша программа не должна была связываться, когда вы использовали два выхода, которые не получили разные выходные данные. Вероятно, произошло то, что ваш компилятор оптимизировал тот, который вы не писали, поэтому он забыл об этом, когда пришло время проверить ошибки компоновщика.