~■はじめにシェーダの柔軟性があがるにつれ、個性的なシェーダの実現から、汎用ベクトルプロセッサへの応用、と世界が変化してきました。今までは実現不可能と思われていた大域照明をリアルタイムで動かそうという努力がなされてきています。今回は、その流れにのって、拡散光でセルフシャドウが無く、相互反射も考慮に入れない場合に関するグローバルイルミネーションを実現してみました。物体に入射する光をレンダリング方程式で集めて拡散光とします。上の図を見ていただくと、球の上部は天球の入射光によって赤く染まり、下部は地面の草の色を反映された緑色になっています。これが今回の効果で、物体が移動したとしても、周りの風景に応じて瞬時にいい感じに色が付きます。(周りの風景が写りこんだ環境マップはおまけです)。グローバルイルミネーションの効果は、環境マップのように法線だけに依存して、表面の位置には依存しないようにしています。いつものようにプログラムです。(リアルタイム大域照明:DirectX9)カーソルキーで、カメラが回って、zやxでズームが変えられます。玉は、「W」、「S」、「Q」、「E」で、上下左右に動きます。マップなし」、「環境マップのみ」の切り替えができます。一応押さえておくと、下のように拡散光と環境マップが合成されて最終的な出力になっています。=ソースには、いつものように適当にファイルが入っています。大事なファイルは次のものです。RADIANCEフォーマット表示用のシェーダ■何をやっているの今回の方法は、環境マップを適当な係数を掛けて平均することにより入射光をSH展開して扱いやすくしておき、後は法線ベクトルからコサイン項(max(N.ω,0))のSH展開を求め、両者の積を足すことによって、拡散光を導出します。数式で説明すれば、拡散光に関するレンダリング方程式の入射光Liに関して、SH展開を施すと(これは頑張ればリアルタイムで可能である)、レンダリング方程式はのように変形できる。ここで、積分された部分を1つにまとめてしまえば、と、ラディアンスを単純な積和の形で書くことができる。これは、シェーダで計算可能な量である。この量は、lm以外には、法線ベクトルNにしか依存しないので、あらかじめ計算しておくことが可能である。今回は、法線ベクトルを反射ベクトルとみなすスフィアマップに、テーブルとしてその値を埋め込んだ。ここで、赤はl=1,m=-1、緑はl=1,m=0、青はl=1,m=1、の係数になっている(実際には、l=m=0の係数をアルファ成分に埋め込んでいる)。係数は適当に補正してあり、色の強さが0.5の時が、Almが0の時である。最初のステップは、環境マップを作ることである。今回は、双放物マップを作成した。スフィアマップは破綻を起こしやすいし、キューブマップはレンダリング回数が発散してしまうからの選択である。場合に応じて、別の方法を選択するものいいであろう。環境マップは動的に作成するのが可能であり、一番上の画面の環境マップは、次のようになっている。物体(ここでは球)のローカル座標系を基準にレンダリングした。レンダリング方法は、適当な座標変換とテクスチャを張るだけである。}座標変換は、昔、動的放物マップを作成した作業をHLSLで書き起こしている。裏面に回り込んだ頂点に関しては、wを負にすることによって、無限遠方に引っ張っている。}ピクセルシェーダは単純にテクスチャを張っている。}■入射光のSH展開さて、次の手順は、レンダリングした環境マップから球面調和関数の係数を求めることである。求める量は、なので、レンダリングした結果に球面調和関数の基底関数を掛けて輪をとればよい。和をとる作業は、ミップマップを作るときの要領で小さな(最終的には1テクセルの大きさまで)テクスチャへ合成を掛ければよい。ここで、問題になるのが面積要素(Jacobian)である。球座標系をデカルト座標系で積分するときには、積分変数の変換で「sinθ」の項が余分に着いた。座標変換をして合成する時には、この項が大事になる。面積要素を放物マップの座標系でテーブル化すると、各UVに対応して、その値は、次のようになる。この係数と、入射方向に応じたSH基底関数の値を掛ると、次のテクスチャができる(それぞれ、放物マップのレンダリング方向に応じて別々のテクスチャができる)。これらは、l=1の場合の係数で、赤がl=-1、緑がl=0、青がl=1の係数を表している。例によって、色の強さが0.5のところがベクトルの0の値を表現している。これらは、変化しない量なので、レンダリング前にあらかじめテクスチャを作成することができる。これら係数を環境マップに乗算すると、次のようになる。ここで、左上がl=m=0、右上がl=1,m=-1、左下がl=1,m=0、右下がl=1,m=1の係数になる。後は、小さくしていけばよい。今回は、64ボックスサンプリングで、1回のレンダリングで1/8にすることを2おこなった(つまり、環境マップの大きさは64x64である)。下のような感じで平均化されていく。実際のレンダリングでは、上の図のように、1つのテクスチャに全てのSH係数を乗せた。これは縮小するときに1度に処理できて便利だと思ってとった処置である。後のサンプリングでテクスチャ座標をずらすだけでことなるSH係数をサンプリングできるというメリットもある。以上で下準備は終了で、後はそれぞれの係数の積和計算をして、ラディアンスを算出します。ピクセルシェーダでは、それぞれの項をベクトル値に戻してから合成し、ラディアンスを計算するとともに、環境マップの張り込みなどを行います。}頂点シェーダでは、ピクセルシェーダで使う、放物マップやスフィアマップの座標値計算しておきます。}■最後にあぁ、しんどかったです。挑戦してみるとより複雑なライティングが実現できるでしょう。もどるimagire@gmail.com。