Прикрепление нескольких шейдеров одного типа в одной программе OpenGL?
При чтении спецификаций OpenGL я заметил, что в нем упоминается, что вы можете включать несколько шейдеров одного и того же типа в одну программу (т.е. более одного GL_VERTEX_SHADER, связанного с glAttachShader). В частности, в OpenGL 4.2, §2.11.3, "Объекты программы": "Несколько объектов шейдера одного типа могут быть прикреплены к одному программному объекту...".
Здесь могут применяться программы и подпрограммы OpenGL, но это было определено до того, как они существовали (на самом деле это восходит к спецификации 2.1, §2.15.2), поэтому я ищу пример этой идеи до GL4. Когда я сделал несколько простых тестов, я обнаружил, что включение более чем одного void main()
вызвало ошибки связывания. Кто-нибудь знает о практическом примере, где это используется?
Ответы
Ответ 1
Вы можете поместить общие функции в отдельный шейдер. Затем скомпилируйте его только один раз и ссылку в нескольких программах.
Это похоже на то, как вы компилируете свои файлы cpp только один раз, чтобы получить статическую или общую библиотеку. Затем вы связываете эту библиотеку с несколькими исполняемыми программами, тем самым сохраняя время компиляции.
Скажем, у вас есть сложная функция освещения:
vec3 ComputeLighting(vec3 position, vec3 eyeDir)
{
// ...
return vec3(...);
}
Затем для каждого из шейдеров, где вы хотите использовать эту функциональность, выполните следующее:
vec3 ComputeLighting(vec3 position, vec3 eyeDir);
void main()
{
vec3 light = ComputeLighting(arg1, arg2);
gl_FragColor = ...;
}
Затем вы компилируете отдельно общий шейдер и основной шейдер. Но делать компиляцию общих шейдеров только один раз.
Ответ 2
Я обнаружил, что включение более чем одного void main() вызвало ошибки связывания
Для каждого этапа шейдера должна быть только основная функция ввода.
практический пример, где это используется (pre-GL4)?
Вы можете объявить функцию в источнике шейдера и не определять ее, а при связывании времени вы можете предоставить определение из другого источника шейдера (очень похожее на привязку c/С++).
Пример:
generate_txcoord.glsl:
#version 330
precision highp float;
const vec2 madd = vec2(0.5, 0.5);
vec2 generate_txcoord(vec2 v)
{
return v * madd + madd;
}
vertex.glsl:
#version 330
precision highp float;
in vec2 vxpos;
out vec2 out_txcoord;
vec2 generate_txcoord(vec2 vxpos); // << declared, but not defined
void main()
{
// generate 0..+1 domain txcoords and interpolate them
out_txcoord = generate_txcoord(vxpos);
// interpolate -1..+1 domain vxpos
gl_Position = vec4(vxpos, 0.0, 1.0);
}