OpenGLを学びます。 レッスン6.1。 PBRまたは物理的に正しいレンダリング。 理論

OGL3

物理的に正しいレンダリング



PBR、または物理ベースのレンダリングは、光伝搬の実際の理論と非常によく一致する理論に基づいた一連の視覚化技術です。 PBRの目的は物理的に信頼できる光のシミュレーションであるため、以前に使用したPhongおよびBlinn-Fong照明モデルに比べてはるかにリアルに見えます。 見た目が良いだけでなく、実際の物理学に非常に近いので、私たち(特にアーティスト)は、照明をリアルに見せるために安価なトリックに頼ることなく、表面の物理的特性に基づいてマテリアルを作成できます。 このアプローチの主な利点は、作成するマテリアルが照明条件に関係なく計画どおりに見えることです。これは、PBRではなく他のアプローチとは言えません。







内容

パート1.はじめに







  1. Opengl
  2. ウィンドウ作成
  3. こんにちはウィンドウ
  4. こんにちはトライアングル
  5. シェーダー
  6. テクスチャー
  7. 変換
  8. 座標系
  9. カメラ


パート2.基本的な照明







  1. 照明の基本
  2. 素材
  3. テクスチャマップ
  4. 光源
  5. 複数の光源


パート3. 3Dモデルをダウンロードする







  1. Assimpライブラリ
  2. メッシュポリゴンクラス
  3. 3Dモデルクラス


パート4.高度なOpenGL機能







  1. 深度テスト
  2. ステンシルテスト
  3. 色混合
  4. 顔のクリッピング
  5. フレームバッファ
  6. キュービックカード
  7. 高度なデータ処理
  8. 高度なGLSL
  9. 幾何学シェーダー
  10. インスタンス化
  11. スムージング


パート5.高度な照明







  1. 高度な照明。 Blinn-Fongモデル。
  2. ガンマ補正
  3. シャドウカード
  4. 全方向シャドウマップ
  5. 法線マッピング
  6. 視差マッピング
  7. HDR
  8. ブルーム
  9. 遅延レンダリング
  10. SSAO


パート6. PBR







  1. 理論
  2. 分析光源
  3. IBL 拡散照射。
  4. IBL ミラー露出。




ただし、PBRは依然として物理の法則に基づく現実の近似であるため、物理レンダリングではなく物理的に正確なレンダリングと呼ばれています。 照明モデルを物理的に正しく呼び出すためには、3つの条件を満たしている必要があります(心配しないでください、すぐにそれらに到達します)。









このチュートリアルシリーズでは、もともとディズニーで開発され、Epic Gamesによるリアルタイムの視覚化に適応したPBRアプローチに焦点を当てます。 金属-誘電体ワークフロー (Eng。Metallicワークフロー、 より良い翻訳を見つけることができませんでした-約Ed。 )に基づいた彼らのアプローチは、多くの人気のあるエンジンで広く文書化され、広く受け入れられており、驚くほど見えます。 このセクションの最後に、次のようなものが表示されます。







このセクションの記事は非常に高度であるため、OpenGLとシェーダーライティングを十分に理解することをお勧めします。 このセクションを学習するために必要な知識の一部を次に示します。 フレームバッファーキュービックマップガンマ補正HDR、および法線マップ 。 数学についてももう少し詳しく説明しますが、可能な限りすべてを説明するために可能な限りのことをすることを約束します。







反射マイクロファセットのモデル



すべてのPBRテクニックは、マイクロフェイスの理論に基づいています。 この理論によれば、高倍率の各表面は、 マイクロフェースと呼ばれる一連の顕微鏡ミラーとして表現できます。 表面の粗さにより、これらのマイクロミラーは異なる方向に向けることができます。













表面が粗いほど、そのマイクロフェースの向きはランダムになります。 これらの小さなミラーをこのように配置すると、(特に鏡面フレアと反射の場合)入射光線が粗い表面でさまざまな方向に散乱され、鏡面フレアが広くなります。 逆もまた同様です。滑らかな表面では、入射光線が一方向に反射される可能性が高くなり、より小さくシャープなグレアが得られます。













