フォトンマッピングの理論
2021/11/30
#3dcg #raytracing
フォトンマッピングのアルゴリズムの理論的な定式化について

このページではフォトンマッピングの理論について解説しています。前提知識としてパストレーシングのアルゴリズムや、モンテカルロ積分, Path Integral LTEなどについて知っているものとします。これらの話題については

で詳しく解説されているので、是非見て下さい。

TL;DR

  • KKをカーネル関数としてf(x)RK(xy)f(y)dyf(x) \approx \int_{\mathbb{R}} K(x - y)f(y)dyと関数近似できる
  • この近似をPath Integral LTEに適用する
  • これをモンテカルロ積分で解く

フォトンマッピングとは

Henrik Wann Jensenという方が90年代の終わりに提唱した光輸送アルゴリズムです。光輸送アルゴリズムには パストレーシング(Path Tracing)双方向パストレーシング(Bidirectional Path Tracing - BDPT) といった手法がありますが、フォトンマッピングは 集光模様(Caustics)SDSパス(SDS Path) と呼ばれる光の経路のレンダリングに強いアルゴリズムです。実装すると以下のような水の底でゆらめく光の模様を綺麗にレンダリングすることができます。

集光模様の例
集光模様の例

SDSパスとはSpecular - Diffuse - Specularとなるような光の経路のことです。例えばガラスに覆われているようなDiffuse面はSDSパスを持ちます。

SDSパスの例
SDSパスの例

このような経路はパストレーシングや双方向パストレーシングなどの手法ではSpecular面に挟まれているが故にレンダリングが難しいです。特に光源に点光源、カメラにピンホールカメラを使っているような場合には、このようなパスをサンプリングする確率は0となり、レンダリングが不可能となります。

アルゴリズムの流れ

フォトンマッピングのアルゴリズムの基本的な流れは以下の通りです。

まず、光源から フォトン(Photon) と呼ばれる光のエネルギーを運ぶ仮想の粒子を飛ばし、パストレーシングと同じようにシーン中で反射を繰り返します。この時、Diffuse面に当たる度にフォトンを フォトンマップ(Photon Map) に格納しておきます。

フォトントレーシング
フォトントレーシング

次に視点側からレイトレーシングを行い、Diffuse面に当たったらフォトンマップから近くにあるフォトンをクエリし、反射放射輝度の推定を行います。フォトンには点の位置, 入射方向, Throughputなどの情報が格納されているので、これらを利用して放射輝度の推定を行います。

放射輝度推定
放射輝度推定

Specular面に当たった場合にはDiffuse面に当たるまで再帰的にレイを追跡し、Diffuse面でフォトンマップを用いた放射輝度推定を行います。

Specularの場合
Specularの場合

フォトンマッピングとは光源側から生成したパスをフォトンマップにキャッシュしておき、カメラ側から生成したパスと効率良く繋げる手法と言えます。つまり双方向パストレーシングのような双方向アルゴリズムの1つです。

生成されるパス
生成されるパス

また、パスをつなげる際には近くにあるフォトンを利用しているため、一定の範囲で "緩く" 接続していると言えます。これによってSDSパスをレンダリングすることが可能になっています。これはパストレーシングや双方向パストレーシングなどのような "点と点を結ぶ" 手法とは大きく異なり、フォトンマッピングを特徴付ける重要な点と言えます。

フォトンマッピングの理論

ここではフォトンマッピングの理論的な部分について

をベースにしながら解説していきます。ここで述べる定式化はJensenのオリジナルのものとは全く異なりますが、フォトンマッピングのアルゴリズムをPath Integral LTEの形で書けるため理論的により明確です。モンテカルロ積分としての解釈も容易なので、後でThroughputの計算を導出する際にも役に立ちます。

カーネル関数近似

ある関数f(x)f(x)の値を、xx周辺のffの値を使って推定することを考えます(関数補間)。

カーネル関数(Kernel Function) K(x)K(x)とは以下のように積分して1になるような関数のことを言います。

