反射ベクトルの求め方

こんにちは、Whileです。
鏡面反射などで出てくる反射ベクトルの求め方でちょっと躓いたので自分用にまとめたいと思います。

問題

反射ベクトル
図のような入射ベクトルLが面上で正反射した時の反射ベクトルを求めます。 入射ベクトルLと法線ベクトルNは正規化されているとします。

反射ベクトルの求め方

反射ベクトルの求め方
上の図のように、入射ベクトルLにベクトルDを2つ足すという考え方で反射ベクトルRを求めます。 これは以下の式で表されます。

 \displaystyle
R = L + 2(-L\cdot N)N

導出

入射ベクトルLにベクトルDを2つ足すという考え方で反射ベクトルRを求めますが、そのためにはベクトルDを求める必要があります。
ベクトルは、そのベクトルと平行なベクトルの定数倍で表すことが出来ます。 (0,1)と(0,2)など簡単な例で考えるとすぐに分かると思います。
ここでは、法線ベクトルNとベクトルDが平行なので、ベクトルDを法線ベクトルNの定数倍で表すことができるということです。この性質を利用して、ベクトルDを求めます。
そのために、内積を行ってベクトルDを長さを求めます。
なぜここで内積が出てくるのでしょうか。内積幾何学的意味を見てみましょう。

内積幾何学的意味
このように、 A\cdot BによってベクトルCの長さを求めることが出来ます。ベクトルAとBを入射ベクトルLと法線ベクトルNに置き換えて上の図を見ると、ベクトルDの長さを求られることが分かると思います。 ここで一点、上の図と同様の結果を得たい場合は、LとNの向いている方向を一致させる必要があることに注意してください。上の図では2つのベクトルが向いている方向が一致(X軸のみに着目すると、両方とも正の方向を向いている)しています。したがって、方向をそろえるために入射ベクトルLを反転させる必要があります。
Dベクトルの求め方
向きをそろえて入射ベクトルLと法線ベクトルNの内積を計算すると、 |D| = cosθであることが分かりました。
よって、ベクトルDは以下のように求められます。

 \displaystyle
D = (-L\cdot N)N = Ncosθ

これでベクトルDが求められました。あとはベクトルの加算を利用して入射ベクトルLに2倍したベクトルDを足すだけですね。

反射ベクトルRを求める
なので、最初に紹介した通り、反射ベクトルRを求める式は

 \displaystyle
R = L + 2(-L\cdot N)N

となるわけです。

最後に

行間が読めないので1から10までの説明がないと躓くことが多いです。
その行間を埋めた解説記事を書いて数学苦手な人の助けになればいいなと思います。

フォンの反射モデル解説 ~拡散反射~

こんにちは、Whileです。今回が初の技術記事です。
最近はシェーダーの勉強やレイトレーシングの実装を行っています。その際に出てきたPhong反射モデルを解説します。
全て解説すると長くなっちゃうので今回は拡散反射のみを扱います。

Phongの反射モデルとは

フォンの反射モデル
Phongの反射モデルはコンピュータグラフィックスにおけるシェーディングで扱われるモデルの一種で、以下の数式で表されます。

 \displaystyle
I = K_{d}I_{in}cosθ_{1} + K_{s}I_{in}(cosθ_{2})^n + K_{a}I_{a}

このモデルは拡散反射・鏡面反射・環境光の3つの要素から構成され、これらを足し合わせてオブジェクト表面の陰影を決定します。

拡散反射

拡散反射とは、物体の表面に入射した光が表面の細かい凹凸によってあらゆる方面に等しく拡散する反射のことを言います。

拡散反射のイメージ

数式でいうとこの部分にあたります。

 \displaystyle I_{d} = K_{d}I_{in}cosθ_{1}

この数式はランバートの法則と呼ばれます。
この式は、拡散反射光  {I}_d の強さは入射角の大きさに反比例する(余弦に正比例する)ということを意味しています。つまり、入射角が大きくなるにつれて拡散反射光が弱くなるということです。

拡散反射光と入射角の関係

  •  {K}_d 拡散反射係数

オブジェクトの表面がRGB各成分をどれだけ反射するかを表します。
例えば、 {K}_d = (0,1,0) だとオブジェクトは緑色の光のみを反射するという意味になります。オブジェクトの色を設定したというイメージに近いです。

  •  {I}_{in} 入射光の強さ

UnityのLightでいうIntensityに相当する部分です。この部分なんですが、光源の拡散反射係数  {I}_d になっている場合もあり混乱しました。UnityのLightでは光源の色も設定できるので、計算式が以下のようになっているんじゃないかと思います。

 \displaystyle I_{d} = I_{in}K_{d}I_{d}cosθ_{1}

これで光源の強さ・色の両方を反映させられるというわけですね。
色々書きましたが、この記事では 光源の強さとして扱います。

先ほどから出ていましたが、入射光とオブジェクト表面の法線とのなす角を入射光と言います。 なお計算時は入射光の逆ベクトル、すなわちオブジェクト表面から光源への方向ベクトルを使用します。

計算時の入射角のイメージ
cosの計算は遅いので、プログラムで使用する際はベクトルの内積に置き換えます。

 \displaystyle 
I_{d} = K_{d}I_{in}(\hat{L}\cdot\hat{N})
  • L オブジェクト表面から見た光源への方向ベクトル
  • N オブジェクト表面上の法線ベクトル
  •  \hat{}は正規化したことを意味します。

こうなる理由は次の通りです。

 \displaystyle 
L \cdot N = |L||N|cosθ_{1}\\

 |L| = |N| = 1になると  =cosθ になります。
よって、 
\hat{L}\cdot\hat{N} = cosθ_{1}
になります。

また、光源方向ベクトルとオブジェクト表面の法線ベクトルのなす角 θ_{1} \frac{π}{2} (= 90°)を超えた場合は、下図のようにオブジェクト表面の裏側から光が当たっていることになるので拡散反射は起きません。

入射角が \frac{π}{2} (= 90°)を超えると拡散反射は起こらない

最後に

フォンの反射モデルの拡散反射について解説してみました。
間違いがあったらご指摘いただけると嬉しいです。
次回記事はフォンの反射モデルにおける鏡面反射の予定です。

ブログはじめました。

はじめまして。情報系大学生のWhileと申します。
エンジニアはアウトプットが重要ということでブログ始めました。

自己紹介

情報工学部のB4です。
ゲーム開発を通じてコンピュータグラフィックス分野に興味を持ったのでこれをメインに勉強しています。
元々Unityを少し触っていたのですが、最近はDirectX12メインです。

このブログの目的

  • 勉強内容の理解度向上、知識定着
  • 開発モチベ向上
  • 自分用メモ

ブログ内容(予定)

内容というかこのブログで触れる技術についてですね。 今ところ以下に関して記事書いてこうかと思ってます。

最後に

自分の為になる記事を書ければいいかと思います!
不定期更新でいきます。 ちょっとメモしておきたいと思ったらどんなに短くても書いていこうかなと思います。

三日坊主にならないように頑張るぞ!!