この資料では 物理ベースレンダリング(Physically Based Rendering) を実現するために必要な数学・理論・実装について説明しています。
次のような事柄をこの資料では説明しています。
確率論
レイトレでの確率論
モンテカルロ積分
レイトレでのモンテカルロ積分
レンダリング方程式の数値計算
確率論
モンテカルロ積分を行うにあたって、確率論の基礎的な部分をある程度抑えている必要があります。ここではそれらの事柄について説明を行います。
確率空間
試行の結果得られる可能性のある標本全体を 標本空間(Sample Space) といい、Ω \Omega Ω で表します。
サイコロを一回投げるという例の場合、それぞれの目に対応するΩ = { ω 1 , ω 2 , ⋯ , ω 6 } \Omega = \{\omega_1, \omega_2, \cdots, \omega_6\} Ω = { ω 1 , ω 2 , ⋯ , ω 6 } を標本空間として取ります。
標本空間から生成されるσ加法族をF \mathcal{F} F で表し、F \mathcal{F} F の元を 事象(Event) と呼びます。特にΩ ∈ F \Omega \in \mathcal{F} Ω ∈ F を全事象、ϕ ∈ F \phi \in \mathcal{F} ϕ ∈ F を空事象と呼びます。
F \mathcal{F} F の元(つまり事象)に対し、確率測度(Probability Measure) P : F → [ 0 , 1 ] P:\mathcal{F} \rightarrow [0, 1] P : F → [ 0 , 1 ] が次のように定義されます。
P P P はF \mathcal{F} F 上の測度
P ( Ω ) = 1 P(\Omega) = 1 P ( Ω ) = 1
確率測度が通常の測度と違うところは、P ( Ω ) = 1 P(\Omega) = 1 P ( Ω ) = 1 が指定されているところです。このため任意の事象A ∈ F A \in \mathcal{F} A ∈ F に対し、0 ≤ P ( A ) ≤ 1 0 \le P(A) \le 1 0 ≤ P ( A ) ≤ 1 を満たします。
3つ組( Ω , F , P ) (\Omega, \mathcal{F}, P) ( Ω , F , P ) を 確率空間(Probability Space) と呼びます。
確率変数
可測関数X : Ω → R X:\Omega \rightarrow \mathbb{R} X : Ω → R を 実数値確率変数(Real Valued Random Variable) といいます。以降確率変数と言う場合は実数値確率変数を指すものとします。
この関数は標本空間の元ω ∈ Ω \omega \in \Omega ω ∈ Ω に対応する実数値を定めます。サイコロを1回投げる例では、サイコロの目の数という確率変数X X X を
X ( ω ) = { 1 ( ω = ω 1 ) 2 ( ω = ω 2 ) ⋮ 6 ( ω = ω 6 ) X(\omega) = \begin{cases}
1 & (\omega = \omega_1) \\
2 & (\omega = \omega_2) \\
\vdots \\
6 & (\omega = \omega_6)
\end{cases} X ( ω ) = ⎩ ⎪ ⎪ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎪ ⎪ ⎧ 1 2 ⋮ 6 ( ω = ω 1 ) ( ω = ω 2 ) ( ω = ω 6 )
のように定義できます。
分布測度
確率変数X X X がある値B B B を取る確率P X ( B ) P_X(B) P X ( B ) を計算することを考えます。この確率は確率変数の逆写像を用いて元の確率空間( Ω , F , P ) (\Omega, \mathcal{F}, P) ( Ω , F , P ) に引き戻し、そこでP P P を用いることで計算できます。
P X ( B ) = P ( { ω ∣ X ( ω ) ∈ B } ) = P ( X − 1 ( B ) ) = P ( X ∈ B ) P_X(B) = P(\{\omega | X(\omega) \in B\}) = P(X^{-1}(B)) = P(X \in B) P X ( B ) = P ( { ω ∣ X ( ω ) ∈ B } ) = P ( X − 1 ( B ) ) = P ( X ∈ B )
P X P_X P X は 分布測度(Distribution Measure) と呼ばれます。
P X P_X P X はR \mathbb{R} R 上の確率測度を定めます。したがって、確率変数X X X により別の確率空間( R , B , P X ) (\mathbb{R}, \mathcal{B}, P_X) ( R , B , P X ) が誘導されます。(B \mathcal{B} B はボレル集合族)
分布関数(累積分布関数)
以下のような関数F X ( x ) F_X(x) F X ( x ) を 分布関数(Distribution Function) または 累積分布関数(Cumulative Distribution Function - cdf) といいます。
F X ( x ) = P X ( [ − ∞ , x ] ) F_X(x) = P_X([-\infty, x]) F X ( x ) = P X ( [ − ∞ , x ] )
分布関数は確率変数から導かれる分布測度を用いて定義されていますが、逆に分布関数を指定することで分布測度が一意に定まります 。
分布関数を用いることで様々な確率が計算できます。例えば確率変数X X X が[ a , b ] [a, b] [ a , b ] に値をとる確率P X ( [ a , b ] ) P_X([a, b]) P X ( [ a , b ] ) は
P X ( [ a , b ] ) = F X ( b ) − F X ( a ) P_X([a, b]) = F_X(b) - F_X(a) P X ( [ a , b ] ) = F X ( b ) − F X ( a )
と計算できます。
確率密度関数
次のような条件を満たすf X ( x ) f_X(x) f X ( x ) を確率密度関数(Probability Density Function - pdf) といいます。
1. ∫ − ∞ ∞ f ( x ) d x = 1 \int_{-\infty}^{\infty} f(x)dx = 1 ∫ − ∞ ∞ f ( x ) d x = 1
2. F X ( x ) = ∫ − ∞ x f ( x ) d x F_X(x) = \int_{-\infty}^x f(x)dx F X ( x ) = ∫ − ∞ x f ( x ) d x
この定義よりd F X d x = f ( x ) \frac{dF_X}{dx} = f(x) d x d F X = f ( x ) となっていることに注意してください。(d F X d x = f ( x ) \frac{dF_X}{dx} = f(x) d x d F X = f ( x ) はRadon-Nikodym微分と呼ばれる。このようなf f f が存在することはRadon-Nikodymの定理より言える)
確率密度関数を指定することで、分布関数が定まり、さらに分布測度が定まるので、確率密度関数を指定することで確率変数を構成することがよく行われます。
例: 一様分布
確率変数X X X が一様分布U ( a , b ) U(a, b) U ( a , b ) に従うとは、X X X の確率密度関数f X ( x ) f_X(x) f X ( x ) が
f X ( x ) = { 1 b − a ( a ≤ x ≤ b ) 0 ( o t h e r w i s e ) f_X(x) = \begin{cases} \frac{1}{b - a} & (a \le x \le b) \\
0 & (otherwise)
\end{cases} f X ( x ) = { b − a 1 0 ( a ≤ x ≤ b ) ( o t h e r w i s e )
となっているときをいいます( a < b ) (a < b) ( a < b ) 。これは閉区間[ a , b ] [a, b] [ a , b ] から点を一様に取ることを意味しています。
例: 正規分布
確率変数X X X が正規分布N ( μ , σ 2 ) N(\mu, \sigma^2) N ( μ , σ 2 ) に従うとは、X X X の確率密度関数f X ( x ) f_X(x) f X ( x ) が
f X ( x ) = 1 2 π σ 2 e − ( x − μ ) 2 2 σ 2 f_X(x) = \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x - \mu)^2}{2\sigma^2}} f X ( x ) = 2 π σ 2 1 e − 2 σ 2 ( x − μ ) 2
になっているときをいいます。確率変数が正規分布に従っていると仮定して、様々な解析を行うことが頻繁にあります。
期待値(平均)
確率変数X X X の 期待値(平均) E [ X ] E[X] E [ X ] を分布測度P X P_X P X による積分として以下のように定義します。
E [ X ] = ∫ D X ( t ) d P X ( t ) = ∫ D X ( t ) f X ( t ) d t E[X] = \int_D X(t)dP_X(t) = \int_D X(t)f_X(t)dt E [ X ] = ∫ D X ( t ) d P X ( t ) = ∫ D X ( t ) f X ( t ) d t
D D D はX X X の値域です。期待値はX X X から出てくる値が平均的にどのような値を取るかを示しています。
注意としてはX X X は常に可積分であるとは限らないので、期待値が計算出来ない場合もあります。
期待値は線形性を持ちます。
E [ a X 1 + b X 2 ] = a E [ X 1 ] + b E [ X 2 ] E[aX_1 + bX_2] = aE[X_1] + bE[X_2] E [ a X 1 + b X 2 ] = a E [ X 1 ] + b E [ X 2 ]
分散
確率変数X X X の 分散 V [ X ] V[X] V [ X ] を以下で定義します。
V [ X ] = E [ ( X − E [ X ] ) 2 ] V[X] = E[(X - E[X])^2] V [ X ] = E [ ( X − E [ X ] ) 2 ]
分散はX X X から出てくる値が平均周りでどれだけばらついているかを表している量です。分散が大きいことはばらつきが大きいことを示します。
分散も常に計算可能とは限らないことに注意してください。
分散は次のような性質を持ちます。
V [ X + Y ] = V [ X ] + V [ Y ] + 2 C o v [ X , Y ] V[X + Y] = V[X] + V[Y] + 2\mathrm{Cov}[X, Y] V [ X + Y ] = V [ X ] + V [ Y ] + 2 C o v [ X , Y ]
C o v [ X , Y ] \mathrm{Cov}[X, Y] C o v [ X , Y ] は共分散といい、
C o v [ X , Y ] = E [ ( X − E [ X ] ) ( Y − E [ Y ] ) ] \mathrm{Cov}[X, Y] = E[(X - E[X])(Y - E[Y])] C o v [ X , Y ] = E [ ( X − E [ X ] ) ( Y − E [ Y ] ) ]
で定義されます。
また、分散はスカラー倍に対しては次のような性質を持ちます。
V [ a X ] = a 2 V [ X ] V[aX] = a^2V[X] V [ a X ] = a 2 V [ X ]
標準偏差
分散の平方根をとったものを 標準偏差(Standard Deviation) といい、σ \sigma σ で表します。
σ ( X ) = V ( X ) \sigma(X) = \sqrt{V(X)} σ ( X ) = V ( X )
分散は元の量を二乗してしまった値のため、元の値の範囲でどれだけばらついているかが分かりにくいという問題点があります。標準偏差は元の値の範囲と一致するように分散を修正したものです。
確率変数変換
確率変数X X X によって誘導された確率空間を( R , B X , P X ) (\mathbb{R}, \mathcal{B}_X, P_X) ( R , B X , P X ) 、確率変数Y Y Y によって誘導された確率空間を( R , B Y , P Y ) (\mathbb{R}, \mathcal{B}_Y, P_Y) ( R , B Y , P Y ) とします。
確率変数X X X と確率変数Y Y Y の間に、関数h : R → R h : \mathbb{R} \rightarrow \mathbb{R} h : R → R による関係Y = h ( X ) Y = h(X) Y = h ( X ) があるとします。もしh h h が単調増加関数なら
F Y ( y ) = P Y ( Y ≤ y ) = P X ( X ≤ h − 1 ( y ) ) = F X ( h − 1 ( y ) ) F_Y(y) = P_Y(Y \le y) = P_X(X \le h^{-1}(y)) = F_X(h^{-1}(y)) F Y ( y ) = P Y ( Y ≤ y ) = P X ( X ≤ h − 1 ( y ) ) = F X ( h − 1 ( y ) )
という関係が成り立つため、確率密度関数の間には
p Y ( y ) = p X ( h − 1 ( y ) ) ∣ d h − 1 d y ( y ) ∣ p_Y(y) = p_X(h^{-1}(y))|\frac{dh^{-1}}{dy}(y)| p Y ( y ) = p X ( h − 1 ( y ) ) ∣ d y d h − 1 ( y ) ∣
という関係が成り立ちます。同様にh h h が単調減少関数の場合もこの式が成り立ちます。つまり、h h h が単調関数ならこのようにして、確率変数変換後の確率密度関数を求めることができます。
多次元確率変数
上では実数値確率変数X : Ω → R X: \Omega \rightarrow \mathbb{R} X : Ω → R を考えましたが、値域をR 2 \mathbb{R^2} R 2 にしたX : Ω → R 2 X : \Omega \rightarrow \mathbb{R}^2 X : Ω → R 2 を考えます。
このような確率変数に対しても確率密度関数が同様に定義されますが、名前が変わります。
結合確率密度関数
次のような条件を満たす関数p X , Y ( x , y ) p_{X, Y}(x, y) p X , Y ( x , y ) を確率変数X X X の 結合確率密度関数(Joint Probability Density Function) といいます。
∫ R 2 p X , Y ( x , y ) d x d y = 1 \int_{\mathbb{R}^2} p_{X, Y}(x, y)dxdy = 1 ∫ R 2 p X , Y ( x , y ) d x d y = 1
P X ( D ) = ∫ D p X , Y ( x , y ) d x d y P_X(D) = \int_D p_{X, Y}(x, y)dxdy P X ( D ) = ∫ D p X , Y ( x , y ) d x d y
周辺確率密度関数
結合確率密度関数p ( x , y ) p(x, y) p ( x , y ) から次のようにして求まる確率密度関数を 周辺確率密度関数(Marginal Probability Density Function) と呼びます。
p X ( x ) = ∫ − ∞ ∞ p X , Y ( x , y ) d y p_X(x) = \int_{-\infty}^{\infty} p_{X, Y}(x, y)dy p X ( x ) = ∫ − ∞ ∞ p X , Y ( x , y ) d y
p Y ( x ) = ∫ − ∞ ∞ p X , Y ( x , y ) d x p_Y(x) = \int_{-\infty}^{\infty} p_{X, Y}(x, y)dx p Y ( x ) = ∫ − ∞ ∞ p X , Y ( x , y ) d x
これらはそれぞれの次元の実数値確率変数X X X とY Y Y の確率密度関数になっています。
条件付き確率密度関数
Y Y Y の値y y y を観測した上でのX X X の確率密度関数p X ∣ Y ( x ) p_{X|Y}(x) p X ∣ Y ( x ) をX X X の 条件付き確率密度関数(Conditional Probability Density Function) といいます。定義は以下の通りです。
p X ∣ Y ( x ∣ y ) = p X , Y ( x , y ) p Y ( y ) ( p Y ( y ) ≠ 0 ) p_{X|Y}(x | y) = \frac{p_{X, Y}(x, y)}{p_Y(y)} ~~~ (p_Y(y) \neq 0) p X ∣ Y ( x ∣ y ) = p Y ( y ) p X , Y ( x , y ) ( p Y ( y ) = 0 )
確率変数の独立
確率変数X X X とY Y Y が 独立(Independent) であるとは
p X ∣ Y ( x ∣ y ) = p X ( x ) p_{X | Y}(x|y) = p_X(x) p X ∣ Y ( x ∣ y ) = p X ( x )
となるときをいいます。
このときX X X とY Y Y の結合確率密度関数は
p X , Y ( x , y ) = p X ( x ) p Y ( y ) p_{X, Y}(x, y) = p_X(x)p_Y(y) p X , Y ( x , y ) = p X ( x ) p Y ( y )
のように表わされます。
モンテカルロ積分
次のような一変数関数の積分を考えます。
I = ∫ a b f ( x ) d x I = \int_a^b f(x)dx I = ∫ a b f ( x ) d x
点x x x は確率密度関数p ( x ) p(x) p ( x ) が指定され、確率変数X X X になっているとします([ a , b ] [a, b] [ a , b ] に値をとるとする)。p ( x ) p(x) p ( x ) により点が( x 1 , x 2 , ⋯ , x N ) (x_1, x_2, \cdots, x_N) ( x 1 , x 2 , ⋯ , x N ) とN N N 個生成されたとします。このときI I I を以下のような計算で近似することができます。
I ^ = 1 N ∑ i = 1 N f ( x i ) p ( x i ) \hat{I} = \frac{1}{N}\sum_{i=1}^N \frac{f(x_i)}{p(x_i)} I ^ = N 1 i = 1 ∑ N p ( x i ) f ( x i )
これをI I I の モンテカルロ積分(Montecarlo Integration) といいます。
各項f ( X ) p ( X ) \frac{f(X)}{p(X)} p ( X ) f ( X ) の期待値を計算してみると
E [ f ( X ) p ( X ) ] = ∫ a b f ( x ) p ( x ) p ( x ) d x = ∫ a b f ( x ) d x = I \begin{aligned}
E[\frac{f(X)}{p(X)}] &= \int_a^b \frac{f(x)}{p(x)}p(x)dx \\
&= \int_a^b f(x)dx = I
\end{aligned} E [ p ( X ) f ( X ) ] = ∫ a b p ( x ) f ( x ) p ( x ) d x = ∫ a b f ( x ) d x = I
となり、各項の期待値はI I I に一致していることが分かります。したがってE [ I ˉ ] E[\bar{I}] E [ I ˉ ] もI I I に一致しているので、I ˉ \bar{I} I ˉ はI I I の 不偏推定量(Unbiased Estimator) になっています。
ここで 大数の法則(Law of large numbers) と呼ばれる次の定理を紹介します。
大数の法則
X 1 , X 2 , ⋯ , X N X_1, X_2, \cdots, X_N X 1 , X 2 , ⋯ , X N を平均μ \mu μ を持つn n n 個の確率変数とする。X n ˉ = 1 n ∑ i = 1 N X i \bar{X_n} = \frac{1}{n}\sum_{i=1}^N X_i X n ˉ = n 1 ∑ i = 1 N X i とすると、n → ∞ n \to \infty n → ∞ としたときにX ˉ \bar{X} X ˉ は確率1でμ \mu μ に収束する。
この定理より、モンテカルロ積分I ˉ \bar{I} I ˉ はNを無限大にすると確率1で求めたい積分I ˉ \bar{I} I ˉ に一致することが分かります。これがモンテカルロ積分でI I I が計算できる理由です。
モンテカルロ積分の誤差
一方でI ˉ \bar{I} I ˉ の分散を計算してみると
V [ I ^ ] = V [ 1 N ∑ i = 1 N f ( x i ) p ( x i ) ] = 1 N 2 V [ ∑ i = 1 N f ( x i ) p ( x i ) ] = 1 N V [ f ( X ) p ( X ) ] = 1 N ∫ a b ( f ( x ) p ( x ) − I ) 2 d x \begin{aligned}
V[\hat{I}] &= V[\frac{1}{N}\sum_{i=1}^N \frac{f(x_i)}{p(x_i)}] \\
&= \frac{1}{N^2}V[\sum_{i=1}^N\frac{f(x_i)}{p(x_i)}] \\
&= \frac{1}{N}V[\frac{f(X)}{p(X)}] \\
&= \frac{1}{N}\int_a^b (\frac{f(x)}{p(x)} - I)^2dx
\end{aligned} V [ I ^ ] = V [ N 1 i = 1 ∑ N p ( x i ) f ( x i ) ] = N 2 1 V [ i = 1 ∑ N p ( x i ) f ( x i ) ] = N 1 V [ p ( X ) f ( X ) ] = N 1 ∫ a b ( p ( x ) f ( x ) − I ) 2 d x
したがって分散はO ( N ) O(N) O ( N ) のオーダーで減少することが分かります。
標準偏差は推定誤差を表していますが、これはO ( N ) O(\sqrt{N}) O ( N ) のオーダーで減少します。これはアルゴリズム論的にはあまり良くない性質です。例えば誤差を1 100 \frac{1}{100} 1 0 0 1 にするためには、サンプル数を10000 10000 1 0 0 0 0 倍にしないといけないことを意味しています。
モンテカルロ積分の収束の遅さを改善するための手法として、重点的サンプリング(Importance Sampling) と呼ばれるものがあります。
高次元積分のモンテカルロ積分
モンテカルロ積分の利点は高次元積分を少ないサンプル数で計算が可能なことです。
以下のような高次元積分を考えます。
I = ∫ ⋯ ⏟ k ∫ D f ( x 1 , ⋯ , x k ) d μ ( x 1 ) ⋯ d μ ( x k ) I = \int \underbrace{\cdots}_k \int_D f(x_1, \cdots, x_k)d\mu(x_1)\cdots d\mu(x_k) I = ∫ k ⋯ ∫ D f ( x 1 , ⋯ , x k ) d μ ( x 1 ) ⋯ d μ ( x k )
それぞれの次元の点を確率変数X 1 , ⋯ , X k X_1, \cdots, X_k X 1 , ⋯ , X k で表します。それぞれの次元の確率変数を互いに独立になるように設定すれば、p X 1 , ⋯ , X k = p X 1 ⋯ p X k p_{X_1, \cdots, X_k} = p_{X_1} \cdots p_{X_k} p X 1 , ⋯ , X k = p X 1 ⋯ p X k となるため、以下のようにモンテカルロ積分でI I I を求めることができます。
I ˉ = 1 N ∑ i = 1 N f ( x 1 i , ⋯ , x k i ) p X 1 ( x 1 i ) p X 2 ( x 2 i ) ⋯ p X k ( x k i ) \bar{I} = \frac{1}{N}\sum_{i=1}^N \frac{f(x_1^i, \cdots, x_k^i)}{p_{X_1}(x_1^i)p_{X_2}(x_2^i)\cdots p_{X_k}(x_k^i)} I ˉ = N 1 i = 1 ∑ N p X 1 ( x 1 i ) p X 2 ( x 2 i ) ⋯ p X k ( x k i ) f ( x 1 i , ⋯ , x k i )
ここでx j i x_j^i x j i は次元j j j のi i i 番目のサンプルを表します。
確率密度関数から点をサンプリングする方法
モンテカルロ積分を行うためには指定した確率密度関数からサンプリング点を生成する必要があります。次のような方法が有名です。
逆関数法(Inverse Transform Sampling)
マルコフ連鎖モンテカルロ法(Markov Chain Monte Carlo - MCMC)
逆関数法
サンプリング点を生成したい確率変数をX X X (ここでは実数値確率変数とします)とし、その確率密度関数をp X ( x ) p_X(x) p X ( x ) とします。まずX X X の分布関数F X ( x ) F_X(x) F X ( x ) を求めます。
F X ( x ) = ∫ − ∞ x p X ( x ) d x F_X(x) = \int_{-\infty}^{x} p_X(x)dx F X ( x ) = ∫ − ∞ x p X ( x ) d x
F X ( x ) F_X(x) F X ( x ) が狭義単調増加関数と仮定します。すると逆関数F X − 1 ( y ) F_X^{-1}(y) F X − 1 ( y ) が存在します。
ここでU U U を一様分布U ( 0 , 1 ) U(0, 1) U ( 0 , 1 ) に従う確率変数とすると、F X − 1 ( U ) F_X^{-1}(U) F X − 1 ( U ) の分布関数は
P ( F X − 1 ( U ) ≤ x ) = P ( U ≤ F X ( x ) ) = F X ( x ) P(F_X^{-1}(U) \le x) = P(U \le F_X(x)) = F_X(x) P ( F X − 1 ( U ) ≤ x ) = P ( U ≤ F X ( x ) ) = F X ( x )
となり、X X X の分布関数F X ( x ) F_X(x) F X ( x ) に一致することが分かります。
したがって[ 0 , 1 ] [0, 1] [ 0 , 1 ] の一様乱数u u u を生成し、x = F X − 1 ( u ) x = F_X^{-1}(u) x = F X − 1 ( u ) とすることで確率変数X X X のサンプルx x x が得られます。
例1
以下のような積分をモンテカルロ積分で計算してみましょう。
∫ 0 π sin 2 x d x = π 2 \int_0^{\pi} \sin^2xdx = \frac{\pi}{2} ∫ 0 π sin 2 x d x = 2 π
[ 0 , π ] [0, \pi] [ 0 , π ] の一様分布を使ってサンプリング点X X X を生成することにします。X X X の確率密度関数はp X ( x ) = 1 π p_X(x) = \frac{1}{\pi} p X ( x ) = π 1 です。
逆関数法を使うと、[ 0 , 1 ] [0, 1] [ 0 , 1 ] の一様乱数u u u に対してx = π u x = \pi u x = π u とすればX X X のサンプルが生成できます。
以下はC++でこれを実装したコードです。
# include <iostream>
# include <cmath>
# include <random>
std:: random_device rnd_dev;
std:: mt19937 mt ( rnd_dev ( ) ) ;
std:: uniform_real_distribution< double > dist ( 0 , 1 ) ;
inline double rnd ( ) {
return dist ( mt) ;
}
inline double f ( double x) {
double v = std:: sin ( x) ;
return v* v;
}
int main ( ) {
const int N = 10000 ;
double sum = 0 ;
for ( int i = 0 ; i < N; i++ ) {
double x = M_PI * rnd ( ) ;
sum += M_PI* f ( x) ;
}
sum /= N;
std:: cout << sum << std:: endl;
return 0 ;
}
収束する様子は以下のようになります。
重点的サンプリング
p ( x ) p(x) p ( x ) を被積分関数f ( x ) f(x) f ( x ) に比例させるように取る方法です。
もし完全に比例させるように取ることができて、p ( x ) = k f ( x ) p(x) = kf(x) p ( x ) = k f ( x ) とできたとします。
このとき∫ a b p ( x ) d x = 1 \int_a^b p(x)dx = 1 ∫ a b p ( x ) d x = 1 という条件があるのでk = 1 I k = \frac{1}{I} k = I 1 です。
この状況でモンテカルロ積分の分散を求めると
V [ I ˉ ] = 1 N ∫ a b ( f ( x ) p ( x ) − I ) 2 = 1 N ∫ a b 0 d x = 0 \begin{aligned}
V[\bar{I}] &= \frac{1}{N}\int_a^b (\frac{f(x)}{p(x)} - I)^2 \\
&= \frac{1}{N}\int_a^b 0 dx = 0
\end{aligned} V [ I ˉ ] = N 1 ∫ a b ( p ( x ) f ( x ) − I ) 2 = N 1 ∫ a b 0 d x = 0
となり、分散が0なので確率1でI ˉ \bar{I} I ˉ はI I I に一致することが分かります。
実際にはp ( x ) p(x) p ( x ) をf ( x ) f(x) f ( x ) に完全に比例するように取ることはできないですが、ある程度似るように取ることができれば収束が早くなることが期待できます。
例2
例1のモンテカルロ積分に重点的サンプリングを適用してみましょう。
被積分関数はsin 2 ( x ) \sin^2(x) sin 2 ( x ) なので、比例定数k k k を用いてp X ( x ) = k sin x p_X(x) = k\sin x p X ( x ) = k sin x と置きます。
確率密度関数は∫ 0 π p X ( x ) d x = 1 \int_0^{\pi} p_X(x)dx = 1 ∫ 0 π p X ( x ) d x = 1 を満たさないといけないので、これよりk = 1 2 k = \frac{1}{2} k = 2 1 と求まります。したがってp X ( x ) = 1 2 sin x p_X(x) = \frac{1}{2}\sin x p X ( x ) = 2 1 sin x です。
X X X のサンプルを生成するために逆関数法を使用します。X X X の分布関数F X ( x ) F_X(x) F X ( x ) を求めると
F X ( x ) = ∫ 0 x 1 2 sin t d t = 1 2 ( 1 − cos x ) F_X(x) = \int_0^x \frac{1}{2}\sin tdt = \frac{1}{2}(1 - \cos x) F X ( x ) = ∫ 0 x 2 1 sin t d t = 2 1 ( 1 − cos x )
となります。したがってF X − 1 ( y ) F_X^{-1}(y) F X − 1 ( y ) は
F X − 1 ( y ) = cos − 1 ( 1 − 2 y ) F_X^{-1}(y) = \cos^{-1}(1 - 2y) F X − 1 ( y ) = cos − 1 ( 1 − 2 y )
と求まります。[ 0 , 1 ] [0, 1] [ 0 , 1 ] の一様乱数u u u を用いてx = F X − 1 ( u ) x = F_X^{-1}(u) x = F X − 1 ( u ) としてX X X のサンプルが生成できます。
以下はこれを実装したC++のコードです。
# include <iostream>
# include <cmath>
# include <random>
std:: random_device rnd_dev;
std:: mt19937 mt ( rnd_dev ( ) ) ;
std:: uniform_real_distribution< double > dist ( 0 , 1 ) ;
inline double rnd ( ) {
return dist ( mt) ;
}
inline double f ( double x) {
double v = std:: sin ( x) ;
return v* v;
}
inline double p ( double x) {
return 0.5 * std:: sin ( x) ;
}
int main ( ) {
const int N = 10000 ;
double sum = 0 ;
for ( int i = 0 ; i < N; i++ ) {
double u = rnd ( ) ;
double x = std:: acos ( 1 - 2 * u) ;
sum += f ( x) / p ( x) ;
}
sum /= N;
std:: cout << sum << std:: endl;
return 0 ;
}
以下は収束の様子を重点的サンプリングを行わない場合を比較したものです。
重点的サンプリングを行ったほうが早く理論値の周辺に収束していることが分かります。
レイトレでのモンテカルロ積分
モンテカルロ積分をレンダリング方程式に適用しようとする場合、確率変数になるのは点の位置x ∈ M x \in \mathcal{M} x ∈ M や、方向ベクトルω ⃗ ∈ S 2 \vec{\omega} \in \mathcal{S^2} ω ∈ S 2 になります。つまり確率変数は実数値確率変数ではなく、M \mathcal{M} M -確率変数やS 2 \mathcal{S^2} S 2 -確率変数となっています。
確率空間の設定
確率空間は明示的には与えず、抽象的に( Ω , F , P ) (\Omega, \mathcal{F}, P) ( Ω , F , P ) と置くことにします。
S 2 \mathcal{S^2} S 2 -確率変数
S 2 \mathcal{S}^2 S 2 -確率変数X S 2 : Ω → S 2 X_{\mathcal{S^2}} : \Omega \rightarrow \mathcal{S^2} X S 2 : Ω → S 2 は方向ベクトルを生成する確率変数です。この確率変数から新たに確率空間( S 2 , F S 2 , P S 2 ) (\mathcal{S^2}, \mathcal{F}_{\mathcal{S^2}}, P_{\mathcal{S^2}}) ( S 2 , F S 2 , P S 2 ) が誘導されます。
X S 2 X_{\mathcal{S^2}} X S 2 の確率密度関数をp S 2 ( ω ⃗ ) = d P S 2 d σ p_{\mathcal{S^2}}(\vec{\omega}) = \frac{dP_{\mathcal{S^2}}}{d\sigma} p S 2 ( ω ) = d σ d P S 2 と表すことにします。方向ベクトルの集合D ∈ S 2 D \in \mathcal{S^2} D ∈ S 2 が与えられたとき、この集合(事象)に対する確率P S 2 P_{\mathcal{S^2}} P S 2 は
P S 2 ( D ) = ∫ D p S 2 ( ω ⃗ ) d σ ( ω ⃗ ) P_{\mathcal{S}^2}(D) = \int_{D} p_{\mathcal{S^2}}(\vec{\omega})d\sigma(\vec{\omega}) P S 2 ( D ) = ∫ D p S 2 ( ω ) d σ ( ω )
と計算できます。
M \mathcal{M} M -確率変数
M \mathcal{M} M -確率変数X M : Ω → M X_{\mathcal{M}} : \Omega \rightarrow \mathcal{M} X M : Ω → M は物体表面上の点を生成する確率変数です。この確率変数から新たに確率空間( M , F M , P M ) (\mathcal{M}, \mathcal{F}_{\mathcal{M}}, P_{\mathcal{M}}) ( M , F M , P M ) が誘導されます。
X M X_{\mathcal{M}} X M の確率密度関数をp M ( x ) = d P M d A p_{\mathcal{M}}(x) = \frac{dP_{\mathcal{M}}}{dA} p M ( x ) = d A d P M と表すことにします。物体表面上の点集合D ∈ M D \in \mathcal{M} D ∈ M が与えられたとき、この集合(事象)に対する確率P M P_{\mathcal{M}} P M は
P M ( D ) = ∫ D p M ( x ) d A ( x ) P_{\mathcal{M}}(D) = \int_D p_{\mathcal{M}}(x)dA(x) P M ( D ) = ∫ D p M ( x ) d A ( x )
と計算できます。
S 2 \mathcal{S^2} S 2 -確率変数とM \mathcal{M} M -確率変数の変換
立体角測度と面積測度の間には次のような関係がありました。
d σ ( ω ⃗ ) = V ( x , x ′ ) G ( x , x ′ ) ∣ cos θ ∣ d A d\sigma(\vec{\omega}) = V(x, x')\frac{G(x, x')}{|\cos{\theta}|}dA d σ ( ω ) = V ( x , x ′ ) ∣ cos θ ∣ G ( x , x ′ ) d A
確率変数変換の式から、p S 2 p_\mathcal{S^2} p S 2 とp M p_\mathcal{M} p M の間には次のような関係が成り立ちます。
p S 2 ( ω ⃗ ) = ∣ cos θ ∣ V ( x , x ′ ) G ( x , x ′ ) p M ( x ′ ) p_\mathcal{S^2}(\vec{\omega}) = \frac{|\cos{\theta}|}{V(x, x')G(x, x')}p_\mathcal{M}(x') p S 2 ( ω ) = V ( x , x ′ ) G ( x , x ′ ) ∣ cos θ ∣ p M ( x ′ )
この式を使うと、経路積分形式で表されたレンダリングの方程式において、方向のサンプリングと物体表面上の点のサンプリングを組み合わせて使うことができるようになります。
レンダリング方程式のモンテカルロ積分
経路積分形式のレンダリング方程式は以下のように表されていました。
I j = ∑ k = 1 ∞ ∫ M ⋯ ∫ M ⏟ k + 1 W e ( x 0 → x 1 ) ∏ i = 1 k { f ( x i − 2 → x i − 1 → x i ) V ( x i − 1 , x i ) G ( x i − 1 , x i ) } L e ( x k → x k − 1 ) d A ( x 0 ) d A ( x 1 ) ⋯ d A ( x k ) I_j = \sum_{k=1}^{\infty}\underbrace{\int_{\mathcal{M}} \cdots \int_{\mathcal{M}}}_{k+1} W_e(x_0 \rightarrow x_1)\prod_{i=1}^{k}\{ f(x_{i-2} \rightarrow x_{i-1} \rightarrow x_i)V(x_{i-1}, x_i)G(x_{i-1}, x_i) \}L_e(x_k \rightarrow x_{k-1})dA(x_0)dA(x_1)\cdots dA(x_k) I j = k = 1 ∑ ∞ k + 1 ∫ M ⋯ ∫ M W e ( x 0 → x 1 ) i = 1 ∏ k { f ( x i − 2 → x i − 1 → x i ) V ( x i − 1 , x i ) G ( x i − 1 , x i ) } L e ( x k → x k − 1 ) d A ( x 0 ) d A ( x 1 ) ⋯ d A ( x k )
これにモンテカルロ積分を適用することを考えます。経路点x 0 , ⋯ , x k x_0, \cdots, x_k x 0 , ⋯ , x k に対応する確率変数をX 0 , ⋯ , X k X_0, \cdots, X_k X 0 , ⋯ , X k とし、それぞれの確率変数は互いに独立であると仮定します。i i i 番目のサンプルを( x 0 i , ⋯ , x k i ) (x_0^i, \cdots, x_k^i) ( x 0 i , ⋯ , x k i ) と表し、それぞれの確率変数の確率密度関数をp X 0 ( x 0 ) , ⋯ , p X k ( x k ) p_{X_0}(x_0), \cdots, p_{X_k}(x_k) p X 0 ( x 0 ) , ⋯ , p X k ( x k ) とすると
I j ˉ = 1 N 1 ∑ i = 1 N 1 W e ( x 0 i → x 1 i ) f ( x − 1 i → x 0 i → x 1 i ) V ( x 0 i , x 1 i ) G ( x 0 i , x 1 i ) L e ( x 1 i → x 0 i ) p X 0 ( x 0 i ) p X 1 ( x 1 i ) + 1 N 2 ∑ i = 1 N 2 W e ( x 0 → x 1 ) f ( x − 1 i → x 0 i → x 1 i ) f ( x 0 i → x 1 i → x 2 i ) V ( x 0 i , x 1 i ) V ( x 1 i , x 2 i ) G ( x 0 i , x 1 i ) G ( x 1 i , x 2 i ) L e ( x 2 i → x 1 i ) p X 0 ( x 0 i ) p X 1 ( x 1 i ) p X 2 ( x 2 i ) + ⋯ \begin{aligned}
\bar{I_j} &= \frac{1}{N_1}\sum_{i=1}^{N_1}\frac{W_e(x_0^i \rightarrow x_1^i)f(x_{-1}^i\rightarrow x_0^i \rightarrow x_1^i)V(x_0^i, x_1^i)G(x_0^i, x_1^i)L_e(x_1^i\rightarrow x_0^i)}{p_{X_0}(x_0^i)p_{X_1}(x_1^i)} \\
&+ \frac{1}{N_2}\sum_{i=1}^{N_2}\frac{W_e(x_0 \rightarrow x_1)f(x_{-1}^i\rightarrow x_0^i \rightarrow x_1^i)f(x_0^i \rightarrow x_1^i \rightarrow x_2^i)V(x_0^i, x_1^i)V(x_1^i, x_2^i)G(x_0^i, x_1^i)G(x_1^i, x_2^i)L_e(x_2^i\rightarrow x_1^i)}{p_{X_0}(x_0^i)p_{X_1}(x_1^i)p_{X_2}(x_2^i)} \\
&+ \cdots
\end{aligned} I j ˉ = N 1 1 i = 1 ∑ N 1 p X 0 ( x 0 i ) p X 1 ( x 1 i ) W e ( x 0 i → x 1 i ) f ( x − 1 i → x 0 i → x 1 i ) V ( x 0 i , x 1 i ) G ( x 0 i , x 1 i ) L e ( x 1 i → x 0 i ) + N 2 1 i = 1 ∑ N 2 p X 0 ( x 0 i ) p X 1 ( x 1 i ) p X 2 ( x 2 i ) W e ( x 0 → x 1 ) f ( x − 1 i → x 0 i → x 1 i ) f ( x 0 i → x 1 i → x 2 i ) V ( x 0 i , x 1 i ) V ( x 1 i , x 2 i ) G ( x 0 i , x 1 i ) G ( x 1 i , x 2 i ) L e ( x 2 i → x 1 i ) + ⋯
のようにしてモンテカルロ積分することができます。無限級数の各項が積分になっているので、項ごとにモンテカルロ積分を適用することでこの形を得ます。
この形では各項の評価に毎回違うサンプルを使っていますが、これは計算コストが高くなるためにあまり良い方法ではありません。後で見るようにPath Tracingではx 0 , x 1 , ⋯ x_0, x_1, \cdots x 0 , x 1 , ⋯ を逐次的に生成し、各項でサンプルの使い回しを行うことで計算コストを抑えています。
無限級数の評価
レンダリング方程式を数値計算するためには、上記の式のように無限級数を評価する必要があります。
次のような無限級数を考えます。
S = S 1 + S 2 + ⋯ = ∑ i = 1 ∞ S i S = S_1 + S_2 + \cdots = \sum_{i=1}^{\infty} S_i S = S 1 + S 2 + ⋯ = i = 1 ∑ ∞ S i
コンピューターで無限個の項を足し合わせることはできないので、有限個の項の総和で無限級数を近似する必要があります。
単純に足し合わせる最大の項数を設定して近似を行っても良いのですが、この場合それより後ろにある項が評価されないために、わずかですがバイアスが残ってしまいます。また、どこまで足し合わせれば良いかは必ずしも明確ではないです。
そこで使用されるのが ロシアンルーレット(Russian Roulette) と呼ばれる確率論的な評価方法です。
ロシアンルーレットによる無限級数の評価
ロシアンルーレットでは次のような手順で無限級数の評価を行います。
次の項を足す確率p ∈ [ 0 , 1 ] p \in [0, 1] p ∈ [ 0 , 1 ] を設定します。
i i i 回目の項を足すかどうか決めているとします。[ 0 , 1 ] [0, 1] [ 0 , 1 ] の一様分布に従う乱数u u u を生成します。
u < p u < p u < p ならS i p i \frac{S_i}{p^i} p i S i を足し合わせます。そうでないなら級数の評価を打ち切ります。
S i S_i S i ではなくてS i p i \frac{S_i}{p^i} p i S i を足していることがポイントです。i i i 番目の項が足される確率はp i p^i p i なので、S i p i \frac{S_i}{p^i} p i S i で足せば期待値が元の無限級数と一致することになります。
次の項を足す確率p p p の設定
p p p を小さな値に設定してしまうと分散が大きくなってしまうので、最初は確率を1にし、徐々に確率を下げていく方法がよく取られます。
レンダリング方程式の数値計算
ここではレンダリング方程式のモンテカルロ積分を利用して、レンダリング方程式の数値解を計算するためのアルゴリズムについて考えます。
レンダリング方程式を数値計算するためのアルゴリズムとしては以下のようなものがあります。
Path Tracing(PT)
Bidirectional Path Tracing(BDPT)
Metropolis Light Transport(MLT)
Stochastic Progressive Photon Mapping(SPPM)
これらのアルゴリズムのどこに相違点があるかと言うと、大まかに言えばサンプルの生成方法に違いがあると言えます。例えば次に見るようにPath Tracingでは視点から逐次的に経路点のサンプルを生成していきますが、BDPTでは視点と光源の両方向から経路点のサンプルを生成していきます。
Path Tracing
パストレーシング(Path Tracing - 経路追跡法) は視点から経路点の生成を行っていく方法です。
ここでレンダリング方程式のモンテカルロ積分の式を再掲します。
I j ˉ = 1 N 1 ∑ i = 1 N 1 W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) V ( x 0 , x 1 ) G ( x 0 , x 1 ) L e ( x 1 → x 0 ) p X 0 ( x 0 ) p X 1 ( x 1 ) + 1 N 2 ∑ i = 1 N 2 W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) f ( x 0 → x 1 → x 2 ) V ( x 0 , x 1 ) V ( x 1 , x 2 ) G ( x 0 , x 1 ) G ( x 1 , x 2 ) L e ( x 2 → x 1 ) p X 0 ( x 0 ) p X 1 ( x 1 ) p X 2 ( x 2 ) + ⋯ \begin{aligned}
\bar{I_j} &= \frac{1}{N_1}\sum_{i=1}^{N_1}\frac{W_e(x_0 \rightarrow x_1)f(x_{-1}\rightarrow x_0 \rightarrow x_1)V(x_0, x_1)G(x_0, x_1)L_e(x_1\rightarrow x_0)}{p_{X_0}(x_0)p_{X_1}(x_1)} \\
&+ \frac{1}{N_2}\sum_{i=1}^{N_2}\frac{W_e(x_0 \rightarrow x_1)f(x_{-1}\rightarrow x_0 \rightarrow x_1)f(x_0 \rightarrow x_1 \rightarrow x_2)V(x_0, x_1)V(x_1, x_2)G(x_0, x_1)G(x_1, x_2)L_e(x_2\rightarrow x_1)}{p_{X_0}(x_0)p_{X_1}(x_1)p_{X_2}(x_2)} \\
&+ \cdots
\end{aligned} I j ˉ = N 1 1 i = 1 ∑ N 1 p X 0 ( x 0 ) p X 1 ( x 1 ) W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) V ( x 0 , x 1 ) G ( x 0 , x 1 ) L e ( x 1 → x 0 ) + N 2 1 i = 1 ∑ N 2 p X 0 ( x 0 ) p X 1 ( x 1 ) p X 2 ( x 2 ) W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) f ( x 0 → x 1 → x 2 ) V ( x 0 , x 1 ) V ( x 1 , x 2 ) G ( x 0 , x 1 ) G ( x 1 , x 2 ) L e ( x 2 → x 1 ) + ⋯
この形では( x 0 , x 1 , ⋯ , x k ) (x_0, x_1, \cdots, x_k) ( x 0 , x 1 , ⋯ , x k ) の各経路点を自由に生成することができます。しかし、もし本当に経路点を自由に生成したとすると、サンプリングされる経路の大半は可視関数V ( x 0 , x 1 ) ⋯ V(x_0, x_1)\cdots V ( x 0 , x 1 ) ⋯ のせいで0に評価されてしまうでしょう。これは明らかに無駄な計算を行っています。
Path Tracingでは経路点を直接サンプリングするのではなく、方向ベクトルをサンプリングすることで間接的に経路点をサンプリングします 。
経路の始点x 0 x_0 x 0 をサンプリングし、そこから先は方向ベクトルω 0 ⃗ , ⋯ \vec{\omega_0}, \cdots ω 0 , ⋯ をサンプリングすることで経路を以下のように生成することができます。
x 1 = r ( x 0 , ω 0 ⃗ ) x 2 = r ( x 1 , ω 1 ⃗ ) ⋮ \begin{aligned}
x_1 &= r(x_0, \vec{\omega_0}) \\
x_2 &= r(x_1, \vec{\omega_1}) \\
&\vdots
\end{aligned} x 1 x 2 = r ( x 0 , ω 0 ) = r ( x 1 , ω 1 ) ⋮
上のモンテカルロ積分を確率密度関数の変換公式を用いると
I j ˉ = 1 N 1 ∑ i = 1 N 1 W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) ∣ cos θ 0 ∣ L e ( x 1 → x 0 ) p ω 0 ( ω 0 ⃗ ) + 1 N 2 ∑ i = 1 N 2 W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) f ( x 0 → x 1 → x 2 ) ∣ cos θ 0 ∣ ∣ cos θ 1 ∣ L e ( x 2 → x 1 ) p ω 0 ( ω 0 ⃗ ) p ω 1 ( ω 1 ⃗ ) + ⋯ \begin{aligned}
\bar{I_j} &= \frac{1}{N_1}\sum_{i=1}^{N_1}\frac{W_e(x_0 \rightarrow x_1)f(x_{-1}\rightarrow x_0 \rightarrow x_1)|\cos{\theta_0}|L_e(x_1\rightarrow x_0)}{p_{\omega_0}(\vec{\omega_0})} \\
&+ \frac{1}{N_2}\sum_{i=1}^{N_2}\frac{W_e(x_0 \rightarrow x_1)f(x_{-1}\rightarrow x_0 \rightarrow x_1)f(x_0 \rightarrow x_1 \rightarrow x_2)|\cos{\theta_0}||\cos{\theta_1}|L_e(x_2\rightarrow x_1)}{p_{\omega_0}(\vec{\omega_0})p_{\omega_1}(\vec{\omega_1})} \\
&+ \cdots
\end{aligned} I j ˉ = N 1 1 i = 1 ∑ N 1 p ω 0 ( ω 0 ) W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) ∣ cos θ 0 ∣ L e ( x 1 → x 0 ) + N 2 1 i = 1 ∑ N 2 p ω 0 ( ω 0 ) p ω 1 ( ω 1 ) W e ( x 0 → x 1 ) f ( x − 1 → x 0 → x 1 ) f ( x 0 → x 1 → x 2 ) ∣ cos θ 0 ∣ ∣ cos θ 1 ∣ L e ( x 2 → x 1 ) + ⋯
となり、V V V とG G G が消えてBRDFとコサイン項のみが残ることが分かります。(p X 0 ( x 0 ) p_{X_0}(x_0) p X 0 ( x 0 ) が消えていることに注意。一般的なカメラの場合、x 0 x_0 x 0 を定めるとω 0 ⃗ \vec{\omega_0} ω 0 が定まるため、逆にω 0 ⃗ \vec{\omega_0} ω 0 を定めるとx 0 x_0 x 0 が定まってしまう。このときX 0 X_0 X 0 の確率密度関数にデルタ関数が含まれるので、1とみなしてよい)
ここでさらに、方向ベクトルの確率密度関数をBRDFとコサイン項に比例するように取って重点的サンプリングを行えば、分散を大幅に減少させることができます。このようなサンプリング方法をBRDF Sampling と呼びます。
さらにPath Tracingでは経路の生成を逐次的に行うことで、計算コストを抑えて効率よくモンテカルロ積分を行います 。どういうことかというと、N 1 = N 2 = ⋯ = N N_1 = N_2 = \cdots = N N 1 = N 2 = ⋯ = N として、総和の順番を入れ替えることで(厳密には無限級数が絶対収束することを示さないといけない)、I j ˉ \bar{I_j} I j ˉ の計算が
I j ˉ = 1 N ∑ i = 1 N ∑ k = 1 ∞ W e ( x 0 i → x 1 i ) { ∏ j = 1 k f ( x j − 2 i → x j − 1 i → x j i ) ∣ cos θ j ∣ } L e ( x k → x k − 1 ) p ω 0 ( ω 0 ⃗ i ) ⋯ p ω k ( ω k ⃗ i ) \bar{I_j} = \frac{1}{N}\sum_{i=1}^{N}\sum_{k=1}^{\infty}\frac{W_e(x_0^i \rightarrow x_1^i)\{\prod_{j=1}^{k}f(x_{j-2}^i\rightarrow x_{j-1}^i \rightarrow x_j^i)|\cos{\theta_j}|\}L_e(x_k \rightarrow x_{k-1})}{p_{\omega_0}(\vec{\omega_0}^i)\cdots p_{\omega_k}(\vec{\omega_k}^i)} I j ˉ = N 1 i = 1 ∑ N k = 1 ∑ ∞ p ω 0 ( ω 0 i ) ⋯ p ω k ( ω k i ) W e ( x 0 i → x 1 i ) { ∏ j = 1 k f ( x j − 2 i → x j − 1 i → x j i ) ∣ cos θ j ∣ } L e ( x k → x k − 1 )
のように置き換えられます。この形では長さk = 1 k = 1 k = 1 でω 0 ⃗ i \vec{\omega_0}^i ω 0 i をサンプリングすると、それが長さk ≥ 2 k \ge 2 k ≥ 2 の経路の評価においても使われるようになっています。つまり、方向ベクトルのサンプリングを繰り返すことで、経路を1つずつ長くしていくということです。
具体的にはi i i 番目のサンプル( ω 0 ⃗ i , ω 1 ⃗ i , ⋯ ) (\vec{\omega_0}^i, \vec{\omega_1}^i, \cdots) ( ω 0 i , ω 1 i , ⋯ ) の評価において
k = 1 k = 1 k = 1 では
W e ( x 0 i → x 1 i ) f ( x − 1 → x 0 → x 1 ) ∣ cos θ 0 ∣ L e ( x 1 → x 0 ) p ω 0 ( ω 0 ⃗ i ) \frac{W_e(x_0^i \rightarrow x_1^i)f(x_{-1} \rightarrow x_0 \rightarrow x_1)|\cos{\theta_0}|L_e(x_1 \rightarrow x_0)}{p_{\omega_0}(\vec{\omega_0}^i)} p ω 0 ( ω 0 i ) W e ( x 0 i → x 1 i ) f ( x − 1 → x 0 → x 1 ) ∣ cos θ 0 ∣ L e ( x 1 → x 0 )
を評価して加算し、k = 2 k = 2 k = 2 では
W e ( x 0 i → x 1 i ) f ( x − 1 → x 0 → x 1 ) f ( x 0 → x 1 → x 2 ) ∣ cos θ 0 ∣ ∣ cos θ 1 ∣ L e ( x 2 → x 1 ) p ω 0 ( ω 0 ⃗ i ) p ω 1 ( ω 1 ⃗ i ) \frac{W_e(x_0^i \rightarrow x_1^i)f(x_{-1} \rightarrow x_0 \rightarrow x_1)f(x_0 \rightarrow x_1 \rightarrow x_2)|\cos{\theta_0}||\cos{\theta_1}|L_e(x_2 \rightarrow x_1)}{p_{\omega_0}(\vec{\omega_0}^i)p_{\omega_1}(\vec{\omega_1}^i)} p ω 0 ( ω 0 i ) p ω 1 ( ω 1 i ) W e ( x 0 i → x 1 i ) f ( x − 1 → x 0 → x 1 ) f ( x 0 → x 1 → x 2 ) ∣ cos θ 0 ∣ ∣ cos θ 1 ∣ L e ( x 2 → x 1 )
を評価して加算していきます。k = 3 k = 3 k = 3 以降も同様です。
どこで経路を打ち切るかが問題になりますが、ここでロシアンルーレットを使用します。ロシアンルーレットの確率p p p を設定し、各k k k で項を評価する前に確率1 − p 1 - p 1 − p で項を評価を取りやめます。もし項を評価する場合は評価した値をp k p^k p k で割る必要があることに注意が必要です。
Path Tracingのアルゴリズム
まとめると、Path Tracingは以下のようなアルゴリズムです。
レンズ上の点をサンプリングし、始点x 0 x_0 x 0 を決める。このときω 0 ⃗ \vec{\omega_0} ω 0 も定まる。
ロシアンルーレットを行う。打ち切りなら終了。
x 0 x_0 x 0 からω 0 ⃗ \vec{\omega_0} ω 0 にレイを飛ばし、衝突点や法線を求める。
長さk k k の項の評価を行う
BRDFを用いてω 1 ⃗ \vec{\omega_1} ω 1 の重点的サンプリングを行う。
2に戻り、同様の手順を繰り返す。