顕微鏡レベルでは、完全に滑らかな表面はありませんが、微小面が十分に小さく、ピクセル空間内でそれらを区別できない場合、 粗さ係数を導入して表面粗さを統計的に近似します。 この係数を使用して、特定のベクトルの方向に向いた微小面の割合を計算できます h 。 このベクトル h 入射光の方向の中間にある中央ベクトルにすぎない l オブザーバーの方向 v 。 これについては、 高度な照明のレッスンで説明しました。ベクトルの合計の比率として定義しました。 l そして v 結果のベクトルの長さ:











h = f r a c l + v | | l + v | | 







中央ベクトルの方向に向いたマイクロフェースが多いほど、鏡面反射ハイライトはよりシャープで明るくなります。 0から1の間にある粗さ係数により、ミクロ面の向きを統計的に近似できます。













ご覧のように、粗さ係数の値を大きくすると、滑らかな表面の小さくて鋭いスポットと比較して、大きなサイズのミラーフレアスポットが得られます。







省エネ。



微小面を考慮に入れた近似を使用すると、すでに特定の形式のエネルギー保存が行われます。反射光のエネルギーは、入射光のエネルギーを超えることはありません(表面が単独で光らない場合)。 上の画像を見ると、表面の粗さが増すと、反射光のスポットは増加しますが、同時に輝度が低下することがわかります。 スポットのサイズに関係なく、反射光の強度がすべてのピクセルで同じである場合、粗い表面はより多くのエネルギーを放出し、エネルギー保存の法則に違反します。 したがって、鏡面反射は滑らかな表面ではより明るく、粗い表面では鈍くなります。







エネルギーを節約するには、拡散成分とミラー成分を明確に分離する必要があります。 その瞬間、光線が表面に到達すると、 反射成分と屈折成分に分割さます。 反射成分は直接反射された光であり、表面を透過しません;私たちはそれを光の鏡の成分として知っています。 屈折成分は、表面に浸透し、表面で吸収される光です。光の拡散成分として知られています。







しかし、光の吸収にはいくつかの微妙な違いがあります。光が表面に触れるとすぐに起こるわけではありません。 物理学の過程から、光は、障害物との衝突の結果としてすべてのエネルギーを失うまで直線的に移動するエネルギーを持つ光子のビームとして説明できることがわかっています。 次の図に示すように、各材料は光線と相互作用できる微粒子で構成されています。 これらの粒子は、衝突のたびに光のエネルギーの一部またはすべてを吸収し、熱に変換します。













一般的な場合、すべてのエネルギーが吸収されるわけではなく、光は(主に)ランダムな方向に散乱し続け、エネルギーがなくなるか、表面から再び出るまで、他の粒子と再び衝突します。 したがって、表面は光線の再放射を開始し、表面の観察された(拡散した)色の形で寄与します。 PBRを使用して、すべての屈折した光は小さな影響領域で吸収および散乱されるという単純な仮定を立て、この領域から離れたところにある表面を離れる散乱光の影響を無視します。 これを考慮に入れた特別なシェーダー技術は、 表面下散乱技術として知られ、革、大理石、ワックスなどの素材の視覚的品質を大幅に向上させますが、パフォーマンスの点では高価です。







光が金属表面で屈折および反射されると、さらなる微妙さが現れます。 金属表面は、 非金属 (つまり誘電体)と光との相互作用が異なります。 それらは、屈折と反射の同じ法則に従いますが、1つの例外があります。屈折した光はすべて、散乱せずに表面に吸収され、鏡面反射光のみが残ります。 つまり、金属表面には拡散色がありません。 この金属と誘電体の明らかな違いにより、PBRコンベヤーでの処理方法が異なり、この記事ではさらに進んでいきます。







反射光と屈折光のこの違いは、エネルギー保存に関するさらに別の観察につながります。それらの値は相互に排他的です。 反射光のエネルギーは材料に吸収されません。 したがって、屈折光の形で表面に吸収されるエネルギーは、反射光を考慮した後の残りのエネルギーです。

この比率を使用するには、最初に反射部分を、表面で反射された入射光線のエネルギーの割合として計算し、次に反射からの屈折光の割合を次のように計算します。







float kS = calculateSpecularComponent(...); // /  float kD = 1.0 - kS; // / 
      
      





