11の機能はほとんど使ってなくてインチキくさいので今回は11の機能についてです。
プログラマブルシェーダは自由度が高く色々なことが出来ますので、
処理がどんどん増えていきます。
縦にコードが長くなるのはそれほど困らないのですが、
場合分けで横に増えていくと困りものです。
例えば、ポリゴンをそのまま表示する場合とテクスチャを張る場合。
ライトを当てる場合と当てない場合。
これだけでもう2 × 2 = 4のシェーダが必要になります。
他にも描画要素はたくさんあるので、
掛け算でシェーダ数が増えて行ってとんでもない数になります。
「100万パワー+100万パワーで200万パワー!」
「いつもの2倍のジャンプが加わって200×2の400万パワー!」
「そしていつもの3倍の回転を加えれば400×3の・・・!
バッファローマン!お前を上回る1200万パワーだーーーーっ!」
みたいなもんです。
if文を使った条件分岐でそれなりに対応は出来そうですが、難しい時もあるでしょう。
そういった状況のためにDirect3D 11からはDynamic Shader Linkageが追加されました。
OOPでおなじみのinterfaceとclassの概念をHLSLで使うことが出来ます。
先ほども出た、ポリゴンそのままとテクスチャ有りの場合分けを例にします。
今回のソース
HSLS側の準備
どちらの場合でも色データがとれればいいので、interfaceは次のように定義しました。| 1 | interface BaseColor | 
|---|---|
| 2 | { | 
| 3 | float4 GetColor(float2 uv); | 
| 4 | }; | 
このinterfaceに対するclassとして次のように実装しました。
| 1 | class RawPolygonColor : BaseColor | 
|---|---|
| 2 | { | 
| 3 | float4 GetColor(float2 uv) | 
| 4 | { | 
| 5 | // 固定で白を返す | 
| 6 | return float4(1, 1, 1, alpha); | 
| 7 | } | 
| 8 | }; | 
| 9 | |
| 10 | class TexturedColor : BaseColor | 
| 11 | { | 
| 12 | float4 GetColor(float2 uv) | 
| 13 | { | 
| 14 | // 与えられたuv座標でテクスチャの色を返す | 
| 15 | float4 color = tex.Sample(wrapSampler, uv); | 
| 16 | color.a *- alpha; | 
| 17 | return color; | 
| 18 | } | 
| 19 | }; | 
interfaceのインスタンス変数も用意します。
| 1 | BaseColor baseColor; | 
|---|
インスタンス変数はこのように使えます。
| 1 | float4 oc = baseColor.GetColor(input.uv); | 
|---|
Direct3D側の準備
Direct3Dから、HLSLのインスタンス変数に実装クラスのインスタンスをセットします。
ID3D11Device::CreateClassLinkageを使って、HLSL上interfaceのDirect3Dインターフェース(ややこしい)を作成します。
| 1 | device_.CreateClassLinkage(&pixelShaderClassLinkage_) | 
|---|
作成したインターフェースはID3D11Device::CreateXXXShaderに渡して関連付けます。
| 1 | device_.CreatePixelShader(compiled.GetBufferPointer(), compiled.GetBufferSize(), pixelShaderClassLinkage_, &pixelShader_) | 
|---|
この後、リフレクションを使って、interfaceが何番目のスロットに対応するかチェックするのですが、
今回はinterfaceのインスタンスが1個のため確実に0番になるので省略します。
classのインスタンスはID3D11ClassLinkage::CreateClassInstanceを使って、HLSL上のクラス名から取得します。
| 1 | pixelShaderClassLinkage_.CreateClassInstance("RawPolygonColor", 0, 0, 0, 0, &pixelShaderRawPolygonColorClass_) | 
|---|---|
| 2 | pixelShaderClassLinkage_.CreateClassInstance("TexturedColor", 0, 0, 0, 0, &pixelShaderTexturedColorClass_) | 
(class内にメンバ変数がある場合は、GetClassInstanceを使います)
あとは表示条件に従ってinterfaceのインスタンス変数にclassインスタンスのどちらかをセットして使います。
| 1 | immediateContext_.PSSetShader(pixelShader_, &pixelShaderRawPolygonColorClass_, 1); | 
|---|