色付きボリュームのモンテカルロレイトレーシング
2021/12/25
#3dcg #raytracing
吸収/散乱係数が波長依存の媒質に対するモンテカルロレイトレーシングについて

この記事はレイトレアドベントカレンダー2021 25日目の記事です。この記事では吸収/散乱係数が波長依存の媒質に対するモンテカルロレイトレーシングの方法について解説しています。前提として24日目の記事の内容は知っているものとします。

TL;DR

  • 最初に波長をランダムにサンプリングする
  • サンプリングした波長で自由行程サンプリング/吸収・散乱イベントサンプリングを行う
  • 全波長分の寄与をMISをしつつ一気に計算する

波長依存の吸収/散乱係数

世の中にある多くの媒質は色がついているように見えます。例えば大気や水は青っぽく見えます。これは吸収/散乱係数の大きさが波長によって異なるためです。

以下は水の吸収係数を表すグラフです。横軸が波長、縦軸が吸収係数です。(データは H. Buiteveld and J. M. H. Hakvoort and M. Donze, "The optical properties of pure water," in SPIE Proceedings on Ocean Optics XII, edited by J. S. Jaffe, 2258, 174--183, (1994) より)

水の吸収係数
水の吸収係数

波長が長い光(赤)は吸収されやすく、波長が短い光(青)は吸収されにくいことが分かります。赤い光が吸収されてしまうので水は青く見えるわけです。

スペクトルレンダラーでは上記の曲線をそのまま吸収係数として使うことが出来ます。RGBレンダラーでは上記の曲線から赤, 緑, 青に対応する波長のデータだけを抜き出して、3次元ベクトルとして吸収係数を表現すれば良いでしょう。

波長依存の場合のボリュームレンダリング方程式

理論的な拠り所を得るために、ここでは吸収/散乱係数が波長依存の場合のボリュームレンダリング方程式(以降VREと呼びます)について考えます。

吸収/散乱係数が波長非依存の場合のVREは以下のような形でした。

L(x,ω)=0tT(x,xsω)(μa(xsω)Le(xsω,ω)+μs(xsω)Ls(xsω,ω))ds+T(x,xtω)L(xtω,ω)\begin{aligned} L(x, \vec{\omega}) &= \int_0^t T(x, x - s\vec{\omega})\bigg( \mu_a(x - s\vec{\omega})L_e(x - s\vec{\omega}, \vec{\omega}) + \mu_s(x - s\vec{\omega})L_s(x - s\vec{\omega}, \vec{\omega}) \bigg)ds \\ &+ T(x, x - t\vec{\omega})L(x - t\vec{\omega}, \vec{\omega}) \end{aligned}

これを吸収/散乱係数が波長依存の形の式に変えるには、波長を表すλ\lambdaという変数を加えてあげるだけです。

L(x,ω,λ)=0tT(x,xsω,λ)(μa(xsω,λ)Le(xsω,ω,λ)+μs(xsω,λ)Ls(xsω,ω,λ))ds+T(x,xtω,λ)L(xtω,ω,λ)(1)\begin{aligned} L(x, \vec{\omega}, \lambda) &= \int_0^t T(x, x - s\vec{\omega}, \lambda)\bigg( \mu_a(x - s\vec{\omega}, \lambda)L_e(x - s\vec{\omega}, \vec{\omega}, \lambda) + \mu_s(x - s\vec{\omega}, \lambda)L_s(x - s\vec{\omega}, \vec{\omega}, \lambda) \bigg)ds \\ &+ T(x, x - t\vec{\omega}, \lambda)L(x - t\vec{\omega}, \vec{\omega}, \lambda) \tag{1} \end{aligned}

これが吸収/散乱係数が波長依存の場合のVREです。これを数値計算することがこの記事の目標になります。

スペクトルレンダリング

