Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

定義済値や定義の意味など、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)を、ベクトルに対して逆から掛けてやることで結果的に逆転置行列を掛けたことにしています。

色の計算

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

edo_m18
現在はUnity ARエンジニア。 主にARのコンテンツ制作をしています。 最近は機械学習にも興味が出て勉強中です。 Unityに関するブログは別で書いています↓ https://edom18.hateblo.jp/
http://edom18.hateblo.jp/
unity-game-dev-guild
趣味・仕事問わずUnityでゲームを作っている開発者のみで構成されるオンラインコミュニティです。Unityでゲームを開発・運用するにあたって必要なあらゆる知見を共有することを目的とします。
https://unity-game-dev-guild.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away