シャドウマップの改良 -側面のジャギーを軽減-

前回HLSLで影の描画 -シャドウマップ- - while( c++ );のシャドウマップを使った影の描画を、もう少しキレイにしてみます。
特にライトへのベクトルと面の法線ベクトルのなす角が90度に近い部分の汚い影ですね。

とりあえず、らしく見えれば良いということで。

実行結果


他のモデルで試してないので正しく描画できているかわかりませんが、
前回より十分使えるレベルになったのではないかと。

考え方

  • ライトベクトルと法線ベクトルのなす角が垂直に近づけば、影も薄くなる。
    • L・N = 影の濃さ
  • 頂点シェーダ内のL・Nをピクセルシェーダに渡して、影を描画するときにピクセルの色に1-L・Nを掛ける。
  • 2乗、3乗するとキレイ(線形より曲線)
shadow.fx
struct VertexOutput
{
    float4 pos : POSITION;
    float4 color : COLOR0;
    float4 shadowmap : TEXCOORD0;
    float4 color2 : TEXCOORD1;    //w=影の濃さ
};

VertexOutput VS( float4 pos : POSITION, float3 normal : NORMAL )
{
    VertexOutput output = ( VertexOutput )0;
    float4 p = mul( pos, M_world );
    output.pos = mul( p, M_view_proj );

    float3 n = mul( normal, M_world );
    n = normalize( n );
    float k = max( dot( light_dir.xyz, n ), 0.0f );
    float4 color = k * light_diffuse * material_diffuse;
    color += light_ambient * material_ambient;
    output.color = color;
    
    //影の濃さ(適当に3乗してみた)
    output.color2.w = k * k * k * 0.6f;
	
    p = mul( pos, M_world );
    p = mul( p, M_lightview_proj );
    output.shadowmap = p;

    return output;
}

float4 PS( VertexOutput input ) : COLOR
{
    float w = 1.0f / input.shadowmap.w;
    float2 tex;
    tex.x = ( 1.0f + input.shadowmap.x * w ) * 0.5f;
    tex.y = ( 1.0f - input.shadowmap.y * w ) * 0.5f;
    float z = tex2D( shadow_sampler, tex ).x;

    float color = input.color;
    if( input.shadowmap.z * w > z + bias )
        color = color * ( 1.0f - input.color2.w );//影の濃さを掛ける

	return color;
}

かなり適当です。
多分もっと一般的な方法があるのではないかと。
自力ではこの程度の方法しか思いつきませんでした。。。

次回予定

  • RenderTagetクラスを作る
    • もう少しまとめてからソースを公開します
    • XNAにもRenderTargetクラスがありますね
    • GraphicsDevice的なものも作るべきか
  • ガウスフィルタ
  • Variance Shadow Maps

追記(2/12)

こちらに解決方法がありました。