22. 物理ベースシェーディング

第10章ではフォンとブリン・フォンの反射モデルを学びました:拡散反射の項、鏡の方向の周りのハイライト、そして光源についての和です。
第12章では、「材質」を物理的にした物がBRDFである事、どの表面もすれすれの角度では鏡になる事(フレネル効果)、粗い表面は小さな鏡が並んだ地形として考えられる事を見ました。
そして、此れらの部品をきちんと組み立てるのは第2部だと約束しました。
其れが此の章です。

物理ベースシェーディングは物理ベースレンダリング(PBR)のシェーディングの部分で、今では映画のレンダラー、ゲームエンジン、glTFの様なファイル形式の標準になっています。
1つの式ではなく、決まり事の集まりです:光を物理的な単位で測る、第12章の法則に従うBRDFを使う、粗さをマイクロファセットモデルで表す、そしてアーティストには有り得ない材質を作れない少数のパラメータ(ベースカラー、メタリック、ラフネス)を渡す。
其の見返りは一貫性です:一度作った材質が、真昼の太陽の下でも、薄暗い部屋でも、映り込みの中でも、調整し直さずに正しく見えます。

計画は次の通りです:

  • 放射測定を正確に(22.1節):立体角、放射束、放射照度、余弦の因子付きの放射輝度、数値での換算、そして測光(ルーメン、ニト)を簡単に。
  • 物理的なBRDFが満たすべき事(22.2節):其の検査と、合格するランバート、不合格のフォン。
  • マイクロファセット理論(22.3節):クック・トランスの式の導出、GGXとベックマンの分布、スミスのマスキング・シャドウイング、F0を使うフレネル、ラフネスの再写像。
  • 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)と、法線の周りの角度ϕです。
辺がdθとdϕの小さな方向の範囲は、単位球から高さdθ、幅sinθdϕの小さな長方形を切り取ります(θでの緯線は半径sinθの円だからです)。
従って其の立体角は:

dω=sinθdθdϕ

此れを使うと、何度も出てくる2つの半球の積分は簡単です:

∫Ωdω=∫02π∫0π/2sinθdθdϕ=2π,∫Ωcosθdω=2π∫0π/2cosθsinθdθ=2π⋅12=π

法線の周りの半頂角βの円錐は2π(1−cosβ)ステラジアンを占めます。
計算例:太陽。 太陽の円盤の角半径は約0.2666°なので、2π(1−cos0.2666°)=6.80×10−5 srを占めます。
小さな円錐ではcosβ≈1−β2/2なので、式はπβ2(βはラジアン)、つまり単位球上の小さな円の面積になります:π⋅0.0046532=6.80×10−5 srで、同じ値です。

放射輝度と余弦の因子

放射輝度は単位面積・単位立体角あたりのパワーですが、其の面積は表面に沿ってではなく、光線に垂直に測ります:

L=d2ΦdAcosθdωW/(m2 sr)

法線nを持つ表面の小さな面dAと、法線から角度シータの方向オメガ、其の周りの細い方向の錐dオメガ。オメガの方向から見ると、面はdA cosシータの短い線分に見える。此れが投影面積

dAcosθは投影面積、つまり方向ωから見た時の面の見かけの大きさです。
放射輝度が目やカメラの測る量なのは此の為です:1つの画素は決まった立体角を見ていて、其の中に収まるだけの面積の表面を見ます。
又、ランバートの法則の余弦も両側から説明出来ます:斜めに届く光はより広い面積に広がり(入射方向ごとにE=Lcosθdω)、斜めに出て行く光はcosθで縮む投影面積から来ます。

他の量は積分で得られます:

量 定義 単位 例
放射束 Φ 全パワー W ランプの全出力
放射強度 I dΦ/dω W/sr 或る方向への点光源
放射照度 E dΦ/dA=∫Licosθdω W/m² 面に届く光
放射発散度 M dΦ/dA=∫Locosθdω W/m² 面から出て行く光
放射輝度 L d2Φ/(dAcosθdω) W/(m²·sr) 1本の光線に沿った光

換算の計算例

等方的な点光源。 電球がΦ=100 Wを4π srの球全体に均等に放つとします:

I=Φ4π=10012.566=7.958 W/sr

d=2 mで光源の方を向いた面はE=I/d2=7.958/4=1.989 W/m²を受け取り、60°傾けると其の半分の0.995 W/m²になります。

ランバート面の発光体。 拡散する発光パネルは半球の全ての方向に同じ放射輝度Lを送るので、放射発散度はM=L∫cosθdω=πLです(第12章の一様な空と同じπです)。
従って100 Wを放つ1 m²のパネルは:

L=ΦπA=100π⋅1=31.83 W/(m2 sr)

小さな面光源。 此のパネルの0.25 m²の一部が2 m離れて受光面の方を向き(cosθl=1)、受光面は30°傾いている(cosθs=0.866)とします。
受光面から見ると、此の一部は約Acosθl/d2=0.25/4=0.0625 srを占め、其の立体角の全てが放射輝度Lを持つので:

E≈L⋅Acosθld2⋅cosθs=31.83×0.0625×0.866=1.723 W/m2

此の「放射輝度 × 立体角 × 余弦」が使えるのは、光源が距離に比べて小さい間だけです。
そうでない時に何が起きるかは22.8節で見ます。

何故太陽は平行光源なのか。 晴れた日の太陽は、太陽を向いた面に大体1000 W/m²を届けます。
其れが6.80×10−5 srに広がっているので、放射輝度は約1000/(6.80×10−5)=1.47×107 W/(m²·sr)で、周りの晴れた空(数十W/(m²·sr))の数十万倍です。
太陽を環境マップの中に入れたレンダラーは、其の小さな円盤にサンプルを当てなければなりません。
太陽は放射照度を指定した平行光源として扱い、空を環境として扱う方が遥かに良いのです。

測光(簡単に)

第3章の測光の量は同じ考え方で、各波長を目の感度V(λ)(第3章の比視感度曲線)で重み付けした物です。
換算係数は、目の感度が最も高い555 nmで683 lm/Wです:

放射量 測光量 単位
放射束 光束 ルーメン(lm)
放射強度 光度 カンデラ(cd = lm/sr)
放射照度 照度 ルクス(lx = lm/m²)
放射輝度 輝度 cd/m²(ニトとも)

計算例。 800 lmとして売られている電球が均等に光を放つなら、光度は800/(4π)=63.66 cdで、其の2 m下の机は63.66/4=15.9ルクスを受けます。
比較すると、オフィスは大体500ルクス程度で照らされ、真夏の直射日光は10万ルクスのオーダーです。
sRGB規格はディスプレイの白を80 cd/m²と想定していて、HDRディスプレイは執筆時点で1,000ニト以上に達します。
此の桁違いの比がある為、物理ベースのレンダラーは浮動小数点のHDRで計算し、最後に露出とトーンマッピングを必要とします(第15章、詳しくは第27章)。
エンジンによってはアーティストが光源をルーメン、カンデラ、ルクスで直接入力出来ます。
シェーディングの数式は同じで、光源の色の単位が変わるだけです。

22.2 物理的なBRDFが満たすべき事