式(1)は波長ごとの放射輝度(分光放射輝度)を計算する式になっています。レンダラーで分光放射輝度をRGBの画像にするためには、以下のように等色関数を用いて分光放射輝度を一度XYZ色空間に変換し、その後XYZをRGBに変換します。

  • L(λ)L(\lambda): 分光放射輝度(正しくはカメラのセンサー応答だが、簡単のためここでは省略)
  • xˉ(λ)\bar{x}(\lambda): Xの等色関数
  • yˉ(λ)\bar{y}(\lambda): Yの等色関数
  • zˉ(λ)\bar{z}(\lambda): Zの等色関数
X=0L(λ)xˉ(λ)dλY=0L(λ)yˉ(λ)dλZ=0L(λ)zˉ(λ)dλ\begin{aligned} X &= \int_0^{\infty} L(\lambda)\bar{x}(\lambda) d\lambda \\ Y &= \int_0^{\infty} L(\lambda)\bar{y}(\lambda) d\lambda \\ Z &= \int_0^{\infty} L(\lambda)\bar{z}(\lambda) d\lambda \end{aligned}

これらの積分は波長をランダムサンプリングすることで、モンテカルロ積分を用いて計算することが出来ます。

  • NN: 波長のサンプル数
  • LL: 波長を表す確率変数
  • pL(λ)p_{L}(\lambda): LLの確率密度関数
X=1Ni=1NL(λi)xˉ(λi)pL(λi)Y=1Ni=1NL(λi)yˉ(λi)pL(λi)Z=1Ni=1NL(λi)zˉ(λi)pL(λi)(2)\begin{aligned} X &= \frac{1}{N}\sum_{i=1}^N \frac{L(\lambda_i)\bar{x}(\lambda_i)}{p_L(\lambda_i)} \\ Y &= \frac{1}{N}\sum_{i=1}^N \frac{L(\lambda_i)\bar{y}(\lambda_i)}{p_L(\lambda_i)} \\ Z &= \frac{1}{N}\sum_{i=1}^N \frac{L(\lambda_i)\bar{z}(\lambda_i)}{p_L(\lambda_i)} \tag{2} \end{aligned}

もっと詳しい話はちょうどアドカレで別の方が書いてくださっているので、そちらも合わせて参考にして下さい。

式(2)から、スペクトルレンダラーの実装ではまず最初に波長をランダムに選び、その波長で分光放射輝度を計算すれば良いです。この場合式(1)の評価は単純に吸収/散乱係数をサンプリングした波長に対応する値にして評価すれば良いだけなので、特に難しいことはありません。

しかしこの方法はただでさえノイズが多くなりがちなモンテカルロレイトレーシングによる計算が、波長のランダムサンプリングによって色ノイズが追加で加わり、収束が遅くなってしまうという問題があります。

波長のランダムサンプリングによる色ノイズ
波長のランダムサンプリングによる色ノイズ

大抵のシーンのレンダリングではスペクトルレンダリングまでやらなくても、RGBによるレンダリングだけで十分なことも多いです。しかし、この方法だとRGBレンダリングをやる場合でもR, G, Bの各成分をランダムにサンプリングしなければならないので効率が悪いです。

そこで、波長はランダムにサンプリングするけれども、その波長だけではなくて全波長分の寄与を一気に計算してしまうという方法を考えます。これが次に紹介する Hero wavelength sampling です。

Hero wavelength sampling

Hero wavelength samplingはWilkie, Alexander, et alによって2014年に導入されたスペクトルレンダリングの手法です。Hero wavelength samplingではランダムにサンプリングされた波長でパスの構築をした後、そのパスの寄与をMulti importance sampling(MIS)を使いつつ全波長分一気に計算するということを行います。そのため単一波長だけで寄与を計算していく場合よりも色ノイズが少なくなります。

以下の画像はRGBレンダリングにおいて左が単一波長でレンダリングした場合、右がHero wavelength samplingでレンダリングした場合です。Hero wavelength samplingの方が色ノイズが減っているのが分かると思います。スペクトルレンダリングだと差はさらに顕著になるはずです。

単一波長とHero wavelength samplingの比較
単一波長とHero wavelength samplingの比較

