• Direct3D 11のDynamic Shader Linkageを試す

    2011年08月25日 20時53分
    Direct3D 11で~とかしれっと書き続けて来ましたが、
    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は次のように定義しました。
    1interface BaseColor
    2{
    3    float4    GetColor(float2 uv);
    4};


    このinterfaceに対するclassとして次のように実装しました。
    1class RawPolygonColor : BaseColor
    2{
    3    float4    GetColor(float2 uv)
    4    {
    5        // 固定で白を返す
    6        return    float4(1, 1, 1, alpha);
    7    }
    8};
    9
    10class 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のインスタンス変数も用意します。
    1BaseColor baseColor;


    インスタンス変数はこのように使えます。
    1float4 oc = baseColor.GetColor(input.uv);


    Direct3D側の準備


    Direct3Dから、HLSLのインスタンス変数に実装クラスのインスタンスをセットします。


    ID3D11Device::CreateClassLinkageを使って、HLSL上interfaceのDirect3Dインターフェース(ややこしい)を作成します。
    1device_.CreateClassLinkage(&pixelShaderClassLinkage_)



    作成したインターフェースはID3D11Device::CreateXXXShaderに渡して関連付けます。
    1device_.CreatePixelShader(compiled.GetBufferPointer(), compiled.GetBufferSize(), pixelShaderClassLinkage_, &pixelShader_)


    この後、リフレクションを使って、interfaceが何番目のスロットに対応するかチェックするのですが、
    今回はinterfaceのインスタンスが1個のため確実に0番になるので省略します。


    classのインスタンスはID3D11ClassLinkage::CreateClassInstanceを使って、HLSL上のクラス名から取得します。
    1pixelShaderClassLinkage_.CreateClassInstance("RawPolygonColor", 0, 0, 0, 0, &pixelShaderRawPolygonColorClass_)
    2pixelShaderClassLinkage_.CreateClassInstance("TexturedColor", 0, 0, 0, 0, &pixelShaderTexturedColorClass_)

    (class内にメンバ変数がある場合は、GetClassInstanceを使います)



    あとは表示条件に従ってinterfaceのインスタンス変数にclassインスタンスのどちらかをセットして使います。
    1immediateContext_.PSSetShader(pixelShader_, &pixelShaderRawPolygonColorClass_, 1);

    コメントを書く

    名前
    本文
    編集用パスワード 入力すると編集が行えます
    管理者のみ閲覧