Spriteの描画にPixelShaderを適用する
About
読み込んだ2次元のテクスチャを描画する際にシェーダ(PixelShader)を使って効果を与えたい場合があります。ここではSpriteBatchによる2次元の描画時にエフェクトを適用する方法について解説しています。
図の左側はPixelShaderを使って、SpriteBatchから与えられたテクスチャをそのまま描画した実行例です。特別な操作を行っていないため、通常のSpriteBatchと同様の結果が得られます。図の右側はPixelShaderによる描画であることを確認するために、透過度が徐々に変化するようなグラデーション処理を施しています。
- WindowsGame1_ApplyAPixelShaderToSprites.zip
- VS2010
- XNA4.0
How To
シェーダをSpriteBatchによる描画にのみ利用する場合、用意するシェーダはPixelShaderだけで十分です。主に頂点情報を取り扱うために用いられるVertexShaderは基本的には不要です。よって、SpriteBatchによる描画へ用いるシェーダの記述、つまりEffectファイルに記述する、最小限のセットは次の様になります。
//SpriteBatchで描画されるTexture texture ScreenTexture; //SpriteBatchで描画されるTextureのサンプラ sampler ScreenTexSampler:register(s0) = sampler_state { Texture = <ScreenTexture>; }; float4 PixelShaderFunction(float2 texCoord:TEXCOORD) : COLOR0 { float4 color = tex2D(ScreenTexSampler,texCoord); return color; } technique Technique1 { pass Pass1 { PixelShader = compile ps_2_0 PixelShaderFunction(); } }
またCPU側、つまりSpriteBatchなどのシェーダ利用側の記述は次の様になります。
//エフェクトを利用した描画の開始 spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, effect); //エフェクトを利用して描画 spriteBatch.Draw(tex2d_Lena, Vector2.Zero, Color.White); spriteBatch.End();
SpriteBatchで描画を開始する際に、その描画で用いるシェーダを指定するための機構がXNAのSpriteBatchには用意されています。そこで利用したいシェーダ、つまりEffectを指定します。その他の引数パラメータについては特に言及しませんが、基本的にnullを指定するとSpriteBatchでデフォルトで利用される値が与えられるようになっています。また第一引数であるSpriteSortModeのデフォルト値はDeferredの様です。
実際にシェーダを利用した描画が開始されると、PixelShaderに指定した関数が実行されます。原則として引数に「float2 texCoord:TEXCOORD」を受け取ることに注意してください。レンダリングしようとするテクスチャ(およびそれに準じるもの)の座標情報が必要な点は、通常の3DCGの描画時に用いられるPixelShaderの基本原理と変わりありません。
また用意するシェーダのグローバル変数には必ず、テクスチャとそのサンプラを用意しておく必要があります。これらはSpriteBatchによる描画が実行される際に、その描画対象のデータが与えられます。このテクスチャ(のサンプラ)が用意されていなければ、描画対象のデータ(描画する色)を参照することが出来なくなります。
用意するテクスチャ(サンプラ)のレジスタ番号は必ず「0」を指定します。それとは別途、処理に用いるためのテクスチャなどを用意する場合は、必ずレジスタ番号を0以外に指定してください。不具合が生じる可能性があります。詳細は次のページを参照してください。
シェーダを生かした描画
基本的な例ではシェーダを介して描画対象であるテクスチャをそのまま描画していますが、それでは本当にシェーダの恩恵を受けているか分からないため、サンプルプログラムとして、シェーダによってグラデーションを施す関数を用意しました。サンプルプログラムではデフォルトで「PixelShaderFunction()」が利用されていますが、「PixelShaderFunction2()」を利用するようにします。シェーダ内に記述された「Pass」の「PixelShader」に関する記述のコメントアウトを入れ替えれば「PixelShaderFunction2()」が利用されるようになります。
float4 PixelShaderFunction2(float2 texCoord:TEXCOORD) : COLOR0 { float4 color = tex2D(ScreenTexSampler,texCoord); color.a *= texCoord.x; return color; } technique Technique1 { pass Pass1 { //PixelShader = compile ps_2_0 PixelShaderFunction(); PixelShader = compile ps_2_0 PixelShaderFunction2(); } }
「PixelShaderFunction2」では、描画対象のテクスチャの色情報を取得した後、そのテクスチャにおけるその色情報の座標からグラデーションを施すような実装を行っています。シェーダ内で得られるテクスチャの座標および色情報は「0~1」で定められます。α値はその色がどれだけ透過しているかを示す値です。そこにテクスチャのx座標を乗じているわけですから、左から右に描画が進むに連れて、徐々に透過率が下がり、最終的に右 端(x=1)となる地点で元の色が描画されることになります。
実際に画像処理などにHLSLを利用したい場合は、テクスチャのピクセル座標が必要になることが多くあります。例えばフィルタリングの処理などは、注目ピクセルを中心とする、周囲のピクセルも参照する必要があるためです。そう行った場合は、必要に応じて次のページを参照するようにして下さい。