このようにして、エネルギー保存の法則により、反射部分と屈折部分の両方の意味を学習します。 このアプローチでは、屈折(拡散)部分も反射部分も1.0を超えず、それらの総エネルギーが入射光エネルギーの値を超えないようにします。これは以前のレッスンでは考慮できませんでした。







反射方程式



上記のことから、いわゆるレンダリング方程式に導かれます。これは非常に賢い人によって発明された複雑な方程式であり、今日では照明をシミュレートするための最良のモデルです。 PBRは、この方程式のより具体的なバージョン( 反射方程式)に厳密に従います。 PBRをよく理解するには、最初に反射方程式を完全に理解することが重要です。











Lop omegao= int limits Omegafrp omegai omegaoLip omegain cdot omegaid omegai







最初は怖いように見えますが、部分的に徐々に分解していきます。 この方程式を理解するには、放射測定をもう少し詳しく調べる必要があります。 放射分析は、電磁放射(可視光を含む)を測定する科学です。 照明を測定するために使用できる放射量はいくつかありますが、エネルギー方程式(英語の放射輝度)と呼ばれ、ここでは文字Lで指定される反射方程式に関連するもののみを使用します。EIは光の強度または強度を定量化するために使用されます。特定の方向から来る。 EJは、いくつかの物理量の組み合わせであるため、想像しやすいように、各物理量に個別に焦点を当てます。







放射束



放射束( \ピ )は、ワットで測定された光透過エネルギーのパワーです。 総光エネルギーは、さまざまな波長の多くの用語で構成されており、それぞれが独自のスペクトル色に対応しています。 この場合、光源から放出されるエネルギーは、これらすべての波長の関数として表すことができます。 390nmから700nmの波長がスペクトルの可視部分を構成します。つまり、この範囲の放射は人間の目で認識できます。 以下の画像では、日光を構成するさまざまな波長のエネルギーの値を見ることができます。













放射束は、すべての波長のこの関数のグラフの下の領域に対応します。 コンピューターグラフィックスの入力として光の波長を直接使用することは実用的ではないため、すべての波長の関数であるRGB(または通常は照明の色と呼ばれる)の3成分の色の関数を使用する代わりに、放射束の簡略化された表現に頼ります。 このような見方は情報のいくらかの損失につながりますが、全体としては最終的な写真にわずかに影響します。







立体角



によって示される立体角 \オ 単位球に投影される図形のサイズまたは面積を提供します。 次のボリュームを持つ方向として想像できます。













あなたが球の中心にいて、図の方向を見ていると想像してください。 結果として得られるシルエットのサイズは立体角になります。







放射強度



放射強度は、立体角ごとの放射束の量、または立体角によって定義される単位面積あたりの光源の強度を測定します。 たとえば、全方向に均等に放射する全方向性光源の場合、放射力とは特定の領域(立体角)あたりの光のエネルギーを意味します。













放射の強度を表す方程式は次のようになります。











I= fracd Phid omega







、ここでIは立体角ごとの放射束f d omega







放射束、力、立体角がわかれば、力による光の立体角Oによって制限された領域Aで観測された合計エネルギーを表すエネルギー輝度方程式を記述することができます。 \ピ











L= fracd2 PhidAd omega cos theta













エネルギーの明るさは、入射光の角度に依存するエリア内の放射量です。 \シ (光の方向と表面の法線の間の角度)通過 cos theta :光は、表面に沿って放射される場合は弱く、何よりも垂直な場合は弱くなります。 これは、 照明の基本に関するチュートリアルの拡散光の計算と似ています。 cos theta 光の方向と表面の法線ベクトルとの間のスカラー積にすぎません:





 float cosTheta = dot(lightDir, N);
      
      





エネルギーの明るさの方程式は、興味のある物理量のほとんどを含むため、非常に便利です。 立体角ωと面積Aが極小であると仮定した場合、EIを使用して、空間内の1点あたり1光線の光束を測定できます。 これにより、単一のポイント(フラグメント)に作用する単一の光線のEIを計算できます。 実際に立体角を変換します \オ 方向ベクトル \オ そして A ポイントまで p 。 したがって、シェーダーでEIを直接使用して、各フラグメントの個々の光線の寄与を計算できます。







