Silverlight 5(Beta)で Teapot + Blinn-Phong ③

  1. 開発環境の準備と DrawingSurface
  2. Teapot クラス
  3. Blinn-Phong シェーダー
  4. 描画
  5. トラックボール
  6. シェーダー パラメータの操作

image

Silverlight 5(Beta)の XNA には BasicEffect のような便利なクラスがないので、自前で頂点シェーダーとピクセルシェーダーをHLSL(Hight Level Shader Language)で書いて、コンパイルして、ロードして、デバイスに設定しなければなりません。ここでは Blinn-Phong シェーダーを実装して適用します。Silverlight 5 (Beta) でサポートされるのはシェーダーバージョン 2(vs_2_0, ps_2_0)です。

Silverlight プロジェクトを選択して、Visual Studio の [プロジェクト]→[新しいフォルダー]を選び「HLSL」フォルダーを作成します。そのフォルダーにBlinn-Phong.vs.hlsl と Blinn-Phong.ps.hlsl ファイルを作成します。HLSLを右クリックし[追加]→[新しい項目]でテンプレートは何でも構わないと思いますが、テキストファイルでも使いましょう。

Blinn-Phong シェーダー(HLSL)

Blinn-Phong はスペキュラー(鏡面反射)を表現するシェーディングで、Phong シェーディングを Blinn が等分角ベクトル(ハーフ ベクトル)を使って表現したものです、詳しくは拙著リアルタイム レンダリングなどを参照してください。

頂点シェーダーでは、各頂点の位置をWVP(World-View-Projection)行列で座標変換するとともに、ライト ベクトルと法線との内積からディフューズ色(拡散反射)と、ライト ベクトルとビュー ベクトルから等分角ベクトルを出力します。

コードからシェーダーに渡す頂点やテクスチャ以外のデータには、座標変換や照明計算に必要な行列や色などがあり、これらはレジスターの形で渡します。1レジスターは4つの浮動小数点で float4 で表し、float4x4 は4つのレジスターを使って行列が渡されることを意味します。Silverlight 側のコードでこれらの変数をデバイスに登録します。詳細はHLSLのドキュメントを参照してください。

// Blinn-Phong.vs.hlsl
float4x4 matWVP : register(c0);
float4 lightPosition : register(c4) ;
float4 viewPosition : register(c5);
float4 k_d : register(c6);
float4x4 matW_I : register(c7);
 
struct VS_OUTPUT
{
float4 Pos: POSITION;
float4 Diffuse: COLOR0;
float3 Normal: TEXCOORD0;
float3 HalfVector: TEXCOORD1;
};

VS_OUTPUT main( float4 inPosition: POSITION , float3 inNormal : NORMAL)
{
VS_OUTPUT Out = (VS_OUTPUT)0;
// transform position to clip space
Out.Pos = mul(inPosition, matWVP);
// light vector in local space
float3 lightVector =
normalize((float3)(mul(lightPosition,matW_I) - inPosition));
// diffuse term
Out.Diffuse = k_d*max(0.2,dot(lightVector, inNormal));

// normal vector
Out.Normal = inNormal;
// view vector in local space
float3 viewVector =
normalize((float3)(mul(viewPosition,matW_I) - inPosition));
// half vector in local space
Out.HalfVector = normalize (viewVector + lightVector);

return Out;
}

ピクセル シェーダーでは頂点シェーダーから渡された法線と等分角ベクトルの内積をとり、Blinn-Phong のシェーディング式にしたがって、レジスターで渡された因子でべき乗を計算し、ディフューズ色に加算して出力します。

// Blinn-Phong.ps.hlsl
float4 k_s : register(c0);

struct VS_OUTPUT
{
float4 Pos: POSITION;
float4 Diffuse: COLOR0;
float3 Normal: TEXCOORD0;
float3 HalfVector: TEXCOORD1;
};

float4 main( VS_OUTPUT ps_in ) : COLOR0
{
// half vector
float3 halfVector = normalize(ps_in.HalfVector);
float3 normalVector = normalize(ps_in.Normal);
// Blinn-Phong specular
float3 specular = k_s.xyz * pow (saturate(dot(normalVector, halfVector)), k_s.w);
// add iterated diffuse and pre-pixel specular
float4 color = ps_in.Diffuse + float4(specular,1);
color.w = 1;
return color;
}

シェーダー コンパイラーの設定

Silverlight プロジェクトをビルド・実行する前に、シェーダーをコンパイルして、リソースとして組み込む必要があります。そこで VisualStudio の  Silverlight プロジェクトのプロパティからビルド イベント タブの[ビルド前に実行するコマンドライン]に以下のコマンドを追加します。これによってプロジェクトをビルドする前に自動的にシェーダーコンパイラーがシェーダーをコンパイルし、エラー一覧にエラーメッセージも表示してくれます。fxc のコマンドライン構文と引数についてはこちらを参照してください。

pushd $(ProjectDir)\HLSL
for /f "tokens=*" %%a in ('dir /b *.vs.hlsl') do (
call "%%DXSDK_DIR%%Utilities\bin\x86\fxc.exe" /T vs_2_0 /O3 /Zpr /Fo %%~na %%a >> hlslcomplog.txt
)
for /f "tokens=*" %%a in ('dir /b *.ps.hlsl') do (
call "%%DXSDK_DIR%%Utilities\bin\x86\fxc.exe" /T ps_2_0 /O3 /Zpr /Fo %%~na %%a >> hlslcomplog.txt
)
popd

image

初めてビルド・デバッグ実行するとエラーで停止するかもしれませんが、デバッグを中止します。生成された Blinn-Phong.vs と Blinn-Phong.ps をソリューション エクスプローラーのHLSLフォルダーに追加します(ソリューションエクスプローラーのHLSLフォルダーを右クリックして[追加]→[既存の項目])。生成されていない場合は hlsl のコンパイル エラーなので、エラーメッセージを見て前述のシェーダーを正しく実装してください。それでもだめなときは前述のコマンドをコマンドファイルにしてコマンド プロンプトから実行して確認してみてください。

Blinn-Phong.vs と Blinn-Phong.ps のそれぞれのプロパティの[ビルドアクション]を Resource にしてください。.ps は自動的に Resource になるのですが(ポストスクリプトファイルと誤解?)、.vs は自分で設定する必要があるようです。上記のファイルの追加もこのResourceの設定も、最初に一度行えばあとは変更する必要はありません。

image

 

次回は、前回実装した Teapot クラスとこのシェーダーを使って描画を行います。

頂点シェーダーとピクセルシェーダーを添付します。

Blinn-Phong.hlsl.zip