Стоимость связывания шейдеров может быть не тривиальной, но она не станет вашим узким местом, если вы не рендерите тысячи элементов без пакетирования всех объектов, которые используют одни и те же шейдеры.
Хотя я не уверен, относится ли это к мобильным устройствам, но графические процессоры не работают ужасно медленно с ветвями, если условие находится между константой и униформой. Оба действительны, оба использовались в прошлом и будут использоваться в будущем, выберите тот, который, по вашему мнению, будет чище в вашем случае.
Кроме того, есть несколько других способов сделать это: «Uber-шейдеры» и небольшая хитрость с тем, как связаны шейдерные программы OpenGL.
«Uber-шейдеры» по сути являются первым выбором, за исключением ветвления, но у вас будет несколько шейдеров. Вместо того чтобы использовать if
заявление, можно использовать препроцессор - #define
, #ifdef
, #else
, #endif
, и обобщать различные версии, в том числе собственно #define
с для того, что вам нужно.
vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif
Вы также можете разбить шейдер на отдельные функции. Имейте один шейдер, который определяет прототипы для всех функций и вызывает их, связывайте множество дополнительных шейдеров, которые включают в себя правильные реализации. Я использовал этот трюк для отображения теней, чтобы упростить обмен информацией о том, как выполняется фильтрация всех объектов без необходимости изменять все шейдеры.
//ins, outs, uniforms
float getShadowCoefficient();
void main()
{
//shading stuff goes here
gl_FragColor = color * getShadowCoefficient();
}
Тогда я мог бы иметь несколько других файлов шейдеров, которые определяют getShadowCoefficient()
, необходимую униформу и ничего больше. Например, shadow_none.glsl
содержит:
float getShadowCoefficient()
{
return 1;
}
И shadow_simple.glsl
содержит (упрощенно от моего шейдера, который реализует CSM):
in vec4 eye_position;
uniform sampler2DShadow shad_tex;
uniform mat4 shad_mat;
float getShadowCoefficient()
{
vec4 shad_coord = shad_mat * eye_position;
return texture(shad_tex, shad_coord).x;
}
И вы можете просто выбрать, хотите ли вы использовать затенение или нет, связав другой shadow_*
шейдер. Это решение вполне может иметь больше накладных расходов, но я хотел бы думать, что компилятор GLSL достаточно хорош, чтобы оптимизировать любые дополнительные издержки по сравнению с другими способами сделать это. Я не проводил никаких тестов по этому вопросу, но мне нравится это делать.