拙訳
要約
この論文は同名のGDC 2008の講義の手引である。これは、球面調和関数(SH)の簡潔な概要を提供し、インタラクティブグラフィクスにおいて使用可能ないくつかの方法と発生するかもしれない問題を議論する。特に、「SHを用いて効率的にライティングモデルを求める方法」、「“リンギング”とは何か、そして、それについてできることは何か」、「SH積の効率的な求め方とそれが使われる所」、といった問題に焦点を当てる。最新バージョンはhttps://www.ppsloan.org/publications/で入手できる。
はじめに
ラプラス方程式[@2]の解である調和関数は様々な分野で広く用いられる。球面調和関数は球に制限したときの解である1。これは物理学において熱方程式 (時間上の温度変化のモデル化[@5; @25])、重力場や電場[@9]のようなポテンシャルの問題を解くために使われてきた。量子化学や量子力学では原子の電子配置や量子角運動量をモデル化するためにも用いられてきた[@16; @51]。グラフィクスに近い所では、散乱現象をモデル化するために使われてきた。コンピュータグラフィックスにおいて、これは広く使われてきた。初期には、ボリューメトリック散乱効果[@18]、大局的な影を持たないマイクロファセットBRDFのための環境反射[@6]、ディフューズでないオフライン光輸送シミュレーション[@40]、BRDF表現[@53]、画像の再ライティング[@28]、制御可能なライティングを伴う画像ベースレンダリング[@54; @55]、光源発光のモデル化[@8]、といった所で使われた。時代が下ると、異方性散乱[@50]やコンピュータビジョン[@3]における研究が増えてくる。
本論の中心はインタラクティブグラフィクスに関連する技術にある。ゲームにおいて広く使われてきた最初の論文は効率的に球面調和関数を用いて放射照度環境マップを表現することで対処する[@35]ものであり、遠方の照明の下にあるディフューズオブジェクトのインタラクティブレンダリングを可能にする。これは同じ制約を持つ制限されたBRDFの種類を扱うために拡張された[@36]。Precomputed Radiance Transfer(PRT)[@41; @20; @24]はライティング環境への静的なオブジェクトやシーンの反応をモデル化するものであり、しばしばSHを用いて表現され、ソフトシャドウやディフューズと単純な艶やかなマテリアルとの相互反射のような複雑な大域照明効果を含む。これは、より一般的なBRDFモデルを扱うため[@20; @23; @42]、表面下散乱を組み込むため[@42]、機械学習による圧縮技術を通じてレンダリング効率を大幅に改善するため[@42]、表面の詳細のような”局所的”なテクスチャをモデル化する様々な技術を扱うため[@43; @44; @45]に拡張された。SHは遠方のライティング環境による単一散乱をモデル化するために使われてきた[@49]。他には、遠方のライティング仮定を持ち上げるために勾配を用いるとき[@1]、相互反射のサポート[@46; @33]を含めた動的オブジェクトに対処するいくつかの技術において[@56; @37]、一般的なBRDFモデルを持つオブジェクトのシャドウイングをモデル化するための可視性の表現として[@12]、変形可能なオブジェクトからの影をモデル化するためにスケーリング操作を用いるとき[@52]、屈折のパラメータ化として[@11]、法線マップによるLevel of Detailの問題に対処するための技術として[@15]用いられる。
より実践的な論文には、PRTの実装の詳細をカバーするもの[@13]、エンジンにこれらの技術を統合する方法[@30]、放射照度ボリュームに対してSHと勾配を使う方法[@31; @32]、投影に関する実践的な問題とSH係数を効率的に量子化する方法[@21]、解析的なスカイライトモデル[@34]をSHに投影して、モデルのパラメータの関数としてSHライトプロブを求めるために大局的多項式フィッティングを用いる良い論文[@14]が含まれる。また、SHを用いて半球上に定義されるよりロバストな投影関数の計算技術も調査されてきた[@22]。
リアルタイムグラフィクスでの多くは、可視性、ライティング、反射率として、単に球面関数を表現する便利な方法として用いられる。他に、ウェーブレット[@39]、キューブマップ上のウェーブレット[@27]、球面放射基底関数[@9]、など[@26]の使用可能な基底関数が多く存在するが、球面調和関数はこの文書で述べられるであろういくつかの素晴らしい特性を持つ。これらのその他の基底関数がより適切となるシナリオが存在することを強調することは重要である。
球面調和関数は幾分手強そうに見えるかもしれないが、実のところ素直である。これは単位円上のFourier基底に類似した球上のソレであり、数値的に計算し易い。信号処理において用いられるFourier基底のように、発生し得る”リンギング”アーティファクトを最小限にするため、(ビデオゲームでは常に行われるであろう)級数の打ち切りを行うときには気を付けなければならない。本論は、球面調和関数を用いて効率的に光を計算および表現する方法、SH表現から従来の光を取り出す方法、“リンギング”の説明とその影響を最小限にする軽減技術、球面調和関数を用いる関数の積の調査を述べる。そこで述べられるのは、これが有用である点と、最適化する価値がある特殊ケースについてである。
背景
定義
球面調和関数は球上の正規直交2基底を定義する。用いるパラメータは以下となる。
ここで、は単純に単位球上の位置である。この基底関数は以下のように定義される。
ここで、はLegendre陪多項式であり、は以下の正規化定数である。
上記の定義は(グラフィクスでない界隈で最も一般的に使われる)複素形式によるものであり、実数値基底は以下の変換によって求められる。
添字は”バンド”を表す。各バンドは多項式の次数と等価であり(すなわち、0は単なる定数関数、1は線形、など)、与えられたバンドには個の関数が存在する。球座標は積分を計算するときに便利であるが、これらを求めるときに一般的に行われるように、多項式を用いて表現することもできる(詳細は付録A1と付録A2を参照)。次数3のSH展開は次数までのすべての基底関数を用いる。
(画像)
球面調和関数はいくつかの方法で可視化できる。ある標準的な方法では、関数の絶対値で同心円状に各点をスケーリングして、符号に基づいて(正なら赤に、負なら青に)色付けすることで、単位球を歪ませる。上の図はこの技術を用いた最初の3つのバンドの画像である。
中央の列()にある関数はZonal Harmonics(ZH)と呼ばれ、後に述べれれるだろうが、これらの関数はZ軸周りに回転対称性を持ち、そのゼロ(関数が0となる位置)はXY平面に並行な球上の輪郭である。()にある関数はSectorial Harmonicsと呼ばれ、そのゼロはリンゴのスライスのような領域を定義する。
代替案として、平面に展開したキューブマップのパラメータ化を用いて描画して可視化する方法がある。キューブマップの展開は以下のようになる。
(画像)
ここでは、大きさは色(正は赤、負は青、ゼロは緑)にエンコードされ、等強度線は関数の勾配に対するさらなる直観を得るために(白で)均等に配置されている(間隔が狭いと関数が素早くに変化する、など)。
(画像)
投影と再構築
SH基底は正規直交であるので、上に定義されるスカラ関数の最小二乗投影は基底関数に対して投影したい関数を単純に積分することで行われる(証明は付録A6)。
これらの係数は関数の近似を再構築するために使用できる。
これは、バンド数を増やすごとにますます正確になる。本論はへの低周波近似に専念するため、より高い周波数表現では他の基礎の方が良い仕事をする傾向にある。次への投影は個の係数を生成する。以下を介して投影係数と基底関数の両方に対する単一の添字を用いることはしばしば便利である。
ここで、である。この方程式は近似関数の方向での計算が個の係数ベクトルと求めた基底関数の内積であることを明確にする。第1係数(または添字付けに依存する)は球上の関数の平均値を表現し、DC項と時折呼ばれる。
基本的な特性
SHの重要な特性のひとつは投影がとのように回転と相互作用するかということである。回転行列によって回転されたを表現する関数をとすると、すなわち、であり、の投影はを回転して再投影することに等しい。この回転不変性はFourier変換における並進不変性に似ている。これは、例えば、ライティングが回転に対して安定となるであろうこと、すなわち、エイリアシングアーティファクトや光源の”ぐらつき”が起こらないであろうことを意味する。下図は方向光源によって照らされる球の画像であり、上段はSHを用い、下段はValveによるアンビエントキューブ基底4を用いている。この基底は付録A9でより詳細に述べられる。これは球上に定義される他の任意の基底である程度発生するだろう。
(画像)
SH基底の正規直交性により、、を任意のSH関数とすると、積の積分は係数ベクトルの内積である。すなわち、である。
畳み込み
円対称性を持つカーネル関数をとすると、このカーネルと元の関数との畳み込みの結果として新しいSHを生成できる。は、回転群ではなく球上でも表現されるようにするため、畳み込みの結果に対して円対称性を持たなければならない。畳み込みは以下の数式を用いて周波数領域で直接行うことができる。
これはの対応する項によっての各バンドを単純にスケーリングすることに等しい。
回転
前述した通り、SHは回転に対して閉じている。SH回転行列はブロック構造にあり、そのとき、各バンドは回転に対して独立であり、密なの部分行列を持つ。この回転行列を計算する方法はいくつかあり、非常に低次(二次以下)では記号的に行うことが最も効率的であるが、それより高次では回転行列をZ-Y-Z系のEuler角に分離する方がより効率的であるように思われる[@19]。
Zonal Harmonics
ある軸の周りに回転対称性を持つ関数を球面調和関数に投影したものはZonal Harmonics(ZH)と呼ばれる。それらがその軸をZ軸とするように向いているならば、関数のゼロは一定の緯度線を形成し、その関数はのみに依存するだろう。この向きにおける係数ベクトルはバンドあたりの非ゼロがひとつだけであるので、次の関数は個ではなく個の係数を持つ。Zonal Harmonicsは輸送を近似するのに使われ[@44]、そして、散乱理論における位相関数の一般的な表現であり[@7; @17]、これは本論において光源をモデル化するときに広範囲に使われるだろう。Zonal Harmonicsの回転は一般的なSHより単純であり、実質的に対角行列となるもので行うことができ、新しい方向におけるSH基底関数を求めることのみを要求する。(SH投影の項のみの)関数のZH係数をとすると、以下の式を用いて新しい方向へ回転させることができる。
すなわち、SH係数は以下のようになる。
SH積
SHに投影された次のSHを用いて表現される2つの関数との積の番目の係数は以下の形式を持つ。
ここで、は三重積テンソルである。
これは階数3の疎な対称テンソルである。SHは多項式であるので、多項式の積は最大次数を持つだろう。このとき、次数までの非ゼロの係数を持つであろうことを意味する。これは乗算されている関数の数が増えるにつれて扱いづらくなるので、早期に積を切り詰めるのが一般的である[@56; @37]。の関数としての非ゼロの係数の数はかなり大きい[@47; @37]ので、効率的なコードを生成するときには注意するしなければならない。指摘しておくと有用である特殊なケースのひとつとして、が固定される(すなわち、遠方のライディングである)ならば、そのコストを大幅に削減するであろう”積の行列”を計算することができる。この行列は対称であり、以下の式を用いて作られる。
この場合における関数との積の計算は単純な行列とベクトルの積となる。
放射照度環境マップ
放射照度環境マップはライトプロブとクランプされたコサイン関数との畳み込みによって生成される。これは放射輝度を表すためにで除算して正規化されるべきである。この畳み込みはSHを用いて効率的に行われることができ[@35]、同様に、直接的にSHから効率的にレンダリングされるのに十分な正確さを持つ。次数3のSHはこのカーネルを近似するのに良い働きをするが、HDR光源を用いているならば、次数5の使用を検討したくなるだろう(次数4のZHの係数はゼロなので、そのバンドは省略できる)。下図はクランプされたコサイン関数と次数3のSH近似の画像であり、赤の曲線がSH近似を示す。左側の図はの関数としてのプロットであり、右側の図は関数の絶対値でスケールした極座標プロットである。
(画像)
下図は次数5の投影(青)も含めたプロットである。
(画像)
次数3のSH近似は(北極)でだけ過剰推定し、南極に大きさを持つ不要なローブを持つ。17の値を反射する方向光源は、法線がその方向を指すとき、反対方向に向かって1の値を反射するだろう(0を反射しているべきなのに)。次数5の近似は、同様の方向を指す法線で31を反射する方向光源では-1を反射するであろう、負のローブを持つ。これらの近似は正確であるが、特に非常に明るい光源を用いている場合、誤差を引き起こし得る。
付録A10は放射照度環境マップを効率的に求めるためのシェーダおよびCPUコードを含む。
ライティングモデル
SHにはライディングを表現する方法が様々存在する。最も簡単なものとして単にキューブマップから投影する方法があるが、計算が高価でなく、アーティストへ公開するものとして有用である可能性を秘めた解析モデルも存在する。最近の論文[@14]では実用的なスカイライトモデル[@34]をSHに投影し、そのモデルのパラメータ空間上でSH係数の大局的多項式フィッティングを行う。
キューブマップからの投影
キューブマップから投影するためには、キューブマップに対してSH基底関数を積分する必要がある。これは各テクセルの中心の方向においてSH基底関数を求めて、そのテクセルに対する微分立体角で重み付けして、その結果を正規化することで数値的に行われることができる。以下はその擬似コードである。
float f[], s[];
float fWtSum = 0;
Foreach(cube map face)
Foreach(texel)
float fTmp = 1 + u^2 + v^2;
float fWt = 4 / (sqrt(fTmp) * fTmp);
EvalSHBasis(texel, s);
f += t(texel) * fWt * s; // ベクトル
fWtSum += fWt;
f *= 4 * Pi / fWtSum; // 球の面積上記のコードにおいて、uとvは+1または-15でない与えられた面上の2つの座標を表し、t(text)はテクセルの色である。EvalSHBasisは(キューブ面での)入力座標を正規化する必要があり、その方向におけるSH基底関数を計算する。(特に低解像度のキューブマップを用いるときに)多少ずれる傾向はあるが、微分立体角の正規化された合計はとなるはずなので、最後の正規化は省略できる(代わりに、サンプル数で割ることができる)。
下図はHDRライトプロブを次数1から6の球面調和関数に再構築した画像である。最終的に、画像は投影されたライトプロブとなる。
(画像)
解析モデル
方向光の計算は自明であり、与えられた方向にSH基底関数を求めて適切にスケールするだけで良い(正規化セクションを参照)。球光源はZonal Harmonicsを用いて効率的に求めることができる。下図はシーンの例を示す図であり、レシーバの位置での入射する放射輝度、球関数を計算したい。中心、半径の球光源があるとすると、だけ離れている点に到達する放射輝度は幾らか?光源のなす半角のサインはであるので、球の適切な部分に対する光源を計算する必要がある。ZH係数はこの角度の関数として閉形式で計算できる。すなわち、である。ここで、はそのなす半角である。次数6までの式については付録A3を参照。
(図1:球光源)
球での技術は一定の放射を持つ円錐(無限大にある円板として考える)をモデル化するのにも使用できる。より柔らかい円錐は可視部分で滑らかな減衰を持つようにモデル化できる6 --- 式は付録A4を参照。
列は次数4と6のものを表し、上段は円錐の投影を、下段は滑らかな減衰を持つ円錐を表す。角度は90°(緑)、45°(赤)、30°(青)、12.5°(黒)である。破線は実際の関数を表し(重ならないようにちょっとだけ円錐に対してずらしてある)、実線はSH近似を表す。一般に、柔らかい円錐のほうが行儀が良い。投影おいて発生するアーティファクトに対処する方法は以下のリンギングセクションの主題である。
(画像)
正規化
[0, 1]のライティングが用いられているならば、光源を直接指す法線を持つ影に隠れていないレシーバに対して反射した放射輝度が1.0になるだろうから、放射輝度ベクトルを正規化するのに便利である。数学的にスケールファクタを計算したいとする。これは、ライティングベクトルで乗算してベクトルに対して積分すると反射した単位放射輝度になり、遮蔽されていないクランプされたコサインローブを表す(正規化されたクランプしたコサインのSHへの投影)。すなわち、以下となる。
正規化ファクタを計算するときは、レンダリングで使用したいバンドのみを使うべきである。をと並行にすると、単純な解析式が得られる。ここでは最初の6つのバンドに対するの係数を示す。
解析的な光では解析的な正規化項を用いることができ、角度の円錐光では以下になる。
しかし、クランプしたコサイン関数と光源の両方の投影誤差が考慮されていないので、結果の光は単位放射輝度を反射しない。方向光7では正規化ファクタはとなり、“アンビエント”光ではとなる。
SHからの従来の光の抽出
SHのライティングベクトルを仮定すれば、単一の方向光源とアンビエント光源として近似することができる。これは頂点シェーダをサポートしないハードウェア上で使われていた。数学的に、反射した放射輝度の二乗誤差が任意の表面法線()に対して最小化するように、方向光の強度()とアンビエント光の強度()を計算したいとする。光源に対する固定の距離()を仮定すると、最小化したい誤差関数は以下のようになる。
ここで、は正規化されたクランプしたコサインである。ライティングがSHで表されるならば、これは単純な解を持つ。新しいライティング環境で表される放射照度環境マップはできるだけ入力の放射照度環境マップに近くあるべきである --- これら2つの環境マップの二乗誤差を最小化することはすべての法線で反射した放射輝度を最小化することと等価である。
ここで、は方向における正規化されたSHの方向光であり、は正規化されたSHの定数光である(単にDCに依存する)。との最適な値は以下となる。
上記のライティングベクトルはすべて正規化されたクランプしたコサインカーネルとの畳み込みによって放射照度環境マップに変換される。上記の内積はDC項を無視し、はライティング環境のDC項である。上記は既知の方向を仮定する。その候補となる方向は”最適線形”な方向[@44]であり、ベクトルを正規化することで形成される。これは、ライティング環境の線形な係数である。
複数の光の抽出
SHライトプロブから複数の光を抽出することもできる。これは、(解析的な光は負のローブを持たないので)リンギングに対抗するため、(この方法で取り出される光源による)艶やかな反射をモデル化するため、少数のシャドウZバッファを用いる(BRDFの拡散と光沢の両部分のために光を取り出す)ために行われるかもしれない。最適線形な方向はライトプロブが単一の光源によって支配されるときに正常に動作する。そうでないには、方向と強度は何らかの方法で最適化される必要がある。これを行う方法のひとつに、関数の極大を見つけるために”上り坂”を登ることがある。SHの滑らか具合を考慮すると、与えられた次数に対して有限の距離が存在し、そこでは、明確なピークから離れた任意の点が最急上昇法を用いてその点に到達することが保証される。点の集合はそのVoronoi8 cellの中心から最も遠い球上の点がこの距離より小さいという特性によって生成できる。これらの点のそれぞれから探査を始めるならば、極大点のすべてを見つける必要がある。これらの距離は、デルタ関数の投影を調べて、ピークとゼロとの角距離を計算することで見つけることができる。この半径のの控えめな推定を用いると、次数ごとに必要となる点の数は最初の6つの次数では{1, 3, 6, 10, 15, 22}となる。
この点の集合はシミュレーションを計算することで計算できる。すなわち、すべての点が他のすべての点に作用するある減衰(例えば、はそれらのユークリッド距離)を伴う力を持つとする。各点で作用する合力を生成し、(これは単なる接線力なので)垂直成分を差し引いて、重みと一緒にこの力によって点を移動する。合力の合計が増加するならば、を半分に減らして再度行い、減少するならば、を倍にして再度行う。これは静電荷の合計を最小化する電子の集合を解いている。
SHライティング環境をとして、極大となる球上の点を見つけたいとする。これは、の極小を見つけることと同じことである。これは非線形最適化問題であり、経験上BFGS法の反復をいくらか行えばそのピークに収束する。基底関数の勾配は最適化手法を用いるときに計算される必要がある。球上の点に対して、多項式の微分は自明であるが、その点が直線探索を行うときに球を離れられるようにする必要がある。そのため、係数を正規化する記号的な入力を用いたい(すなわち、の代わりに)。これは正規化された位置での勾配を計算して以下の正規化関数のヤコビアンで乗算することで行われる。
ここで、はである。
(画像)
上図は3個、2個、1個の方向光とアンビエント光で近似したときの放射輝度(上段)および放射照度(下段)ライティング環境の比較画像である。個の(大きさの観点で)最重要なピークがあるとすると、これは最小二乗的に方向およびアンビエント強度を解く。
2つのローブに対する光の強度を計算するための式は以下となる。
ここで、である。
そのアンビエント項は以下である。
3つの光に対して、その強度は以下となる。
ここで、である。
この行列は対称であり、そのアンビエント係数は以下である。
これらの式の導出は付録A5にある。
自由度(方向と強度)のすべてを追加して非線形ソルバを用いると、初期の推測として上記の技術を用いるとすれば、より高品質な結果を生成するだろう。
リンギング
リンギングは、Gibbs現象とも呼ばれ、信号処理における一般的な問題である。不連続性を持つ信号が(連続的な関数のみを表現できる)有限のFourier基底に投影されるとき、オーバーシュートやアンダーシュートがその不連続性の周囲に発生する。不連続性を持たない関数でも投影が切り詰められる場合に同様の挙動を示す可能性がある。我々は、ライティングモデルを調査するとき、そして、放射照度環境マップの表現(クランプしたコサイン関数の投影)において、これらの問題をすでに確認していた。同様の問題は表面設計において発生する。ここでは、一連の幾何的制約を満たそうとするとき、望ましくない振動が発生する可能性がある。これらの問題には2つの一般的な解法が存在する。
- 切り詰めた投影係数にシグマファクタを用いて窓を掛ける方法。これは信号処理において最も一般的な解法であり、球面調和関数で自明に使用できる[@8; @41; @37]。
- 標準の最小二乗誤差ではなく、変分関数のいくつかの形式を最小化する方法(例えば、曲率の大きさを最小化する)。これはコンピュータを利用した幾何的設計において一般的に行われるが、球面調和関数を用いて効率的に行われることもできる[@38]。
窓掛け9
リンギングアーティファクトを最小化する方法のひとつに、カットオフ周波数に近づくにつれてゼロに漸減する投影係数を持つカーネルを周波数領域において乗算する方法がある。この関数は切り詰めた周波数帯でゼロに到達するように引き伸ばされたsinc関数10であり、Lanczosのシグマファクタ11を用いる、と言われる。直観的に、(1Dで)これが行っていることは、その関数を過度なリンギングなしで表現されるのに十分な滑らかさにするための、空間領域におけるタイトなボックス関数との畳み込みである。Gibbs現象に対抗するより洗練された方法[@10; @4]が存在するが、これらはゲーム用として便利ではないであろう区分的な解析関数を生成するのにSH係数を用いる。
(画像)
経験上、窓関数の選択はリンギングとブラーリングの間をトレードオフする柔軟性を持たせることほどには重要ではない。左の画像は6次のSH用にスケールされた2つの窓関数(赤はsinc、青はHanning窓と呼ばれるraised cosineローブ)を示している(7次のバンドではゼロに達するので、使われる最後の値は5次で求められ、その関数は整数でのみ求められるだろう)。Hanning関数はLancosz関数より速く減衰する。これは、より積極的にそれをブラーさせる12。
(画像)
上図はLanczosおよびHanningのシグマファクタを用いた結果を示す。投影されている信号は次数6のデルタ関数である。これは、SHに投影できる”最大ピークの”信号であり、リンギングアーティファクトを示す。デルタ関数の投影はZHでありので、これらは球の断面を示し、は固定される。放射状の大きさがプロットされ、ローブの符号は互い違いになる。
すべてのグラフを一緒に見ると(赤はデルタ関数のそのままの投影を示す)、窓掛けがどれだけ信号をブラーしつつ、リンギングを除去しているかを確認できる(図の原点近くに見られる)。
(画像)
汎関数の最小化
代わりのアプローチとして、二乗近似誤差に加えていくつかの関数を最小化することを試みる。これを行う方法のひとつに、一連の制約を満たし(例えば、少数の点での厳密な再構築)、そして、いくつかの誤差汎関数を最小化するために(十分な自由度があると仮定して)余りの”スラック”変数を用いる方法がある[@38]。ゲームやグラフィクスでしばしば用いられる低いSH次数であれば、このアプローチは実践的であるように思えないので、これ以上の時間を費やすことはないだろう。代替案として、大きな振動に不利となるノルムを最小化することを試みる。これは素直なやり方で球面調和関数で行われることができる。Laplace作用素、または、Laplacianはスカラ関数の勾配の発散であり、非混合偏微分の和と等価である。
単位球上の球面座標では、これは以下のようになる。
二乗Laplacianの積分は球上で用いられる曲率の大きさである[@38]。その最小化したい関数は以下となる。
これに若干の調整を加えたい。生の投影係数は既知であるので、重み付けされた二乗Laplacianを最小化しつつも、できるだけ最小二乗の結果に近い新しい係数を見つけたい。これは閉形式で行われることができ(付録A6参照)、与えられると最終的に以下の係数になる。
これはに依存する窓関数に等しいことに注意する。がゼロのときは最小二乗の係数が得られ、が無限大のときは曲率がゼロでありDC項が得られる。を選ぶアプローチのひとつに、固定量、例えば、半分に二乗Laplacianを減らして解く方法がある。これはいずれかの標準の求根テクニックを用いて行われることができる。Newtons法を用いてこれを行う方法の説明は付録A7を参照のこと。下図は6次のデルタ関数を二乗Laplacianが元の10%(の緑)、50%(の青)になるように解いた結果である。最後のプロットはデルタ関数それ自身と合わせたものである。
(画像)
下図は実際のライティング環境を用いた画像である。画像の1列目は2列目の等値線プロット(青が負)であり、幅の広い(より滑らかな)窓で窓掛けしている。4列目は3列目の等値線プロットであり、より狭い(ブラーの少ない)フィルタで平滑化している。上段は元の画像であり、すべての結果は6次で示される。
(画像)
窓掛けは賢く用いられるべきである。放射照度環境マップを用いるとき、クランプされたコサイン関数との畳み込みは高周波を積極的に減衰し、窓掛けはほとんど必要としない。また、法線の変化が多く存在するシーンではレシーバの法線が滑らかであるシーンほどリンギングアーティファクトを示さない傾向にある。下図はシェーディング結果に窓掛けがどれだけ影響を与えるかを示す(“ドア”と地面の)単純なシーンの画像である。リンギングが発生しているエリアは2段目で強調される。
(画像)
HDRや適度に明るい光を用いるとき、リンギングはより厳しい問題であり、放射照度環境マップでさえある程度の窓掛けを必要とするかもしれない。
リンギングで起こり得るもうひとつの問題は色アーティファクトである。下の画像では、方向性の黄色の光で(右上から次数6でほぼ縁が)照らされる球と白色の適度なアンビエント光がある。上段は放射照度環境マップを用い、下段は次数6のPRTを用いる(すなわち、コサインカーネルのより正確な近似が用いられる)。1列目は窓掛けなしであり、2列目は次数4のHanning窓を用い、その下は次数5である。窓掛けしないバージョンは両方とも正のローブ(次数3、負の次数6)を示し、青の帯は方向光の負のリングに起因する(アンビエント光により赤と緑が除かれるが、青だけそのままにする)。
(画像)
内容依存の窓掛け
ライティングは大局的に窓を掛けられることができるが、最後の陰影付けされた画像にリングが与える影響度に基づいて窓を掛けることもできる。その例を以下に示す。(ハイライトが飽和する)明るい方向光源を用いてマットな(ただし、ディフューズではなく、パワー10を持つPhongの)ボールのようなものをレンダリングする。窓掛けを適用しないならば、主要なハイライトはより鋭いが、リング由来のアーティファクトは明確である。ライティングが窓を掛けられるならば、リングは消えるが、主要なハイライトは同様にブラーされる。代わりに、鋭いハイライトを維持しつつリンギングアーティファクトを取り除くために、反射ベクトルと支配的な光ベクトルとの間の角度に対して、これが小さい場合に窓掛けはせず、大きくなるに従って窓掛けした光源と窓掛けしない光源とをブレンドすることができる。この画像の列は以下に示される。
(画像)
ブレンディングを制御するのに使われる式は以下のようになる。
ここで、は窓掛けされていない光源の重み(窓掛けされる方は)であり、は窓掛けされた光源を完全に用いるときを定めるしきい値であり、はブレンドの遷移領域を制御する。この図では、であり、である。これらのパラメータを試すことができ、しきい値は窓掛けの量とマテリアル特性に大きく依存するだろう。
光源が方向性のものでないならば、方向光源によってどれだけうまく近似できるを計算して、どれだけブレンドするかを決めるときにそれを計算に入れることができる(最も単純な方法は、ライティング環境が方向光による近似にどれだけ近いか、と、法線または反射ベクトルが支配的な光ベクトルにどれだけ近いか、との間のテンソル積を計算することだろう)。より複雑なシェーディング、例えば、PRTでは、支配的な輸送方向が使用でき、輸送関数への近似度合いは未だにテンソル積においてもうひとつのファクタとすることができる(なので、項のいずれもうまく近似しないときに窓を掛ける)。
ライティングが動的であるならば、光が変化するたびに発生し得る時間的なアーティファクトに気を付ける必要があるだろう(すなわち、シャドウや反射が鋭くなる、など)。それでも、静的SHライトプロブのようなものでは、この技術は上手く動作するはずである。
SH積
SHを用いて表される2つの関数の積のSH表現を計算することはしばしば有用である。例となるシナリオには以下がある。
- 大きな飛行物体(可視性×光)、または、シーンの単純な可視性モデル(大きな建物など)に基づいてスカイライトモデルに穴を開ける。
- 可視性関数を乗算する。これは動的で近似的な大域照明を行うときに発生する。
- SHライトプロブをスケールまたは修正する。0から1までのある定数の乗算は、例えば、雲を近似するのに使われることができる。
周波数領域における積の計算は非常に複雑であり、要するに、2つのSHベクトルと”三重積テンソル”の掛け算になる。このコードは効率的に生成でき[@47]、本論では説明されないだろう。とはいえ、言及する価値のある特殊な場合がいくつかある。
定数関数との積
SH関数のひとつをたくさん使いたい場合、積の行列と呼ばれる密な行列を作ることができ、これは三重積を、計算コストがかなり小さくなる、単純な行列とベクトルの積にする。次数6の積は、2527個の掛け算が、[@47]で生成されたコードでは1296個の掛け算になる。
可変次数との積
これは出力次数が、局所的な放射輝度環境を表現できるように、例えば2次のように、低次であるときに特に一般的である。これらの場合でのコードの特例化はコードの複雑さを大幅に減少させる。例えば、2つの6次のSHの積は、6次の結果を計算するときは2527の乗算と1995の加算があるが、3次の結果を計算するときは933の乗算と676の加算13のみで済む。もうひとつの例は単純なアンビエントオクルージョンであり、この場合、項のひとつは単なるDCであり、DCの値で他のベクトルをスケールしなければならない。最後に、2つの関数のひとつはより低次(すなわち、線形な可視性を乗算するだけ)となるかもしれない。これも、そのコストを削減できる。
Zonal Harmonicsとの積
関数のひとつがZonal Harmonicであるならば、それと同じフレームに他の関数を回転して(その対称性により2つのEuler角のみを必要とするため、回転の計算コストがより小さい)、積を計算して、回転し直すことができる。ZHフレームにおける疎な性質は相当量の作業を取り除き、パーフォーマンスを増加することができる。1つがZを向くZHである、2つの6次関数の積は380個の乗算と249個の加算のみ必要とする。任意のZHでは、(関数のひとつが常にある任意の方向にある)100万回の積の計算時間は約1.2秒であり、一方で、一般的な6次の積は3秒以上かかるので、この技術はほぼ3倍速くする。
解析的関数との積
関数のひとつが解析的な形式をもつならば、積の行列に等しいものを解析的に計算することでより正確になる。一例として、水平線より下ではすべてゼロとするとき(地面があるときに便利)、クランプしたコサイン関数との積を取るとき、がある。これを解析的に行うことは、解析的関数の無限次数展開を持つことと等価であり、一般に、これらの場合ではSH展開を用いるよりはるかに高速であるだろう。これらの2つの例のコードは付録A8にある。
おわりに
球面調和関数は、ゲームでは特にライティングで、極めて有用なツールである。本論が、これの使い方とこれを使う時に当たり得る課題の和らげ方、に光明を投じることを願うばかりである。本論で述べたアイデアを拡張する方法がいくつかある。(窓関数で用いる)窓掛け係数は負(または正)のローブの大きさ、または、ゼロになるべき方向を指すときに反射した放射輝度の大きさを最小化するために解くことができる。光を抽出するとき、非線形最適化に基づくより厳格な技術は使用できるかもしれず[@29; @44]、より一般的なライティングモデル(例えば、光源からの円錐の角度を含む)が抽出できるかもしれない。フィッティング処理に窓を掛けてみることの調査をする価値もあるかもしれない。まず、関数の滑らかなバージョンにフィットさせて、窓掛けの量を減らしていくことで、より良い極小値へ効果的に舵取りを行う。内容依存の窓掛けのアイデアは、特にPRTのような技術と統合するとき、具体化する必要がある。
球面調和関数で色々やっているときに非常に貴重であると判明したツールのひとつは記号的計算プログラムである。私はMaple(https://www.maplesoft.com/)を用いたが、Mathematica(http://www.wolfram.com/)のような他のプログラムも同様に機能するだろう。DirectX SDK(http://msdn.microsoft.com/directx)はPRTと放射照度環境マップの両方を使うサンプルを付属した、計算、回転、積、いくつかの解析的ライティングモデルのための関数を持つ。
謝辞
作業の多くは、Microsoft Researchのグラフィクスグループに配属されたときに始まり、他の協力者と、特に、長期に渡る実りの多い論文シリーズを執筆するJohn Snyderと共に行われた。また、Hao Chen(Bungie)、Arn Arndt、James Grieves、Clint Hanson(当時EA)、Loren McQuade(Blizzard在籍中)、Dan Baker(MSとFiraxis)、Alex Evans(当時Lionhead)、Tom Forsyth(Muckyfoot)、Willem de Boer(Muckyfoot)、Alex Manchor Ko(Naughty Dog)、Naty Hoffman(SCEA)、chris Oat(ATI)等、幾人かのゲーム開発者と球面調和関数の議論をさせて頂いた。Jason Sandlin、Ben Luna、Jon SteedはMicrosoftにてサンプルやテストコードに関してやってもらった。そして、SHやその他の話題についてGDAlgorithmsメーリングリストにて議論に参加できたことを嬉しく思う。
References
(訳注:原著を参照してください)
付録A1 SH基底関数の計算のための再帰的規則
漸化式[@48]はSH基底関数の多項式の形式を効率的に求めるのに使用できる。基底関数の定式を再掲する。
単位球上の点をとすると、(Zのみに依存し、で割られる)Legendre陪多項式はこれらの再帰性を用いて求めることができる()。
ここで、は内部ループで増加し、は外部ループで増加する。
三角関数の加法定理は(球上の座標から計算できるようにをかけられた)依存の項を求めるのに使用できる。ここで、である。
元の式では、をに、をに置き換えている。一般に、共通の部分式を自然と因数に分解するため、これらの式に基づくコードを生成することはより効率的である。
付録A2 SH基底の多項式の形式
SH基底関数の多項式の形式は以下にリスト化される。はバンド番号、は基底関数である。Mapleがとの順をごちゃまぜにすることに注意する…
付録A3 球光源に対するZH係数
ラジアン角に対する球光源があるとすると、最初の6つのバンドの記号的な積分は以下のようになる。
付録A4 滑らかな円錐に対するZH係数
ラジアン角に対する円錐があるとすると、その光源は北極で強度1を持ち、角度で0に減衰する。6次では、この関数は単精度を用いて約8°以下の角度を求めるべきではない。平滑化関数の微分は北極とで0となる。最初の6つのバンドは以下となる。
付録A5 方向およびアンビエント光を伴うSH環境マップを近似するために係数を解く
方向にある方向光と元のライティング環境との間の近似誤差を最小化する強度を計算できる。
ここで、はライティング環境のSH表現であり、は方向にあるライティングモデルのSH表現である14。この解は以下となる。
アンビエント光を追加したいならば、誤差関数を最小化する必要がある。
ライティングに畳み込みを吸収させ、各変数に関して微分すると以下のようになる。
そして、最小値を見つけるために2つの式がゼロ15に等しいとして解く。はスカラの関数であり16、SHの直交性により、その積分はすべて単純なSHベクトルの内積となる。これは以下の式となる。
ここで、
とについて解くと、
同じ結果に達するより単純な方法が存在することが判明している。環境と光の両方がDC項を含まない方向光の強度を解き、スケールされた方向光を用いるときに環境のDC項を再構築するアンビエント項を計算する。これは最終的に以下となる。
上記の式において、内積はDC項を無視し、は環境光のDC項である。2つや3つの光に対して同様の技術を用いるだろう(その場合、光の強度と同時にを扱うと式はより汚くなる)。
複数の光は同様のやり方で行われることができ、まず、すべての光ベクトルからDCを取り除き、2つの光で、以下の誤差関数をもたらす。
その後、係数のそれぞれに関して微分して0に対して解く。以下の式で強度を得る。
ここで、
が方向に独立して一定であることは指摘しておく価値がある(これは次数とベクトルが畳み込まれるかどうかに依存する)。そのアンビエント項は以下のようになる。
3つの光では、その強度は以下となる。
ここで、である。
この行列は対称であり、このアンビエント係数は以下となる。
付録A6 最小二乗投影
まず、正規直交基底関数に対して、実際に最小二乗投影が基底関数に対して積分することで達成されることを示そう。以下の関数を最小化する係数ベクトルを見つけたいとする。
これは各係数に関して微分することで行われることができ、第1階微分を0に対して解く17。
基底関数は正規直交であるので、であることが知られ、この事実を利用して0に対して解くと、以下を得る。
こうして、直接積分が最小二乗の結果をもたらすようにする。
そして、球上で積分された二乗Laplacianに基づくペナルティを含む誤差汎関数を最小化する係数ベクトルを導く。上の式により、純粋な二乗誤差を最小化する係数ベクトルは分かっている。indexingに使われる関数を導入する。
そして、その誤差関数は以下となる。
微分すると、以下を得る。
0に対して解くと、以下を得る。
付録A7 二乗Laplacianを減らすためにラムダに対して解く
これはNewtons法を用いて極めて簡単に行われることができる。二乗Laplaciandは以下となる。
の値()の配列は静的であり、の値の配列はで計算できる。Newtons法は初期の推定値を取り(この問題では0でうまく機能する)、以下の漸化式を用いて洗練する。
ここで、は根を探索する関数であり、は一階微分である。をを含むで置き換え、因数分解すると、以下となる。
ここで、は元の二乗Laplacianである。反復回数が最大に達するか、逐次近似の絶対値がしきい値を下回るまで反復する(実践では1e-6が上手く機能するように思える)。これは次数の(すべての分母の積で乗算する)多項式として表現できる。ここで、はその次数である。これは2次かそれより下の次数でのみ有用であるだろう。この場合、根の閉形式の解が計算できたとしても、反復による解よりはるかに速いかどうかは明らかでない。
付録A8 解析的関数によるSH乗算のコード
以下の2つは両方とも半球上で定義される関数である。ひとつ目は支配的な地面を持つシーンで役立ち得る定数である。ふたつ目はZでクランプしたコサインである。
// Zにおける半球での6次のライティングの乗算から6次のSH係数を生成する
void HemiMult(float* R, float* L) {
R[0] = 0.433012702f * L[2] - 0.1653594569f * L[12] + 0.1036445247f * L[30] + 0.5f * L[0];
R[1] = 0.5f * L[1] + 0.4192627457f * L[5] - 0.1711632992f * L[19];
R[2] = -0.05412658775f * L[20] + 0.5f * L[2] + 0.2420614591f * L[6] + 0.433012702f * L[0];
R[3] = 0.5f * L[3] - 0.1711632992f * L[21] + 0.4192627457f * L[7];
R[4] = 0.5f * L[4] - 0.1713860232f * L[28] + 0.4133986423f * L[10];
R[5] = -0.06477782793f * L[29] + 0.4192627457f * L[1] + 0.5f * L[5] + 0.2614562582f * L[11];
R[6] = 0.5f * L[6] - 0.1448476267f * L[30] + 0.2420614591f * L[2] + 0.3697549864f * L[12];
R[7] = -0.06477782793f * L[31] + 0.4192627457f * L[3] + 0.5f * L[7] + 0.2614562582f * L[13];
R[8] = 0.5f * L[8] - 0.1713860232f * L[32] + 0.4133986423f * L[14];
R[9] = 0.5f * L[9] + 0.41015625f * L[17];
R[10] = 0.2685102947f * L[18] + 0.5f * L[10] + 0.4133986423f * L[4];
R[11] = 0.360244363f * L[19] + 0.5f * L[11] + 0.2614562582f * L[5];
R[12] = 0.2790440836f * L[20] + 0.5f * L[12] - 0.1653594569f * L[0] + 0.3697549864f * L[6];
R[13] = 0.5f * L[13] + 0.360244363f * L[21] + 0.2614562582f * L[7];
R[14] = 0.2685102947f * L[22] + 0.4133986423f * L[8] + 0.5f * L[14];
R[15] = 0.41015625f * L[23] + 0.5f * L[15];
R[16] = 0.408100316f * L[26] + 0.5f * L[16];
R[17] = 0.2720668773f * L[27] + 0.5f * L[17] + 0.41015625f * L[9];
R[18] = 0.2685102947f * L[10] + 0.35621916f * L[28] + 0.5f * L[18];
R[19] = 0.2856107251f * L[29] - 0.1711632992f * L[1] + 0.5f * L[19] + 0.360244363f * L[11];
R[20] = 0.2790440836f * L[12] + 0.5f * L[20] + 0.3498002708f * L[30] - 0.05412658775f * L[2];
R[21] = 0.2856107251f * L[31] + 0.360244363f * L[13] + 0.5f * L[21] -
0.1711632992f * L[3];
R[22] = 0.5f * L[22] + 0.35621916f * L[32] + 0.2685102947f * L[14];
R[23] = 0.2720668773f * L[33] + 0.5f * L[23] + 0.41015625f * L[15];
R[24] = 0.5f * L[24] + 0.408100316f * L[34];
R[25] = 0.5f * L[25];
R[26] = 0.408100316f * L[16] + 0.5f * L[26];
R[27] = 0.5f * L[27] + 0.2720668773f * L[17];
R[28] = 0.5f * L[28] - 0.1713860232f * L[4] + 0.35621916f * L[18];
R[29] = -0.06477782793f * L[5] + 0.5f * L[29] + 0.2856107251f * L[19];
R[30] = 0.3498002708f * L[20] + 0.1036445247f * L[0] - 0.1448476267f * L[6] + 0.5f * L[30];
R[31] = -0.06477782793f * L[7] + 0.2856107251f * L[21] + 0.5f * L[31];
R[32] = 0.5f * L[32] - 0.1713860232f * L[8] + 0.35621916f * L[22];
R[33] = 0.5f * L[33] + 0.2720668773f * L[23];
R[34] = 0.5f * L[34] + 0.408100316f * L[24];
R[35] = 0.5f * L[35];
}
// Zにおけるクランプしたコサインでの6次のライティングの乗算から6次のSH係数を生成する
void CosMult(float* R, float* L) {
// 整形用の定数
const float T1 = 0.09547032698f;
const float T2 = 0.1169267933f;
const float T3 = 0.2581988897f;
const float T4 = 0.2886751347f;
const float T5 = 0.2390457218f;
const float T6 = 0.2535462764f;
const float T7 = 0.2182178903f;
const float T8 = 0.1083940384f;
const float T9 = 0.2519763153f;
const float TA = 0.2439750183f;
const float TB = 0.3115234375f;
const float TC = 0.2512594538f;
const float TD = 0.31640625f;
R[0] = 0.25f * L[0] - 0.03125f * L[20] + T4 * L[2] + 0.1397542486f * L[6];
R[1] = 0.2236067977f * L[5] + T2* L[11] - 0.02896952533f * L[29] + 0.1875f * L[1];
R[2] = 0.375f * L[2] + T4 * L[0] + T3 * L[6] - 0.01495979856f * L[30] + T1 * L[12];
R[3] = 0.2236067977f * L[7] - 0.02896952533f * L[31] + T2* L[13] + 0.1875f * L[3];
R[4] = 0.101487352f * L[18] + 0.1889822365f * L[10] + 0.15625f * L[4];
R[5] = 0.2236067977f * L[1] + T5 * L[11] + 0.3125f * L[5] + 0.09568319309f * L[19];
R[6] = T6 * L[12] + T3 * L[2] + 0.3125f * L[6] + 0.113550327f * L[20] + 0.1397542486f * L[0];
R[7] = T5 * L[13] + 0.09568319309f * L[21] + 0.2236067977f * L[3] + 0.3125f * L[7];
R[8] = 0.15625f * L[8] + 0.101487352f * L[22] + 0.1889822365f * L[14];
R[9] = 0.09068895910f * L[27] + 0.1666666667f * L[17] + 0.13671875f * L[9];
R[10] = T7 * L[18] + 0.2734375f * L[10] + 0.09068895910f * L[28] + 0.1889822365f * L[4];
R[11] = T8 * L[29] + TA * L[19] + T5 * L[5] + 0.30078125f * L[11] + T2* L[1];
R[12] = T9 * L[20] + 0.328125f * L[12] + T6 * L[6] + 0.1028316139f * L[30] + T1 * L[2];
R[13] = 0.30078125f * L[13] + T8 * L[31] + TA * L[21] + T5 * L[7] + T2* L[3];
R[14] = 0.2734375f * L[14] + 0.09068895910f * L[32] + 0.1889822365f * L[8] + T7 * L[22];
R[15] = 0.0906889591f * L[33] + 0.13671875f * L[15] + 0.1666666667f * L[23];
R[16] = 0.1507556723f * L[26] + 0.123046875f * L[16];
R[17] = 0.24609375f * L[17] + 0.1666666667f * L[9] + 0.201007563f * L[27];
R[18] = 0.101487352f * L[4] + T7 * L[10] + 0.2302830933f * L[28] + 0.28125f * L[18];
R[19] = TD * L[19] + 0.09568319309f * L[5] + TA * L[11] + 0.2461829819f * L[29];
R[20] = T9 * L[12] + TC * L[30] + 0.113550327f * L[6] - 0.03125f * L[0] + TD * L[20];
R[21] = 0.2461829819f * L[31] + TA * L[13] + 0.9568319309e-1f * L[7] + TD * L[21];
R[22] = 0.101487352f * L[8] + 0.28125f * L[22] + T7 * L[14] + 0.2302830933f * L[32];
R[23] = 0.201007563f * L[33] + 0.1666666667f * L[15] + 0.24609375f * L[23];
R[24] = 0.1507556723f * L[34] + 0.123046875f * L[24];
R[25] = 0.1127929688f * L[25];
R[26] = 0.2255859375f * L[26] + 0.1507556723f * L[16];
R[27] = 0.9068895910e-1f * L[9] + 0.201007563f * L[17] + 0.2631835938f * L[27];
R[28] = 0.2302830933f * L[18] + 0.9068895910e-1f * L[10] + 0.30078125f * L[28];
R[29] = 0.1083940385f * L[11] + 0.2461829819f * L[19] - 0.02896952533f * L[1] + TB * L[29];
R[30] = 0.322265625f * L[30] + TC * L[20] - 0.01495979856f * L[2] + 0.1028316139f * L[12];
R[31] = 0.2461829819f * L[21] - 0.02896952533f * L[3] + TB * L[31] + 0.1083940385f * L[13];
R[32] = 0.09068895910f * L[14] + 0.2302830933f * L[22] + 0.30078125f * L[32];
R[33] = 0.09068895910f * L[15] + 0.201007563f * L[23] + 0.2631835938f * L[33];
R[34] = 0.2255859375f * L[34] + 0.1507556723f * L[24];
R[35] = 0.1127929688f * L[35];
}付録A9 アンビエントキューブ基底
アンビエントキューブ基底はValveで使われる[@26]。6つの基底関数を含み、それぞれが半球上に定義される。
この基底は直交ではないので、係数は基底関数に対する積分では生成できない。最適な投影係数を計算するためには、線形な最小二乗問題を解く(付録A6と似ているが、正規直交基底関数を持たない)。
ここで、はアンビエントキューブ基底関数である。これを微分すると以下を得る。
積分は線形であるので、項を並び替えることができ、0について解くと、以下を得る。
左辺はとなる行列の行であり、右辺はベクトル(関数×基底関数の積分)である。これは線形システムをもたらし、の逆行列は以下となる。
この基底を用いて表現される関数をSHに投影するため、SH基底に対してを積分する。2次球面調和関数では、その結果は以下の行列となる。
二次より上の偶数の次数はアンビエントキューブ基底の零空間にあり、二次より上の次数はクランプしたコサイン関数の零空間にある。すなわち、放射照度環境マップが使われているならば、より高い次数は必要ない。アンビエントキューブ基底はDC項を厳密に再構築でき、線形項を近似し、二次基底関数の2つを厳密に再構築し、零空間にある二次基底関数の3つを持つ。
SHからアンビエントキューブ基底に投影するためには、以下の誤差関数を最小化する必要がある。
ここで、は(畳み込まれると仮定される)SHライティング係数である。もう一度、未知の関数に関して微分すると、
そして、0に対して解くと、
同様に、これは線形システムとなる。ここで、は以前と同様であり、はとなる行列である。行列はSHからアンビエントキューブ基底に移すときに使用できる。
付録A10 放射照度環境マップに対するシェーダおよびCPUコード
ライティング環境の二次SH表現があるとすると、シェーダコードを生成するのはかなり単純である。[@35]では、行列表現が用いられるが、これは二次球面調和関数のより直接的な計算と比べてより多くの命令18 (15対11)とより多くの定数(12対7)を必要とすることが判明している。多項式の主定数をライティング係数に折りたたみ、(float4を用いて)チャネルによって以外のすべてをグループ化して、を色としてそのままにして、の一部をDCに折りたたむ。計算用シェーダコードと定数をセットアップするためのCPUコードは以下に示される。シェーダコードに渡される法線は正規化される必要があり、第4チャネルは1.0である必要がある。CPUコードは二次放射輝度SH係数への3つのfloatポインタの配列と定数をバインドするためのEffectを取る。
// 放射照度環境マップに含まれる定数
float4 cAr;
float4 cAg;
float4 cAb;
float4 cBr;
float4 cBg;
float4 cBb;
float4 cC;
float3 ShadeIrad(float4 vNormal) {
float3 x1, x2, x3;
// 多項式の線形および定数項
x1.r = dot(cAr,vNormal);
x1.g = dot(cAg,vNormal);
x1.b = dot(cAb,vNormal);
// 二次多項式4つ
float4 vB = vNormal.xyzz * vNormal.yzzx;
x2.r = dot(cBr,vB);
x2.g = dot(cBg,vB);
x2.b = dot(cBb,vB);
// 最終的な二次多項式
float vC = vNormal.x*vNormal.x - vNormal.y*vNormal.y;
x3 = cC.rgb * vC;
return x1+x2+x3;
}void SetSHEMapConstants(float* fLight[3], ID3DXEffect* pEffect) {
// ライティング環境の定数
D3DXVECTOR4 vCoeff[3];
static const float s_fSqrtPI = ((float)sqrtf(D3DX_PI));
const float fC0 = 1.0f/(2.0f*s_fSqrtPI);
const float fC1 = (float)sqrt(3.0f)/(3.0f*s_fSqrtPI);
const float fC2 = (float)sqrt(15.0f)/(8.0f*s_fSqrtPI);
const float fC3 = (float)sqrt(5.0f)/(16.0f*s_fSqrtPI);
const float fC4 = 0.5f*fC2;
for(int iC = 0; iC < 3; iC++) {
vCoeff[iC].x = -fC1 * fLight[iC][3];
vCoeff[iC].y = -fC1 * fLight[iC][1];
vCoeff[iC].z = fC1 * fLight[iC][2];
vCoeff[iC].w = fC0 * fLight[iC][0] - fC3 * fLight[iC][6];
}
pEffect->SetVector("cAr", &vCoeff[0]);
pEffect->SetVector("cAg", &vCoeff[1]);
pEffect->SetVector("cAb", &vCoeff[2]);
for(int iC = 0; iC < 3; iC++) {
r vCoeff[iC].x = fC2 * fLight[iC][4];
vCoeff[iC].y = -fC2 * fLight[iC][5];
vCoeff[iC].z = 3.0f*fC3 * fLight[iC][6];
vCoeff[iC].w = -fC2 * fLight[iC][7];
}
pEffect->SetVector("cBr", &vCoeff[0]);
pEffect->SetVector("cBg", &vCoeff[1]);
pEffect->SetVector("cBb", &vCoeff[2]);
vCoeff[0].x = fC4 * fLight[0][8];
vCoeff[0].y = fC4 * fLight[1][8];
vCoeff[0].z = fC4 * fLight[2][8];
vCoeff[0].w = 1.0f;
pEffect->SetVector("cC", &vCoeff[0]);
}バージョン履歴
- 2008年 2月14日 最初の公開バージョン
- 2008年 4月 1日 SH計算時の漸化式を付録に追加して、付録の番号を付け直す
- 2009年 3月17日 漸化式のtypoを修正
- 2009年11月30日 アンビエント光と最適線形な方向のtypoを修正
- 2010年 2月10日 積の行列の定義のtypo(指摘してくれたDon Holdenに感謝)
Footnotes
-
これらは球座標における解の角度部分である。 ↩
-
正規直交基底は、がのとき、それ以外のときとなる特性を持つものである。 ↩
-
訳注:このメモでは、SHに対する”order”は「次数」と、多項式に対する”degree”は注記付きで次数としています。 ↩
-
この基底はSHを求めるより効率的であり、6つの基底関数のうち任意の球上の点で非ゼロとなるのは3つのみである。 ↩
-
すなわち、+X面上では、yとzになるだろう。 ↩
-
“ease spline”が用いられる。これは制約を持つ三次多項式であり、一意に定まる三次多項式はである。 ↩
-
これは4次より大きいライティングを仮定していない。5次および6次では正規化ファクタはとなる。 ↩
-
球上の点の集合をとすると、与えられた点のVoronoi cellはその集合における他のいかなる点よりに近い球上のすべての点を含む。 ↩
-
信号処理における”窓を掛ける”という用語は空間領域においてより一般的に使用される。例えば、画像をフィルタリングするときにフィルタの空間的な大きさが”窓掛け”され、1Dの信号のFFTを取るときにその信号は周期的にするためにスケールされるかもしれない。本論において、これらは周波数領域において行われている。 ↩
-
であり、のとき最大値となる。 ↩
-
時折シグマファクタはGibbs現象をより積極的に減らすためにべき乗されるだろう。これは、その信号を繰り返し畳み込むのと同等である。 ↩
-
Lancoszの二乗はHanning関数に近いが、少しだけ速く減衰する。2.25の高さとなるデルタ関数の再構築では、Hanning関数は大きさ12.0105の窓を必要とし、Lancoszは大きさ9.8725の窓を必要とする。その結果は見た目には区別できないように見える。 ↩
-
これらの結果は[@47]の出力を適用したナイーブなアルゴリズムを用いているので、より効率的なコードが生成できるかもしれない。 ↩
-
放射輝度(ベクトルのまま)か放射照度(ベクトルの畳み込み)のいずれかを用いて最適化できる。 ↩
-
そのHessian行列はであり、正の固有値を持つ。すなわち、これは最小値である。 ↩
-
SHベクトルはDC項において非ゼロのみを持つ。 ↩
-
二階混合偏微分はすべてゼロであり、非混合偏微分はすべて1であるので、そのHessianは単位行列であり、極小を持つ。 ↩
-
スカラGPUでは、このギャップは、60対42となり、さらに重大になる。 ↩