DirectX11でなんとなしに現れた
動的シェーダーリンク(Dynamic Shader Linkage)ってのをやってみましたよ~
どんなものかというと、
例えばシェーダーでディフューズテクスチャを使うか使わないかの場合
パフォーマンスを無視するとifで条件分岐
パフォーマンスを考慮するとシェーダーファイルの分割って事になるわけですが管理が面倒
それをシェーダーファイルを分割することもなく
CPU側で条件分岐を使って動的に処理を変更してやろうってな処理ですね(多分)
一応、ポスビではテクスチャの条件分岐を避けるために
テクスチャOffの場合は白い1*1のテクスチャを転送とかやってますがね・・・
ちょいと説明が難しいので、ここで簡単なDirectX11シェーダーを・・・
//動的シェーダーリンクテストシェーダー struct VS_IN { float4 pos : POSITION; float3 nor : NORMAL; float2 tex : TEXCOORD; }; struct PS_IN { float4 pos : SV_POSITION; float3 Normal : TEXCOORD0; float2 tex : TEXCOORD1; }; float4x4 worldViewProj : WVP; Texture2D picture : DiffuseTexture; SamplerState pictureSampler : LinearSampler; //コンスタントバッファ cbuffer VSMatrix : register( b0 ) { float4 World; }; //インターフェイス interface BaseShade { float4 GetColor( PS_IN input ); }; //元 BaseShade baseShade; //クラス達 class DefaultShade : BaseShade { float4 GetColor( PS_IN input ) { //判断の為、法線を出力 return float4(input.Normal.rgb,1); } }; class TextureShade : BaseShade { float4 GetColor( PS_IN input ) { float4 Out = picture.Sample(pictureSampler, input.tex);; return Out; } }; DefaultShade shade1; TextureShade shade2; PS_IN VS( VS_IN input ) { PS_IN output = (PS_IN)0; output.pos = mul(input.pos, worldViewProj); output.tex = input.tex; output.Normal = input.nor; return output; } float4 PS( PS_IN input ) : SV_Target { float4 col = baseShade.GetColor( input ) * World; return col; } technique10 Render { pass P0 { SetGeometryShader( 0 ); SetVertexShader( CompileShader( vs_5_0, VS() ) ); SetPixelShader( CompileShader( ps_5_0, PS() ) ); } }
こんな感じのシェーダーです
まず最初にC#等でお馴染みの、Interfaceで元の処理を作り
クラスで拡張します!
で、今回の場合はピクセルシェーダーですが
そいつではInterfaceの処理を書く
これでシェーダー側は終わりで
あとは、プログラム側からテクスチャ有りの場合はBaseShadeはshade2 = (TextureShade)
なしの場合はBaseShadeはshade1 = (DefaultShade)
ってな処理を書けば
重いGPUの条件分岐を使うこと無く、シェーダーファイルを増やすこともなく
テクスチャ有り無しのシェーダーの切り替えが出来るってわけですな・・・
テクニックの変更でも良さそうですが
DirectX11はパスごとに頂点レイアウトを送るので、そこら辺も考えると便利なのかも知れませんね~
もんしょさんの例の場合はifを使ったシェーダーよりも2倍程度の速度が得られるみたいです
ついでに、定数バッファによるシェーダーへの値転送をやってみましたが
(↑のシェーダーで言うとVSMatrixの部分)
SharpDXさん・・・
定数バッファの値の動的変化はちょいと面倒みたいで
バッファを新規に作成する以外は
マーシャリングしてどうのこうのって事をしなくちゃいけないみたいですね~面倒
動的に値を送れないのであれば、定数バッファの
シェーダーに値を送るのが1回で済むので、パフォーマンスが有利ってのはどうなんでしょう?
初期化段階で送るんだったら、そんなにスピードいらないだろうって思うのですが・・・
シェーダーの定数バッファ内から定数を習得して変更ってのは出来るみたいなので
個々単位では変更できそうかな??
それだったら・・・
コメント