22. 物理ベースシェーディング
第10章ではフォンとブリン・フォンの反射モデルを学びました:拡散反射の項、鏡の方向の周りのハイライト、そして光源についての和です。
第12章では、「材質」を物理的にした物がBRDFである事、どの表面もすれすれの角度では鏡になる事(フレネル効果)、粗い表面は小さな鏡が並んだ地形として考えられる事を見ました。
そして、此れらの部品をきちんと組み立てるのは第2部だと約束しました。
其れが此の章です。
物理ベースシェーディングは物理ベースレンダリング(PBR)のシェーディングの部分で、今では映画のレンダラー、ゲームエンジン、glTFの様なファイル形式の標準になっています。
1つの式ではなく、決まり事の集まりです:光を物理的な単位で測る、第12章の法則に従うBRDFを使う、粗さをマイクロファセットモデルで表す、そしてアーティストには有り得ない材質を作れない少数のパラメータ(ベースカラー、メタリック、ラフネス)を渡す。
其の見返りは一貫性です:一度作った材質が、真昼の太陽の下でも、薄暗い部屋でも、映り込みの中でも、調整し直さずに正しく見えます。
計画は次の通りです:
- 放射測定を正確に(22.1節):立体角、放射束、放射照度、余弦の因子付きの放射輝度、数値での換算、そして測光(ルーメン、ニト)を簡単に。
- 物理的なBRDFが満たすべき事(22.2節):其の検査と、合格するランバート、不合格のフォン。
- マイクロファセット理論(22.3節):クック・トランスの式の導出、GGXとベックマンの分布、スミスのマスキング・シャドウイング、を使うフレネル、ラフネスの再写像。
- 1つの光源を完全に計算(22.4節):C++とシェーダーのコード付き。
- メタリック・ラフネスワークフロー(22.5節)、スペキュラー・グロッシネスワークフローとglTF。
- PBRでのイメージベーストライティング(22.6節):球面調和関数による放射照度、スプリットサム近似、エネルギー補償。
- 更なる層(22.7節):クリアコート、シーン、異方性、表面下散乱。
- リアルタイムの面光源(22.8節):代表点と線型変換コサイン。
此の内容は検定のシラバスの範囲を超えますが、其の土台は検定の項目です:第10章の反射モデル、第12章の写実的表現法のBRDF、フレネル、マイクロファセットです。
第12章の放射測定とBRDFの基礎(12.2節〜12.4節)、第3章のリニアな色(3.7節)、第11章の環境マッピング(11.9節)、そして線型代数 第4章と第5章の内積と外積を前提とします。
積分が幾つか出てきますが、第12章と同じく、何を足し合わせているかを必ず言葉で説明し、どれも数値で確かめてあります。
此処で学ぶ事は全てOpenGLシリーズの第24章で実装します。
又、其の一部を事前計算する為のサンプリング手法は第23章のテーマです。
22.1 放射測定を正確に
第12章では4つの放射測定の量を1つの表で紹介しました。
BRDFを組み立てるには、もう少し正確に、特に余弦の因子が何処から来るのかを知る必要があります。
式で表す立体角
表面の上の方向は2つの角度で表せます:法線から測る(法線で0、地平線で)と、法線の周りの角度です。
辺がとの小さな方向の範囲は、単位球から高さ、幅の小さな長方形を切り取ります(での緯線は半径の円だからです)。
従って其の立体角は:
此れを使うと、何度も出てくる2つの半球の積分は簡単です:
法線の周りの半頂角の円錐はステラジアンを占めます。
計算例:太陽。 太陽の円盤の角半径は約0.2666°なので、 srを占めます。
小さな円錐ではなので、式は(はラジアン)、つまり単位球上の小さな円の面積になります: srで、同じ値です。
放射輝度と余弦の因子
放射輝度は単位面積・単位立体角あたりのパワーですが、其の面積は表面に沿ってではなく、光線に垂直に測ります:
は投影面積、つまり方向から見た時の面の見かけの大きさです。
放射輝度が目やカメラの測る量なのは此の為です:1つの画素は決まった立体角を見ていて、其の中に収まるだけの面積の表面を見ます。
又、ランバートの法則の余弦も両側から説明出来ます:斜めに届く光はより広い面積に広がり(入射方向ごとに)、斜めに出て行く光はで縮む投影面積から来ます。
他の量は積分で得られます:
| 量 | 定義 | 単位 | 例 |
|---|---|---|---|
| 放射束 | 全パワー | W | ランプの全出力 |
| 放射強度 | W/sr | 或る方向への点光源 | |
| 放射照度 | W/m² | 面に届く光 | |
| 放射発散度 | W/m² | 面から出て行く光 | |
| 放射輝度 | W/(m²·sr) | 1本の光線に沿った光 |
換算の計算例
等方的な点光源。 電球が Wを srの球全体に均等に放つとします:
mで光源の方を向いた面は W/m²を受け取り、60°傾けると其の半分の0.995 W/m²になります。
ランバート面の発光体。 拡散する発光パネルは半球の全ての方向に同じ放射輝度を送るので、放射発散度はです(第12章の一様な空と同じです)。
従って100 Wを放つ1 m²のパネルは:
小さな面光源。 此のパネルの0.25 m²の一部が2 m離れて受光面の方を向き()、受光面は30°傾いている()とします。
受光面から見ると、此の一部は約 srを占め、其の立体角の全てが放射輝度を持つので:
此の「放射輝度 × 立体角 × 余弦」が使えるのは、光源が距離に比べて小さい間だけです。
そうでない時に何が起きるかは22.8節で見ます。
何故太陽は平行光源なのか。 晴れた日の太陽は、太陽を向いた面に大体1000 W/m²を届けます。
其れが srに広がっているので、放射輝度は約 W/(m²·sr)で、周りの晴れた空(数十W/(m²·sr))の数十万倍です。
太陽を環境マップの中に入れたレンダラーは、其の小さな円盤にサンプルを当てなければなりません。
太陽は放射照度を指定した平行光源として扱い、空を環境として扱う方が遥かに良いのです。
測光(簡単に)
第3章の測光の量は同じ考え方で、各波長を目の感度(第3章の比視感度曲線)で重み付けした物です。
換算係数は、目の感度が最も高い555 nmで683 lm/Wです:
| 放射量 | 測光量 | 単位 |
|---|---|---|
| 放射束 | 光束 | ルーメン(lm) |
| 放射強度 | 光度 | カンデラ(cd = lm/sr) |
| 放射照度 | 照度 | ルクス(lx = lm/m²) |
| 放射輝度 | 輝度 | cd/m²(ニトとも) |
計算例。 800 lmとして売られている電球が均等に光を放つなら、光度は cdで、其の2 m下の机はルクスを受けます。
比較すると、オフィスは大体500ルクス程度で照らされ、真夏の直射日光は10万ルクスのオーダーです。
sRGB規格はディスプレイの白を80 cd/m²と想定していて、HDRディスプレイは執筆時点で1,000ニト以上に達します。
此の桁違いの比がある為、物理ベースのレンダラーは浮動小数点のHDRで計算し、最後に露出とトーンマッピングを必要とします(第15章、詳しくは第27章)。
エンジンによってはアーティストが光源をルーメン、カンデラ、ルクスで直接入力出来ます。
シェーディングの数式は同じで、光源の色の単位が変わるだけです。
22.2 物理的なBRDFが満たすべき事
第12章では、物理的なBRDF の3つの性質を挙げました(此処からは、入射方向を光源へ向かう、出射方向を目へ向かうと書きます。どちらも表面から外へ向かう単位ベクトルです):
- 非負:。
- 相反性:。
- エネルギー保存:全ての入射方向について、方向アルベドが1以下:
は、から届いた光のうち、どの方向であれ表面から出て行く割合です。
此の3つの決まりは、どんなシェーディングモデルにも手計算や数値計算で掛けられる検査です。
3つ目をレンダラー全体で確かめるのが、第12章のホワイトファーネステストです:白い物体(アルベド1、吸収無し)を放射輝度1の一様な環境に置くと、受け取った分を丁度反射するので、見えなくならなければなりません。
ランバートは合格
ランバート面のBRDF (第12章12.3節)では:
正の値で、明らかに相反的で(方向に全く依存しません)、ならホワイトファーネステストに丁度合格します。
フォンは不合格
第10章のフォンのモデルは、光源ごとにに光源の色を掛けます。
「BRDF × 放射照度」と読むと、光源の放射照度はなので、鏡面反射の部分は次のBRDFに相当します:
(此処では第10章のフォンの指数を使っています。22.3節からは、はマイクロファセットの粗さを意味します。)
相反性が成り立ちません:は対称(を鏡映してと内積を取るのも、を鏡映してと内積を取るのも同じ)ですが、分母はではなくで、すれすれの光では発散さえします。
普通の修正は、割り算を落とした「修正」フォンのBRDF です。
エネルギーが指数に依存します。 法線に沿って届く光ではなのでで、修正フォンのローブのアルベドは:
| 指数 | ローブのアルベド | の時 |
|---|---|---|
| 1 | 1.047(入った以上の光が出る) | |
| 10 | 0.262 | |
| 100 | 0.031 |
一見無難なでも、広いローブはエネルギーを生み出し、鋭いローブは殆ど全てを失います。
此れが第10章の「指数を大きくするとハイライトは小さくなるが明るくはならない」と言う観察を数値にした物です。
本物の磨かれた表面は同じ総量をより小さなローブに反射するので、ピークは明るくならなければなりません。
直し方は正規化係数です:は、指数に関係無く垂直入射でのアルベドが丁度になります(で、で)。
其れでもは1を超え得ますし、フレネル効果は無く、物理的な表面の様にハイライトの大きさと強さを結び付ける物も有りません。
正規化したブリン・フォン(係数は約)は、マイクロファセットモデルが主流になる前の中間段階として人気がありました。
22.3 マイクロファセット理論
考え方
粗い表面は小さなファセットが並んだ地形で、其の1つ1つが完全な鏡です(第12章12.3節)。
からの光がの目に届くのは、法線がハーフベクトル
を向いたファセットを通る時だけで、しかも光源と目のどちらも他のファセットに遮られていない時だけです:
マイクロファセット理論は此の絵を、3つの要素でBRDFにします:
- 法線分布関数(NDF):を向くファセットがどれだけあるか。
- マスキング・シャドウイング関数(幾何減衰項):其のうち照らされていて、且つ見えている割合。
- フレネル項 :1つのファセットが自分の入射角でどれだけ鏡の様に反射するか(第12章12.4節)。
ファセットは光の波長より十分大きく(幾何光学が使える)、画素より十分小さい(統計だけを気にすれば良い)と仮定します。
クック・トランスの式の導出
Robert CookとKenneth Torrance(1982年)は、此れらを第12章の式にまとめました:
4と2つの余弦が何処から来るのかを見ましょう。
先ずの正確な意味です:面積の表面の欠片で、法線がの周りの小さな立体角に入るファセットの総面積はです。
巨視的な表面に投影すると、各ファセットは自分の面積 × を覆い、全てのファセットを合わせると丁度を覆います。
此処から、全てのNDFが満たすべき正規化が出てきます:
では光を1歩ずつ追いましょう。
- 放射輝度の光がの周りの小さな立体角から届きます。を向いたファセットは其れを角度で受けるので、受け取るパワーはです。
- 其の割合が鏡面反射され、更に其の割合が影にも隠れにもなりません。
- 反射された光はの周りの立体角へ出て行きます。鏡を或る角度だけ傾けると、反射光は其の2倍の角度だけ回るので、反射方向はファセットの法線より4倍(2次元の其々で2倍)広く広がります。正確な関係はです。
- 出て行く放射輝度は、投影面積あたり、立体角あたりのパワーです。
まとめると、(「ハーフベクトル」とはそう言う意味です)を使って:
BRDFは入射する放射照度あたりの出て行く放射輝度なので、割ると丁度クック・トランスの式になります。
が対称である限り式はとについて対称なので、相反性は自動的に満たされます。
D:ベックマン、GGX、ブリン・フォン
との角度を、分布の粗さのパラメータを(小さい程滑らか)と書きます。
知っておくべき分布は3つです:
- ベックマン分布は、粗い表面の光学(Petr BeckmannとAndré Spizzichino、1963年)から来た物で、傾きがガウス分布に従うと仮定します。クックとトランスは1982年に此れを使いました。
- GGXは、Bruce Walter、Stephen Marschner、Hongsong Li、Kenneth Torranceが2007年(「Microfacet Models for Refraction through Rough Surfaces」)にグラフィックスへ持ち込みました。同じ関数はT. S. TrowbridgeとK. P. Reitzが1975年に小さな楕円体で出来た表面について導いていたので、トローブリッジ・ライツ分布とも呼びます。今では殆ど何処でも標準です。
- NDFとしてのブリン・フォン:第10章のに係数を付けると正しく正規化された分布になり、とすると粗さのベックマンに似た形になります(ウォルターらが此の対応を示しています)。ブリン・フォンが良いモデルだった本当の理由は此処にあります。
GGXの正規化の確認は3行で済みます。
、とし、と置換すると():
22.4節のC++のプログラムは此れを3つの粗さで数値的に確かめます。
ベックマンと正規化したブリン・フォンも同じ検査に合格します(Pythonでも確かめました)。
計算例。 ではGGXもベックマンも最大値を取り、ならです。
ピークから離れると違いが出ます:
| GGX、 | ベックマン、 | |
|---|---|---|
| 0° | 5.093 | 5.093 |
| 10° | 2.415 | 3.293 |
| 20° | 0.671 | 0.784 |
| 30° | 0.226 | 0.0437 |
| 45° | 0.0705 | 0.0000023 |
30°のGGXの値を手で計算してみましょう:なので括弧の中は、其の2乗は、そしてです。
ベックマンのガウス分布は崖から落ちる様に減りますが、GGXは長い裾を保ちます:45°では約3万倍大きいです。
其の裾は本物の材質で見える物です:鋭いハイライトが柔らかい光に囲まれています(ランプの下のクロムの蛇口や車のクリアコートを見て下さい)。
測定した材質にはGGXの方が良く合う事が多く、其れがベックマンに取って代わった理由の1つです(ウォルターらは幾つかの粗いガラスの試料で此れを示し、後で触れるBurley 2012のディズニーの測定も同じ方向を指しました)。
裾を更に長く又は短く調整出来る「一般化」版(GTR、スチューデントのt分布)もありますが、此処では名前だけにします。
ラフネスの再写像
式の中のは、アーティストが入力する値ではありません。
Brent Burley(ディズニー、「Physically-Based Shading at Disney」、SIGGRAPH 2012)は、其の物のスライダーでは面白い材質が全て下の端に詰まってしまう事を見つけました。
そして、知覚的ラフネスを
で使うと、見た目の変化が均等に広がる事を示しました。
Unreal Engine 4(Karis 2013)とglTF 2.0も同じ再写像を採用しています。
「ラフネス0.5」と言えば、の事です:
| ラフネス | GGXのピーク | |
|---|---|---|
| 0.25 | 0.0625 | 81.49 |
| 0.5 | 0.25 | 5.093 |
| 0.75 | 0.5625 | 1.006 |
| 1 | 1 | 0.3183 |
ではGGXは定数になります:ファセットの法線は(投影面積で数えて)全ての方向を同じ頻度で向きます。
では1つの方向に潰れて完全な鏡になり、点光源は其れに丁度当たる事が出来ません。
其の為、リアルタイムのシェーダーはラフネスを小さな最小値で制限します(OpenGLシリーズは0.03を使います)。
G:スミスのマスキングとシャドウイング
Bruce Smith(1967年)は、粗い表面による電波の散乱の研究で、ランダムな表面上の点が或る方向から見える確率を計算しました。
グラフィックスで採用された其の考え方は、表面の高さと傾きが点ごとに相関しないと仮定する事で、此れによってマスキングはNDFで決まる方向の関数1つで表せます。
から見えるファセットの割合は:
Eric Heitz(「Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs」、JCGT 2014)は、マスキング(目の方向)とシャドウイング(光源の方向)の組み合わせ方を整理しました:
- 分離型:。照らされる事と見える事が独立な事象であるかの様に扱います。
- 高さ相関:。谷の底のファセットは影にも隠れにもなり易く、山頂のファセットはどちらにもなり難い。此の形は其れを考慮していて、より正確です。なので、常に分離型より少し大きくなります。
此れもハイツによる便利な検査です:どの視線方向でも、見えているファセットの投影面積は巨視的な表面の投影面積に等しくなければなりません:
(「弱いホワイトファーネステスト」)。
此のを使ったGGXが、 = 0.25、0.5、1、 = 1と0.5で此れを5桁まで満たす事を数値的に確かめました。
には平方根と正接が要るので、リアルタイムのコードではシュリックの近似 (又は)が良く使われます。
とすると、ではスミスのGGXと完全に一致し(どちらもになります)、其れ以外では近似になります:
| スミス厳密、 | シュリック、 | スミス厳密、 | |
|---|---|---|---|
| 0.8 | 0.9914 | 0.9697 | 0.8889 |
| 0.6 | 0.9737 | 0.9231 | 0.7500 |
| 0.2 | 0.7749 | 0.6667 | 0.3333 |
が最も効くのはすれすれの角度と粗い表面で、分母のが発散するのを抑えます。
便利な工夫として、と分母は普通可視項 としてまとめて計算します。
高さ相関のGGXでは、少し式変形すると(でを書き直します):
となり、0になり得る余弦での割り算が有りません。
22.4節のシェーダーは此の形を使います。
Karis(Unreal Engine 4、2013年)は、点光源にはシュリックの形で(粗い表面がすれすれの角度で明る過ぎない様にする意図的な再写像)、イメージベーストライティングにはを使いました。
OpenGLシリーズは其れに従っているので、両方を見掛けても驚かないで下さい。
F:ハーフベクトルで計算するフレネル
各ファセットは鏡なので、第12章のフレネルの割合を自分の入射角で反射します。
其の角度は(又は)とファセットの法線の角度で、との角度ではありません:
垂直入射での反射率は、鏡面反射の項の唯一の材質定数です:
| 材質 | (リニア) | 備考 |
|---|---|---|
| 水 | 0.02 | |
| ガラス、プラスチック、殆どの誘電体 | 0.04 | |
| ダイヤモンド | 0.17 | |
| 金 | (1.0, 0.766, 0.336) | 色付き |
| 銅 | (0.955, 0.638, 0.538) | 色付き |
| 銀、アルミニウム | 全チャンネルで約0.91〜0.99 | 殆ど白 |
誘電体の値は第12章のから来ます。
逆に解くとなので、典型的な範囲0.02〜0.05はが1.33〜1.58である事を意味します。
金属は正面から50〜100%を反射し、其のは波長に依存します。
其れが金属の色です。
公開されている表は数パーセント異なります(金の緑チャンネルは測定によって約0.71〜0.77と幅があります)。
此処ではOpenGLシリーズの値を使います。
ローブ
45°で入射する光について、鏡面反射のBRDF()を、入射面内の各出射方向での、つまり其の方向へ向かう反射光の割合として描いた物です:
粗いローブはピークが33分の1ですが遥かに広いので、合計は同じ位です。
此れが正規化の働きです。
其のピークは42°にあり、少し法線側です。
の因子とマスキングが、すれすれ側を削るからです。
BRDFの値其の物は逆の振る舞いをします:すれすれの方向に向かって大きくなります(とフレネルが勝つ為です)。
粗い表面がすれすれの角度で明るい反射を見せるのは此の為で、TorranceとSparrowが1967年に本物の材質について記述した「オフスペキュラーピーク」です。
検定のポイント
第10章の反射モデルと第12章のBRDFに繋がる点です:
- マイクロファセットのBRDF:。D = を向くファセットの量(法線分布)、G = 影にも隠れにもならない割合(幾何減衰)、F = 1つのファセットのフレネル反射率で、との角度で計算する。
- NDFはではなく、(投影面積)で正規化される。
- 細いハイライトは明るくなければならない:正規化したローブはエネルギーを保存し、フォンの正規化していないローブは保存しない。
- フォンの鏡面反射の項にはフレネル効果が無く、BRDFとして見ると相反的でない。
22.4 1つの光源を完全に計算する
1つの点で全てを計算してみましょう。
比べられる様に、第10章の計算例の幾何を使います:
- 、、。
- 放射強度 W/srの点光源が距離に。
- 材質:ベースカラー(橙色)、メタリック、ラフネス。メタリックのパラメータと、や拡散の部分の決まりは22.5節で説明します。誘電体では、になります。
ステップ1:内積。
第10章で、長さが出ているので、です。
つまり関係するファセットには、光が45°()で当たります。
ステップ2:D。 、で、は丁度です:
(対応するのブリン・フォンのNDFでは、此処でです。ピークは同じ5.093で、形が少し違います。)
ステップ3:G。 、:
分離型ではで、殆ど同じです。
どちらの角度もすれすれから遠いからです。
カリスのではで、点光源向けの意図通り、目に見えて暗くなります。
ステップ4:F。 :
ステップ5:鏡面反射のBRDF。
3つのチャンネル全てで同じです:誘電体のハイライトは白です。
ステップ6:拡散反射のBRDF。 表面で反射されなかった光が中に入り、拡散して出て来ます:
ステップ7:出て行く放射輝度。 放射照度は W/m²なので:
同じ点を金で。 、にすると、ベースカラーがになり、拡散の部分は消えて:
でも問題ありません:BRDFは1ステラジアンあたりの密度で、1以下でなければならないのは其の積分(アルベド)だけです。
同じ幾何での第10章のフォンの結果と比べると、誘電体のハイライトは拡散色に対して遥かに弱く(0.064対0.244で約4分の1。第10章のフォンでは0.332対0.48で約3分の2でした)、代わりにすれすれの角度ではフレネルによって強くなります。
フォンでは決して起きなかった事です。
C++では
式を小さなプログラムにした物です。
線型代数シリーズのlinalg.hhのVec3、dot、normalizeを使います。
の正規化を数値的に(の輪についての中点和で)確かめ、上の2つの結果を再現します:
#include <cmath>
#include <cstdio>
#include <initializer_list>
#include "linalg.hh"
constexpr float kPi = 3.14159265358979f;
Vec3 mul(Vec3 a, Vec3 b) { return {a.x * b.x, a.y * b.y, a.z * b.z}; }
Vec3 lerp(Vec3 a, Vec3 b, float t) { return a + t * (b - a); }
// D: GGX / Trowbridge-Reitz normal distribution, alpha = roughness^2
float distributionGgx(float nDotH, float alpha) {
float a2 = alpha * alpha;
float d = nDotH * nDotH * (a2 - 1.0f) + 1.0f;
return a2 / (kPi * d * d);
}
// Smith's Lambda for GGX; c = cosine between the normal and l (or v)
float smithLambda(float c, float alpha) {
float tan2 = (1.0f - c * c) / (c * c);
return 0.5f * (-1.0f + std::sqrt(1.0f + alpha * alpha * tan2));
}
// G2: height-correlated masking-shadowing
float geometrySmith(float nDotL, float nDotV, float alpha) {
return 1.0f / (1.0f + smithLambda(nDotL, alpha) + smithLambda(nDotV, alpha));
}
// F: Schlick's approximation with an RGB F0
Vec3 fresnelSchlick(float cosTheta, Vec3 f0) {
float w = std::pow(1.0f - cosTheta, 5.0f);
return f0 + w * (Vec3{1, 1, 1} - f0);
}
// The full BRDF (diffuse + specular) of the metallic-roughness model.
Vec3 brdf(Vec3 n, Vec3 l, Vec3 v, Vec3 base, float metallic, float roughness) {
Vec3 h = normalize(l + v);
float nl = dot(n, l), nv = dot(n, v), nh = dot(n, h), vh = dot(v, h);
float alpha = roughness * roughness;
Vec3 f0 = lerp({0.04f, 0.04f, 0.04f}, base, metallic);
Vec3 F = fresnelSchlick(vh, f0);
float dg = distributionGgx(nh, alpha) * geometrySmith(nl, nv, alpha) / (4.0f * nl * nv);
Vec3 kd = (1.0f - metallic) * (Vec3{1, 1, 1} - F);
return mul(kd, base) / kPi + dg * F;
}
int main() {
// 1. The NDF is normalized: integral of D(h) cos(theta_h) over the hemisphere = 1
for (float r : {0.25f, 0.5f, 1.0f}) {
const int steps = 200000;
const double dTheta = (kPi / 2) / steps;
double sum = 0;
for (int i = 0; i < steps; ++i) {
double th = (i + 0.5) * dTheta; // midpoint of ring i
double c = std::cos(th), s = std::sin(th);
sum += distributionGgx(c, r * r) * c * s * 2 * kPi * dTheta; // ring: 2 pi sin(th) dTheta sr
}
printf("r = %.2f: integral of D cos = %.4f\n", r, sum);
}
// 2. One light: the vectors of chapter 10, I = 50 W/sr at distance 5
Vec3 n{0, 1, 0}, l{0, 0.6f, 0.8f}, v{0, 0.8f, -0.6f};
float irradiance = 50.0f / 25.0f * dot(n, l);
Vec3 orange = brdf(n, l, v, {0.8f, 0.4f, 0.2f}, 0.0f, 0.5f);
Vec3 gold = brdf(n, l, v, {1.0f, 0.766f, 0.336f}, 1.0f, 0.5f);
for (Vec3 f : {orange, gold}) {
Vec3 radiance = irradiance * f;
printf("f = (%.4f, %.4f, %.4f) L = (%.4f, %.4f, %.4f)\n", f.x, f.y, f.z,
radiance.x, radiance.y, radiance.z);
}
return 0;
}
r = 0.25: integral of D cos = 1.0000
r = 0.50: integral of D cos = 1.0000
r = 1.00: integral of D cos = 1.0000
f = (0.3077, 0.1857, 0.1247) L = (0.3692, 0.2229, 0.1497)
f = (1.5154, 1.1615, 0.5113) L = (1.8185, 1.3939, 0.6136)
シェーダーでは
シェーダーでは普通、22.3節の可視項を使って同じ物を書き、光源は其れを向いた面に届ける放射照度(、点光源なら)として渡します:
static const float PI = 3.14159265;
float distributionGgx(float nDotH, float alpha) {
float a2 = alpha * alpha;
float d = nDotH * nDotH * (a2 - 1.0) + 1.0;
return a2 / (PI * d * d);
}
// V = G2 / (4 (n.l)(n.v)) for height-correlated Smith-GGX
float visibilitySmithGgx(float nDotL, float nDotV, float alpha) {
float a2 = alpha * alpha;
float lv = nDotL * sqrt(nDotV * nDotV * (1.0 - a2) + a2);
float vl = nDotV * sqrt(nDotL * nDotL * (1.0 - a2) + a2);
return 0.5 / (lv + vl);
}
float3 fresnelSchlick(float cosTheta, float3 f0) {
return f0 + (1.0 - f0) * pow(1.0 - cosTheta, 5.0);
}
// Outgoing radiance for one light that delivers lightIrradiance to a surface facing it.
float3 shadePbr(float3 n, float3 v, float3 l, float3 lightIrradiance,
float3 baseColor, float metallic, float roughness) {
float3 h = normalize(l + v);
float nDotL = saturate(dot(n, l));
float nDotV = max(dot(n, v), 1e-4);
float nDotH = saturate(dot(n, h));
float vDotH = saturate(dot(v, h));
float alpha = max(roughness, 0.03) * max(roughness, 0.03);
float3 f0 = lerp(float3(0.04, 0.04, 0.04), baseColor, metallic);
float3 F = fresnelSchlick(vDotH, f0);
float3 specular = distributionGgx(nDotH, alpha) * visibilitySmithGgx(nDotL, nDotV, alpha) * F;
float3 diffuse = (1.0 - F) * (1.0 - metallic) * baseColor / PI;
return (diffuse + specular) * lightIrradiance * nDotL;
}const float PI = 3.14159265;
float distributionGgx(float nDotH, float alpha) {
float a2 = alpha * alpha;
float d = nDotH * nDotH * (a2 - 1.0) + 1.0;
return a2 / (PI * d * d);
}
// V = G2 / (4 (n.l)(n.v)) for height-correlated Smith-GGX
float visibilitySmithGgx(float nDotL, float nDotV, float alpha) {
float a2 = alpha * alpha;
float lv = nDotL * sqrt(nDotV * nDotV * (1.0 - a2) + a2);
float vl = nDotV * sqrt(nDotL * nDotL * (1.0 - a2) + a2);
return 0.5 / (lv + vl);
}
vec3 fresnelSchlick(float cosTheta, vec3 f0) {
return f0 + (1.0 - f0) * pow(1.0 - cosTheta, 5.0);
}
// Outgoing radiance for one light that delivers lightIrradiance to a surface facing it.
vec3 shadePbr(vec3 n, vec3 v, vec3 l, vec3 lightIrradiance,
vec3 baseColor, float metallic, float roughness) {
vec3 h = normalize(l + v);
float nDotL = clamp(dot(n, l), 0.0, 1.0);
float nDotV = max(dot(n, v), 1e-4);
float nDotH = clamp(dot(n, h), 0.0, 1.0);
float vDotH = clamp(dot(v, h), 0.0, 1.0);
float alpha = max(roughness, 0.03) * max(roughness, 0.03);
vec3 f0 = mix(vec3(0.04), baseColor, metallic);
vec3 F = fresnelSchlick(vDotH, f0);
vec3 specular = distributionGgx(nDotH, alpha) * visibilitySmithGgx(nDotL, nDotV, alpha) * F;
vec3 diffuse = (1.0 - F) * (1.0 - metallic) * baseColor / PI;
return (diffuse + specular) * lightIrradiance * nDotL;
}static const float PI = 3.14159265;
float distributionGgx(float nDotH, float alpha) {
float a2 = alpha * alpha;
float d = nDotH * nDotH * (a2 - 1.0) + 1.0;
return a2 / (PI * d * d);
}
// V = G2 / (4 (n.l)(n.v)) for height-correlated Smith-GGX
float visibilitySmithGgx(float nDotL, float nDotV, float alpha) {
float a2 = alpha * alpha;
float lv = nDotL * sqrt(nDotV * nDotV * (1.0 - a2) + a2);
float vl = nDotV * sqrt(nDotL * nDotL * (1.0 - a2) + a2);
return 0.5 / (lv + vl);
}
float3 fresnelSchlick(float cosTheta, float3 f0) {
return f0 + (1.0 - f0) * pow(1.0 - cosTheta, 5.0);
}
// Outgoing radiance for one light that delivers lightIrradiance to a surface facing it.
float3 shadePbr(float3 n, float3 v, float3 l, float3 lightIrradiance,
float3 baseColor, float metallic, float roughness) {
float3 h = normalize(l + v);
float nDotL = saturate(dot(n, l));
float nDotV = max(dot(n, v), 1e-4);
float nDotH = saturate(dot(n, h));
float vDotH = saturate(dot(v, h));
float alpha = max(roughness, 0.03) * max(roughness, 0.03);
float3 f0 = lerp(float3(0.04, 0.04, 0.04), baseColor, metallic);
float3 F = fresnelSchlick(vDotH, f0);
float3 specular = distributionGgx(nDotH, alpha) * visibilitySmithGgx(nDotL, nDotV, alpha) * F;
float3 diffuse = (1.0 - F) * (1.0 - metallic) * baseColor / PI;
return (diffuse + specular) * lightIrradiance * nDotL;
}が本当にになっているかを、計算例の数値(、、なので)で手早く確かめます:
OpenGLシリーズは此の関数の変種(シュリックのを使う物)を第24章で、第22章の法線マップと一緒に実装します。
22.5 メタリック・ラフネスワークフロー
2種類の物質
ファセットが鏡面反射しなかった光()がどうなるかで、全ての材質は2つに分かれます:
- 誘電体(非金属:プラスチック、木、石、塗料、肌、水)は数パーセントしか鏡面反射せず、其の色は付きません()。残りは中に入って顔料に散乱され、吸収されなかった色を帯びて全ての方向に出て来ます。此れが拡散反射で、其の色をアルベドと呼びます。
- 金属(導体)は50〜100%を鏡面反射し、に色が付きます。中に入った光は自由電子によってナノメートルの深さで吸収されるので、金属には拡散反射が全く有りません。
つまり原理的には、材質には2つの色が要ります:拡散色とです。
しかし本物の材質では、両方が「自由」になる事はありません:誘電体のは殆ど決まった灰色で、金属には拡散色が有りません。
パラメータ
メタリック・ラフネスワークフローは、バーリーのディズニーのモデル(2012年)とUnreal Engine 4(2013年)が広め、glTF 2.0が標準化した物で、此の事実を3つの主なパラメータで利用します:
- ベースカラー :誘電体ならアルベド、金属なら。
- メタリック(金属度):0から1。
- ラフネス(粗さ):0から1で、。
此れらから:
そしてBRDFは22.4節の物です:
glTFの仕様(付録B)は同じ物を混合として書いています:の誘電体のBRDF mix(diffuse, specular, F)、ベースカラーをとしてフレネルに使う金属のBRDF、そして其の間のmix(dielectric, metal, metallic)です。
展開すると上の式になります。
其の参考実装はにGGXを使い、可視項を光源側の因子と視点側の因子の積(分離型のスミスのGGX)として書いていて、実装によって違ってよいと明記しています。
での計算例:
| メタリック | 拡散色 | 何か | |
|---|---|---|---|
| 0 | (0.04, 0.04, 0.04) | (0.8, 0.4, 0.2) | 橙色のプラスチック:橙色の本体と白いハイライト |
| 1 | (0.8, 0.4, 0.2) | (0, 0, 0) | (架空の)橙色の金属:橙色の反射だけ |
| 0.5 | (0.42, 0.22, 0.12) | (0.4, 0.2, 0.1) | 本物の材質ではない |
中間のメタリックの値は、どんな本物の物質も表しません。
テクスチャの中の移り変わり(半分が錆、半分がむき出しの鋼の画素や、其の境目でフィルタされたテクセル)の為に有ります。
良く出来たメタリックマップのテクセルは殆どが丁度0か1です。
此の章の式其のもので(平行光源1つと空、空は22.6節のイメージベーストライティングで)、金のベースカラーについて空間全体をレンダリングした物です:
見るべき所:一番上の行ではハイライトが白く、球の色は拡散の項から来ています。
滑らかなプラスチックの球は、フレネルが上がる縁でだけ地平線を映します。
一番下の行では映り込み自体が金色で、拡散の陰影は全く有りません。
粗い金の球が其れでも金属に見えるのは、其の「拡散の様な」光が、実はとてもぼやけた金色の映り込みだからです。
列を下に辿ると、拡散光が消えて映り込みが取って代わります。
テクスチャ
glTFでは、パラメータは係数とテクスチャの積から来ます:
baseColorTextureは色をsRGBで符号化して持ち、GPUがシェーディングの前にリニアに復号します(第3章3.7節)。metallicRoughnessTextureはラフネスを緑チャンネル、メタリックを青チャンネルに、リニアなデータとして持ちます。ラフネスもメタリックも色ではないので、sRGBとして復号すると値が歪みます。normalTexture(第11章の法線マップ)、occlusionTexture(焼き込んだアンビエントオクルージョン、赤チャンネル。glTFは間接光にだけ適用します)、emissiveTextureで揃います。
此れらが第11章(11.10節)で触れた「ラフネスマップやメタリックマップ」です。
ラフネスマップの引っ掻き傷は丁度其処でハイライトを鋭く又はぼやけさせ、むき出しの金属に描いたロゴはメタリックマップで0になります。
現実のアルベドは誘電体のベースカラーにも便利な目安になります:殆どの物は約0.03(木炭)より暗くも約0.9(新雪)より明るくもないので、真っ黒や真っ白のベースカラーは警告のサインです。
スペキュラー・グロッシネスワークフロー
古いスペキュラー・グロッシネスワークフローは2つの色を別々に持ちます:拡散色、スペキュラー色(RGBの)、そしてグロッシネス(普通)です。
メタリック・ラフネスからの変換は直接出来ます:
金(、、)は、拡散色(0, 0, 0)、スペキュラー色(1.0, 0.766, 0.336)、グロッシネス0.7になります。
逆方向はいつも出来る訳ではありません:拡散色(0.5, 0.5, 0.5)とスペキュラー色(0.2, 0.2, 0.2)は、4%の誘電体でも拡散色が黒い金属でもありません。
其の自由度がスペキュラーワークフローの利点(の宝石や其の他の珍しい誘電体)でもあり、危険(拡散0.9とスペキュラー0.9でエネルギーが生まれる)でもあります。
又、メタリック・ラフネスなら1チャンネルで済む所に、RGBのスペキュラーテクスチャが要ります。
glTFの其の為の拡張KHR_materials_pbrSpecularGlossinessは、2021年にKhronosによってアーカイブされました(読み込みには使えますが、新しいファイルには推奨されません)。
代わりにKHR_materials_iorとKHR_materials_specularの拡張が、メタリック・ラフネスの材質で誘電体のを調整出来る様にしています。
何故第10章のモデルより優れているのか
第10章のフォンのパラメータと比べてみましょう:
- エネルギー:が拡散と鏡面を結び付け、正規化されたがハイライトの幅と高さを結び付けます。アーティストが暗闇で光る材質を作ってしまう事は出来ません。
- フレネルが組み込まれているので、どの材質もすれすれの角度で反射が明るくなります。第10章のレンダリングがプラスチックの様に見えた主な原因は此れでした。
- 少数で意味のあるパラメータ:ラフネスは太陽の下でも洞窟の中でも環境の映り込みでも同じ意味なので、材質をシーン、ツール、エンジンの間で共有出来ます(glTFは其の為の物です)。
- 環境光は独立した概念として消えます:環境も同じBRDFを通して照らします(次の節)。
22.6 PBRでのイメージベーストライティング
第12章(12.13節)では、HDRの環境マップによるイメージベーストライティングを紹介し、一様な空の中の白いランバート面の球が丁度空の放射輝度を示す事を見ました。
本物の環境と完全なBRDFでは、各画素が毎フレーム、半球全体について次を計算しなければなりません:
リアルタイムのレンダラーは、2つの項について別々に、出来るだけ多くを事前計算します。
拡散:放射照度と球面調和関数
拡散の項は定数 × 放射照度です:
は法線だけに依存するので、で引く小さなキューブマップ、放射照度マップとして保存出来ます。
更に小さく出来ます:クランプした余弦との積分は強いぼかしで、細部を全て消すので、少しの数で足ります。
Ravi RamamoorthiとPat Hanrahan(「An Efficient Representation for Irradiance Environment Maps」、SIGGRAPH 2001)は、色チャンネルごとに9個の球面調和関数(SH)の係数で十分な事を示しました。
SHは、球面上の関数にとって、1次元の信号にとっての正弦波の様な物です。
周波数の高くなるバンドにまとめられ(バンドごとに個の関数。バンド0〜2で個)、クランプした余弦のぼかしはバンドを定数倍するだけです:
| バンド | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 0 |
バンド3は丁度0で、バンド4はバンド0の4%しか無いので、バンド2より上を全て捨ててもほんの少ししか失いません。
(射影其の物と、ゲームでのSHのライトプローブは、第24章で詳しく計算します。)
バンド0と1だけを使った計算例です。
放射輝度が方向の上向き具合だけで決まる空を、、で考えます(天頂で0.8、地平線で0.5、真下で0.2)。
定数のは純粋にバンド0、1次のは純粋にバンド1なので、放射照度は:
| 法線 | 白い漆喰(): | |
|---|---|---|
| 上 | 2.1991 | 0.560 |
| 横 | 1.5708 | 0.400 |
| 下 | 0.9425 | 0.240 |
此の3つの値は、空を球面上で数値積分して確かめました。
5桁まで一致します。
22.5節の球の格子は丁度此の方法で、其の空から射影した9個の係数で照らしています。
鏡面:スプリットサム近似
鏡面の項はもっと難しく、、ラフネス、に依存するので、表にするには次元が多過ぎます。
Brian Karis(「Real Shading in Unreal Engine 4」、SIGGRAPH 2013)はスプリットサム近似を提案しました。
積分を個のサンプルで推定し(モンテカルロ法、第23章)、其の和を其々事前計算出来る2つの因子に分けます:
- プリフィルタ済み環境マップは、GGXのローブの形で環境をぼかした物です。ミップマップの各段が増えていくラフネスを持ち、反射方向で引きます。に依存しない様に、カリスは(表面を正面から見ている)と仮定します。其の為、濡れた道路ですれすれの角度に見える長く伸びた映り込みは失われます。此れが此の手法の代償です。
- BRDFの積分は、白い環境に対する鏡面のローブの方向アルベドです。、ラフネス、に依存します。シュリックを()と書くとを外に出せて、積分はになり、とはとラフネスだけに依存します。此れが小さな2次元テクスチャ、BRDFルックアップテーブル(BRDF LUT)です。
実行時の鏡面のIBLはprefiltered(r, roughness) * (F0 * A + B)で、テクスチャの参照2回です。
手で出来る確認。 ラフネス0では全てのハーフベクトルがなので、、で、表は、を持つ筈です。
するとは丁度シュリックの式です。
では、で、強さの完全な鏡です。
(60°)では、で、ガラスなら、第12章の60°でのシュリックの値です。
ラフネスが付くと値は下がります。
図の表(OpenGLシリーズと同じく、シュリックのとで計算)では、例えば、で、なので、其処でガラスは白い環境のを反射します。
和を効率良く計算する方法(GGXの重点的サンプリング)は第23章の内容で、OpenGLシリーズは第24章で3つのテクスチャ全てを作ります。
単散乱で失われるエネルギー
鏡面のローブだけにホワイトファーネステストを掛けてみましょう:の金属(完全な鏡の材質)を一様な白い環境に置きます。
其の方向アルベドはでので、1になる筈です。
なりません:
| ラフネス | 0.25 | 0.5 | 0.75 | 1 |
|---|---|---|---|---|
| でのアルベド | 0.996 | 0.916 | 0.627 | 0.307 |
では閉じた式さえあります:、で、でのアルベドはです。
光の70%が消えます。
何処へ行くのでしょうか?
此のモデルは1回だけ鏡面反射された光を数えます。
ファセットに当たり、隣のファセットへ反射され、2回以上跳ね返ってから出て行く光は、によって単に捨てられます。
滑らかな表面では無視出来ますが、粗い金属では目に見えて暗くなり過ぎます:
Christopher KullaとAlejandro Conty Estevez(ソニー・ピクチャーズ・イメージワークス、SIGGRAPH 2017)は、失われたエネルギーを戻す2つ目のローブを加えました。
リアルタイムのエンジンは同じ考えの安価な形、鏡面の項に掛ける倍率を使います(Emmanuel Turquin、2019年):
はでのアルベドで、LUTのです。
ならアルベドはになり、ファーネステストに合格します(下の行)。
、では、倍率は完全な金属でですが、誘電体ではだけです。
誘電体のファセットは、跳ね返る度に殆どの光を表面の中へ失うからです。
22.7 更なる層
基本のモデルで殆どの不透明な材質を表せます。
実際のアセットには幾つかの追加のローブが要ります。
glTFは其れらを拡張として定義し、バーリーのディズニーのモデルはパラメータとして持ち、エンジンは似た組み合わせを実装しています。
- クリアコート:下地の上の薄い透明なニス(車の塗装、漆塗りの木、カーボンファイバー)。誘電体のに固定され、独自のラフネスを持つ2つ目の鏡面のローブです。下の層は、コートが反射した分だけ、大体倍に暗くなります。glTFでは
KHR_materials_clearcoat。 - シーン:表面から繊維が立っているベルベット等の布は、光をすれすれの角度へ散乱し、柔らかく明るい縁を作ります。逆さにした様な分布を使います(Conty EstevezとKullaの2017年の「Charlie」シーンが一例です)。glTFでは
KHR_materials_sheen。 - 異方性:ヘアライン加工の金属、髪、サテンのハイライトは一方向に伸びます。GGXの分布に、接線と従接線(第11章の接空間)に沿った2つの粗さを持たせます:。なら普通のGGXに戻ります(で正規化を数値的に確かめました)。glTFでは
KHR_materials_anisotropy。 - 表面下散乱と透過:第12章(12.6節)のBSSRDFです。リアルタイムのエンジンは、肌の上でぼかした拡散光、回り込みライティング、事前計算したプロファイル等で近似し、映画のレンダラーはレイで追います。glTFには薄い透明物と厚い透明物の為の
KHR_materials_transmissionとKHR_materials_volumeがあります。ボリューム其の物は第28章で扱います。 - 粗い拡散面:ランバートは滑らかな艶消しの面には理想的ですが、粗い面(粘土、月)は平たく見え、すれすれの角度で明るくなります。バーリーの拡散の項はランバートにを掛けます。で、はとの角度です。で光源と目が一緒に法線から80°にある時(、)倍率は2.49で明るい再帰反射に、では0.65ですれすれの角度で暗くなります。(エネルギーを正確には保存しません。オーレン・ナイヤー(1994年)から最近のエネルギーを保存する物まで、他の粗い拡散のモデルは此の問題を別の方法で扱います。)
バーリーのモデル、ディズニーのプリンシプルドBRDFは、此の考え方を言葉にしました:パラメータは直感的で、0から1の範囲を取り、どの組み合わせも有り得る物であるべきだ、と言う事です。
ベースカラーと10個のスカラーのパラメータ(subsurface、metallic、specular、specular tint、roughness、anisotropic、sheen、sheen tint、clearcoat、clearcoat gloss)を持ち、今日の制作向けの材質モデルの殆どは其の子孫です。
22.8 リアルタイムの面光源
点光源と平行光源は数学的な理想化です。
本物のランプには大きさがあり、其れが柔らかい影(第11章と第24章)と、ランプの形をしたハイライト(蛍光灯からの長い筋、窓からの長方形)を生みます。
第10章(10.9節)でリアルタイムの近似を約束しました。
此処で見ていきます。
正確な答えは、光源の立体角に限ったレンダリング方程式です:
オフラインのレンダラーは此れをサンプリングします(第23章)。
リアルタイムには2つの古典的な考え方があります。
代表点
面光源を、其の上の上手く選んだ1点、代表点で置き換え、其の点を普通の点光源としてシェーディングします。
鏡面の項に最適な点は、反射レイに最も近い点です:球の光源なら反射方向が球の中心に最も近付く所、管の光源なら線分上の最も近い点です。
するとハイライトが光源の形になります。
ローブは今や「より大きな光源」を見ているので、広げてエネルギーを正規化し直す必要があります。
カリス(2013年)は、光源の見かけの大きさに応じてを大きくする事で此れを行います。
球と管には安価で説得力がありますが、大きな長方形ではそれ程でもありません。
多角形の閉じた式と線型変換コサイン
多角形の光源の拡散の項には、ランバート(1760年)以来知られている厳密な閉じた式があります。
シェーディングする点から見た多角形の頂点(其の点からのベクトル)を正規化してとすると:
(で、頂点は点から見て反時計回りの順に並べます。)
此の数は第12章のラジオシティの点から多角形への形態係数で、放射照度は其の倍です。
計算例。 1辺2の正方形の光源が、点の真上の高さ1にあります。
、頂点はです:
- どの頂点も距離にあります。隣り合う2つ、例えばとはなので、 radです。
- 其の外積はに比例し(点と其の辺を通る平面)、単位ベクトルはで、との内積は0.70711です。
- 対称性から4つの辺の寄与は同じです:形態係数 。
なら放射照度は W/m²で、白い漆喰の床()はを示します。
(正方形の上で力任せに数値積分しても同じ0.55413になります。)
22.1節の「小さな光源」の近似と比べてみましょう: W/m²で、2倍以上多過ぎます。
正方形の殆どの部分は、中心より斜めに、且つ遠くから見えるからです。
鏡面の項については、Eric Heitz、Jonathan Dupuy、Stephen Hill、David Neubelt(「Real-Time Polygonal-Light Shading with Linearly Transformed Cosines」、SIGGRAPH 2016)が見事な技を見つけました。
多角形での積分を今閉じた式で計算した、クランプした余弦の分布を取り、其の全ての方向にの行列を掛けます(線型変換、線型代数 第8章)。
引き伸ばし、せん断し、拡大縮小すると、与えられた視線角とラフネスでのGGXのローブにとても良く合うローブが作れます。
此れが線型変換コサイン(LTC)です。
変換したローブを多角形で積分するのは、で変換した多角形で普通の余弦を積分するのと同じで、其れは再びランバートの式です。
従って実行時には:(、ラフネス)で小さな事前計算の表からを引き、多角形の頂点を変換し、地平線で切り取り、辺の和を計算します。
結果は長方形や其の他の多角形の正確な面光源のライティングで(論文はテクスチャ付きの光源も扱い、後の研究が線分や円盤に広げました)、執筆時点で幾つかのエンジンが使っています。
GLSLシリーズの第10章では、シェーダーでのより簡単な面光源の近似を見せています。
22.9 まとめ
- 放射輝度は投影面積あたりで測る。、半球は sr、。ランバート面の発光体は。測光は同じ量をで重み付けした物:ルーメン、カンデラ、ルクス、ニト。
- 物理的なBRDFは非負、相反的で、方向アルベドが1以下(ホワイトファーネステスト)。ランバート()は合格。フォンの鏡面の項は相反的でなく、アルベドはで正規化しない限り指数に依存する。
- マイクロファセットのBRDF:。4はから来る。NDFはを満たす。
- GGX(トローブリッジ・ライツ)は長い裾を持つ。ベックマンはガウス型。正規化したブリン・フォンはに対応する。知覚的ラフネス:。
- スミス:、高さ相関の(ハイツ2014)、シュリックの近似は(点光源にはカリスの)。フレネルはと(誘電体で0.04、金属は色付き)を使う。
- メタリック・ラフネス:、拡散はにを掛ける。glTFはラフネスをリニアなテクスチャのG、メタリックをBに持つ。スペキュラー・グロッシネスは拡散色との色を別々に持つ。
- IBL:拡散は放射照度(、9個のSH係数、バンドの係数、、)から。鏡面はスプリットサムで、プリフィルタ済み環境 × BRDF LUTの。を仮定する。
- 単散乱のマイクロファセットモデルは粗い表面でエネルギーを失う(を正面から見るとアルベドは)。エネルギー補償はローブを倍する。
- 追加のローブ:クリアコート、シーン、異方性のGGX、表面下散乱と透過、バーリーの粗い拡散。ディズニーのプリンシプルドBRDF。
- 面光源:球と管には代表点。拡散にはランバートの多角形の閉じた式。GGXには線型変換コサイン(ハイツら2016)。
22.10 用語
| English | 日本語 |
|---|---|
| physically based rendering / shading (PBR) | 物理ベースレンダリング/シェーディング |
| radiometry / photometry | 放射測定/測光 |
| solid angle, steradian | 立体角、ステラジアン |
| projected area | 投影面積 |
| radiant flux / radiant intensity | 放射束/放射強度 |
| irradiance / radiant exitance | 放射照度/放射発散度 |
| radiance | 放射輝度 |
| luminous flux (lumen) / luminous intensity (candela) | 光束(ルーメン)/光度(カンデラ) |
| illuminance (lux) / luminance (cd/m², nit) | 照度(ルクス)/輝度(cd/m²、ニト) |
| BRDF | 双方向反射率分布関数 |
| reciprocity / energy conservation | 相反性/エネルギー保存 |
| directional albedo | 方向アルベド |
| white furnace test | ホワイトファーネステスト |
| normalization factor | 正規化係数 |
| microfacet theory | マイクロファセット理論 |
| half vector | ハーフベクトル |
| normal distribution function (NDF) | 法線分布関数 |
| GGX distribution (Trowbridge–Reitz) | GGX分布(トローブリッジ・ライツ分布) |
| Beckmann distribution | ベックマン分布 |
| masking–shadowing function | マスキング・シャドウイング関数(幾何減衰項) |
| height-correlated Smith G | 高さ相関のスミスのG |
| visibility term | 可視項 |
| Fresnel term, F0 | フレネル項、F0(垂直入射での反射率) |
| perceptual roughness | 知覚的ラフネス |
| dielectric / metal (conductor) | 誘電体(非金属)/金属(導体) |
| metallic–roughness workflow | メタリック・ラフネスワークフロー |
| base color / metallic / roughness | ベースカラー/メタリック(金属度)/ラフネス(粗さ) |
| specular–glossiness workflow | スペキュラー・グロッシネスワークフロー |
| irradiance map | 放射照度マップ |
| spherical harmonics (SH) | 球面調和関数 |
| prefiltered environment map | プリフィルタ済み環境マップ |
| split-sum approximation | スプリットサム近似 |
| BRDF lookup table (LUT) | BRDFルックアップテーブル(LUT) |
| multiple scattering / energy compensation | 多重散乱/エネルギー補償 |
| clear coat / sheen / anisotropy | クリアコート/シーン/異方性 |
| Disney principled BRDF | ディズニーのプリンシプルドBRDF |
| area light | 面光源 |
| representative point | 代表点 |
| form factor | 形態係数(フォームファクタ) |
| linearly transformed cosines (LTC) | 線型変換コサイン(LTC) |
22.11 課題
- ★ 0.5 m²のランバート面のパネルが合計40 Wを放ちます。其の放射輝度を求めて下さい。次に、パネルが点の方を向き、点の面が45°傾いている時の、3 m離れた点での放射照度を「放射輝度 × 立体角 × 余弦」で見積もって下さい。又、1,200 lmの等方的な電球をカンデラに換算し、其の1.5 m下の照度を求めて下さい。
- ★ ラフネスについて、、GGXのピーク、とでのを求めて下さい。同じでのベックマンのでの値と、2つの比も求めて下さい。
- ★★ を示し、正規化したブリン・フォンが正しいNDFである事を確かめて下さい。次に、のGGXについて、でのを厳密に、及びのシュリックで求め、での分離型と高さ相関のを求めて下さい。
- ★★ ベースカラー(0.9, 0.6, 0.3)、メタリック0.25、ラフネス0.4の材質があります。其の、拡散色、及び等価なスペキュラー・グロッシネスのパラメータを答えて下さい。次に、に対応する屈折率と、其の誘電体のでのシュリックの反射率を求めて下さい。
- ★★★ 放射輝度がの空があります。SHのバンドの係数を使って、上・横・下を向いた法線の放射照度を求め、下を向いた法線でも光を受ける理由を説明して下さい。次に、スプリットサム近似が濡れた道路に映る街灯の伸びた映り込みを作れない理由と、其のBRDFの表を全ての環境マップで共有出来る理由を言葉で論じて下さい。
選択問題
問1 ★ 次のうち、メタリック・ラフネスワークフローについて正しい物はどれか。
| あ | メタリックの値0.5は、塗装した金属の多くの様な、典型的な本物の材質を表す。 |
| い | ラフネスはアーティストに色として見せるので、sRGBのテクスチャに保存する。 |
| う | 完全に金属の材質では、ベースカラーがF0として使われ、拡散反射は0になる。 |
| え | 誘電体では、ベースカラーがF0として使われ、拡散色は0.04に固定される。 |
| お | ラフネスrは、何の再写像もせずに其の儘GGX分布のアルファとして使われる。 |
問2 ★ 次のうち、マイクロファセット(クック・トランス)のBRDFの各項について正しい物はどれか。
| あ | 法線分布関数Dは、余弦を掛けずに半球全体で積分すると1になる様に正規化される。 |
| い | フレネル項Fは、巨視的な法線nと光源方向の角度で計算する。 |
| う | 分母の係数4は、RGBAの4つの色チャンネルを補正する為の物である。 |
| え | GGX分布は、ピークから遠い所ではベックマン分布より速く減衰する。 |
| お | 幾何減衰項Gは、他のマイクロファセットによって光源又は視点から隠されるマイクロファセットを考慮する。 |
問3 ★★ 次のうち、スプリットサム近似によるイメージベーストライティングについて正しい物はどれか。
| あ | プリフィルタ済み環境マップは、ランバート面の拡散反射の為の放射照度を、ベースカラーごとに1段ずつ持つ。 |
| い | 全ての視線方向について完全なBRDFを計算するので、すれすれの角度での伸びた映り込みを正確に再現する。 |
| う | BRDFルックアップテーブルは、環境マップが変わる度に計算し直さなければならない。 |
| え | BRDFルックアップテーブルはn・vとラフネスだけに依存し、環境マップには依存しないので、全ての環境で共有出来る。 |
| お | 事前計算は不要で、実行時に画素ごとにGGXのローブを環境マップ全体で積分する。 |
22.12 実践課題
物理ベースの材質を3つの視線角で手計算し、法線分布を数値的に確かめ、第10章のフォンのモデルと比べます。
電卓(、累乗、三角関数付き)、紙、定規、分度器を用意して下さい。
手順7のグラフには方眼紙があると便利です。
設定は2次元の断面です(全て平面の中で起きます)。
表面の法線は、光は左側のから来て、光源は其れを向いた面に W/m²を届ける平行光源です。
材質は青いプラスチックで、ベースカラー、メタリック0、ラフネスです。
- 描く。 表面、、を分度器で描き、右側に = 20°、40°(鏡の方向)、70°の3つの視線方向を描きます。
- ハーフベクトル。 各視線についてを計算して描きます。、、、を書き出します。(2次元ではハーフベクトルの角度は2つの符号付きの角度の平均なので、を分度器で確かめられます。)
- D。 と、各視線でのGGXの値を計算します。
- G。 各視線についてと、高さ相関のを計算します。比較の為、のシュリックの形も計算します。
- FとBRDF。 でを、鏡面の項、拡散の項、そして出て行く放射輝度を3つのチャンネル全てで計算します。
- 正規化。 自分のでを、9つの輪の中点和で確かめます:について、 radとしてを足し合わせます。小さな表を作って下さい。
- グラフ。 鏡面の放射輝度(1チャンネル)を3つの点でに対して描き、比較の為にフォンの値 × (第10章の形で、、指数)も加えます。
自分で確かめる方法:どのも長さ1でとの間にあります。
は鏡の方向の視線で最大です(其処ではで)。
は0と1の間でが大きくなると減り、シュリックの値は其れより少し小さくなります。
は0.04と1の間で、が大きくなると増えます。
鏡面の部分は3つのチャンネルで同じ、拡散の部分は青です。
輪の和は1から2%程度以内に収まります(9つの輪は粗いので、18個にすると更に近付きます)。
輪の和が1から大きく外れたら、(投影面積)を掛けたか、にラジアンを使ったかを確かめて下さい。
最後にグラフを見て下さい:物理ベースのハイライトは、フォンの様に鏡の方向の先で単純に落ちてはいきません。
式のどの因子が其の違いを生むのかを説明して下さい。
コメント(0)
まだコメントはありません。
ログインするとコメント出来ます。