MISは別々のサンプリング戦略から得られる寄与を良い感じに合算してくれるものですが、Hero wavelength samplingで言う戦略とは それぞれの波長で構築されるパスを別々のサンプリング戦略として見る という意味です。

例えばある色付きボリュームで波長をランダムに選び、モンテカルロレイトレーシングによってパスを構築したとします。ここで構築されるパスは別の波長を選んだ場合でも(確率密度が0でなければ)サンプリングできるはずです。つまり そのパスを作ることの出来るサンプリング戦略は波長の個数分だけ存在 することになります。

あるパスは別の波長を選んだ場合でも構築できる
あるパスは別の波長を選んだ場合でも構築できる

Hero wavelength samplingはガラスのように各波長で散乱方向が一意に定まるような材質では単一波長だけで寄与を計算した場合と計算効率が同じになってしまうのですが、ボリュームの場合は基本的にそのようなことが起こらないのでHero wavelength samplingを使ったほうが効率が良いです。ボリューム以外にもDiffuse面のスペクトルレンダリングなどにも有効だと思います。

今、分光放射輝度を計算したい対象の波長がλ1,λ2,,λC\lambda^1, \lambda^2, \cdots, \lambda^CのようにCC個あるとします。CC個の波長の中から波長λh\lambda^hを毎回ランダムに1つ選び、その波長でパスを構築するとします。この時Hero wavelength samplingでは以下のようにして全波長分の寄与を一気に計算します。

  • NN: パス構築のサンプル数
  • xˉi\bar{x}_i: ii番目のサンプルのパス
  • wj(xˉi,λj)w_j(\bar{x}_i, \lambda^j) jj番目の波長でパスxˉi\bar{x}_iを構築する戦略のMISウェイト
  • p(xˉi,λih)p(\bar{x}_i, \lambda_i^h): hh番目の波長を使ってパスxˉi\bar{x}_iを構築する時の同時確率密度
X=1Ni=1Nj=1Cwj(xˉi,λj)L(xˉi,λj)p(xˉi,λih)xˉ(λj)(3)X = \frac{1}{N}\sum_{i=1}^N\sum_{j=1}^C w_j(\bar{x}_i, \lambda^j)\frac{L(\bar{x}_i, \lambda^j)}{p(\bar{x}_i, \lambda_i^h)}\bar{x}(\lambda^j) \tag{3}

ここではXX成分だけ表示していますが、YY, ZZも同様の式になります。

RGBレンダリングの場合は次のようにR, G, Bの各成分を表すOne-hot vectorを導入することで、式(3)と同様の枠組みで記述できます。

  • δi,j\delta_{i, j}: クロネッカーのデルタ
  • rgbi=(δ1,iδ2,iδ3,i)\boldsymbol{rgb}_i = \begin{pmatrix} \delta_{1, i} \\ \delta_{2, i} \\ \delta_{3, i} \end{pmatrix}
RGB=1Ni=1Nj=13wj(xˉi,λj)L(xˉi,λj)p(xˉi,λih)rgbj(4)RGB = \frac{1}{N}\sum_{i=1}^N\sum_{j=1}^3 w_j(\bar{x}_i, \lambda^j)\frac{L(\bar{x}_i, \lambda^j)}{p(\bar{x}_i, \lambda_i^h)}\boldsymbol{rgb}_j \tag{4}

ここでは式(3)をベースに話を進めていきます。

MISウェイトはバランスヒューリスティックを使うとすると、次のように計算できます。

wj(xˉi,λj)=pj(xˉi,λj)k=1Cpk(xˉi,λj)=p(xˉi,λih)k=1Cpk(xˉi,λih)\begin{aligned} w_j(\bar{x}_i, \lambda^j) &= \frac{p_j(\bar{x}_i, \lambda^j)}{\sum_{k=1}^C p_k(\bar{x}_i, \lambda^j)} \\ &= \frac{p(\bar{x}_i, \lambda_i^h)}{\sum_{k=1}^C p_k(\bar{x}_i, \lambda_i^h)} \end{aligned}

