物理ベースレンダリングについてメモ

はじめに

この記事はシリーズ記事です。目次はこちら。

この記事では物理ベースレンダリングについてメモ書きをして、参考になる記事をメモします。

素人が調べたことまとめているだけなので誤りが含まれているかもしれません。 誤りを見つけた方は連絡をくれると嬉しいです……。 そして、参考資料に挙げている記事のほうがこの記事よりよっぽどわかりやすいので、この記事のことは忘れて参考資料を見たほうが幸せになれるかもしれません……。

物理ベースレンダリングとは

3Dのシェーディングのモデルには感覚的なモデルと物理ベースのモデルというものがあります。

Phongシェーディングによる鏡面反射モデルは、反射ベクトルと視線ベクトルが近いとき明るくなるという性質をもとに感覚的に作られたモデルになります。

一方、物理ベースのモデルというのは物理的な根拠のある式や実際の物理データに基づくマテリアルなどを利用します。 物理的根拠に基づいているというのは、エネルギー保存則をおおよそ満たしていて、BRDF導出元の幾何学モデルが物理的な微細構造を考慮した上で導出していて、パラメータが実際の想定した測定値にうまくフィットしているようなものです。

エネルギー保存則

エネルギー保存則というのは入射する光より射出する光が大きくならないようにできているものです。 前回に書いたような何も考えていないlambertやblinn-phongはエネルギー保存則をじつは満たしていないものです。

微小構造を表現する幾何学モデル

幾何学モデルというのはマイクロファセット理論というのがよく用いられています。 この理論に基づいた導出をされた式は何も考えずに作られた式よりもっともらしい結果になりそうです。

パラメータと測定値

よくある物理ベースモデルでは入力となるデータのalbedoとmetallicとroughnessの値の組み合わせで現実のマテリアルを表現します。 もっとパラメータが増えることもありますが……。 このパラメータで現実の実際の材質を表現できるようになっています。

このパラメータはスキャンされたデータを使うことが多いです? 従来のようにアーティストが感覚的に色を決めるのではなく現実世界を測定したデータをもとに作成するのが物理ベースレンダリングの特徴です。

Behind the Scenes of Substance Source’s Scanned Materials | Substance

物理「ベース」レンダリング

物理ベースレンダリングと言っていて物理レンダリングと言わないのは、物理現象をすべて再現しているわけではないというのがあります。 実測データになるべくフィットするように作られていますが、例えば光の回析現象のような波動としての性質は表せなかったりします。

まあ、現実の大体のいい感じの近似になっているモデルだと思っておけば問題ないです?

光の単位

最初に物理ベースレンダリングをやる上で重要な光の種類と光の単位について見ていきます。

光には「放射量」と「測光量」の2種類があります。

放射量は光を純粋なエネルギーとして捉えた測り方です。 光のエネルギーはW(ワット)などの物理で出てくる単位で表すことができます。

測光量は人間の目が受けて実際に感じる明るさです。 人間の目は光の波長によって感じる光の明るさに差があります。 それも考慮した光の量ということになります。

放射量は物理量ですが、測光量は心理物理量と呼ばれます。

放射量や測光量は幾何学的な分類があり、特にレンダリングで気にするのは放射束、放射輝度、放射照度などがあります。 それぞれを見ていきます。

放射束・光束

放射束はある領域を単位時間あたりに通過する光のエネルギーのことです。 放射束Φ\Phiの単位はW(ワット)です。

これに対応する測光量は光束で単位はlm(ルーメン)です。 LED電球とかに書かれている単位ですね。

放射輝度・輝度

放射輝度は単位射影面積あたりかつ単位立体角あたりの放射束です。 方向性を強く意識した光量単位という感じです。

ライティング計算で放射輝度を利用するにはBRDFとコサイン項を乗算し半球面上に積分します。 レイトレーシングなどでモンテカルロ積分を行うことが多いようです? リアルタイムレンダリングというよりレイトレで意識することの多い単位かもしれません。

対応する測光量は輝度で、単位はcd/m2cd/m^2(カンデラ/平方メートル)、またはnit(ニト)です。

放射照度・照度

