複合BSDFについて
2022/12/24
#3dcg #raytracing
複合BSDFの評価, サンプリングについて

この記事はレイトレアドベントカレンダー 2022 24日目の記事です. この記事では様々なマテリアルを表現する際に使われる複合BSDFの評価とサンプリングの方法について解説しています.

複合BSDFとは

物理ベースレンダリングにおいては、物体の質感はBRDF, またはBTDFと呼ばれる以下のような関数ffで表現されます.

f(x,ωi,ωo)f(x, \vec{\omega_i}, \vec{\omega_o})
  • xx: 位置
  • ωi\vec{\omega_i}: 光の入射方向
  • ωo\vec{\omega_o}: 光の出射方向

ffが反射を表現する場合はBRDF, 透過, 屈折を表現する場合はBTDFと呼ばれます.

複合BSDF とは複数のBRDF, BTDFの集まりで構成される以下のような関数ffのことを言います.

f(x,ωi,ωo)=k=1Nakfk(x,ωi,ωo)(1)f(x, \vec{\omega_i}, \vec{\omega_o}) = \sum_{k=1}^N a_k f_k(x, \vec{\omega_i}, \vec{\omega_o}) \tag{1}
  • aka_k: kk番目のBRDF, BTDFの係数
  • fkf_k: kk番目のBRDF, BTDF

物理ベースレンダリングにおいては, 様々な見た目のマテリアルを1つのBSDFで表現するために, このような複合BSDFが使われます. 例えば有名なマテリアルモデルであるDisney BRDFは以下のように5つのBRDFからなる複合BSDFになっています.

f=adiffusefdiffuse+asubsurfacefsubsurface+asheenfsheen+aspecularfspecular+aclearcoatfclearcoatf = a_{diffuse} f_{diffuse} + a_{subsurface} f_{subsurface} + a_{sheen} f_{sheen} + a_{specular} f_{specular} + a_{clearcoat} f_{clearcoat}

(各項の詳細についてはmemoRANDOM - Disney Principled BRDFを参照してください)

それぞれのBRDFの係数やパラメーターを変化させることで, 1つのBSDFで様々な見た目のマテリアルを再現することが出来ます. 以下はDisney BRDFで表現することの出来るマテリアルの例です.

Disney BRDF
Disney BRDF

現在はDisney BRDFをベースにUE4 BRDF, Disney BSDF, Arnold Standard Surfaceなど様々なマテリアルモデルがありますが, いずれも複合BSDFの形になっています.

レイトレーシングで複合BSDFを扱う場合, 複合BSDFの評価と方向ベクトルのサンプリングが必要です. 以下では複合BSDFの評価とサンプリングの方法について見ていきます.

複合BSDFの評価

位置xx, 出射方向ωo\vec{\omega_o}, 入射方向ωi\vec{\omega_i}が与えられた時の評価は単純に式(1)に従い, 各BRDF, BTDFの評価結果に係数をかけて足し合わせるだけです.

f(x,ωi,ωo)=k=1Nakfk(x,ωi,ωo)f(x, \vec{\omega_i}, \vec{\omega_o}) = \sum_{k=1}^N a_k f_k(x, \vec{\omega_i}, \vec{\omega_o})

複合BSDFからの方向ベクトルのサンプリング

複合BSDFから方向ベクトルをサンプリングする場合, 式(1)のNN個のBRDF, BTDF(以降まとめてBxDFと呼びます)の中から1つのBxDFを選び, 選んだBxDFから方向ベクトルをサンプリングするという流れを踏みます. ここでは1つのBxDFを選ぶという過程をBxDFサンプリングと呼ぶことにします.

BxDFサンプリング

最も簡単なのはランダムに1つのBxDFを選ぶことですが, これは選んだBxDFの係数aka_k00である場合に非効率です. そこで, ランダムではなく, 係数aka_kの大きさに比例するようにBxDFをサンプリングすることを考えます.

何番目のBxDFが選択されたかを表す確率変数をIIとすると, IIの確率質量関数を次のように設定すれば, 係数aka_kの大きさに比例するようにBxDFがサンプリングされます.

pI(i)=aik=1Nakp_I(i) = \frac{a_i}{\sum_{k=1}^N a_k}

ここでは係数aka_kは全て正の実数であると仮定します. 実際にはDisney BRDFなどでは係数aka_kがRGBになったりします. この場合はRGBをLuminanceに変換するなどして, 正の実数に変換しておきます.

IIからは次のようにしてBxDFのインデックスをサンプリング出来ます.

// BxDFのインデックスをサンプリングして返す
// p: 確率質量関数
// N: BxDFの数
uint32_t sample_bxdf(const float* p, uint32_t N)
{
    const float xi = random(); // [0, 1]の乱数を生成

    float cdf = 0.0f;
    for(uint32_t i = 0; i < N; ++i)
    {
        cdf += p[i];
        if(xi < u) return i;
    }

    return N - 1;
}

これでBxDFのサンプリングが出来るようになりました. 今ii番目のBxDFがサンプリングされたとすると, 方向ベクトルはBxDF fif_iの重点的サンプリングで生成すれば良いです. 例えばfif_iがLambert BRDF, Oren-Nayar BRDFならCosine weighted hemisphere sampling, Microfacet BxDFならVNDF samplingをすれば良いです.

方向ベクトルの確率密度の評価

複合BSDFからサンプリングされた入射方向ベクトルωi\vec{\omega_i}を使い, レンダリング方程式をモンテカルロ積分で評価することを考えます.

Ωf(x,ωo,ωi)Li(ωi)cosθidσ(ωi)1Nk=1Nf(x,ωo,ωik)Li(ωik)cosθikp(ωik)\int_{\Omega} f(x, \vec{\omega_o}, \vec{\omega_i})L_i(\vec{\omega_i})\cos{\theta_i}d\sigma(\vec{\omega_i}) \approx \frac{1}{N}\sum_{k=1}^N \frac{f(x, \vec{\omega_o}, \vec{\omega_i}^k)L_i(\vec{\omega_i}^k)\cos{\theta_i^k}}{p(\vec{\omega_i^k})}

この式を評価するためには方向ベクトルの確率密度関数p(ωi)p(\vec{\omega_i})の値が必要です. 今のサンプリング方法の場合, これは以下のような式で計算出来ます.

p(ωi)=k=1Nakpk(ωi)k=1Nak\begin{aligned} p(\vec{\omega_i}) &= \frac{\sum_{k=1}^N a_k p_k(\vec{\omega_i})}{\sum_{k=1}^N a_k} \\ \end{aligned}
  • pk(ωi)p_k(\vec{\omega_i}): kk番目のBxDFから方向ベクトルをサンプリングする時の確率密度関数

つまり, p(ωi)p(\vec{\omega_i})は各BxDFの方向ベクトルサンプリングの確率密度関数をaka_kで重みづけた平均になっています. この式はMulti importance samplingの1サンプルモデルと対応しています. 方向ベクトルのサンプリング戦略はBxDFの個数分だけあるので, そこにMulti importance samplingを適用すると, この形の式が得られます.

References