Il costo di associazione degli shader potrebbe non essere banale, ma non sarà il collo di bottiglia a meno che non si stiano eseguendo il rendering di migliaia di articoli senza raggruppare tutti gli oggetti che utilizzano gli stessi shader.
Anche se non sono sicuro che questo si applichi ai dispositivi mobili, ma le GPU non sono tremendamente lente con i rami se la condizione è tra una costante e un'uniforme. Entrambi sono validi, entrambi sono stati utilizzati in passato e continueranno ad essere utilizzati in futuro, scegli quello che ritieni più pulito nel tuo caso.
Inoltre, ci sono alcuni altri modi per ottenere questo risultato: "Uber-shader" e un piccolo trucco con il modo in cui i programmi di shader OpenGL sono collegati.
Gli "Uber-shader" sono essenzialmente la prima scelta, meno la ramificazione, ma avrai più shader. Invece di usare if
affermazioni, si utilizza il preprocessore - #define
, #ifdef
, #else
, #endif
, e compilare diverse versioni, tra cui la corretta #define
s per quello che ti serve.
vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif
Puoi anche suddividere lo shader in funzioni separate. Avere uno shader che definisce i prototipi per tutte le funzioni e le chiama, collegare un gruppo di shader extra che includono le implementazioni appropriate. Ho usato questo trucco per la mappatura delle ombre, per semplificare lo scambio di filtri su tutti gli oggetti senza dover modificare tutti gli shader.
//ins, outs, uniforms
float getShadowCoefficient();
void main()
{
//shading stuff goes here
gl_FragColor = color * getShadowCoefficient();
}
Quindi, potrei avere più altri file shader che definiscono getShadowCoefficient()
, le uniformi necessarie e nient'altro. Ad esempio, shadow_none.glsl
contiene:
float getShadowCoefficient()
{
return 1;
}
E shadow_simple.glsl
contiene (semplificato dal mio shader che 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;
}
E puoi semplicemente scegliere se vuoi l'ombreggiatura collegando uno shadow_*
shader diverso . Questa soluzione potrebbe benissimo avere più overhead, ma mi piacerebbe pensare che il compilatore GLSL sia abbastanza buono da ottimizzare qualsiasi overhead aggiuntivo rispetto ad altri modi per farlo. Non ho eseguito alcun test su questo, ma è il modo in cui mi piace farlo.