放射照度は単位面積あたりの放射束です。 Φ\Philmの点光源があったときにrr離れた位置で垂直に光が指す場合の放射照度は、半径rrの球の表面積が4πr24 \pi r^2なのでΦ4πr2\frac{\Phi}{4 \pi r^2}と計算できます。

対応する測光量は照度で、単位はlux(ルクス)です。

物理量と心理物理量のおおよその変換

人間が一番敏感な緑色の光(波長555nm)で1Wの放射束は、およそ683.002lm(ルーメン)だそうです。

同じW数でもスペクトルによって即光量は変わってくるのであれですが、おおよその値で変換をしたいときは683.002をWにかけてやればおおよそのlmになります。

色について

光には色がついています。 これについて軽くメモします。

スペクトルレンダリングとRGBレンダリング

RGBの3次元ベクトルを物理量または心理物理量に掛け合わせて3次元ベクトルで光を表現するようです? これは非常に雑な近似で、例えばナトリウムランプのような黄色の波長しか出ていない光について、反射する材質がその波長を反射するかどうかで見え方が変わるはずのものを、RGBで表現すると黄色を表現するためにRG成分に値を持つ光として表現されるため、RとGを反射する材質ならば何でも反射されてしまいます。

オフラインレンダリングなどではスペクトルレンダリングというものが行われたりもするようです。 ナトリウムランプなどの特定の波長のみが放出されるライトなどが正しく扱われることが期待できます。

コストなどの問題からリアルタイムレンダリングではRGBレンダリングが主流のようです。

RGB空間の種類

RGB空間にもいくつかの種類があります。

sRGB色空間

一番使われるのはsRGB色空間です。 これはLinearとGammaのときのsRGBとはまた別なので注意です。

ほとんどのコンピュータのモニタはsRGBが使われており、出力フラグメントに何も考えずにRGBの値を入れて表示されるのはsRGBです。

ACEScg色空間

映画芸術科学アカデミーによる映画のコンピュータグラフィックスレンダリング用に開発された色空間です。 レンダリング用の作業色空間に使い、その後ディスプレイ用に変換します。

ACESではHDR画像を各種モニタで表示する際のトーンマッピングも定義されています。 ACESによるトーンマッピングはディスプレイによらない中間表現への変換RRTと、各種モニタごとに調整されたODTという変換の組み合わせでなっています。

その他の色空間

Adobe 1998色空間、DCI-P3色空間、Rec. 2020色空間など色々あります。

色空間とレンダリング

レンダリング操作は色空間で得られる結果が異なり、DCI-P3やACEScg色空間でレンダリングを粉うと、線形sRGB空間で行うよりも正確な結果を生み出すことがわかっています。


今回のシリーズではACES色空間でレンダリングを行う予定です。

レンダリング方程式

レンダリングに使う色と光について説明をしてきました。 それでは次にレンダリングの計算についてみていきます。

レンダリングの計算とはカメラのセンサーに届く放射輝度、または輝度を求めることになります。 物理ベースのレンダリングは、何らかのビュー レイのセットに沿ってカメラに入る放射輝度を計算することになります。

ボリュームレンダリングのような媒質で満たされた空間を通過して伝搬する光は吸収や散乱などが起こりますが、とりあえずそれらの媒質が存在しないものとして考えることにします。 その場合、カメラに入る放射輝度は最も近いオブジェクトのサーフェスからカメラの方向への放射輝度に等しくなります。

ccをカメラの位置、ω-\overrightarrow{\omega}をビュー レイに沿う方向として入射放射輝度はLi(c,ω)L_i(c,-\overrightarrow{\omega})と表記されます。 xxをビュー レイと最も近いサーフェスの交点、ω\overrightarrow{\omega}のビューの方向として放射輝度Lo(x,ω)L_o(x, \overrightarrow{\omega})というものを考えたとき、先に述べた等しくなる関係から、

Li(c,ω)=Lo(x,ω)L_i(c, -\overrightarrow{\omega}) = L_o(x, \overrightarrow{\omega})

が言えます。

次の目標はLo(x,ω)L_o(x, \overrightarrow{\omega})を求めることです。 xxの位置から放出される放射輝度Lo(x,ω)L_o(x, \overrightarrow{\omega})は自己発光により放射される放射輝度LeL_eと反射される放射輝度LrL_rの和となります。