第12章では、物理的なBRDF f(𝐥,𝐯)の3つの性質を挙げました(此処からは、入射方向を光源へ向かう𝐥、出射方向を目へ向かう𝐯と書きます。どちらも表面から外へ向かう単位ベクトルです):

  • 非負:f≥0。
  • 相反性:f(𝐥,𝐯)=f(𝐯,𝐥)。
  • エネルギー保存:全ての入射方向について、方向アルベドが1以下:

E(𝐥)=∫Ωf(𝐥,𝐯)cosθvdωv≤1

E(𝐥)は、𝐥から届いた光のうち、どの方向であれ表面から出て行く割合です。
此の3つの決まりは、どんなシェーディングモデルにも手計算や数値計算で掛けられる検査です。
3つ目をレンダラー全体で確かめるのが、第12章のホワイトファーネステストです:白い物体(アルベド1、吸収無し)を放射輝度1の一様な環境に置くと、受け取った分を丁度反射するので、見えなくならなければなりません。

ランバートは合格

ランバート面のBRDF f=ρ/π(第12章12.3節)では:

E=ρπ∫Ωcosθdω=ρπ⋅π=ρ≤1

正の値で、明らかに相反的で(方向に全く依存しません)、ρ=1ならホワイトファーネステストに丁度合格します。

フォンは不合格

第10章のフォンのモデルは、光源ごとにkd(𝐧⋅𝐥)+ks(𝐫⋅𝐯)αに光源の色を掛けます。
「BRDF × 放射照度」と読むと、光源の放射照度はE⊥(𝐧⋅𝐥)なので、鏡面反射の部分は次のBRDFに相当します:

fs=ks(𝐫⋅𝐯)α𝐧⋅𝐥

(此処では第10章のフォンの指数αを使っています。22.3節からは、αはマイクロファセットの粗さを意味します。)
相反性が成り立ちません:𝐫⋅𝐯は対称(𝐥を鏡映して𝐯と内積を取るのも、𝐯を鏡映して𝐥と内積を取るのも同じ)ですが、分母は𝐧⋅𝐯ではなく𝐧⋅𝐥で、すれすれの光では発散さえします。
普通の修正は、割り算を落とした「修正」フォンのBRDF fs=ks(𝐫⋅𝐯)αです。
エネルギーが指数に依存します。 法線に沿って届く光では𝐫=𝐧なので𝐫⋅𝐯=cosθvで、修正フォンのローブのアルベドは:

E=ks∫Ωcosαθcosθdω=ks⋅2π∫0π/2cosα+1θsinθdθ=ks2πα+2

指数 α ローブのアルベド ks=0.5の時
1 2.094ks 1.047(入った以上の光が出る)
10 0.5236ks 0.262
100 0.0616ks 0.031

一見無難なks=0.5でも、広いローブはエネルギーを生み出し、鋭いローブは殆ど全てを失います。
此れが第10章の「指数を大きくするとハイライトは小さくなるが明るくはならない」と言う観察を数値にした物です。
本物の磨かれた表面は同じ総量をより小さなローブに反射するので、ピークは明るくならなければなりません。
直し方は正規化係数です:fs=ksα+22π(𝐫⋅𝐯)αは、指数に関係無く垂直入射でのアルベドが丁度ksになります(α=10でα+22π=1.910、α=100で16.23)。
其れでもkd+ksは1を超え得ますし、フレネル効果は無く、物理的な表面の様にハイライトの大きさと強さを結び付ける物も有りません。
正規化したブリン・フォン(係数は約α+88π)は、マイクロファセットモデルが主流になる前の中間段階として人気がありました。

22.3 マイクロファセット理論

考え方

粗い表面は小さなファセットが並んだ地形で、其の1つ1つが完全な鏡です(第12章12.3節)。
𝐥からの光が𝐯の目に届くのは、法線がハーフベクトル

𝐡=𝐥+𝐯‖𝐥+𝐯‖

を向いたファセットを通る時だけで、しかも光源と目のどちらも他のファセットに遮られていない時だけです:

拡大した粗い表面の断面。左上にl、v、其のハーフベクトルh、巨視的な法線nを描いてあり、hはnから10度傾いている。法線がhと等しいファセットは色付きで、lからの光をvへ反射する物は黄色、隣の山が光を遮る物は橙色、山が目から隠す物はピンク。其の他のファセットは灰色

マイクロファセット理論は此の絵を、3つの要素でBRDFにします:

  • 法線分布関数(NDF)D(𝐡):𝐡を向くファセットがどれだけあるか。
  • マスキング・シャドウイング関数(幾何減衰項)G(𝐥,𝐯):其のうち照らされていて、且つ見えている割合。
  • フレネル項 F(𝐯⋅𝐡):1つのファセットが自分の入射角でどれだけ鏡の様に反射するか(第12章12.4節)。

ファセットは光の波長より十分大きく(幾何光学が使える)、画素より十分小さい(統計だけを気にすれば良い)と仮定します。

クック・トランスの式の導出

Robert CookとKenneth Torrance(1982年)は、此れらを第12章の式にまとめました:

fs(𝐥,𝐯)=D(𝐡)G(𝐥,𝐯)F(𝐯⋅𝐡)4(𝐧⋅𝐥)(𝐧⋅𝐯)

4と2つの余弦が何処から来るのかを見ましょう。
先ずDの正確な意味です:面積dAの表面の欠片で、法線が𝐡の周りの小さな立体角dωhに入るファセットの総面積はD(𝐡)dωhdAです。
巨視的な表面に投影すると、各ファセットは自分の面積 × 𝐧⋅𝐡を覆い、全てのファセットを合わせると丁度dAを覆います。
此処から、全てのNDFが満たすべき正規化が出てきます:

∫ΩD(𝐡)(𝐧⋅𝐡)dωh=1

では光を1歩ずつ追いましょう。

  1. 放射輝度Liの光が𝐥の周りの小さな立体角dωlから届きます。𝐡を向いたファセットは其れを角度𝐥⋅𝐡で受けるので、受け取るパワーはLidωl(𝐥⋅𝐡)D(𝐡)dωhdAです。
  2. 其の割合Fが鏡面反射され、更に其の割合Gが影にも隠れにもなりません。
  3. 反射された光は𝐯の周りの立体角dωoへ出て行きます。鏡を或る角度だけ傾けると、反射光は其の2倍の角度だけ回るので、反射方向はファセットの法線より4倍(2次元の其々で2倍)広く広がります。正確な関係はdωh=dωo/(4𝐯⋅𝐡)です。
  4. 出て行く放射輝度は、投影面積dA(𝐧⋅𝐯)あたり、立体角dωoあたりのパワーです。

まとめると、𝐥⋅𝐡=𝐯⋅𝐡(「ハーフベクトル」とはそう言う意味です)を使って:

Lo=FGLidωl(𝐥⋅𝐡)Ddωo4(𝐯⋅𝐡)dAdA(𝐧⋅𝐯)dωo=DGF4(𝐧⋅𝐯)Lidωl

BRDFは入射する放射照度Li(𝐧⋅𝐥)dωlあたりの出て行く放射輝度なので、割ると丁度クック・トランスの式になります。
Gが対称である限り式は𝐥と𝐯について対称なので、相反性は自動的に満たされます。

D:ベックマン、GGX、ブリン・フォン