RK(x)dx=1\int_{\mathbb{R}} K(x)dx = 1

このような関数を用いるとf(x)f(x)は以下のようにxx周辺の値を使って近似することができます。

f(x)RK(xy)f(y)dyf(x) \approx \int_{\mathbb{R}} K(x - y)f(y)dy

これを カーネル関数近似 と呼ぶことにします。

例えばKKとしてデルタ関数を用いれば

Rδ(xy)f(y)dy=f(x)\int_{\mathbb{R}} \delta(x - y)f(y)dy = f(x)

となり, f(x)f(x)と一致します。

もちろん実際にはデルタ関数を用いることは出来ないので、以下のように00でピークを持つような関数を用いて推定を行います。この関数は平均0, 分散σ2\sigma^2の正規分布の密度関数です。このようなカーネルをガウシアンカーネルと呼びます。

K(x)=12πσ2exp(12σ2x2)K(x) = \frac{1}{\sqrt{2\pi\sigma^2}}\exp(-\frac{1}{2\sigma^2}x^2)
ガウシアンカーネル
ガウシアンカーネル

幅の広いカーネルを用いるほど関数近似の誤差は大きくなります。

上で説明したのは1次元の場合でしたが、多次元の場合は

K(x,y)=K(xy)K(x, y) = K(\|x - y\|)

のように点xxと点yyの間の距離を使うことで1次元のカーネルに帰着させて同様に関数近似が行えます。

f(x)RdK(x,y)f(y)dyf(x) \approx \int_{\mathbb{R^d}} K(x, y)f(y)dy

3点形式のLTEのカーネル関数近似

以下のような3点形式のLTEに対してカーネル関数近似を適用することを考えます。

  • Lo(x1x2)L_o(x_1 \to x_2): x1x_1からx2x_2に出射する放射輝度
  • M\mathcal{M}: シーン上の点全体
  • Li(x0x1)L_i(x_0 \to x_1): x0x_0からx1x_1に入射する放射輝度
  • ff: BSDF
  • GG: 幾何項
Lo(x1x2)=MLi(x0x1)f(x0x1x2)G(x0,x1)dA(x0)L_o(x_1 \to x_2) = \int_{\mathcal{M}} L_i(x_0 \to x_1)f(x_0 \to x_1 \to x_2)G(x_0, x_1)dA(x_0)
3点形式のLTE
3点形式のLTE

今、x1x_1LiL_i, ff, GGの値を知ることができないとします。この場合x1x_1でカーネル関数近似を適用すると

Lo(x1x2)=MMK(y,x1)Li(x0y)f(x0yx2)G(x0,y)dA(x0)dA(y)(1)L_o(x_1 \to x_2) = \int_{\mathcal{M}}\int_{\mathcal{M}} K(y, x_1)L_i(x_0 \to y)f(x_0 \to y \to x_2)G(x_0, y)dA(x_0)dA(y) \tag{1}

となり、x1x_1周辺のyyの位置でのLiL_iffの値を使って推定することができます。これが3点形式のLTEにカーネル関数近似を適用した形です。

カーネル関数近似を適用した3点形式のLTE
カーネル関数近似を適用した3点形式のLTE

3点形式のLTEのカーネル関数近似(緩く接続した場合)

式(1)ではx1x_1を全てyyに置き換えてカーネル関数近似を行っていました。全て置き換えるのではなく、部分的に置き換える場合を考えます。

Lo(x1x2)=MMK(y,x1)Li(x0y)f(x0y,x1x2)G(x0,y)dA(x0)dA(y)L_o(x_1 \to x_2) = \int_{\mathcal{M}}\int_{\mathcal{M}} K(y, x_1)L_i(x_0 \to y)f(x_0 \to y, x_1 \to x_2)G(x_0, y)dA(x_0)dA(y)

ここではffの中身をx0yx2x_0 \to y \to x_2からx0y,x1x2x_0 \to y, x_1 \to x_2に変えています。図で表すと以下のような形です。

緩く接続した場合
緩く接続した場合

