2016-09-19 InlineのLaTexを入れ替え。ついでに編集。
モンテカルロ積分: Monte Carlo Integraion
背後にある基本的なアイデア
モンテカルロ積分の背後にある基本的なアイデアは、xの関数f(x)の領域Ωでの積分を、ランダムなサンプリングXi=(x1,x2,…xN)を用いて近似することです。
上記の\hat{I}のことをMonte Carlo Estimatorと呼ぶそうです。なぜこの式で近似できるかは直感的に分かる気がしますが、まずは、これの期待値を考えます。
ここでE[f(Xi)]は領域Ω内での離散的なサンプリングXiの関数f(Xi)の期待値です。これを連続な関数f(x)を用いて書き直すならば、f(x)に、xの確率密度関数:probability density function:PDF p(x)を乗算して積分することになります。
例えばPDFが一定、つまりXiの分布が一様であると仮定すると、以下の様になります。
つまりMonte Carlo Estimatorの期待値を求めることで、元来求めたかった積分の解である、Iを求めることができるわけです。
積分したい関数f(x)について
f(x)について何も前提条件がなければ、上記のように一様なサンプリングを行うしかありません。ただ、f(Xi)の分散が大きい場合、得られる解の分散も大きくなります。つまり近似した積分の値の誤差が大きくなる傾向にあります。
もし、関数f(x)に関して何らかの前提条件、たとえば、領域Ω内のある領域では値が大きくなり、またある領域では値が0に近くなるなどが分かれば、値が大きくなるところを重点的にサンプリングすることで、f(Xi) の分散が小さくなるようにサンプリング出来るでしょう。ただし、サンプリングの分布は領域Ωにおいて一様ではなくなり、サンプリングのPDF p(x)は定数ではなくなるため、上記の式は成り立ちません。
ここで、f(x)を以下のように分解した式のg(x)の積分について考えます。
\hat{I_g}の期待値は、以下のようになります。
これを、元のIの式に代入すると、以下のようになります。
つまり、サンプリングの確率密度を考慮したMonte Carlo Estimatorを定義すると、以下のようになります。
Lambert Diffuseを、一様ランダムベクトルで積分してみる
まずはじめに、Lambert Diffuseモデルの反射を考えてみたいと思います。
θは微小面の法線と入射光の成す角です。 Lambert DiffuseのBRDFはkd/πで一定です。Liが入射光のradianceで、これを見かけ上の微小面積に投影してBRDFを乗算すればLo : radianceが求まると思います。
さて、先のモンテカルロ積分の式に上記積分を当てはめていきます。まずLiのサンプリングを決めます。サンプリングは半球の全領域で一様とします。したがって、PDFは以下のように一定になります。
一方f(x)は、以下のようになります。
Loの近似値は以下のように表すことができます。
半球上に分布する一様ランダムベクトルの生成
モンテカルロ積分は、式内にサンプリングのPDFがあるので、上記のモンテカルロ積分の式は、下記のようなサンプリングの関数と対になって使用しなければなりません。今回のサンプリングは一様ランダムベクトルなのでベクトルの生成方法はいろいろ考えられますが、一例として下記のように行うこととします。使用するのは2つの0~1の一様乱数, u1, u2です。これを用いて半球状に一様なベクトルを生成します。z軸を天頂方向(つまり0~1)としています。
vec3 SampleUniform(float u1, float u2) { float r = sqrt(1.0f - u1 * u1); float phi = 2 * PI * u2; return vec3(r * cos(phi) , r * sin(phi), u1); }
半球上に分布する一様ランダムベクトルの生成(2)
上記のサンプリング関数をPDFから求めることも出来ます。逆変換法:inversion methodと呼ばれる方法です。
まず、PDFは、p(ω) = 1/2πで一定ですが、具体的なベクトルのPDFをを求めるため、極座標系の関数p(θ,φ)が必要になります。単位球の微小面積は以下のように求まるので、これを利用し、p(θ,φ)を求めます。
次に、θの周辺密度関数:marginal density function:MDFを求めます。
次に、φの条件付密度関数:conditional density function p(φ|θ)を求めます。
ここで、p(θ)とp(φ|θ)の累積分布関数:cumulative distribution function:CDF P(θ)とP(φ|θ)を求めます。
さて。ここで上記のCDFについて考えてみます。CDFはサンプリングの領域において0~1へと増加していきます。たとえば、P(θ)は、θが0~π/2の値をとるのにしたがって、0~1へと増加していきます。この増加の傾きは、θのPDFによって与えられます。
ここで、CDFの逆関数を考えてみます。P(θ)をξ1とした場合、P(θ)の逆関数は以下のようになります。
この関数は、ξ1が0~1の値をとるのにしたがって増加してゆき、θは0~π/2の値をとります。この関数の傾きはθのPDFの逆数になるはずです。ここで、ξ1に0~1の一様乱数を与えたときに得られるθの分布は、θのPDFに従うことになります。
同様にP(φ|θ)の逆関数は以下のようになり、こちらもφのMDFの分布に従います。
このことを利用して、2つの0~1の一様乱数より、サンプリングベクトルの生成を行うことが出来ます。
vec3 SampleUniform(float u1, float u2) { float theta = arccos(1-u1); float phi = 2 * pi * u2; return vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); }
少し計算を整理すれば、以下のようになります。章のはじめに書いた関数と、u1の向きが逆になっているだけで、同様の関数が得られました。
vec3 SampleUniform(float u1, float u2) { z = 1 - u1 r = sqrt(1- z*z); float phi = 2 * pi * u2; return vec3(r * cos(phi), r * sin(phi), z); }
Lambert Diffuseをcosine weighted samplingで積分してみる
Lambert Diffuseモデルにおけるサンプリングベクトルの分布について
ここで、Lambert Diffueseをモンテカルロ積分をする上で、もっと効率の良いサンプリングベクトルの分布について考えてみたいと思います。簡単なことですが、cos(θ)が0に近い領域ではLiの値にかかわらずLoの値が小さくなります。ということは、その領域でLiの不正確なサンプリングをしても、全体の誤差に与える影響が小さいということになります。言い換えれば、サンプルの数を減らしても全体の誤差に与える影響が小さいということです。一方でcos(θ)が大きな値になる領域では、全体の誤差に与える影響が大きいので、なるべく正確なサンプリングをしたほうが良好な結果が得られるはずです。つまり、積分したい関数の値とサンプリングのPDFは比例関係であるのが望ましいということです。
ただし、この条件は一般的に非常に困難です。なぜなら、PDFは領域全体で積分した時に1になる必要があり、上式の比例定数を求めるためにはf(x)の積分を求める必要があります。
この式内の積分を求めることは、モンテカルロ積分で求めたいものを求めることになり本末転倒になるというわけです。したがって、通常p(x)はf(x)の係数の一部であったり、f(x)をテイラー展開をして低次の項を用いたりするようです。
cosine weighted sampling
上記をふまえると、LambertDiffueseをモンテカルロ積分するならば、PDF:p(ω)はcos(θ)に比例するのが好ましいといえます。PDFは領域全体で1にならなくてはならないことを用いて比例定数を求めます。
したがって、PDFは以下のようになります。
上記のPDFにinversion methodを適用して、サンプリング用の関数を作ります。
θのMDFは、以下のようになります。
一方、φのconditional density functionは以下のようになります。
CDFはそれぞれ以下のようになります。
CDFの逆関数はそれぞれ以下のようになります。
上記をふまえ、サンプリング関数は以下のようになります。
vec3 SampleCosineWeighted(float u1, float u2) { float theta = asin(sqrt(u1)); float phi = 2 * pi * u2; return vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); }
上記を少し整理すると、以下のようになります。
vec3 SampleCosineWeighted(float u1, float u2) { float r = sqrt(u1); float phi = 2 * pi * u2; return vec3(r * cos(phi), r * sin(phi), sqrt(1-u1)); }
一方で、モンテカルロ積分の式は、下記の通りとなります。