𝐧と𝐡の角度をθh、分布の粗さのパラメータをα(小さい程滑らか)と書きます。
知っておくべき分布は3つです:

DBeckmann=exp(−tan2θh/α2)πα2cos4θh,DGGX=α2π((𝐧⋅𝐡)2(α2−1)+1)2,DBP=n+22π(𝐧⋅𝐡)n

  • ベックマン分布は、粗い表面の光学(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章の(𝐧⋅𝐡)nに係数n+22πを付けると正しく正規化された分布になり、n≈2/α2−2とすると粗さαのベックマンに似た形になります(ウォルターらが此の対応を示しています)。ブリン・フォンが良いモデルだった本当の理由は此処にあります。

GGXの正規化の確認は3行で済みます。
c=cosθh、dω=sinθdθdϕとし、u=c2と置換すると(du=−2csinθdθ):

∫ΩDcdω=2π∫0π/2α2csinθπ(c2(α2−1)+1)2dθ=∫01α2(u(α2−1)+1)2du=α2α2−1(1−1α2)=1

22.4節のC++のプログラムは此れを3つの粗さで数値的に確かめます。
ベックマンと正規化したブリン・フォンも同じ検査に合格します(Pythonでも確かめました)。

計算例。 θh=0ではGGXもベックマンも最大値1/(πα2)を取り、α=0.25なら1/(π⋅0.0625)=5.093です。
ピークから離れると違いが出ます:

θh GGX、α=0.25 ベックマン、α=0.25
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の値を手で計算してみましょう:cos230°=0.75なので括弧の中は0.75⋅(0.0625−1)+1=0.296875、其の2乗は0.088135、そしてD=0.0625/(π⋅0.088135)=0.2257です。
ベックマンのガウス分布は崖から落ちる様に減りますが、GGXは長い裾を保ちます:45°では約3万倍大きいです。

シータhに対するDを対数目盛で0度から75度まで、アルファ0.0625、0.25、0.5625について描いた物。GGXは実線、ベックマンは破線。ピークは同じで、ベックマンはピーク付近で少し広いが急に落ち、GGXは長い裾を保つ

其の裾は本物の材質で見える物です:鋭いハイライトが柔らかい光に囲まれています(ランプの下のクロムの蛇口や車のクリアコートを見て下さい)。
測定した材質にはGGXの方が良く合う事が多く、其れがベックマンに取って代わった理由の1つです(ウォルターらは幾つかの粗いガラスの試料で此れを示し、後で触れるBurley 2012のディズニーの測定も同じ方向を指しました)。
裾を更に長く又は短く調整出来る「一般化」版(GTR、スチューデントのt分布)もありますが、此処では名前だけにします。

ラフネスの再写像

式の中のαは、アーティストが入力する値ではありません。
Brent Burley(ディズニー、「Physically-Based Shading at Disney」、SIGGRAPH 2012)は、α其の物のスライダーでは面白い材質が全て下の端に詰まってしまう事を見つけました。
そして、知覚的ラフネスrを

α=r2

で使うと、見た目の変化が均等に広がる事を示しました。
Unreal Engine 4(Karis 2013)とglTF 2.0も同じ再写像を採用しています。
「ラフネス0.5」と言えばr=0.5、α=0.25の事です:

ラフネス r α=r2 GGXのピーク 1/(πα2)
0.25 0.0625 81.49
0.5 0.25 5.093
0.75 0.5625 1.006
1 1 0.3183

r=1ではGGXは定数D=1/πになります:ファセットの法線は(投影面積で数えて)全ての方向を同じ頻度で向きます。
r=0では1つの方向に潰れて完全な鏡になり、点光源は其れに丁度当たる事が出来ません。
其の為、リアルタイムのシェーダーはラフネスを小さな最小値で制限します(OpenGLシリーズは0.03を使います)。

G:スミスのマスキングとシャドウイング

Bruce Smith(1967年)は、粗い表面による電波の散乱の研究で、ランダムな表面上の点が或る方向から見える確率を計算しました。
グラフィックスで採用された其の考え方は、表面の高さと傾きが点ごとに相関しないと仮定する事で、此れによってマスキングはNDFで決まる方向の関数Λ(𝐯)1つで表せます。
𝐯から見えるファセットの割合は:

G1(𝐯)=11+Λ(𝐯),ΛGGX(𝐯)=−1+1+α2tan2θv2

Eric Heitz(「Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs」、JCGT 2014)は、マスキング(目の方向)とシャドウイング(光源の方向)の組み合わせ方を整理しました:

  • 分離型:G2=G1(𝐥)G1(𝐯)。照らされる事と見える事が独立な事象であるかの様に扱います。
  • 高さ相関:G2=11+Λ(𝐥)+Λ(𝐯)。谷の底のファセットは影にも隠れにもなり易く、山頂のファセットはどちらにもなり難い。此の形は其れを考慮していて、より正確です。(1+a)(1+b)=1+a+b+ab≥1+a+bなので、常に分離型より少し大きくなります。

此れもハイツによる便利な検査です:どの視線方向でも、見えているファセットの投影面積は巨視的な表面の投影面積に等しくなければなりません:

∫ΩG1(𝐯)max(𝐯⋅𝐡,0)D(𝐡)dωh=𝐧⋅𝐯

(「弱いホワイトファーネステスト」)。
此のΛを使ったGGXが、α = 0.25、0.5、1、𝐧⋅𝐯 = 1と0.5で此れを5桁まで満たす事を数値的に確かめました。

Λには平方根と正接が要るので、リアルタイムのコードではシュリックの近似 G1(x)≈xx(1−k)+k(x=𝐧⋅𝐯又は𝐧⋅𝐥)が良く使われます。
k=α/2とすると、α=1ではスミスのGGXと完全に一致し(どちらも2x/(1+x)になります)、其れ以外では近似になります:

𝐧⋅𝐯 スミス厳密、α=0.25 シュリック、k=0.125 スミス厳密、α=1
0.8 0.9914 0.9697 0.8889
0.6 0.9737 0.9231 0.7500
0.2 0.7749 0.6667 0.3333

左:法線との角度に対するG1。ラフネス0.5と1について、厳密なスミスを実線、k = アルファ/2のシュリックを破線で描いた物。ラフネス1では2つが重なる。どちらも急な角度までは1に近く、90度で0に落ちる。右:シュリックのフレネル。F0が0.04の非金属、F0が0.172のダイヤモンド、そして1、0.766、0.336から始まる金の赤・緑・青のチャンネル。全て90度で1になる

Gが最も効くのはすれすれの角度と粗い表面で、分母の1/(𝐧⋅𝐯)が発散するのを抑えます。
便利な工夫として、G2と分母は普通可視項 V=G2/(4(𝐧⋅𝐥)(𝐧⋅𝐯))としてまとめて計算します。
高さ相関のGGXでは、少し式変形すると(tan2θ=(1−x2)/x2でΛを書き直します):

V=0.5(𝐧⋅𝐯)(𝐧⋅𝐥)2(1−α2)+α2+(𝐧⋅𝐥)(𝐧⋅𝐯)2(1−α2)+α2

となり、0になり得る余弦での割り算が有りません。
22.4節のシェーダーは此の形を使います。
Karis(Unreal Engine 4、2013年)は、点光源にはシュリックの形でk=(r+1)2/8(粗い表面がすれすれの角度で明る過ぎない様にする意図的な再写像)、イメージベーストライティングにはk=α/2を使いました。
OpenGLシリーズは其れに従っているので、両方を見掛けても驚かないで下さい。

F:ハーフベクトルで計算するフレネル

各ファセットは鏡なので、第12章のフレネルの割合を自分の入射角で反射します。
其の角度は𝐥(又は𝐯)とファセットの法線𝐡の角度で、𝐧との角度ではありません:

F=F0+(1−F0)(1−𝐯⋅𝐡)5

垂直入射での反射率F0は、鏡面反射の項の唯一の材質定数です:

材質 F0(リニア) 備考
水 0.02 n=1.33
ガラス、プラスチック、殆どの誘電体 0.04 n=1.5
ダイヤモンド 0.17 n=2.42
金 (1.0, 0.766, 0.336) 色付き
銅 (0.955, 0.638, 0.538) 色付き
銀、アルミニウム 全チャンネルで約0.91〜0.99 殆ど白

誘電体の値は第12章のF0=((n−1)/(n+1))2から来ます。
逆に解くとn=(1+F0)/(1−F0)なので、典型的な範囲0.02〜0.05はnが1.33〜1.58である事を意味します。
金属は正面から50〜100%を反射し、其のF0は波長に依存します。
其れが金属の色です。
公開されている表は数パーセント異なります(金の緑チャンネルは測定によって約0.71〜0.77と幅があります)。
此処ではOpenGLシリーズの値を使います。

ローブ

45°で入射する光について、鏡面反射のBRDF(F=1)を、入射面内の各出射方向でのfcosθo、つまり其の方向へ向かう反射光の割合として描いた物です:

45度で入射する光に対する2つの鏡面反射のローブ。ラフネス0.3では鏡の方向に沿った細い棘で、最大値は13.84。ラフネス0.7では広いローブで最大値は0.42しかなく、少し法線側に傾いている。各ローブは同じ高さに拡大して描いてある

粗いローブはピークが33分の1ですが遥かに広いので、合計は同じ位です。
此れが正規化の働きです。
其のピークは42°にあり、少し法線側です。
cosθoの因子とマスキングが、すれすれ側を削るからです。
BRDFの値f其の物は逆の振る舞いをします:すれすれの方向に向かって大きくなります(1/(𝐧⋅𝐯)とフレネルが勝つ為です)。
粗い表面がすれすれの角度で明るい反射を見せるのは此の為で、TorranceとSparrowが1967年に本物の材質について記述した「オフスペキュラーピーク」です。

検定のポイント

第10章の反射モデルと第12章のBRDFに繋がる点です:

  • マイクロファセットのBRDF:f=DGF/(4(𝐧⋅𝐥)(𝐧⋅𝐯))。D = 𝐡を向くファセットの量(法線分布)、G = 影にも隠れにもならない割合(幾何減衰)、F = 1つのファセットのフレネル反射率で、𝐯と𝐡の角度で計算する。
  • NDFは∫Ddω=1ではなく、∫D(𝐧⋅𝐡)dω=1(投影面積)で正規化される。
  • 細いハイライトは明るくなければならない:正規化したローブはエネルギーを保存し、フォンの正規化していないローブは保存しない。
  • フォンの鏡面反射の項にはフレネル効果が無く、BRDFとして見ると相反的でない。

22.4 1つの光源を完全に計算する

1つの点で全てを計算してみましょう。
比べられる様に、第10章の計算例の幾何を使います:

  • 𝐧=(0,1,0)、𝐥=(0,0.6,0.8)、𝐯=(0,0.8,−0.6)。
  • 放射強度I=50 W/srの点光源が距離d=5に。
  • 材質:ベースカラー𝐛=(0.8,0.4,0.2)(橙色)、メタリックm=0、ラフネスr=0.5。メタリックのパラメータと、F0や拡散の部分の決まりは22.5節で説明します。誘電体ではF0=0.04、𝐤d=(1−F)になります。

ステップ1:内積。
第10章で𝐥+𝐯=(0,1.4,0.2)、長さ2が出ているので、𝐡=(0,0.98995,0.14142)です。

𝐧⋅𝐥=0.6,𝐧⋅𝐯=0.8,𝐧⋅𝐡=0.98995(θh=8.13°),𝐯⋅𝐡=0.8⋅0.98995−0.6⋅0.14142=0.70711

つまり関係するファセットには、光が45°(cos45°=0.70711)で当たります。

ステップ2:D。 α=0.52=0.25、α2=0.0625で、(𝐧⋅𝐡)2=1.96/2=0.98は丁度です:

D=0.0625π(0.98⋅(0.0625−1)+1)2=0.0625π⋅0.081252=0.06250.020739=3.0136

(対応するn=2/0.0625−2=30のブリン・フォンのNDFでは、此処で322π⋅0.9815=3.76です。ピークは同じ5.093で、形が少し違います。)

ステップ3:G。 tan2θl=(1−0.36)/0.36=1.7778、tan2θv=0.36/0.64=0.5625:

Λ(𝐥)=−1+1+0.0625⋅1.77782=−1+1.054092=0.027046,Λ(𝐯)=−1+1.0351562=0.008713
G2=11+0.027046+0.008713=0.96548

分離型では0.97367⋅0.99136=0.96526で、殆ど同じです。
どちらの角度もすれすれから遠いからです。
カリスのk=(0.5+1)2/8=0.28125では0.60.6⋅0.71875+0.28125⋅0.80.8⋅0.71875+0.28125=0.84211⋅0.93431=0.78678で、点光源向けの意図通り、目に見えて暗くなります。

ステップ4:F。 (1−0.70711)5=0.292895=0.0021555:

F=0.04+0.96⋅0.0021555=0.042069

ステップ5:鏡面反射のBRDF。

fs=DG24(𝐧⋅𝐥)(𝐧⋅𝐯)F=3.0136⋅0.965484⋅0.6⋅0.8F=2.909551.92F=1.51539⋅0.042069=0.063751

3つのチャンネル全てで同じです:誘電体のハイライトは白です。

ステップ6:拡散反射のBRDF。 表面で反射されなかった光1−F=0.957931が中に入り、拡散して出て来ます:

fd=(1−F)𝐛π=0.957931⋅(0.8,0.4,0.2)3.14159=(0.243935,0.121968,0.060984)

ステップ7:出て行く放射輝度。 放射照度はE=Id2(𝐧⋅𝐥)=5025⋅0.6=1.2 W/m²なので:

f=fd+fs=(0.307686,0.185719,0.124735),Lo=fE=(0.36922,0.22286,0.14968) W/(m2 sr)

同じ点を金で。 𝐛=(1.0,0.766,0.336)、m=1にすると、ベースカラーがF0になり、拡散の部分は消えて:

F=(1.0,0.76650,0.33743),f=1.51539F=(1.51539,1.16155,0.51134),Lo=(1.81846,1.39386,0.61361)

f>1でも問題ありません:BRDFは1ステラジアンあたりの密度で、1以下でなければならないのは其の積分(アルベド)だけです。
同じ幾何での第10章のフォンの結果と比べると、誘電体のハイライトは拡散色に対して遥かに弱く(0.064対0.244で約4分の1。第10章のフォンでは0.332対0.48で約3分の2でした)、代わりにすれすれの角度ではフレネルによって強くなります。
フォンでは決して起きなかった事です。

C++では

式を小さなプログラムにした物です。
線型代数シリーズのlinalg.hhのVec3、dot、normalizeを使います。
Dの正規化を数値的に(θの輪についての中点和で)確かめ、上の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節の可視項Vを使って同じ物を書き、光源は其れを向いた面に届ける放射照度(E⊥、点光源ならI/d2)として渡します:

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;
}

