今更だけど

トゥーンシェーダを実装してみた。
まず、色の階調化だけど、これは簡単にできた。

ライトのベクトルと法線の内積をとって、UV座標を計算。ベクトルは正規化しないとU値が1より大きくなるので注意。このままでは、値が0以下のこともありえるので、0から1の範囲になるように調整する。

次は、輪郭線の抽出。さっきと同じで、視線のベクトルと法線の内積をUV座標のV値に代入する。

後は計算したUVを元にトゥーン用のテクスチャから色を拾って描画。これで、おしまい。

描画してみた

何か輪郭線が汚い。上手く抽出できてないようだ。


以下、fxファイルの中身

float4x4 mWVP;
float3 vLight = {0.557f, -0.557f, 0.557f}; // ライトの方向
float3 vEye;

// 頂点シェーダー出力
struct VS_OUTPUT
{
    float4 Pos : POSITION;  // 座標
    float2 Tex : TEXCOORD0; // テクスチャUV
};

VS_OUTPUT ToonVS(float4 Pos : POSITION, float4 Normal : NORMAL)
{
    VS_OUTPUT Out = (VS_OUTPUT)0;

    Out.Pos = mul(Pos, mWVP); // 座標変換
    float3 N = normalize(Normal.xyz); // 法線を正規化

    Out.Tex.x = max(dot(vLight, N), 0) * 0.5f + 0.5f; // 0から1の範囲に修正

    float3 E = normalize(vEye - Pos.xyz); // 視線のベクトル
    Out.Tex.y = dot(E, N); // vを計算、内積が小さいとき、輪郭抽出を行う

    return Out;
}

technique ToonShader
{
    pass P0
    {
        VertexShader = compile vs_2_0 ToonVS();
    }
}