実際、EEに関しては、通常、ポイントpに入射するすべての入射光に関心があります。これはEE全体の合計であり、放射照度として知られています。 EYと照射を知ると、反射方程式に戻ることができます。











Lop omegao= int limits Omegafrp omegai omegaoLip omegain cdot omegaid omegai







今、私たちはそれを知っています L レンダリング方程式では、表面p上のある点と、入射光の無限に小さい立体角のEEです。  omegai 、入力方向ベクトルと見なすことができます  omegai 。 エネルギーが乗算されることに注意してください cos theta -製品の反射方程式で表される、光の入射方向と表面の法線の間の角度 n cdot omegai 。 反射方程式は、反射EIの合計を計算します Lop omegao ポイント p に向かって ωo 、オブザーバへの発信方向です。 またはそれ以外: Lo 点の反射放射照度を測定します p から見た場合  omegao







反射方程式はすべての入射放射線の合計である照射に基づいているため、1つの入射光方向だけでなく、半球内のすべての入射光方向からの光を測定します \オ を中心に p 。 表面の法線に沿って方向付けられた半球として説明できます n













領域内のすべての値の合計、または半球の場合は体積を計算するために、すべての入力方向に方程式を統合します d omegai 半球内 \オ 。 レンダリング方程式と反射方程式の両方に解析的な解決策はないため、積分を数値的に解きます。 これは、半球反射方程式の小さな離散ステップの結果を取得することを意味します \オ そして、それらをステップサイズで平均します。 これはリーマン和と呼ばれ、次のコードで大まかに表すことができます。







 int steps = 100; float sum = 0.0f; vec3 P = ...; vec3 Wo = ...; vec3 N = ...; float dW = 1.0f / steps; for(int i = 0; i < steps; ++i) { vec3 Wi = getNextIncomingLightDir(i); sum += Fr(P, Wi, Wo) * L(P, Wi) * dot(N, Wi) * dW; }
      
      





各離散ステップのdWは、次のように考えることができます。 d omegai 反射方程式で。 数学的に d omegai は積分を計算する微分であり、コードのdWとは異なりますが(これはリーマン和の離散ステップであるため)、計算を容易にするためにそのように考えることができます。 離散ステップを使用すると、積分の正確な値ではなく、常におおよその量が得られることに注意してください。 注意深い読者であれば、ステップ数を増やすことでリーマン和の精度を高めることができることに気付くでしょう。







反射方程式は、すべての入射光方向の放射を合計します  omegai 半球 \オ それがポイントに達する p 反射光の量を返します Lo 視聴者に向かって。 入ってくる放射は、すでに慣れ親しんでいる光源から、または各入ってくる方向のEIを決定する環境マップから来ることができます。これについては、IBLチュートリアルで説明します。







左側にある唯一の未知はシンボルです frBRDF関数または2ビーム反射率関数として知られ、表面材料の特性に基づいて入射放射の値をスケーリング(または重み付け)します。







BRDF



BRDFは、入射光の方向を受け入れる関数です。  omegai 、オブザーバーへの方向  omegao 表面に垂直 n およびパラメーター a これは表面粗さです。 BRDFは、個々の光線の量を概算します  omegai 材料の特性を考慮して、不透明な表面の最終反射光に寄与します。 たとえば、表面が完全に滑らかな場合(ほぼ鏡のように)、BRDF関数はすべての入射光線に対して0.0を返します。  omegai 、ビームと同じ角度(反射後)のものを除く  omegao 関数は1.0を返します。







BRDFは、前述のマイクロフェースの理論に基づいて、材料の反射特性と屈折特性を近似します。 BRDFを物理的にもっともらしいものにするためには、エネルギー保存の法則に従う必要があります。つまり、反射光の総エネルギーが入射光のエネルギーを超えてはなりません。 技術的には、Blinn-Fongモデルは同じものを受け入れるBRDFと見なされます  omegai そして  omegao 入り口で。 ただし、Blinn-Fongモデルは、エネルギー保存の法則への準拠を保証しないため、物理的に正しいとは見なされません。 照明に対する表面反応を近似するために、物理的に正しいBRDFがいくつかあります。 ただし、ほぼすべてのリアルタイムグラフィックパイプラインは、 クックトーランスBRDFとして知られるBRDFを使用します。