分子の確率密度は現在注目している戦略が与えられたパスを作る確率密度ですが、これは各jjで波長λih\lambda_i^hから作られるパスを共有して使いまわすので全てp(xˉi,λih)p(\bar{x}_i, \lambda_i^h)になります。分母の確率密度はkk番目の波長が仮にサンプリングされた時にそのパスを作る確率密度を表しています。引数はパスxˉi\bar{x}_iを作るのに使った波長を表しているのでλih\lambda_i^hであることに注意してください。

これを式(3)に代入すると次のような式を得ます。

  • P(λih)P(\lambda_i^h): 波長λih\lambda_i^hを選ぶ確率
  • p(xˉiλk)p(\bar{x}_i | \lambda_k): 波長λk\lambda_kを使ってパスxˉi\bar{x}_iを構築する時の条件付き確率密度
X=1Ni=1Nj=1CL(xˉi,λj)k=1Cpk(xˉi,λih)xˉ(λj)=1Ni=1Nj=1CL(xˉi,λj)k=1CP(λk)p(xˉiλk)xˉ(λj)(5)\begin{aligned} X &= \frac{1}{N}\sum_{i=1}^N\sum_{j=1}^C \frac{L(\bar{x}_i, \lambda^j)}{\sum_{k=1}^C p_k(\bar{x}_i, \lambda_i^h)}\bar{x}(\lambda^j) \\ &= \frac{1}{N}\sum_{i=1}^N\sum_{j=1}^C \frac{L(\bar{x}_i, \lambda^j)}{\sum_{k=1}^C P(\lambda^k)p(\bar{x}_i | \lambda^k)}\bar{x}(\lambda^j) \tag{5} \end{aligned}

MISウェイトの分子が相殺されて消えて、割とシンプルな形の式になりました。パスを作る波長λih\lambda_i^hのサンプリングの方法には自由度がありますが、それについては後ほど説明したいと思います。

VREのモンテカルロ積分へのHero wavelength samplingの適用

一様媒質の場合のVREのモンテカルロ積分に対してHero wavelength samplingを適用することを考えます。ここでは簡単のため散乱イベントが選択された時の寄与をHero wavelength samplingで計算することにします。

24日目の記事の式(13)から、吸収/散乱係数が波長非依存の場合で散乱イベントが選択された時の寄与は以下のように書けるのでした。

L^(x,ω)=T(x,xsω)μsLs^(xsω,ω)pS(s)Ps(6)\widehat{L}(x, \vec{\omega}) = \frac{T(x, x - s\vec{\omega})\mu_s\widehat{L_s}(x - s\vec{\omega}, \vec{\omega})}{p_S(s)P_s} \tag{6}

この式をHero wavelength samplingを使って波長依存の吸収/散乱係数の場合に拡張していきます。CC個の波長λ1,λ2,,λC\lambda^1, \lambda^2, \cdots, \lambda^Cの中からランダムに波長λh\lambda^hを選んでその波長でパスを作り、全波長分の寄与をMISを使いつつ一気に評価していきます。式(5)の分子のLLを式(6)の分子として見て、式を導出していきます。

まず式(5)の分子に当たる部分は、単純に評価をjj番目の波長λj\lambda^jの吸収/散乱係数を使ったものに置き換えるだけです。

T(x,xsω,λj)μs(λj)Ls^(xsω,ω,λj)T(x, x - s\vec{\omega}, \lambda^j)\mu_s(\lambda^j)\widehat{L_s}(x - s\vec{\omega}, \vec{\omega}, \lambda^j)

これを使うと式(6)は次のように書き換えられます。

j=1CT(x,xsω,λj)μs(λj)Ls^(xsω,ω,λj)k=1CP(λk)p(xˉiλk)xˉ(λj)(7)\sum_{j=1}^C \frac{T(x, x - s\vec{\omega}, \lambda^j)\mu_s(\lambda^j)\widehat{L_s}(x - s\vec{\omega}, \vec{\omega}, \lambda^j)}{\sum_{k=1}^C P(\lambda^k)p(\bar{x}_i | \lambda^k)} \bar{x}(\lambda^j) \tag{7}