Vが本当にG2/(4(𝐧⋅𝐥)(𝐧⋅𝐯))になっているかを、計算例の数値(𝐧⋅𝐥=0.6、𝐧⋅𝐯=0.8、α2=0.0625なので1−α2=0.9375)で手早く確かめます:

0.64⋅0.9375+0.0625=0.6625=0.813941,0.36⋅0.9375+0.0625=0.4=0.632456
V=0.50.6⋅0.813941+0.8⋅0.632456=0.50.488365+0.505964=0.50.994329=0.50285=0.965481.92

OpenGLシリーズは此の関数の変種(シュリックのGを使う物)を第24章で、第22章の法線マップと一緒に実装します。

22.5 メタリック・ラフネスワークフロー

2種類の物質

ファセットが鏡面反射しなかった光(1−F)がどうなるかで、全ての材質は2つに分かれます:

  • 誘電体(非金属:プラスチック、木、石、塗料、肌、水)は数パーセントしか鏡面反射せず、其の色は付きません(F0≈0.04)。残りは中に入って顔料に散乱され、吸収されなかった色を帯びて全ての方向に出て来ます。此れが拡散反射で、其の色をアルベドと呼びます。
  • 金属(導体)は50〜100%を鏡面反射し、F0に色が付きます。中に入った光は自由電子によってナノメートルの深さで吸収されるので、金属には拡散反射が全く有りません。