Cook-Torrens BRDFには、拡散部分とミラー部分の両方が含まれています。











fr=kdflambert+ksfcooktorrance







こっち kd -入射光エネルギーの屈折率、 ks -反映されます。 BRDFの左側には、方程式の拡散部分が含まれます。ここでは、 flambert 。 これは、いわゆるランバート散乱です。 これは拡散照明に使用したものと似ており、一定です。











flambert= fracc pi







どこで c -アルベドまたは表面色(拡散表面テクスチャ)。 除算  pi 以前に示されたBRDFを含む積分は、  pi (これについては、IBLチュートリアルで説明します)。







このLambertian散乱が以前使用していた拡散照明の表現に似ていることに驚かれるかもしれません:表面の色に表面の法線と光の方向の間のスカラー積を掛けたものです。 スカラー積はまだ存在していますが、BRDFから派生しています。 n cdot omegai 積分で Lo


BRDFの拡散部分には、より現実的に見えるさまざまな式がありますが、パフォーマンスの点ではより高価です。 さらに、エピックゲームズが結論付けたように、ほとんどのリアルタイムレンダリングの目的には、ランバート散乱が十分です。







Cook-Torrens BRDFのミラー部分はわずかに改善されており、次のように説明されています。











fcooktorrance= fracDFG4 omegao cdotn omegai cdotn







3つの関数と分母の標準化係数で構成されます。 文字D、F、およびGはそれぞれ、表面の反射特性の特定の部分を近似する特定のタイプの機能を表します。 これらは、正規分布関数(NDF)、フレネル方程式、およびジオメトリ関数として知られています。







これらの関数はそれぞれ、物理的に同等なものの近似であり、それらには、基礎となる物理モデルへのより正確な近似を目的としたさまざまな実装があります。 より現実的な結果をもたらすものもあれば、パフォーマンスの点でより効果的なものもあります。 Epic GamesのBrian Carisは、さまざまなタイプの近似について多くの研究を行っています。詳細については、 こちらをご覧ください 。 Epic GamesのUnreal Engine 4と同じ機能を使用します。つまり、DはTrowbridge-Reitz GGX 、FはFresnel-Schlick近似、GはSmithのSchlick-GGXです。







正規分布関数



正規分布関数Dは、中央ベクトルに沿って正確に方向付けられた微小面の相対表面積を統計的に近似します h 。 粗さのパラメーターを考慮して、マイクロフェースの全体的な配置の統計的な近似値を決定するNDFが多数あります。 Trowbridge-Reitz GGXとして知られるものを使用します。











NDFGGXTRnh alpha= frac alpha2 pin cdoth2 alpha21+12







こっち h 中央ベクトルです  alpha -表面粗さの値。 選択した場合 h 表面の法線と光の方向の間の中央ベクトルとして、粗さパラメーターを変更すると、次の図が得られます。













粗さが小さい(つまり、表面が滑らかである)場合、中央ベクトルの方向に向けられた微小面は小さな半径に集中します。 この高濃度により、NDFは非常に明るいスポットを提供します。 マイクロフェースがよりランダムな方向に向けられている粗い表面では、中​​央ベクトルの方向に向けられた多数のマイクロフェースが見つかります。 h より大きな半径に配置されているため、スポットカラーがより灰色になります。







GLSLコードでは、Trowbridge-Reitz GGX正規分布関数は次のようになります。







 float DistributionGGX(vec3 N, vec3 H, float a) { float a2 = a*a; float NdotH = max(dot(N, H), 0.0); float NdotH2 = NdotH*NdotH; float nom = a2; float denom = (NdotH2 * (a2 - 1.0) + 1.0); denom = PI * denom * denom; return nom / denom; }
      
      





ジオメトリ関数



ジオメトリ関数は、その微視的な不規則性が重なり合う相対的な表面積を統計的に近似し、光線の透過を防ぎます。













NDFの場合と同様に、ジオメトリ関数は入力として表面粗さ係数を受け入れます。この場合、次のことを意味します。粗い表面ほど、マイクロフェースのシェーディングの可能性が高くなります。 使用するジオメトリ関数は、GGXとSchlick-Beckmann近似の組み合わせであり、Schlick-GGXとして知られています。











GSchlickGGXnvk= fracn cdotvn cdotv1k+k