このパスはyyx1x_1を無理やり繋げた形になっています。これは物理的に正確な意味でのパスではありません(地面に沿って光が進んでいるということになる)。 そのような意味で"緩く"接続されたパスと言えます。

何故このような緩い接続を考えるかと言うと、冒頭でも述べた通り、フォトンマッピングではこの緩い接続がSDSパスなどをレンダリングするために重要であり、これを理論的に説明するためにこのような緩いカーネル関数近似を考えます。

Path Integral LTEのカーネル関数近似

続いてカーネル関数近似をPath Integral LTEに適用することを考えます。簡単のため経路長3のパスのPath Integral LTEを考えます。

  • IjI_j: jj番目のピクセルの寄与
  • M\mathcal{M}: シーン上の点全体
  • LeL_e: 光源から出る放射輝度
  • GG: 幾何項
  • ff: BSDF
  • WejW_e^{j}: jj番目のピクセルのセンサー応答
Ij=M4Le(x0x1)G(x0,x1)f(x0x1,x2)G(x1,x2)f(x1x2x3)G(x2,x3)Wej(x2x3)dA(x0)dA(x1)dA(x2)dA(x3)I_j = \int_{\mathcal{M}^4}L_e(x_0 \to x_1)G(x_0, x_1)f(x_0 \to x_1, \to x_2)G(x_1, x_2)f(x_1 \to x_2 \to x_3)G(x_2, x_3)W_e^{j}(x_2 \to x_3)dA(x_0)dA(x_1)dA(x_2)dA(x_3)
Path Integral LTE
Path Integral LTE

今, x2x_2で緩い接続の意味でのカーネル関数近似を適用するとします。式は以下のようになります。

Ij=M5Le(x0x1)G(x0,x1)f(x0x1,y)G(x1,y)K(y,x2)f(x1y,x2x3)G(x2,x3)Wej(x2x3)dA(x0)dA(x1)dA(y)dA(x2)dA(x3)I_j = \int_{\mathcal{M}^5} L_e(x_0 \to x_1)G(x_0, x_1)f(x_0 \to x_1, \to y)G(x_1, y)K(y, x_2)f(x_1 \to y, x_2 \to x_3)G(x_2, x_3)W_e^{j}(x_2 \to x_3)dA(x_0)dA(x_1)dA(y)dA(x_2)dA(x_3)
カーネル関数近似を適用したPath Integral LTE
カーネル関数近似を適用したPath Integral LTE

この式はx2x_2においてフォトンマップを用いて放射輝度推定を行っていることに対応します(フォトンの位置はyy)。

モンテカルロ積分

先程のPath Integral LTEの緩いカーネル関数近似をモンテカルロ積分することを考えます。

今、光源側からフォトンを飛ばしてx0,x1,yx_0, x_1, yと経路を構築し、カメラ側からパストレーシングによってx3,x2x_3, x_2と経路を構築したとします。この時、先程の緩いカーネル関数近似を行ったPath Integral LTEのモンテカルロ積分は以下のように書けます。

  • NN: 経路生成のサンプル数
  • p(x)p(x): 点xxを生成する確率密度
  • p(xixj)p(x_i|x_j): 点xjx_jから点xix_iを生成する時の条件付き確率密度
Ij1Ni=1NLe(x0ix1i)G(x0i,x1i)f(x0ix1i,yi)G(x1i,yi)K(yi,x2i)f(x1iyi,x2ix3i)G(x2i,x3i)Wej(x2ix3i)p(x0i)p(x1ix0i)p(yix1i)p(x2ix3i)p(x3i)(2)I_j \approx \frac{1}{N}\sum_{i=1}^N \frac{L_e(x_0^i \to x_1^i)G(x_0^i, x_1^i)f(x_0^i \to x_1^i, \to y^i)G(x_1^i, y^i)K(y^i, x_2^i)f(x_1^i \to y^i, x_2^i \to x_3^i)G(x_2^i, x_3^i)W_e^{j}(x_2^i \to x_3^i)}{p(x_0^i)p(x_1^i|x_0^i)p(y^i|x_1^i)p(x_2^i|x_3^i)p(x_3^i)} \tag{2}