つまり原理的には、材質には2つの色が要ります:拡散色とF0です。
しかし本物の材質では、両方が「自由」になる事はありません:誘電体のF0は殆ど決まった灰色で、金属には拡散色が有りません。

パラメータ

メタリック・ラフネスワークフローは、バーリーのディズニーのモデル(2012年)とUnreal Engine 4(2013年)が広め、glTF 2.0が標準化した物で、此の事実を3つの主なパラメータで利用します:

  • ベースカラー 𝐛:誘電体ならアルベド、金属ならF0。
  • メタリック(金属度)m:0から1。
  • ラフネス(粗さ)r:0から1で、α=r2。

此れらから:

𝐅0=lerp(0.04,𝐛,m)=0.04(1−m)+𝐛m,𝐜diff=𝐛(1−m)

そしてBRDFは22.4節の物です:

f=(1−𝐅)𝐜diffπ+DG𝐅4(𝐧⋅𝐥)(𝐧⋅𝐯)

glTFの仕様(付録B)は同じ物を混合として書いています:F0=0.04の誘電体のBRDF mix(diffuse, specular, F)、ベースカラーをF0としてフレネルに使う金属のBRDF、そして其の間のmix(dielectric, metal, metallic)です。
展開すると上の式になります。
其の参考実装はDにGGXを使い、可視項を光源側の因子と視点側の因子の積(分離型のスミスのGGX)として書いていて、実装によって違ってよいと明記しています。

𝐛=(0.8,0.4,0.2)での計算例:

メタリック m 𝐅0 拡散色 𝐛(1−m) 何か
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節のイメージベーストライティングで)、金のベースカラーについて空間全体をレンダリングした物です:

ベースカラー1.0、0.766、0.336の25個の球の格子。列はラフネス0.05、0.25、0.5、0.75、1。行はメタリック0、0.25、0.5、0.75、1。一番上の行は淡い黄色のプラスチックで、白い太陽のハイライトがラフネスと共に大きく淡くなり、滑らかな球の縁には地平線がうっすら映る。一番下の行は金で、拡散光は無く、空・地平線・太陽の映り込みが黄色く色付く。滑らかな金の球は地平線をくっきり映し、粗い球は柔らかい金色の玉になる

見るべき所:一番上の行ではハイライトが白く、球の色は拡散の項から来ています。
滑らかなプラスチックの球は、フレネルが上がる縁でだけ地平線を映します。
一番下の行では映り込み自体が金色で、拡散の陰影は全く有りません。
粗い金の球が其れでも金属に見えるのは、其の「拡散の様な」光が、実はとてもぼやけた金色の映り込みだからです。
列を下に辿ると、拡散光が消えて映り込みが取って代わります。

テクスチャ

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)、そしてグロッシネスg(普通g=1−r)です。
メタリック・ラフネスからの変換は直接出来ます:

𝐜diff=𝐛(1−m),𝐜spec=lerp(0.04,𝐛,m),g=1−r

金(𝐛=(1.0,0.766,0.336)、m=1、r=0.3)は、拡散色(0, 0, 0)、スペキュラー色(1.0, 0.766, 0.336)、グロッシネス0.7になります。
逆方向はいつも出来る訳ではありません:拡散色(0.5, 0.5, 0.5)とスペキュラー色(0.2, 0.2, 0.2)は、4%の誘電体でも拡散色が黒い金属でもありません。
其の自由度がスペキュラーワークフローの利点(F0=0.17の宝石や其の他の珍しい誘電体)でもあり、危険(拡散0.9とスペキュラー0.9でエネルギーが生まれる)でもあります。
又、メタリック・ラフネスなら1チャンネルで済む所に、RGBのスペキュラーテクスチャが要ります。
glTFの其の為の拡張KHR_materials_pbrSpecularGlossinessは、2021年にKhronosによってアーカイブされました(読み込みには使えますが、新しいファイルには推奨されません)。
代わりにKHR_materials_iorとKHR_materials_specularの拡張が、メタリック・ラフネスの材質で誘電体のF0を調整出来る様にしています。

何故第10章のモデルより優れているのか

第10章のフォンのパラメータka,kd,ks,αと比べてみましょう:

  • エネルギー:(1−F)が拡散と鏡面を結び付け、正規化されたDがハイライトの幅と高さを結び付けます。アーティストが暗闇で光る材質を作ってしまう事は出来ません。
  • フレネルが組み込まれているので、どの材質もすれすれの角度で反射が明るくなります。第10章のレンダリングがプラスチックの様に見えた主な原因は此れでした。
  • 少数で意味のあるパラメータ:ラフネスは太陽の下でも洞窟の中でも環境の映り込みでも同じ意味なので、材質をシーン、ツール、エンジンの間で共有出来ます(glTFは其の為の物です)。
  • 環境光は独立した概念として消えます:環境も同じBRDFを通して照らします(次の節)。

22.6 PBRでのイメージベーストライティング

第12章(12.13節)では、HDRの環境マップによるイメージベーストライティングを紹介し、一様な空の中の白いランバート面の球が丁度空の放射輝度を示す事を見ました。
本物の環境と完全なBRDFでは、各画素が毎フレーム、半球全体について次を計算しなければなりません:

