さて、計算が終わったので、シェーダーを実装して結果をライトマップに焼き込んだものと比べてみましょう。

シェーダーコードはこちら。関数の引数の p はライトローカル座標系での位置、n が法線ベクトル、areaSizeAndHalfSizexy 成分がエリアライトの縦横のサイズ、zw 成分がサイズを2で割ったもので、関数の戻り値が前のページでの積分結果 \(\frac{2I}{L_0}\) を返します。

さて、上記の関数は前のページの \(\frac{2I}{L_0}\) を返します。エリアライト上の点光源が角度\(\theta\)方向に放出するライトの強さを \(L_0\cos\theta\) としていたので、Unity のエリアライトが持つ Intensity プロパティは、
\begin{eqnarray*}
L_0\int_{0}^{2\pi}d\phi\int_{0}^{\frac{\pi}{2}}\cos\theta\sin\theta d\theta & = & \pi L_0\left[\sin^2\theta\right]_{0}^{\frac{\pi}{2}} \\
& = & \pi L_0
\end{eqnarray*}
で計算できると考えるのが妥当です。なので、上記関数の戻り値に Intensity\(/2\pi\) を掛けたものをシェーダーの出力とします。

このシェーダーの出力と、Unityでベイクしたエリアライトの結果を比べてみます。

上のシェーダーの全ての分岐がテストされるように、ライトの位置を動かしながら、いくつかスクリーンショットを撮りました。
各画像の左側がシェーダーでレンダリングしたもの、右側がライトマップにベイクしたものです。また、Player Settings で Color Space を Linear に設定しています。

もう、完全に一致していると言っていいレベルじゃないでしょうか。前回は一生懸命計算して違う結果になってしまい、心が折れかけましたが、これは嬉しい。この計算をフラグメントシェーダーで行うのはちょっと気が引けますが、影の濃さを評価するために頂点シェーダーで行うくらいはいいかなと思うので、これを使ってエリアライトの影のプロジェクターを実装してみようと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Anti Spam Code *