シェーダーをバインドするコストは簡単ではないかもしれませんが、同じシェーダーを使用するすべてのオブジェクトをバッチ処理せずに数千のアイテムをレンダリングしない限り、ボトルネックになることはありません。
これがモバイルデバイスに当てはまるかどうかはわかりませんが、条件が定数とユニフォームの間にある場合、GPUがブランチでひどく遅くなることはありません。どちらも有効です。どちらも過去に使用されたものであり、今後も使用されます。どちらの場合も、どちらが適切であるかを選択してください。
さらに、これを実現する方法は他にもいくつかあります。「Uber-shaders」と、OpenGLシェーダープログラムのリンク方法のちょっとしたトリックです。
「Uber-shaders」は基本的に最初の選択ですが、分岐はありませんが、複数のシェーダーがあります。if
ステートメントを使用する代わりに、プリプロセッサを使用します- #define
、#ifdef
、#else
、、#endif
適切などの異なるバージョン、コンパイル#define
に必要なもののために秒。
vec4 color;
#ifdef PER_VERTEX_COLOR
color = in_color;
#else
color = obj_color;
#endif
シェーダーを個別の関数に分割することもできます。すべての関数のプロトタイプを定義して呼び出すシェーダーを1つ用意し、適切な実装を含む追加のシェーダーの束をリンクします。このトリックをシャドウマッピングに使用して、すべてのシェーダーを変更しなくても、すべてのオブジェクトでフィルタリングがどのように行われるかを簡単に交換できるようにしました。
//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コンパイラは他の方法でオーバーヘッドを最適化するのに十分であると考えたいと思います。私はこれについてテストを実行していませんが、それは私がそれを行うのが好きな方法です。