Lo(𝐯)=∫Ωf(𝐥,𝐯)Li(𝐥)(𝐧⋅𝐥)dωl

リアルタイムのレンダラーは、2つの項について別々に、出来るだけ多くを事前計算します。

拡散:放射照度と球面調和関数

拡散の項は定数 × 放射照度です:

Ld=𝐜diffπ∫ΩLi(𝐥)(𝐧⋅𝐥)dωl=𝐜diffπE(𝐧)

E(𝐧)は法線だけに依存するので、𝐧で引く小さなキューブマップ、放射照度マップとして保存出来ます。
更に小さく出来ます:クランプした余弦との積分は強いぼかしで、細部を全て消すので、少しの数で足ります。
Ravi RamamoorthiとPat Hanrahan(「An Efficient Representation for Irradiance Environment Maps」、SIGGRAPH 2001)は、色チャンネルごとに9個の球面調和関数(SH)の係数で十分な事を示しました。
SHは、球面上の関数にとって、1次元の信号にとっての正弦波の様な物です。
周波数の高くなるバンドl=0,1,2,…にまとめられ(バンドごとに2l+1個の関数。バンド0〜2で1+3+5=9個)、クランプした余弦のぼかしはバンドlを定数A^l倍するだけです:

バンド l 0 1 2 3 4
A^l π=3.1416 2π/3=2.0944 π/4=0.7854 0 −π/24=−0.1309

バンド3は丁度0で、バンド4はバンド0の4%しか無いので、バンド2より上を全て捨ててもほんの少ししか失いません。
(射影其の物と、ゲームでのSHのライトプローブは、第24章で詳しく計算します。)

バンド0と1だけを使った計算例です。
放射輝度が方向の上向き具合だけで決まる空L(𝝎)=a+bωyを、a=0.5、b=0.3で考えます(天頂で0.8、地平線で0.5、真下で0.2)。
定数のaは純粋にバンド0、1次のbωyは純粋にバンド1なので、放射照度は:

E(𝐧)=A^0a+A^1bny=0.5π+0.3⋅2π3ny=1.5708+0.6283ny

法線 E 白い漆喰(ρ=0.8):Ld=ρE/π
上 (0,1,0) 2.1991 0.560
横 (1,0,0) 1.5708 0.400
下 (0,−1,0) 0.9425 0.240

此の3つの値は、空を球面上で数値積分して確かめました。
5桁まで一致します。
22.5節の球の格子は丁度此の方法で、其の空から射影した9個の係数で照らしています。

鏡面:スプリットサム近似

鏡面の項はもっと難しく、𝐯、ラフネス、F0に依存するので、表にするには次元が多過ぎます。
Brian Karis(「Real Shading in Unreal Engine 4」、SIGGRAPH 2013)はスプリットサム近似を提案しました。
積分をN個のサンプルで推定し(モンテカルロ法、第23章)、其の和を其々事前計算出来る2つの因子に分けます:

1N∑kf(𝐥k,𝐯)Li(𝐥k)(𝐧⋅𝐥k)p(𝐥k)≈(∑kLi(𝐥k)(𝐧⋅𝐥k)∑k𝐧⋅𝐥k)⏟プリフィルタ済み環境⋅(1N∑kf(𝐥k,𝐯)(𝐧⋅𝐥k)p(𝐥k))⏟BRDFの積分

  • プリフィルタ済み環境マップは、GGXのローブの形で環境をぼかした物です。ミップマップの各段が増えていくラフネスを持ち、反射方向で引きます。𝐯に依存しない様に、カリスは𝐧=𝐯=𝐫(表面を正面から見ている)と仮定します。其の為、濡れた道路ですれすれの角度に見える長く伸びた映り込みは失われます。此れが此の手法の代償です。
  • BRDFの積分は、白い環境に対する鏡面のローブの方向アルベドです。𝐧⋅𝐯、ラフネス、F0に依存します。シュリックをF=F0(1−Fc)+Fc(Fc=(1−𝐯⋅𝐡)5)と書くとF0を外に出せて、積分はF0A+Bになり、AとBは𝐧⋅𝐯とラフネスだけに依存します。此れが小さな2次元テクスチャ、BRDFルックアップテーブル(BRDF LUT)です。

スプリットサムのBRDFルックアップテーブルを画像にした物。横軸はn・vで0から1、縦軸はラフネスで0から1。赤がA、緑がBを持つ。滑らかな表面を正面から見ると全てを反射するので右下が明るい赤で、粗く又はすれすれになる程暗い赤になる。緑は、フレネルの上昇が集中する、滑らかな表面のn・vが0に近い所にだけある

実行時の鏡面のIBLはprefiltered(r, roughness) * (F0 * A + B)で、テクスチャの参照2回です。
手で出来る確認。 ラフネス0では全てのハーフベクトルが𝐧なので、𝐯⋅𝐡=𝐧⋅𝐯、G=1で、表はA=1−(1−𝐧⋅𝐯)5、B=(1−𝐧⋅𝐯)5を持つ筈です。
するとF0A+Bは丁度シュリックの式です。
𝐧⋅𝐯=1ではA=1、B=0で、強さF0の完全な鏡です。
𝐧⋅𝐯=0.5(60°)ではA=1−0.55=0.96875、B=0.03125で、ガラスなら0.04⋅0.96875+0.03125=0.0700、第12章の60°でのシュリックの値です。
ラフネスが付くと値は下がります。
図の表(OpenGLシリーズと同じく、シュリックのGとk=α/2で計算)では、例えば𝐧⋅𝐯=0.5、r=0.5でA=0.729、B=0.019なので、其処でガラスは白い環境の0.04⋅0.729+0.019=0.048を反射します。
和を効率良く計算する方法(GGXの重点的サンプリング)は第23章の内容で、OpenGLシリーズは第24章で3つのテクスチャ全てを作ります。

単散乱で失われるエネルギー

鏡面のローブだけにホワイトファーネステストを掛けてみましょう:F0=1の金属(完全な鏡の材質)を一様な白い環境に置きます。
其の方向アルベドはF=1でのA+Bで、1になる筈です。
なりません:

ラフネス r 0.25 0.5 0.75 1
𝐧⋅𝐯=1でのアルベド 0.996 0.916 0.627 0.307

r=1では閉じた式さえあります:D=1/π、G1(x)=2x/(1+x)で、𝐧⋅𝐯=1でのアルベドは14π∫ΩG1dω=1−ln2=0.3069です。
光の70%が消えます。
何処へ行くのでしょうか?
此のモデルは1回だけ鏡面反射された光を数えます。
ファセットに当たり、隣のファセットへ反射され、2回以上跳ね返ってから出て行く光は、Gによって単に捨てられます。
滑らかな表面では無視出来ますが、粗い金属では目に見えて暗くなり過ぎます:

一様な灰色の環境の中に、F0が1の金属の球を5個ずつ2行、ラフネス0.2から1で並べた物。上の行(単散乱のみ)では、滑らかな球は見えないが、粗い球程暗くなり、一番粗い球の中心は背景の約3分の1。下の行(エネルギー補償あり)では、5個の球全てが背景に完全に溶け込み、細い輪郭線だけが位置を示す