ここで上付きのiiii番目のサンプルを表しています。この式は各iiで毎回光源側とカメラ側からランダムに経路構築を行い、yyx2x_2を緩く接続するようなアルゴリズムを表現しています。

モンテカルロ積分
モンテカルロ積分

フォトンのThroughputを

βi=Le(x0ix1i)G(x0i,x1i)f(x0ix1i,yi)G(x1i,yi)p(x0i)p(x1ix0i)p(yix1i)\beta_i = \frac{L_e(x_0^i \to x_1^i)G(x_0^i, x_1^i)f(x_0^i \to x_1^i, \to y^i)G(x_1^i, y^i)}{p(x_0^i)p(x_1^i|x_0^i)p(y^i|x_1^i)}

カメラ側からのレイのThroughputを

Ti=G(x2i,x3i)Wej(x2ix3i)p(x2ix3i)p(x3i)T_i = \frac{G(x_2^i, x_3^i)W_e^{j}(x_2^i \to x_3^i)}{p(x_2^i|x_3^i)p(x_3^i)}

とすると、式(2)は以下のように書けます。

Ij1Ni=1NβiK(yi,x2i)f(x1iyi,x2ix3i)TiI_j \approx \frac{1}{N}\sum_{i=1}^N\beta_i K(y^i, x_2^i)f(x_1^i \to y^i, x_2^i \to x_3^i)T_i

フォトンマッピング

式(2)は各iiで光源側とカメラ側から毎回別々の経路を構築するような式になっていました。フォトンマッピングでは冒頭で述べた通り、フォトンマップを使うことで予め光源側からのパスの生成を行ってキャッシュしておきます。

フォトンマップを用いたモンテカルロ積分
フォトンマップを用いたモンテカルロ積分

フォトンマップ作成に使うフォトン数をNpN_p、カメラ側からの経路生成のサンプル数をNNとすると、式(2)は以下のように書き換えることができます。

Ij1Ni=1N(1Npp=1NpβpK(yp,x2i)f(x1pyp,x2ix3i))Ti(3)I_j \approx \frac{1}{N}\sum_{i=1}^N \bigg(\frac{1}{N_p}\sum_{p=1}^{N_p}\beta_pK(y^p, x_2^i)f(x_1^p \to y^p, x_2^i \to x_3^i)\bigg)T_i \tag{3}

ここで()()で囲った部分がフォトンマップを用いた放射輝度推定に対応する部分です。フォトンマッピングの説明でよく 密度推定(Density Estimation) と言われている部分に対応します。(以上の議論の流れを見れば分かる通り、密度推定というよりは関数近似と呼ぶほうが適切なように思います)

TiT_iの部分はカメラ側からのパストレーシングの部分に対応します。これを()()の項と掛け合わせることでjj番目のピクセルの値が推定できます。

式(3)では()()内の総和を全てのフォトンに対して行っていますが、実際にはカーネル関数は点x2x_2から離れたところでは0または非常に小さな値を取ります。例えばカーネル関数として

K(x,y)={1πr2(xyr)0(otherwise)K(x, y) = \begin{cases} \frac{1}{\pi r^2} & (\|x-y\| \le r) \\ 0 & (otherwise) \end{cases}

という半径rrの円上で定数となるようなカーネルを使うと、点x2x_2から半径rr以上の位置にあるフォトンに対して総和を取っても、カーネルの値が0になるため無駄です。そこで実際にはx2x_2の近傍にあるフォトンのみを用いて総和を取ります。このためフォトンマップを表現するデータ構造としては近傍探索が効率良く行えるOctreeやKd-treeなどのデータ構造が選ばれます。

式(3)がフォトンマッピングの理論的な部分を全て説明する式です。今回は経路長3の場合で考えましたが、他の経路長の場合でも同様の式を得ることができます。

次回は今回の内容を元に、フォトンマッピングの実装について説明します。

次回

References