O custo de vincular shaders pode não ser trivial, mas não será o seu gargalo, a menos que você esteja processando milhares de itens sem agrupar todos os objetos que usam os mesmos shaders.
Embora eu não tenha certeza se isso se aplica a dispositivos móveis, as GPUs não são terrivelmente lentas com ramificações se a condição estiver entre constante e uniforme. Ambos são válidos, ambos foram usados no passado e continuarão a ser usados no futuro, escolha o que você achar que seria mais limpo no seu caso.
Além disso, existem algumas outras maneiras de conseguir isso: "Uber-shaders" e um pouco de truque com a maneira como os programas de OpenGL shader são vinculados.
"Uber-shaders" são essencialmente a primeira escolha, menos a ramificação, mas você terá vários shaders. Em vez de usar if
declarações, você pode usar o pré-processador - #define
, #ifdef
, #else
, #endif
, e compilar versões diferentes, incluindo os adequados #define
s para o que você precisa.
vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif
Você também pode dividir o shader em funções separadas. Tenha um shader que defina protótipos para todas as funções e as chame, vincule vários shaders extras que incluem as implementações apropriadas. Usei esse truque para o mapeamento de sombras, para facilitar a troca de como a filtragem é feita em todos os objetos sem precisar modificar todos os shaders.
//ins, outs, uniforms
float getShadowCoefficient();
void main()
{
//shading stuff goes here
gl_FragColor = color * getShadowCoefficient();
}
Então, eu poderia ter vários outros arquivos de sombreador que definem getShadowCoefficient()
, os uniformes necessários e nada mais. Por exemplo, shadow_none.glsl
contém:
float getShadowCoefficient()
{
return 1;
}
E shadow_simple.glsl
contém (simplificado do meu shader que implementa os CSMs):
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;
}
E você pode simplesmente escolher se deseja ou não sombreamento vinculando um shadow_*
sombreador diferente . Essa solução pode muito bem ter mais sobrecarga, mas eu gostaria de pensar que o compilador GLSL é bom o suficiente para otimizar qualquer sobrecarga extra em comparação com outras maneiras de fazer isso. Ainda não testei isso, mas é dessa maneira que gosto de fazê-lo.