ちょっと怪しいところがあるので、計算間違いがある可能性を捨てきれませんが、とりあえずシェーダーを実装してみて、ライトマップに焼き込んだ結果を比べることで、計算が正しそうかどうか判断することにします。

これが実装してみたシェーダーコードです。とりあえずテストコードなので最適化とかは考えてません。引数の p はライトローカル座標系での位置、n が法線ベクトル、halfAreaSize がエリアライトの縦横のサイズを2で割ったもので、戻り値が前のページでの積分結果 \(\frac{I}{L_0}\) を返します。

さて、上記の関数は前のページの \(\frac{I}{L_0}\) を返します。\(L_0\) はエリアライト上の点光源が単位立体角あたりに放出するライトの強さを表していたわけですが、これを Unity のエリアライトが持つ Intensity プロパティから計算しなければなりません。今、点光源が半球上の立体角に一様にライトを放出するとしているので、Intensity \(= 2\pi L_0\) と考えるのが妥当です。なので、上記関数の出力に Intensity\(/2\pi\) を掛けたものをシェーダーの出力とします。

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

上のシェーダーの全ての分岐がテストされるように、ライトの位置を動かしながら、いくつかスクリーンショットを撮りました。また、log の項と arctan の項がちゃんと入るように、ライトを少し傾けています。

各画像の左側がシェーダーでレンダリングしたもの、右側がライトマップにベイクしたものです。また、Player Settings で Color Space を Linear に設定しています。

なんかそれっぽい結果は得られたものの、全然違う!
これは計算間違いというよりも、そもそものエリアライトのモデルが違うんじゃなかろうか?顕著な違いが見られるのはライトの真横の部分。シェーダーで計算した方は真横にもくっきりライトが当たっちゃってる。
試しに上のシェーダーの出力に p.z*rsqrt(dot(p, p)) をかけてみた結果がこちら。

ちょっと近づきました。やっぱりモデルが違って、エリアライトが点光源の集まりだという前提が間違っていたみたいです。というわけで、これは失敗作。モデルを考え直して次回に続く。

コメントを残す

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

Anti Spam Code *