LoginSignup
14
11

More than 5 years have passed since last update.

[Unity] Cgでのライティングについてメモ

Last updated at Posted at 2014-09-23

定義済値や定義の意味など、Unityでよしなにやってくれている部分などを含めて単純なDiffuseライティングをやるメモ。

シンプルなコード例

簡単なライティングをするコード例。

SubShader {
    Tags {
        "RenderType"="Opaque"
        "LightMode"="ForwardBase"
    }
    LOD 200

    Pass {
        CGPROGRAM

        #pragma vertex vert
        #pragma fragment frag

        struct vertInput {
            float4 vertex    : SV_POSITION;
            float4 normal    : NORMAL;
            float2 texcoord  : TEXCOORD0;
            float2 texcoord2 : TEXCOORD1;
        };

        struct vert2frag {
            float4 position : POSITION;
            float2 uv       : TEXCOORD0;
            float2 uv2      : TEXCOORD1;
            float4 color    : COLOR0;
        };

        uniform sampler2D _MainTex;
        uniform sampler2D _NormalTex;
        uniform fixed4 _LightColor0;

        vert2frag vert(vertInput v) {
            vert2frag o;

            float4 wpos    = mul(UNITY_MATRIX_MVP, v.vertex);
            float4 wnormal = mul(v.normal, _World2Object);
            float  diffuse = max(0, dot(_WorldSpaceLightPos0, wnormal));

            o.position = wpos;
            o.color    = _LightColor0 * diffuse;

            return o;
        }

        float4 frag(vert2frag i) : COLOR {
            return i.color;
        }

        ENDCG
    }
} 

ライティングの準備

  • "LightMode"="ForwardBase"タグをつける

これを付けないとライティングに関する情報が取得できません。

  • uniform fixed4 _LightColor0を宣言

uniform変数として、fixed4型の_LightColor0という変数を宣言します。
ここに、ライトの色が渡されます。

頂点シェーダで計算

頂点シェーダは以下のようになっています。

vert2frag vert(vertInput v) {
    vert2frag o;

    float4 wpos    = mul(UNITY_MATRIX_MVP, v.vertex);
    float4 wnormal = mul(v.normal, _World2Object);
    float  diffuse = max(0, dot(_WorldSpaceLightPos0, wnormal));

    o.position = wpos;
    o.color    = _LightColor0 * diffuse;

    return o;
}
wnormalの計算時、normalizeしてしまっていたので削除しました。normalizeするとうまく動きません。

処理としては法線をワールド空間座標に変換したのちに、ライトの位置との内積を取っています。
_WorldSpaceLightPos0はひとつ目のライトの位置です。これは自動的に宣言されているのでそのまま利用することが出来ます。

ちなみにUnityでは、DirectionalLightも視覚的に位置が表示されますが、実際には回転が影響を与えます。(当たり前ですが)
視覚的に見えている分、おや?となってしまうので勘違いしないようにしましょうw

法線の計算

法線の計算については、ワールド空間座標への変換を行っていますが、変換には若干の注意が必要です。
こちらの記事がとても参考になりました)

結論だけ言うと、 モデル行列の逆転置行列を掛ける 必要があります。
が、そこは少しだけ楽をして、Unityから渡されるモデル行列の逆行列(_World2Object)を、ベクトルに対して逆から掛けてやることで結果的に逆転置行列を掛けたことにしています。

色の計算

あとは、ライトの色と法線とライト位置から求めた内積を掛けあわせて最終的な色を決定している、というわけです。

14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11