Lo(x,ω)=Le(x,ω)+Lr(x,ω)L_o(x, \overrightarrow{\omega}) = L_e(x, \overrightarrow{\omega}) + L_r(x, \overrightarrow{\omega})

ここでは透明なサーフェスやグローバル表面化散乱を考えないこととします。 すると、xxの点に当たる光を外向きに向け直して戻す、ローカルな反射現象を見ることでLrL_rを考えられます。 位置xxのローカルな反射は、入る光の方向ω\overrightarrow{\omega'}と視線方向ω\overrightarrow{\omega}に依存した関数fr(x,ω,ω)f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})を利用して次のように書き換えられます。

Lo(x,ω)=Le(x,ω)+Ωfr(x,ω,ω)(ωn)Li(x,ω)dωL_o(x, \overrightarrow{\omega}) = L_e(x, \overrightarrow{\omega}) + \int_{\Omega}f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})(\overrightarrow{\omega'} \cdot \overrightarrow{n})L_i(x, \overrightarrow{\omega'}) d\overrightarrow{\omega'}

この式をレンダリング方程式と呼びます。 Ωdω\int_{\Omega}d\overrightarrow{\omega'}xxの位置の法線方向の半球全体での積分です。

この式について詳しく見ていきましょう。

BRDF

この先ほど導入した関数fr(x,ω,ω)f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})がかの有名なBRDF(双方向反射率分布関数)です。 ある地点xxω\overrightarrow{\omega'}方向から入射した光のどれだけがω\overrightarrow{\omega}方向へ反射するのかという反射分布を示す確率密度関数となっています。

注意が必要なのは入社する放射輝度と反射する放射輝度の比ではないということです。 入射光については放射照度となっています。

fr(x,ω,ω)=dLr(x,ω)dE(x)=dLr(x,ω)Li(x,ω)(nω)dωf_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega}) = \frac{dL_r(x, \overrightarrow{\omega})}{dE(x)} = \frac{dL_r(x, \overrightarrow{\omega})}{L_i(x, \overrightarrow{\omega'})(\overrightarrow{n}\cdot\overrightarrow{\omega'})d\overrightarrow{\omega'}}

これはレンダリング方程式でコサイン項が式の上で分離するからこのように定義されているらしいです。

このBRDFは実は正確にはSVBRDFまたはSBRDFとよんだほうが正しかったりします。 もとの導出のBRDFは一様なサーフェスに定義され、どこでも同じとされていましたが、基本的に一様なサーフェスというのは現実世界には存在しません。 単一の素材であっても、かすり傷やシミなどで反射特性が部分的に変化します。 このように場所によって反射特性が違うサーフェスを意味扱うためにfr(x,ω,ω)f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})は位置xxに依存した関数として定義されています。 このよう関数はSVBRDF(空間可変BRDF)やSBRDF(空間BRDF)と呼ばれます。 が、実際にはより短いBRDFという言葉がSBRDFを表す用語として使われることが多いようです。

スペクトルレンダリングではなくRGBレンダリングを行う場合、このBRDFはRGBの3次元ベクトルを返すことになります。

放射輝度とBRDFとレンダリング方程式