次に式(7)の分母を計算していきます。

波長λh\lambda^hを選ぶ確率をPλh(λh)P_{\lambda^h}(\lambda^h)とします。この時P(λk)=Pλh(λh)P(\lambda^k) = P_{\lambda^h}(\lambda^h)です。

p(xˉλk)p(\bar{x} | \lambda^k)は次のように書けます。

p(xˉλk)=pS(s,λk)Ps(λk)pS(s,λk)=μt(λk)T(x,xsω,λk)Ps(λk)=μs(λk)μt(λk)\begin{aligned} p(\bar{x} | \lambda^k) &= p_S(s, \lambda^k)P_s(\lambda^k) \\ p_S(s, \lambda^k) &= \mu_t(\lambda^k)T(x, x - s\vec{\omega}, \lambda^k) \\ P_s(\lambda^k) &= \frac{\mu_s(\lambda^k)}{\mu_t(\lambda^k)} \end{aligned}

これを式(7)に代入して最終的に次の式を得ます。

j=1CT(x,xsω,λj)μs(λj)Ls^(xsω,ω,λj)Pλh(λh)k=1CpS(s,λk)Ps(λk)xˉ(λj)(8)\sum_{j=1}^C \frac{T(x, x - s\vec{\omega}, \lambda^j)\mu_s(\lambda^j)\widehat{L_s}(x - s\vec{\omega}, \vec{\omega}, \lambda^j)}{P_{\lambda^h}(\lambda^h)\sum_{k=1}^C p_S(s, \lambda^k)P_s(\lambda^k)} \bar{x}(\lambda^j) \tag{8}

これが散乱イベントにHero wavelength samplingを適用した場合の寄与の計算方法です。

ここでは省略しますが、吸収イベントが選択された場合や、レイが媒質の終端に到達した場合も似たような計算によって式を導出できます。基本的には式(5)の分子分母をそれぞれの場合に置き換えていくだけです。

波長サンプリング

パスを構築する波長λh\lambda^hの選び方に関してはこれまで何も言及してこなかったので、ここではそれについて見ていきます。

まず最も簡単なのはCC個の波長から一様にランダムに選択する方法です。この場合Pλh(λh)P_{\lambda^h}(\lambda^h)は以下で表されます。

Pλh(λh)=1CP_{\lambda^h}(\lambda^h) = \frac{1}{C}

この方法はシンプルですが、吸収/散乱係数の波長依存が強い場合にはfireflyが出てしまうことがあります。これは式(8)の分子の値が大きく、分母の値が小さい場合などに発生します。

そこで、Wrenninge, Magnus, Ryusuke Villemin, and Christophe Heryによる論文では波長を選択する確率を現在のレイのThroughputに比例させる方法が述べられています。これであれば式(8)の分子の値が大きい時には同時に分母の値も大きくなるので、fireflyは出にくくなります。

以下は表面化散乱のレンダリングにおいて波長を一様にサンプリングする場合(左)と、レイのThroughputに比例させてサンプリングする場合(右)の比較です。波長を一様にサンプリングする場合ではfireflyが出ていますが、Throughput比例の場合は綺麗にレンダリング出来ていることが分かります。

波長を一様にサンプリングする場合とThroughput比例の場合の比較
波長を一様にサンプリングする場合とThroughput比例の場合の比較

Throughput比例の場合はレイのThroughputをt(λk)t(\lambda^k)とすると、Pλh(λh)P_{\lambda^h}(\lambda^h)は以下で表されます。

Pλh(λh)=t(λh)k=1Ct(λk)P_{\lambda^h}(\lambda^h) = \frac{t(\lambda^h)}{\sum_{k=1}^C t(\lambda^k)}

逆関数法を用いればこのような離散確率分布からのサンプルを得ることができます。詳しくは以下のPBRTのページを参照して下さい。

References