C#でツールを作る その15.1 -ランバート反射-

もっとも単純なライティングですね。
輪郭線もシェーダで描画したいので、はちゅねのモデルから面を反転した黒いメッシュを削除しました。

サンプル

  • download
  • VC#2008EE
  • VertexShader2.0
  • PixelShader2.0
  • miku
    • miku01.x
    • miku01.fx
    • miku01.mqo
    • miku.dds
    • miku.jpg
    • miku_alpha.tga

Lambert

  • Ia:ライトのアンビエント
  • Ka:マテリアルのアンビエント
  • Id:ライトのディフューズ
  • Kd:マテリアルのディフューズ
  • N:頂点法線
  • L:ライトベクトル

fxファイル

//-----------------------------------------------------------
//global
//-----------------------------------------------------------
float4x4 Mw;    //ワールド行列
float4x4 Mv;    //ビュー行列
float4x4 Mp;    //プロジェクション行列

float4 mat_diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
float4 mat_ambient = { 0.0f, 0.0f, 0.0f, 0.0f };

float4 light_dir = { 0.0f, 0.0f, 1.0f, 0.0f };
float4 light_diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
float4 light_ambient = { 0.2f, 0.2f, 0.2f, 1.0f };

texture tex;
sampler test_sampler = sampler_state
{
    Texture = <tex>;
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = NONE;
    AddressU = Clamp;
    AddressV = Clamp;
};
//-----------------------------------------------------------
//struct
//-----------------------------------------------------------
struct VertexInput
{
    float4 pos : POSITION;
    float3 normal : NORMAL;
    float2 tex : TEXCOORD0;
};

struct VertexOutput
{
    float4 pos : POSITION;
    float4 color : COLOR0;
    float2 tex : TEXCOORD0;
};

struct PixelOutput
{
    float4 color : COLOR0;
};
//-----------------------------------------------------------
//vertex shader
//-----------------------------------------------------------

VertexOutput TestVertexShader( VertexInput input )
{
    VertexOutput output;
	
    //座標変換
    float4 world_pos = mul( input.pos, Mw );
    float4 view_pos = mul( world_pos, Mv );
    output.pos = mul( view_pos, Mp );
	
    //ライティング(lambert)
    float3 L = -light_dir.xyz;
    output.color.rgb =
        mat_diffuse.rgb * light_diffuse * max( dot( L, input.normal ), 0.0f ) +
        mat_ambient.rgb * light_ambient;
    output.color.a = mat_diffuse.a;
	
    output.tex = input.tex;
    return output;
}
//-----------------------------------------------------------
//pixel shader
//-----------------------------------------------------------

PixelOutput TestPixelShader( VertexOutput input )
{
    PixelOutput output;
    output.color = tex2D( test_sampler, input.tex ) * input.color;
    return output;
}
//-----------------------------------------------------------
//technique
//-----------------------------------------------------------
technique test
{
    pass P0
    {
        VertexShader = compile vs_2_0 TestVertexShader();
        PixelShader = compile ps_2_0 TestPixelShader();
		
        ZEnable = true;
        ZWriteEnable = true;
        Lighting = false;
        AlphaBlendEnable = true;
        CullMode = CCW;
        SrcBlend = SRCALPHA;
        DestBlend = INVSRCALPHA;
    }
}

まとめ

  • pass単位でレンダーステートを設定できるのは便利。
  • 複数のpassはどうやって使い分ければいいのか?
  • pass実行中にSetValue不可。これではまった。。。
  • XNAのEffectクラスが使いやすそう。
  • エフェクトで使用するメッシュやテクスチャの指定はアノテーションを使うべきなのか。