Skip to content

改訂前の参考解説

このページは改訂前の教材です。現在の授業の回番号・内容は、後期の授業計画で確認してください。

第16回 法線と基本的なランバート照明

2 / 4 内積による面の明るさ ​

このステップの目的

このステップでは、法線と光の方向を正規化し、内積からランバート照明の明るさを求める方法を学びます。

光の方向を定義する ​

この実装では、光の方向を「表面から光源へ向かう方向」と定義します。光が進んでくる向きとは逆向きになる点に注意してください。

例として、光源がオブジェクトの上方にある状況を考えてみましょう。表面から光源へ向かう方向は、World空間の上向きを表す(0, 1, 0)となります。上を向いた面ほど、その法線がこの方向とそろい、より強く光を受けることになります。

この回では、すべての表面に同じ光の方向を与えます。光源までの距離による減衰や、Scene内のDirectional Lightから値を取得する処理は含めません。マテリアルに指定したベクトルを使って、計算による明暗の変化を確認していきましょう。

比べる二つのベクトルをそろえる ​

まずはShaderLabのPropertiesへ、光の方向を指定する次の項目を追加してください。

shaderlab
_Tint ("Tint", Color) = (1, 1, 1, 1)
_LightDir ("Direction To Light (World)", Vector) = (0, 1, 0, 0)

続いて、既存のUnityPerMaterial内へ、対応する次の宣言を追加してください。

hlsl
float4 _Tint;
float4 _LightDir;

マテリアルからは4つの数値が渡されますが、この計算で使用するのはxyzの3成分だけです。末尾のw成分は計算には使いません。

次に Frag() 内の normalWS の宣言を残し、その下に光の向きを正規化する行を追加します。

hlsl
float3 normalWS = normalize(input.normalWS);
float3 lightDirWS = normalize(_LightDir.xyz);

両方の変数は、World空間の向きを表しています。もしObject空間の法線とWorld空間の光の方向をそのまま比較してしまうと、オブジェクトの回転が正しく反映されません。

なお、光の方向には(0, 0, 0)以外の値を指定してください。長さが0のベクトルには向きがないため、正規化して光の方向として使うことができません。

内積から照らされ方を求める ​

続いて、正規化した二つのベクトルの内積を計算します。

hlsl
float3 lightDirWS = normalize(_LightDir.xyz);
float diffuse = saturate(dot(normalWS, lightDirWS));

dotは二つのベクトルの内積を求めます。どちらも長さが1の単位ベクトルの場合、内積は二つの方向が一致すると1、直角になると0、反対を向くと−1になります。

saturateは、入力値を0〜1の範囲へ制限(クランプ)します。裏側を向く面の負の内積を0へそろえることで、光を向いている面だけを明るく照らすことができます。

法線と光の方向の関係内積この式で使う明るさ
二つの方向が一致する11
二つの方向のなす角が60度0.50.5
二つの方向が直角になる00
二つの方向が反対を向く−10

このdiffuseは、ランバート照明における角度の係数です。最終的な色を求めるためには、表面の色や光の色も組み合わせます。

まず明暗だけを出力する ​

前のステップの法線を色にする return 行を、次の行に置き換えます。求めた明暗の係数だけを出力し、結果を確認します。

hlsl
return float4(diffuse, diffuse, diffuse, 1.0);

この式は、同じ明るさをRGBのすべての成分に入れます。このように白黒(グレイスケール)で表示することで、テクスチャの模様と照明による明暗を明確に区別して確認できます。

  1. 光の方向を(0, 1, 0)に設定し、上を向いた面が明るくなることを確認します。
  2. 光の方向を(1, 0, 0)へ変更し、World空間のX軸の正方向を向いた面が明るくなることを確認します。
  3. 光の方向を固定したままオブジェクトを回転させ、それに追従して明るい面が変わることを確認します。

比較後は光の方向を (0, 1, 0)、オブジェクトの回転を変更前へ戻します。白黒の出力はこのまま残し、ステップ4で表面の色を合成します。

チェックリスト
  • 光の方向を「表面から光源へ向かう方向」として正しく指定できていますか。
  • 法線と光の方向をWorld空間へそろえていますか。
  • dotとsaturateがそれぞれ何を計算するか説明できますか。
  • 光の方向を変更する前に、どの面が明るくなるかを予想できますか。