Christopher KullaとAlejandro Conty Estevez(ソニー・ピクチャーズ・イメージワークス、SIGGRAPH 2017)は、失われたエネルギー1−E(𝐯)を戻す2つ目のローブを加えました。
リアルタイムのエンジンは同じ考えの安価な形、鏡面の項に掛ける倍率を使います(Emmanuel Turquin、2019年):

fms=fs(1+F01−E(𝐯)E(𝐯))

E(𝐯)はF=1でのアルベドで、LUTのA+Bです。
F0=1ならアルベドはE⋅(1+(1−E)/E)=1になり、ファーネステストに合格します(下の行)。
r=1、𝐧⋅𝐯=1では、倍率は完全な金属で1+0.6931/0.3069=3.26ですが、誘電体では1+0.04⋅2.259=1.09だけです。
誘電体のファセットは、跳ね返る度に殆どの光を表面の中へ失うからです。

22.7 更なる層

基本のモデルで殆どの不透明な材質を表せます。
実際のアセットには幾つかの追加のローブが要ります。
glTFは其れらを拡張として定義し、バーリーのディズニーのモデルはパラメータとして持ち、エンジンは似た組み合わせを実装しています。

  • クリアコート:下地の上の薄い透明なニス(車の塗装、漆塗りの木、カーボンファイバー)。誘電体のF0=0.04に固定され、独自のラフネスを持つ2つ目の鏡面のローブです。下の層は、コートが反射した分だけ、大体(1−clearcoat⋅Fc)倍に暗くなります。glTFではKHR_materials_clearcoat。
  • シーン:表面から繊維が立っているベルベット等の布は、光をすれすれの角度へ散乱し、柔らかく明るい縁を作ります。逆さにした様な分布を使います(Conty EstevezとKullaの2017年の「Charlie」シーンが一例です)。glTFではKHR_materials_sheen。
  • 異方性:ヘアライン加工の金属、髪、サテンのハイライトは一方向に伸びます。GGXの分布に、接線𝐭と従接線𝐛(第11章の接空間)に沿った2つの粗さを持たせます:D=1παtαb((𝐭⋅𝐡)2/αt2+(𝐛⋅𝐡)2/αb2+(𝐧⋅𝐡)2)2。αt=αbなら普通のGGXに戻ります(αt=0.2,αb=0.6で正規化を数値的に確かめました)。glTFではKHR_materials_anisotropy。
  • 表面下散乱と透過:第12章(12.6節)のBSSRDFです。リアルタイムのエンジンは、肌の上でぼかした拡散光、回り込みライティング、事前計算したプロファイル等で近似し、映画のレンダラーはレイで追います。glTFには薄い透明物と厚い透明物の為のKHR_materials_transmissionとKHR_materials_volumeがあります。ボリューム其の物は第28章で扱います。
  • 粗い拡散面:ランバートは滑らかな艶消しの面には理想的ですが、粗い面(粘土、月)は平たく見え、すれすれの角度で明るくなります。バーリーの拡散の項はランバートに(1+(FD90−1)(1−cosθl)5)(1+(FD90−1)(1−cosθv)5)を掛けます。FD90=0.5+2rcos2θdで、θdは𝐥と𝐡の角度です。r=1で光源と目が一緒に法線から80°にある時(θd=0、FD90=2.5)倍率は2.49で明るい再帰反射に、r=0では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節)でリアルタイムの近似を約束しました。
此処で見ていきます。

正確な答えは、光源の立体角ΩLに限ったレンダリング方程式です:

Lo=∫ΩLf(𝐥,𝐯)Le(𝐧⋅𝐥)dωl

オフラインのレンダラーは此れをサンプリングします(第23章)。
リアルタイムには2つの古典的な考え方があります。

代表点

面光源を、其の上の上手く選んだ1点、代表点で置き換え、其の点を普通の点光源としてシェーディングします。
鏡面の項に最適な点は、反射レイに最も近い点です:球の光源なら反射方向が球の中心に最も近付く所、管の光源なら線分上の最も近い点です。
するとハイライトが光源の形になります。
ローブは今や「より大きな光源」を見ているので、広げてエネルギーを正規化し直す必要があります。
カリス(2013年)は、光源の見かけの大きさに応じてαを大きくする事で此れを行います。
球と管には安価で説得力がありますが、大きな長方形ではそれ程でもありません。

多角形の閉じた式と線型変換コサイン

多角形の光源の拡散の項には、ランバート(1760年)以来知られている厳密な閉じた式があります。
シェーディングする点から見た多角形の頂点𝐩1,…,𝐩k(其の点からのベクトル)を正規化して𝐩^iとすると:

1π∫ΩL(𝐧⋅𝐥)dω=12π∑i=1kθi𝐧⋅𝐩^i×𝐩^i+1‖𝐩^i×𝐩^i+1‖,θi=arccos(𝐩^i⋅𝐩^i+1)

(𝐩k+1=𝐩1で、頂点は点から見て反時計回りの順に並べます。)
此の数は第12章のラジオシティの点から多角形への形態係数で、放射照度は其のπLe倍です。

計算例。 1辺2の正方形の光源が、点の真上の高さ1にあります。
𝐧=(0,1,0)、頂点は(±1,1,±1)です:

床の上の点pと上向きの法線n、其の真上の高さ1にある1辺2の正方形の光源。pから4つの頂点へ破線が伸び、隣り合う2つの頂点へのレイの間の角度は70.53度

  • どの頂点も距離3にあります。隣り合う2つ、例えば(1,1,1)と(−1,1,1)は𝐩^i⋅𝐩^i+1=(−1+1+1)/3=1/3なので、θi=arccos(1/3)=70.53°=1.23096 radです。
  • 其の外積は(0,2,2)に比例し(点と其の辺を通る平面)、単位ベクトルは(0,0.70711,0.70711)で、𝐧との内積は0.70711です。
  • 対称性から4つの辺の寄与は同じです:形態係数 =12π⋅4⋅1.23096⋅0.70711=0.55413。

Le=10なら放射照度はE=π⋅10⋅0.55413=17.41 W/m²で、白い漆喰の床(ρ=0.8)はLd=ρLe⋅0.55413=4.433を示します。
(正方形の上で力任せに数値積分しても同じ0.55413になります。)
22.1節の「小さな光源」の近似と比べてみましょう:Le⋅A/d2=10⋅4/1=40 W/m²で、2倍以上多過ぎます。
正方形の殆どの部分は、中心より斜めに、且つ遠くから見えるからです。

鏡面の項については、Eric Heitz、Jonathan Dupuy、Stephen Hill、David Neubelt(「Real-Time Polygonal-Light Shading with Linearly Transformed Cosines」、SIGGRAPH 2016)が見事な技を見つけました。
多角形での積分を今閉じた式で計算した、クランプした余弦の分布を取り、其の全ての方向に3×3の行列𝐌を掛けます(線型変換、線型代数 第8章)。
引き伸ばし、せん断し、拡大縮小すると、与えられた視線角とラフネスでのGGXのローブにとても良く合うローブが作れます。
此れが線型変換コサイン(LTC)です。
変換したローブを多角形で積分するのは、𝐌−1で変換した多角形で普通の余弦を積分するのと同じで、其れは再びランバートの式です。
従って実行時には:(𝐧⋅𝐯、ラフネス)で小さな事前計算の表から𝐌−1を引き、多角形の頂点を変換し、地平線で切り取り、辺の和を計算します。
結果は長方形や其の他の多角形の正確な面光源のライティングで(論文はテクスチャ付きの光源も扱い、後の研究が線分や円盤に広げました)、執筆時点で幾つかのエンジンが使っています。
GLSLシリーズの第10章では、シェーダーでのより簡単な面光源の近似を見せています。