レンダリング方程式はLi(x,ω)L_i(x, \overrightarrow{\omega'})を積分し求める形になっています。

Lo(x,ω)=Le(x,ω)+Ωfr(x,ω,ω)Li(x,ω)(ωn)dωL_o(x, \overrightarrow{\omega}) = L_e(x, \overrightarrow{\omega}) + \int_{\Omega}f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})L_i(x, \overrightarrow{\omega'})(\overrightarrow{\omega'} \cdot \overrightarrow{n}) d\overrightarrow{\omega'}

この式はリアルタイムレンダリングでは直接使わなかったりします。 レイトレではこちらを主に使うかも。 今回扱っているラスタライザ形式でもIBLを実装する際にはこちらの式を意識することになりますが……。

積分計算が入り解析的に解けないのでモンテカルロ法などを使って数値積分することになります。 リアルタイムでは重たい処理になるのでこの式を使わない、あるいはIBLなど事前計算をしておくなどの手法が使われます。

放射照度とBRDFとレンダリング方程式

リアルタイムレンダリングで使うのはこちらの形式です。

Lr(x)=fr(x,ω,ω)E(x)=fr(x,ω,ω)E(x)(ωn)L_r(x) = f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})E(x) = f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})E_{\perp}(x)(\overrightarrow{\omega'} \cdot \overrightarrow{n})

積分が消えて放射照度をBRDFに掛けるだけになりました。

ポイントライト、スポットライト、ディレクショナルライトはこの放射照度をBRDFに掛け合わせる形で計算します。 IBLは放射輝度を使うのであれですが……。 リアルタイムではこちらの放射照度を使う計算がメインになります。

各種ライトの強さとレンダリング時の扱い

放射照度で計算できると書きました。 それについて詳しく見てみます。

IBLについてはまた別の機会に。

平行光源

平行光源のライトの強さは放射照度または照度で入力します。 太陽光が100000luxなどというやつですね。 この放射照度は垂直の場合の照度なのでBRDFに掛けるまえにコサイン項をかけることになります。

ポイントライト・スポットライト

一方、ポイントライトやスポットライトは放射照度で定義するのは都合が悪いです。 というのも、距離で減衰するからですね。 距離とは関係ない放射束W、もしくは光束lm(ルーメン)を光源の強さとして利用します。

この放射束Φ\PhiをどうやってBRDFに掛ける放射照度EEに変換するかというと、次のようにします。

E=Φ4π(ωn)E = \frac{\Phi}{4\pi}(\overrightarrow{\omega'} \cdot \overrightarrow{n})

これは次のようにして導かれます。

E=Φ(ωn)4πr2E = \frac{\Phi(\overrightarrow{\omega'} \cdot \overrightarrow{n})}{4 \pi r^2}

Φ\Phiの光源からrr離れた位置の放射照度はΦ(ωn)4πr2\frac{\Phi(\overrightarrow{\omega'} \cdot \overrightarrow{n})}{4 \pi r^2}です。 4πr24\pi r^2というのは球の表面積で、放射束がこの面積に均等に割り振られることを考えると放射照度は4πr24\pi r^2で割った値になります。 また、斜めから入射してくる場合、コサイン項(ωn)(\overrightarrow{\omega'} \cdot \overrightarrow{n})が必要となります。

ポイントライト・スポットライトの距離の減衰

ポイントライトの距離の減衰1r2\frac{1}{r^2}はそのまま組み込むと問題が生じる場合があります。

一つはrrが0の場合。 0除算で発散をしてしまいます。 これに対する対処としては例えばFrostbiteというゲームエンジンでは、rr0.010.01へのクランプを行います。

1r21max(r2,0.012)\frac{1}{r^2} \simeq \frac{1}{max(r^2, 0.01^2)}

https://seblagarde.files.wordpress.com/2015/07/coursenotesmovingfrostbitetopbrv32.pdf

もう一つは大きな距離でほとんど0になったものについての扱いです。 残念ながら1r2\frac{1}{r^2}は有限の距離では0にはなりません。 有限の距離で0になってくれればそのライトの計算を省くことができ効率が良くなります。 このために先に上げたFrostbiteというゲームエンジンでは窓関数をかけています。

fwin(r)=(1(rrmax)4)+2f_win(r) = (1 - (\frac{r}{r_{max}})^4)^{+2}

ここで+2+2は値が負ならば2乗の前に0クランプをします。 rmaxr_maxがライトの最大半径です。

スポットライトの強さ

スポットライトは、その放射束が特定の方向のみに射出されていると考えると、W数が同じならばコーンの角度が小さいほど明るくなるはずです。 Frostbiteではこれがアーティストの作業がしにくくなり、また最適化しにくいという問題からこの挙動は再現しないことにしたそうです。 Frostbiteでは次の式でスポットライトの強さを計算しています。

E=Φπr2E = \frac{\Phi}{\pi r^2}

この記事のシリーズでもそれに習って実装していくことにします。

BRDFの式

ここまでBRDFの式fr(x,ω,ω)f_r(x, \overrightarrow{\omega'}, \overrightarrow{\omega})の中身については触れてきませんでした。 これからその中身について眺めていくことにします。

拡散反射と鏡面反射

BRDFは2つの成分に分離できます。 これ入ってしまえば近似の一つですが、反射の仕方が大きく違うため分離しても十分もっともらしい見た目を提供できます。

1.png

Wes McDermott「The Comprehensive PBR Guide by Allegorithmic - vol. 1 Light and Matter : The theory of Physically-Based Rendering and Shading」©Allegorithmic から引用

拡散反射というのは光が物体と衝突して、そのうち屈折して物体内に侵入した分が、散乱現象の結果再び物体表面の外へ出ていく現象です。 方向がばらばらになっているのが特徴です。

SSS(表面化散乱)を思い浮かべる人もいるかも知れません。 厳密にはSSSとして扱わなければならないものですが、表面化散乱距離が十分に短くカメラが遠い場合などは、光が入射した点から射出されるものと見なし、単純化されたモデルとして捉えられます。 このような入射と射出が同じ表面化散乱と区別してSSSをグローバル表面化散乱と言ったりもするようです?

鏡面反射は物体表面で入射光を鏡面反射方向に反射するものです。 通常、物体表面にはある程度の粗さがあるため、鏡面反射方向だけでなく若干拡散します。 これもまとめて鏡面反射成分として扱います。

拡散反射BRDF

拡散反射BRDFの式を見てみます。 式にはいくつか種類がありますが、ここでは正規化ランバートを挙げます。 拡散反射(diffuse)成分のBRDFfr,df_{r,d}

fr,d(x)=ρdπf_{r,d}(x) = \frac{\rho_d}{\pi}

です。 ρd\rho_dはディフューズアルベドです。

以前実装した普通のLambertシェーダはπ\piで除算していませんでした。 これは実はエネルギー保存則を満たしていないものとなります。 π\piで除算することで正規化しています。 π\piというのはcosθ\cos\thetaの半球積分から導出されます。 導出に興味のある方は参考資料の方を見てください。

これ以外にも様々な拡散反射BRDFがありますがそれは参考資料の方を見てください。

鏡面反射BRDF

鏡面反射のBRDFモデルにはCook-Torranceモデルを使うのが定石です。 Cook-Torranceモデルは次のような式で表現されます。

fr,s(x,ω,ω)=FDG4(nω)(nω)f_{r,s}(x, \overrightarrow{\omega'}, \overrightarrow{\omega}) = \frac{FDG}{4(\overrightarrow{n} \cdot \overrightarrow{\omega'})(\overrightarrow{n} \cdot \overrightarrow{\omega})}

F

Cook-Torranceモデルの式のFFがフレネル項です。 Schlickの近似式で次のように表現されます。

Fr(h)=F0+(1F0)(1(lh))5F_r(\overrightarrow{h}) = F_0 + (1 - F_0)(1 - (\overrightarrow{l} \cdot \overrightarrow{h}))^5

h\overrightarrow{h}はハーフベクトルです。

F0F_0の値は垂直入射におけるフレネル反射係数です。 metallicが1の場合、BaseColorテクスチャ経由でF0F_0が渡されることになります。 metallicが0の場合は、vec3(0.04)が使われます。 この4%というのは一般的な不導体を網羅する値だそうです。

マイクロファセット理論

先のCook-Torranceモデルの式は微正面(マイクロファセット)理論をもとに作られた式です。 1px未満に落ち込んでしまう微正面というものを扱います。 マイクロファセットは、次の図のようにガタガタした面として考えられます。

2.jpeg

Wes McDermott「The Comprehensive PBR Guide by Allegorithmic - vol. 1 Light and Matter : The theory of Physically-Based Rendering and Shading」©Allegorithmic より引用

マイクロファセットは微小面とは言いますが、波動光学が必要になるものは考えないことにします。 幾何光学の領域で考えることができます。

このマイクロファセット平面にあたったときにどの方向に反射するかというのを考えます。 微正面の向きはややランダムで、その「巨視的なサーフェスの法線」に強いピークがあります。 ランダムさをサーフェスの粗さとして与えると、あらさが大きいほどマイクロファセットの法線は大きく広がります。 すると反射がぼやけるような効果を生み出します。

殆どのサーフェスでは微小サーフェス法線の分布は等方性ですが、ものによっては異方性のものがあります。

マイクロファセット理論では、ただ単にマイクロファセットの法線分布を扱うだけではなく、シャドウイングとマスキングも式に含めます。

マイクロファセット理論を活用した式の中にはさらに相互反射を考えるものもあったりしますが、基本的には法線分布と幾何減衰を考えるのがマイクロファセット理論です。

D

Cook-Torranceモデルの式のDDが法線分布関数(NDF)です。

式にはいろいろな種類がありますが、ここではGGX(Throwbridge-Reiz)を紹介します。

DGGX(h)=α2π((nh)2(α21)+1)2D_{GGX}(h) = \frac{\alpha^2}{\pi((n \cdot h)^2(\alpha^2 - 1) + 1)^2}

この式はエネルギー保存が考慮され長いテールを持ちスーパーラフを表現できるモデルです。 α\alphaはラフネスの値です。

ほかの式については参考資料を参考にしてください。

G

Cook-Torranceモデルの式のGGが幾何減衰項です。 シャドウイングとマスキングを考慮する項です。

よく使われるのはSmithモデルにSchlickの近似式を使ったものです。

k=α22Gschlick(v)=nv(nv)(1k)+kGSmith(l,v,h)=Gschlick(l)Gschlick(v)k = \frac{\alpha^2}{2} \\ G_{schlick}(v) = \frac{n \cdot v}{(n \cdot v)(1 - k) + k}\\ G_{Smith}(l, v, h) = G_{schlick}(l)G_{schlick}(v)

拡散反射と鏡面反射を組み合わせたBRDF

拡散反射と鏡面反射のBRDFについて述べました。 これを組み合わせて一つのBRDFとして扱います。

単純に足し合わせるとエネルギー保存則に違反するのでkdk_dという拡散反射成分の光の割合を用いて次のようにします。 鏡面反射光fr,sf_{r,s}にはFFで鏡面反射成分の割合がすでに入っているので掛ける必要がありません。

fr=kdfr,d+fr,sf_r = k_df_{r,d} + f_{r,s}

このFFの値を求めるのに必要なF0F_0はmettalicパラメータをベースに金属の場合BaseColorを、非金属の場合は4%のグレーを入れるようです。 そうして求めたFFから次のようにしてkdk_dを求めます。

kd=1Fkdkd(1metallic)k_d = 1 - F\\ k_d \leftarrow k_d \cdot (1 - metallic)

更に複雑なBRDF

異方性やクリアコートを扱えたり、さらにレイヤーになったマテリアルを扱えたりとバリエーションは色々あります。 興味があれば調べてみると良いでしょう。

露出

カメラにやってくる放射輝度を求めることができました。 これをディスプレイに表示するには露出というものを考える必要があります。

現実のカメラを考えると露出というのはシャッタースピードやセンサー感度、絞りといった要素で決まります。 これらの要素を一緒くたにして露出として特定の定数をかけることで画面に表示する明るさを決めます。

Auto exposure

ゲームなどで使うにはシーンの明るさに応じて露出の値を変更する実装を行う事が多いです。 明順応や暗順応などをエミュレートすることもあります。

物理ベースカメラ

Frostbiteというゲームエンジンでは物理ベースカメラというものが実装されています。 露出をちゃんとシャッタースピードとセンサー感度と絞りから求めます。 これらの値を他のポストエフェクトの被写界深度などに与えることでより正確なポストエフェクトがかけられます。

トーンマッピングとガンマ補正

HDRレンダリングではLDRなディスプレイ向けにトーンマッピングを施す必要もあるでしょう。

トーンマッピングにもいろいろなものが提案されていて、Reinhardは有名な初期に使われたトーンマッピングオペレータです。

この記事のシリーズではACESの規格のトーンマッピングを利用します。

参考資料

おわりに

物理ベースレンダリングの理論などを適当にメモしました。 次回からは実装を行っていきます。

  • 3DCG
  • PBR