ここに k 再指定です  alpha ジオメトリ関数を直接照明に使用するかIBL照明に使用するかによって異なります。











kdirect= frac alpha+128











kIBL= frac alpha22







値に注意してください  alpha エンジンが粗さをどのように変換するかによって異なる場合があります  alpha 。 次のレッスンでは、この再割り当てが関連する方法と場所について詳細に説明します。







ジオメトリを効率的に近似するために、視線方向(ジオメトリの重複)とライトの方向ベクトル(ジオメトリの自己シャドウイング)の両方を考慮する必要があります。 Smithメソッドを使用して両方のケースを検討できます。











Gnvlk=GsubnvkGsubnlk







Schlick-GGXでのスミスメソッドの使用 Gsub 異なる粗さRの次の図を示します。













ジオメトリ関数は、[0.0、1.0]の間の係数です。白(または1.0)はマイクロフェースのシェーディングがないことを意味し、黒(または0.0)はマイクロフェースのフルシェーディングを意味します。







GLSLでは、ジオメトリ関数は次のコードに変換されます。







 float GeometrySchlickGGX(float NdotV, float k) { float nom = NdotV; float denom = NdotV * (1.0 - k) + k; return nom / denom; } float GeometrySmith(vec3 N, vec3 V, vec3 L, float k) { float NdotV = max(dot(N, V), 0.0); float NdotL = max(dot(N, L), 0.0); float ggx1 = GeometrySchlickGGX(NdotV, k); float ggx2 = GeometrySchlickGGX(NdotL, k); return ggx1 * ggx2; }
      
      





フレネル方程式



フレネル方程式は、反射光と屈折光の比率を表します。これは、表面を見る角度に依存します。 光が表面に当たると、フレネルの式は、この表面を見る角度に基づいて反射光の割合を示します。 この反射率とエネルギー保存の法則から、光の屈折部分を直接取得できます。これは残りのエネルギーに等しくなります。







各サーフェスまたはマテリアルには、サーフェスを直接見たときに観察されるレベルの基本反射率がありますが、サーフェスを斜めに見た場合、 すべての反射がより顕著になります。 おそらく木製または金属製のテーブルを最初に垂直に、次に90度に近い角度で見ることで、自分で確認できます。 反射がより顕著になることがわかります。 理論的には、すべての表面は、90度の理想的な角度で見たときに光を完全に反射します。 この効果はフレネルと名付けられ、フレネル方程式によって記述さます。







フレネル方程式は非常に複雑ですが、幸いなことに、フレネル-シュリック近似を使用し単純化できます。











FSchlickhvF0=F0+1F01h cdotv5







F0 表面の基本的な反射率を表します。これは、屈折率またはIOR (屈折の指数)と呼ばれるものを使用して計算します。ベクトルが90度に達する)、フレネル効果が強くなるため、反射が大きくなります:













フレネル方程式にはいくつかの微妙な点があります。 , - . (), , . , ( F0 ) ( 0 , ) -, , .







. , , :













: 0.17, , , ( ) 0.5 1.0. , “”, F0 RGB ( ).







, metallic workflow: , (metalness), , .







: , ; , . , 0.0 1.0. - , , , . , .



F0 , , - , , . :







 vec3 F0 = vec3(0.04); F0 = mix(F0, surfaceColor.rgb, metalness);
      
      





, . , F0 . 0.04 . , , , F0 . , , .







- :







 vec3 fresnelSchlick(float cosTheta, vec3 F0) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); }
      
      





cosTheta .







-



BRDF - :











Lo(p,ωo)=Ω(kdcπ+ksDFG4(ωon)(ωin))Li(p,ωi)nωidωi







. , , F . ks , , ks 。 , :











Lo(p,ωo)=Ω(kdcπ+DFG4(ωon)(ωin))Li(p,ωi)nωidωi







, PBR. , , . , , .







PBR



, PBR, , , PBR. , PBR, . , : , .







, PBR, :













: , . , . , ; .







: , , . , , .







: . , PBR-, , : .







: , . . , . PBR- , , (1.0 — ) .







AO (ambient occlusion) : AO . , , . AO , . . , 3D-.







. PBR, , . , PBR, PBR-, , , .







関連資料






All Articles