研究開発日誌

CG研究・開発のちょっとしたメモ書き

Unityシェーダー:LambertShader

2014-12-25 Unity

Unityで開発したLambertShader.

Lambert反射の成分は,ライトベクトル$\mathbf{L}$と法線ベクトル$\mathbf{N}$が成す角度の関数で表されます.環境光の色$\mathbf{c_a}$,反射率$k_a$,拡散反射の色$\mathbf{c_d}$,拡散反射率$k_d$を合わせた最終的な色$I$の計算式は, $I = k_a \mathbf{c_a} + k_d (\mathbf{L} \cdot \mathbf{N}) \mathbf{c_d} $のように表すことができます. 以下では,主にピクセルシェーダー上でライティング計算を行い,最終的なシェーディング結果を計算しています.

// Pixel処理でシェーディング計算を行うLambertShader
Shader "Custom/LambertShader" {
    // LambertShaderのパラメータを宣言
    Properties {
        // 環境光の色
        // _Ka: 反射率
        _Ambient ("Ambient Color", Color) = (0.3,0.3,1,1)
        _Ka ("Ka", Range (0.01, 1)) = 0.5

        // 拡散反射の色
        // _Kd: 反射率
        _Diffuse ("Diffuse Color", Color) = (0.3,0.3,1,1)
        _Kd ("Kd", Range (0.01, 1)) = 0.8
    }
    SubShader {
    pass{
        // Unityのライトオブジェクトを使ったLightMode
        Tags { "LightMode" = "ForwardBase" }

        // Cgプログラムを使用する宣言
        // 頂点処理とピクセル処理を行うことを宣言
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"

        // Cgプログラムで使う変数
        // Propertiesブロックと対応付ける
        float4 _Ambient;
        float  _Ka;

        float4 _Diffuse;
        float   _Kd;


        // 頂点からピクセルに転送されるデータ
        struct vertexOutput {
            float4 pos : SV_POSITION; // 座標変換後の位置
            float3 L   : TEXCOORD0; // ライトベクトル
            float3 N   : TEXCOORD1; // 法線ベクトル
        };

        // 頂点毎の処理
        // pos, L, N, RVのデータを計算する.
        vertexOutput vert(appdata_base v) : POSITION
        {
            vertexOutput output;
            // 座標変換後の位置
            output.pos = mul (UNITY_MATRIX_MVP, v.vertex);

            // 法線ベクトル
            float3 N = v.normal;
            output.N = N;

            // ライトベクトル
            output.L = ObjSpaceLightDir(v.vertex);

            return output;
        }

        // ピクセル毎の処理
        // LambertShadingのライティング計算を行う
        float4 frag(vertexOutput input) : COLOR
        {
            // 頂点処理で計算したベクトルデータを正規化して取り出す
            float3 L = normalize( input.L );
            float3 N = normalize( input.N );

            // 環境光成分I_aを計算
            float4 I_a = _Ka * _Ambient;

            // 拡散反射成分I_dを計算
            float LdN = clamp( dot(L, N), 0, 1 );
            float4 I_d = _Kd * LdN * _Diffuse;

            // 足し合わせて最終的な色を計算する
            float4 I = I_a + I_d;

            return I;
        }
        ENDCG
        }
    }
    FallBack "Diffuse"
}

参考文献

[1] Lambertian reflectance - Wikipedia: http://en.wikipedia.org/wiki/Lambertian_reflectance