22.9 まとめ

  • 放射輝度L=d2Φ/(dAcosθdω)は投影面積あたりで測る。dω=sinθdθdϕ、半球は2π sr、∫cosθdω=π。ランバート面の発光体はM=πL。測光は同じ量をV(λ)で重み付けした物:ルーメン、カンデラ、ルクス、ニト。
  • 物理的なBRDFは非負、相反的で、方向アルベドが1以下(ホワイトファーネステスト)。ランバート(ρ/π)は合格。フォンの鏡面の項は相反的でなく、アルベドks⋅2π/(α+2)は(α+2)/(2π)で正規化しない限り指数に依存する。
  • マイクロファセットのBRDF:fs=DGF/(4(𝐧⋅𝐥)(𝐧⋅𝐯))。4はdωh=dωo/(4𝐯⋅𝐡)から来る。NDFは∫D(𝐧⋅𝐡)dω=1を満たす。
  • GGX(トローブリッジ・ライツ)D=α2/(π((𝐧⋅𝐡)2(α2−1)+1)2)は長い裾を持つ。ベックマンはガウス型。正規化したブリン・フォンはn≈2/α2−2に対応する。知覚的ラフネス:α=r2。
  • スミス:G1=1/(1+Λ)、高さ相関のG2=1/(1+Λl+Λv)(ハイツ2014)、シュリックの近似はk=α/2(点光源にはカリスの(r+1)2/8)。フレネルは𝐯⋅𝐡とF0(誘電体で0.04、金属は色付き)を使う。
  • メタリック・ラフネス:𝐅0=lerp(0.04,𝐛,m)、拡散は𝐛(1−m)に(1−F)を掛ける。glTFはラフネスをリニアなテクスチャのG、メタリックをBに持つ。スペキュラー・グロッシネスは拡散色とF0の色を別々に持つ。
  • IBL:拡散は放射照度(E(𝐧)、9個のSH係数、バンドの係数π、2π/3、π/4)から。鏡面はスプリットサムで、プリフィルタ済み環境 × BRDF LUTのF0A+B。𝐧=𝐯=𝐫を仮定する。
  • 単散乱のマイクロファセットモデルは粗い表面でエネルギーを失う(r=1を正面から見るとアルベドは1−ln2≈31%)。エネルギー補償はローブを1+F0(1−E)/E倍する。
  • 追加のローブ:クリアコート、シーン、異方性の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 課題

  1. ★ 0.5 m²のランバート面のパネルが合計40 Wを放ちます。其の放射輝度を求めて下さい。次に、パネルが点の方を向き、点の面が45°傾いている時の、3 m離れた点での放射照度を「放射輝度 × 立体角 × 余弦」で見積もって下さい。又、1,200 lmの等方的な電球をカンデラに換算し、其の1.5 m下の照度を求めて下さい。
  2. ★ ラフネスr=0.3について、α、GGXのピークD(0)、θh=15°と30°でのDを求めて下さい。同じαでのベックマンの30°での値と、2つの比も求めて下さい。
  3. ★★ ∫Ωn+22πcosnθcosθdω=1を示し、正規化したブリン・フォンが正しいNDFである事を確かめて下さい。次に、α=0.5のGGXについて、𝐧⋅𝐯=0.5でのG1を厳密に、及びk=α/2のシュリックで求め、𝐧⋅𝐥=𝐧⋅𝐯=0.5での分離型と高さ相関のG2を求めて下さい。
  4. ★★ ベースカラー(0.9, 0.6, 0.3)、メタリック0.25、ラフネス0.4の材質があります。其の𝐅0、拡散色、及び等価なスペキュラー・グロッシネスのパラメータを答えて下さい。次に、F0=0.05に対応する屈折率と、其の誘電体の𝐯⋅𝐡=0.3でのシュリックの反射率を求めて下さい。
  5. ★★★ 放射輝度がL(𝝎)=0.4+0.4ωyの空があります。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次元の断面です(全て平面z=0の中で起きます)。
表面の法線は𝐧=(0,1)、光は左側のθl=40°から来て𝐥=(−sin40°,cos40°)、光源は其れを向いた面にE⊥=3 W/m²を届ける平行光源です。
材質は青いプラスチックで、ベースカラー𝐛=(0.1,0.2,0.6)、メタリック0、ラフネスr=0.6です。

  1. 描く。 表面、𝐧、𝐥を分度器で描き、右側にθv = 20°、40°(鏡の方向)、70°の3つの視線方向𝐯=(sinθv,cosθv)を描きます。
  2. ハーフベクトル。 各視線について𝐡=(𝐥+𝐯)/‖𝐥+𝐯‖を計算して描きます。𝐧⋅𝐥、𝐧⋅𝐯、𝐧⋅𝐡、𝐯⋅𝐡を書き出します。(2次元ではハーフベクトルの角度は2つの符号付きの角度の平均なので、θhを分度器で確かめられます。)
  3. D。 αと、各視線でのGGXの値Dを計算します。
  4. G。 各視線についてΛ(𝐥)とΛ(𝐯)、高さ相関のG2を計算します。比較の為、k=α/2のシュリックの形も計算します。
  5. FとBRDF。 F0=0.04でFを、鏡面の項fs、拡散の項(1−F)𝐛/π、そして出て行く放射輝度Lo=fE⊥(𝐧⋅𝐥)を3つのチャンネル全てで計算します。
  6. 正規化。 自分のαで∫Dcosθhdω=1を、9つの輪の中点和で確かめます:θk=5°,15°,…,85°について、Δθ=10°=0.17453 radとしてD(θk)cosθk⋅2πsinθk⋅Δθを足し合わせます。小さな表を作って下さい。
  7. グラフ。 鏡面の放射輝度(1チャンネル)を3つの点でθvに対して描き、比較の為にフォンの値ks(𝐫⋅𝐯)αP × E⊥(第10章の形で、ks=0.04、指数αP=2/α2−2)も加えます。

自分で確かめる方法:どの𝐡も長さ1で𝐥と𝐯の間にあります。
Dは鏡の方向の視線で最大です(其処では𝐡=𝐧でD=1/(πα2))。
G2は0と1の間でθvが大きくなると減り、シュリックの値は其れより少し小さくなります。
Fは0.04と1の間で、θvが大きくなると増えます。
鏡面の部分は3つのチャンネルで同じ、拡散の部分は青です。
輪の和は1から2%程度以内に収まります(9つの輪は粗いので、18個にすると更に近付きます)。
輪の和が1から大きく外れたら、cosθk(投影面積)を掛けたか、Δθにラジアンを使ったかを確かめて下さい。
最後にグラフを見て下さい:物理ベースのハイライトは、フォンの様に鏡の方向の先で単純に落ちてはいきません。
式のどの因子が其の違いを生むのかを説明して下さい。


コメント(0)

まだコメントはありません。