Le coût de la liaison des shaders n'est peut-être pas trivial, mais ce ne sera pas votre goulot d'étranglement à moins que vous ne rendiez des milliers d'articles sans regrouper tous les objets qui utilisent les mêmes shaders.
Bien que je ne sois pas sûr que cela s'applique aux appareils mobiles, mais les GPU ne sont pas horriblement lents avec des branches si la condition est entre une constante et un uniforme. Les deux sont valides, les deux ont été utilisés dans le passé et continueront d'être utilisés à l'avenir, choisissez celui qui, selon vous, serait le plus propre dans votre cas.
De plus, il existe plusieurs autres façons d'y parvenir: "Uber-shaders" et une petite astuce avec la façon dont les programmes de shaders OpenGL sont liés.
Les "Uber-shaders" sont essentiellement le premier choix, moins la ramification, mais vous aurez plusieurs shaders. Au lieu d'utiliser des if
déclarations, vous utilisez le préprocesseur - #define
, #ifdef
, #else
, #endif
et compiler différentes versions, y compris le bon #define
s pour ce dont vous avez besoin.
vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif
Vous pouvez également diviser le shader en fonctions distinctes. Avoir un shader qui définit les prototypes pour toutes les fonctions et les appelle, lier un tas de shaders supplémentaires qui incluent les implémentations appropriées. J'ai utilisé cette astuce pour le mappage d'ombres, pour faciliter la permutation du filtrage sur tous les objets sans avoir à modifier tous les shaders.
//ins, outs, uniforms
float getShadowCoefficient();
void main()
{
//shading stuff goes here
gl_FragColor = color * getShadowCoefficient();
}
Ensuite, je pourrais avoir plusieurs autres fichiers de shaders qui définissent getShadowCoefficient()
, les uniformes nécessaires et rien d'autre. Par exemple, shadow_none.glsl
contient:
float getShadowCoefficient()
{
return 1;
}
Et shadow_simple.glsl
contient (simplifié par rapport à mon shader qui implémente les 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;
}
Et vous pouvez simplement choisir si vous souhaitez ou non ombrer en liant un ombrage différent shadow_*
. Cette solution peut très bien avoir plus de surcharge, mais j'aimerais penser que le compilateur GLSL est assez bon pour optimiser toute surcharge supplémentaire par rapport à d'autres façons de le faire. Je n'ai effectué aucun test à ce sujet, mais c'est ainsi que j'aime le faire.