PixelShaderを使ったCustomEffect
Now Editing!
About
WPFではHLSLを使って記述したPixelShaderをCustomEffectとして適用する事ができます。端的にいえば、PixelShaderを使う事で、GPUを介して画像(UI)に特殊な効果を施すことができる、ということです。
How to
利用するPixelShaderはあらかじめコンパイルされている必要があります。つまりHLSLを用いて記述された「.fxファイル」のままではWPFからその関数(PixelShader)を呼び出して実行する事ができないということです。シェーダのコンパイルについては次のページを参照されたい。
シェーダにパラメータを渡す
テクスチャ(sampler)
参照用テクスチャの情報を与える場合などは、
/// <summary> /// Shader内で参照するテクスチャ(Sampler)を設定するためのプロパティ。 /// </summary> public Brush RefTexture { get { return (Brush)GetValue(Property_Tex2d_RefTexture); } set { SetValue(Property_Tex2d_RefTexture, value); } } public static readonly DependencyProperty Property_Tex2d_RefTexture = ShaderEffect.RegisterPixelShaderSamplerProperty ("RefTexture",//シェーダ内でのSampler(グローバル変数)の名前 typeof(SimpleCustomShader),//このクラスの名前 1,//シェーダ内でのSamplerのレジスタ番号 SamplingMode.NearestNeighbor//シェーダ内でのSampling方法 );
制限
この内容はHLSLやその他の環境でシェーダを利用したことがある方に向けられています
WPFでPixelShaderを利用する場合には、サンプラ(sampler)に直接値を引き渡すためか、シェーダ内で定義した「sampler_state」は全て適用されません(≒sampler_stateで参照するテクスチャを定義しない)。つまり他のDirectXで利用されていたPixelShaderなどを使いまわさない場合は、シェーダ内でTextureを用意して、「sampler_state」から参照するなどの記述が一切必要ないわけです。使い回しによって「sampler_state」が記述されている場合でも問題なく動作しますが、sampler_stateに設定した全てのパラメータは有効とならない点に注意する必要があります。
サンプリング方法に関しては、DependencyPropertyの「SamplingMode」でのみ設定できる様です。しかしここには「NearestNeighbor」か「BiLinear」しかありません。「MagFilter = Point;」などの設定も無効化されるわけですから、事実上「ドットバイドット(dot by dot)≒ピクセル単位」でサンプリングする事ができないことになります。出力結果自体はWPFのUI設定でピクセル単位の描画にすることは出来ますが、サンプリング自体がどうしようもないので、例えば8bitのファミコンの絵などを出力する場合には、凄くぼやけた絵が得られます。
その他のパラメータ(float)
floatで表すことのできるパラメータを与える場合などは
/// <summary> /// シェーダ内で参照する任意の値を設定するためのプロパティ。 /// ここでは赤成分を操作するための値とする。 /// </summary> public float RedValue { get { return (float)GetValue(Property_RedValue); } set { SetValue(Property_RedValue, value); } } public static readonly DependencyProperty Property_RedValue = DependencyProperty.Register( "RedValue",//シェーダ内でのグローバル変数の名前 typeof(float),//与えるデータの型 typeof(SimpleCustomShader));//,//このクラスの名前
Rendartargetについて
マルチターゲット(パス)レンダリングのためのRendarTargetの指定は、XNAやDirectXでプログラミングするようには出来ないようです(やり方があったら教えて頂きたい)。ただし、空の画像(RendarTarget)に対してレンダリングする、という意味で、1つのRendarTargetを指定するような事は可能です。その場合は、RendarTargetBitmapのインスタンスを利用します。事実上、空のBitmapとして扱う事ができるので、RendarTargetを1つ指定するのと同様の挙動を可能にします。
…