El costo de enlazar sombreadores puede no ser trivial, pero no será su cuello de botella a menos que esté renderizando miles de artículos sin agrupar todos los objetos que usan los mismos sombreadores.
Aunque no estoy seguro de si esto se aplica a los dispositivos móviles, pero las GPU no son terriblemente lentas con ramas si la condición es entre una constante y un uniforme. Ambos son válidos, ambos se han usado en el pasado y se seguirán usando en el futuro, elija el que considere más limpio en su caso.
Además, hay algunas otras formas de lograr esto: "Uber-shaders" y un pequeño truco con la forma en que se vinculan los programas de sombreadores OpenGL.
Los "Uber-shaders" son esencialmente la primera opción, menos la ramificación, pero tendrás múltiples shaders. En lugar de utilizar if
las declaraciones, se utiliza el preprocesador - #define
, #ifdef
, #else
, #endif
, y compilar diferentes versiones, incluyendo las adecuadas #define
s para lo que necesita.
vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif
También puede dividir el sombreador en funciones separadas. Tenga un sombreador que defina prototipos para todas las funciones y los llame, vincule un montón de sombreadores adicionales que incluyen las implementaciones adecuadas. He usado este truco para el mapeo de sombras, para facilitar el intercambio de cómo se realiza el filtrado en todos los objetos sin tener que modificar todos los sombreadores.
//ins, outs, uniforms
float getShadowCoefficient();
void main()
{
//shading stuff goes here
gl_FragColor = color * getShadowCoefficient();
}
Entonces, podría tener varios otros archivos de sombreador que definan getShadowCoefficient()
, los uniformes necesarios y nada más. Por ejemplo, shadow_none.glsl
contiene:
float getShadowCoefficient()
{
return 1;
}
Y shadow_simple.glsl
contiene (simplificado desde mi sombreador que implementa 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;
}
Y simplemente puede elegir si desea sombrear o no vinculando un shadow_*
sombreador diferente . Es muy posible que esta solución tenga más gastos generales, pero me gustaría pensar que el compilador GLSL es lo suficientemente bueno para optimizar cualquier gasto adicional en comparación con otras formas de hacerlo. No he realizado ninguna prueba sobre esto, pero es la forma en que me gusta hacerlo.