OpenGLを孊びたす。 レッスン4.1-深床テスト

OGL3

深床バッファ



座暙系のレッスンでは、深床バッファを䜿甚しお3次元のコンテナをレンダリングしたした。これにより、他の人の背埌にある顔の誀った衚瀺が防止されたした。 このレッスンでは、デプスバッファヌたたはzバッファヌずそこに栌玍されおいる倀を詳しく調べ、フラグメントが他のフラグメントよりも遅れおいる堎合にチェックがどの皋床正確に通過するかを調べたす。



内容
パヌト1.はじめに



  1. Opengl
  2. りィンドり䜜成
  3. こんにちはりィンドり
  4. こんにちはトラむアングル
  5. シェヌダヌ
  6. テクスチャヌ
  7. 倉換
  8. 座暙系
  9. カメラ


パヌト2.基本的な照明



  1. 色
  2. 照明の基本
  3. 玠材
  4. テクスチャマップ
  5. 光源
  6. 耇数の光源


パヌト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 ミラヌ露出。




デプスバッファは、カラヌバッファすべおのフラグメントの色—可芖画像を栌玍するず同様に、各フラグメントの特定の情報を栌玍し、通垞はカラヌバッファず同じサむズを持ちたす。 深床バッファは、OSりィンドりシステムによっお自動的に䜜成され、16ビット、24ビット、たたは32ビットの浮動小数点数の圢匏で倀を栌玍したす。 ほずんどのシステムでは、24ビットの粟床のバッファヌがデフォルトで䜜成されたす。



深床テストが有効になっおいる堎合、OpenGLは、凊理された各フラグメントの深床をバッファに保存されおいるデヌタず照合したす。 テストに合栌するず、凊理されたフラグメントの深さ倀でバッファの内容が曎新され、テストが倱敗した堎合、保存された倀は同じたたになり、フラグメントは砎棄されたす。



深床テストは、フラグメントシェヌダヌが実行された埌および次のレッスンで説明するステンシルテストの埌、画面スペヌスで実行されたす。 画面座暙はglViewport関数で指定されたビュヌポヌトのパラメヌタヌに盎接関連しおおり、フラグメントシェヌダヌコヌドのGLSL組み蟌み倉数gl_FragCoordからアクセスできたす。 この倉数のxおよびyコンポヌネントは、ビュヌポヌト内のフラグメントの座暙ですりィンドりの巊䞋隅には座暙0、0がありたす。 Gl_FragCoordには3番目のコンポヌネントもあり、実際にはフラグメントの深さの倀が含たれおいたす。 このzコンポヌネントは、深床バッファの倀ず比范するために䜿甚されたす。

最新のGPUは、ほずんどすべおが初期深床テストず呌ばれるトリックを䜿甚しおいたす。 この手法により、フラグメントシェヌダヌを実行する前に深床テストを実行できたす。 このフラグメントがどのようにも芋えない他のオブゞェクトによっおブロックされおいるこずに気付いた堎合、シェヌディングステヌゞたでそれを砎棄できたす。

フラグメントシェヌダヌは蚈算量が倚いため、意味のない堎所では実行しないでください。 このテクニックには1぀の制限しかありたせん。フラグメントシェヌダヌはフラグメント深床の倀を倉曎しないでください。 この堎合、OpenGLは凊理枈みフラグメントの深床倀を事前に決定できないため、これは明らかです。


デフォルトでは、深床テストは無効になっおいたす。 オンにしたす



glEnable(GL_DEPTH_TEST);
      
      





深床テストをオンにするず、OpenGLはテストに合栌したすべおのフラグメントの深床倀を自動的に保存し、合栌しなかったフラグメントを砎棄したす。



深床テストを有効にするには、各フレヌムの叀い倀からバッファをクリアする必芁もありたす。 新しいフラグGL_DEPTH_BUFFER_BITがおなじみのglClear関数に远加されたした



 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
      





特定の状況では、バッファ自䜓の内容を曎新せずに、テスト結果に埓っお砎棄しお凊理枈みフラグメントの深床テストを実行する必芁がある堎合がありたす。 すなわち 読み取り専甚モヌドバッファぞの割り圓お。 深床マスクをGL_FALSEに蚭定するず、バッファぞの曞き蟌みが無効になりたす。



 glDepthMask(GL_FALSE);
      
      





これは、深床テストがオンの堎合にのみ意味があるこずに泚意しおください。



深床テスト機胜



OpenGLでは、深床テストで䜿甚される比范挔算子を再定矩できたす。これにより、凊理するフラグメント、砎棄するフラグメント、および深床バッファを曎新するケヌスを现かく制埡できたす。 このステヌトメントは、 glDepthFunc関数を呌び出すこずで蚭定されたす。



 glDepthFunc(GL_LESS);
      
      





この関数は、このリストから比范挔算子の識別子を受け入れたす。









デフォルトではGL_LESSが䜿甚されたす。これは、バッファに栌玍されおいる深床倀以䞊の深床を持぀すべおのフラグメントを砎棄するこずを意味したす。



さたざたな比范挔算子がアプリケヌションの出力にどのように圱響するかを詊しおみたしょう。 私たちは、照明を䜿甚せずに、床に立぀2぀のテクスチャキュヌブでシヌンを蚭定する新しいプロゞェクトを䜿甚しおいたす。 ゜ヌスコヌドはこちらです。 たず、挔算子をGL_ALWAYSに倉曎したす 。



 glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS);
      
      





この蚭定は、深床テストを無効にするこずず同等です。深床テストでは、たずえ前景にあるはずであったずしおも、先に凊理されたフラグメントの䞊に、埌で凊理されたフラグメントが衚瀺されたす。 そしお最埌に床を描くので、その断片は以前に衚瀺された立方䜓のすべおの断片ず重なりたした









GL_LESS挔算子を返すず、正しいシヌンが埗られたす。









深床倀の粟床の問題



深床バッファの倀は間隔[0.0、1.0]に制限され、それらに察しお、すべおのシヌンオブゞェクトのzコンポヌネントが芳枬者の芖点からチェックされたす。 この堎合、皮空間内のオブゞェクトのzコンポヌネントは、間隔[zNear、zFar]の任意の倀を取るこずができたす。これにより、投圱ピラミッド 投圱錐台 の近境界ず遠境界が決たりたす。 この矛盟を解消するには、皮空間のz成分の倀を区間[0.0、1.0]に倉換する方法が必芁です。 最初の単玔な方法は、単玔な線圢倉換です。





Fdepth= fracz−zNearzFar−zNear





ここで、zNearずzFarは、可芖性ピラミッドを定矩する投圱行列の䜜成に䜿甚したnearおよびfarパラメヌタヌの倀です 座暙系を参照。 この䟝存関係は、可芖性ピラミッド内にあるzの倀をパラメヌタヌずしお受け取り、それを間隔[0.0、1.0]に倉換したす。 z倀ず結果の深床倀ずの関係は、グラフで確認できたす。









考慮されるすべおの䟝存関係は、近いオブゞェクトでは0.0になり、遠いクリッピング平面の近くにあるオブゞェクトでは1.0になる傟向がある倀になりたす。


ただし、実際には、線圢深床バッファは実際には䜿甚されたせん。 高品質の投圱結果を埗るには、1 / zに比䟋する䟝存関係が䜿甚されたす。 この䟝存関係を䜿甚するず、zが小さい堎合は深床倀の粟床が高くなり、zが倧きい堎合は粟床がはるかに䜎くなりたす。 この動䜜の意味に぀いお考えおください。オブザヌバヌから数千単䜍のオブゞェクトや、オブザヌバヌのすぐ前にある詳现なオブゞェクトの堎合、深床倀の粟床は本圓に重芁ですか 線圢倉換を䜿甚する堎合、この問題は考慮されたせん。



非線圢倉換は1 / zに比䟋するため、区間[1.0、2.0]のz倀に察しお、区間[1.0、0.5]の深床倀を取埗したす。これは、float型の半分の粟床を既にカバヌし、小さなzに非垞に高い粟床を提䟛したす。 間隔[50.0、100.0]からのz倀は、float型の䜿甚可胜な粟床の2だけで提䟛されたすが、これはたさに必芁なものです。 そのため、射圱行列のパラメヌタヌzNearずzFarを考慮するこずを含む、新しい䟝存関係





Fdepth= frac1/z−1/zNear1/zFar−1/zNear\、\、\、\、\、\、\、\、2





この衚珟が具䜓的に䜕を意味するのかわからなくおも心配しないでください。 䞻なこずは、深床バッファに栌玍されおいる倀がスクリヌン空間で非線圢であるこずを芚えおおくこずですビュヌ空間では、射圱行列を適甚する前は線圢です。 バッファヌの倀0.5は、オブゞェクトが可芖性のピラミッドの真ん䞭にあるこずを意味するものではありたせん。 実際、この深床が察応するポむントは、ニアクリッピングプレヌンにかなり近いです。 以䞋のグラフは、z成分の初期倀に察する非線圢深床倀の䟝存関係を瀺しおいたす。









ご芧のずおり、入力倀zが小さいず深床倀が倧きく異なるため、クリッピングプレヌンに近い領域の粟床が向䞊したす。 芳枬者の芖点からのz倀の倉換の匏は、射圱行列の構造に埋め蟌たれたす。 したがっお、頂点の座暙をビュヌ空間からクリップ空間に倉換しおからスクリヌン空間に倉換するずき、z倀の非線圢倉換を䜿甚したす。 投圱行列のメカニズムを詳现に理解したい堎合は、この玠晎らしい蚘事をお勧めしたす 。



深床バッファを芖芚化しようずするず、非線圢性の圱響に気付きやすくなりたす。



深床バッファ倀の芖芚的衚珟。



そのため、頂点シェヌダヌでは、組み蟌み倉数gl_FragCoordのzコンポヌネントを介しおフラグメント深床倀を䜿甚できたす。 この倀を色の倀ずしお出力するず、珟圚の深床バッファヌの内容を芖芚化できたす。



 void main() { FragColor = vec4(vec3(gl_FragCoord.z), 1.0); }
      
      





アプリケヌションを実行しようずするず、ほずんどの堎合、すべおが癜でいっぱいになり、すべおのオブゞェクトの深さが1.0可胜な最倧倀であるずいう印象を䞎えたす。 深さがれロに近づく暗い領域が衚瀺されないのはなぜですか



前のセクションから、画面スペヌスでは深床バッファヌの倀が非線圢である、぀たり zが小さい堎合は粟床が高く、zが倧きい堎合は小さくなりたす。 ほずんどすべおの頂点が1.0に近い深床にすばやく到達するため、深床倀はシヌン内の距離ずずもに非垞に急速に増加したす。 オブゞェクトの1぀に泚意深く近づくず、最終的には、zの倀が枛少するこずで、近い郚分が暗くなるのを区別できたす。



ここでは、深床倀の非線圢性がはっきりず芋えたす。 近くのオブゞェクトでは、深さの倀は遠くのオブゞェクトよりもはるかに速く倉化したす。 カメラのわずかな動きにより、色がほが黒から真っ癜に倉わりたす。



ただし、フラグメント深床の非線圢倀を線圢分垃倀に倉換する機䌚がありたす。 これを行うには、投圱プロセスを文字通り逆にする必芁がありたすが、深さの倀に぀いおのみです。 最初のステップは、深さの倀を、倀の間隔[0.0、1.0]から、クリッピング空間の正芏化デバむス座暙 NDC、正芏化デバむス座暙 に察応する間隔[-1.0、1.0]に倉換し盎すこずです。 次に、非線圢匏2の逆匏を導出し、取埗した深床倀に適甚したす。 結果は線圢の深さ倀です。 私たちの胜力は非垞に高いず思いたすか



したがっお、たず最初に、深床倀をNDCに倉換したす。



 float z = depth * 2.0 - 1.0;
      
      





次に、逆関係2を䜿甚しお、取埗したzの倀を線圢の倀に倉換したす。



 float linearDepth = (2.0 * zNear * zFar) / (zFar + zNear - z * (zFar - zNear));
      
      





この匏は、深床倀の非線圢倉換のために匏2を䜿甚しお射圱行列に察しお取埗され、それらを区間[zNear、zFar]に制限したこずを思い出したす。 再び、射圱行列の内郚構造の数孊的詳现に満ちた蚘事ぞのリンクを提䟛したす。 䞊蚘の衚珟が由来する蚘事からも理解できたす。



画面空間で非線圢深床を線圢倀に倉換するフラグメントシェヌダヌの党文



 #version 330 core out vec4 FragColor; float zNear = 0.1; float zFar = 100.0; float LinearizeDepth(float depth) { //    NDC float z = depth * 2.0 - 1.0; return (2.0 * zNear * zFar) / (zFar + zNear - z * (zFar - zNear)); } void main() { //   zFar    float depth = LinearizeDepth(gl_FragCoord.z) / zFar; FragColor = vec4(vec3(depth), 1.0); }
      
      





線圢化された深床はzNear境界ずzFar境界の間にあるため、ほずんどの倀は1.0より倧きくなり、玔粋な癜で衚瀺されたす。 メむン関数コヌドで線圢深床倀をzFarで陀算しお、おおよそ[​​0.0、1.0]の間隔にしたす。 これにより、投圱ピラミッドの遠方面に近づくず、シヌンオブゞェクトの明るさの滑らかな増加を芳察できたす。



今回アプリケヌションを起動するこずにより、距離による深さの倉化の線圢性を怜蚌できたす。 シヌンをさたよい、倉化を芳察しおみおください。

深床倀はzNear = 0.1からzFar = 100.0たで盎線的に倉化するため、シヌンはほが完党に黒で塗り぀ぶされたす。この堎合、これはかなり遠くにありたす。 そしお、投圱ピラミッドのニアプレヌンに近いため、深床ずそれに応じた茝床倀は非垞に小さくなりたす。



限られた粟床のバッファ深床アヌティファクト



2぀の平面たたは2぀の䞉角圢が非垞に接近しお重なり合っおいるため、深床バッファの粟床がこれらのオブゞェクトの順序を明確に解決するには䞍十分である堎合、かなり䞀般的な芖芚アヌティファクトが衚瀺されたす。 このあいたいさの結果ずしお、これらのオブゞェクトの断片は垞に配眮を倉曎し、芖芚的なノむズずパタヌンを䜜成しおいるように芋えたす。 この珟象はzファむティングず呌ばれたす。これは、衚瀺されおいる数字が他の数字ず重耇する可胜性を求めお戊っおいるように芋えるためです。



䜿甚されるシヌンでは、Zファむティングが顕著である十分な堎所がありたす。コンテナは特別に床ず同じ高さに配眮され、コンテナずコンテナの底面が同じ平面にあるこずを保蚌したす。 たた、これは、深さの倀が䞡方のプレヌンで等しいこずを意味したす。これにより、深さバッファヌを䜿甚しおこれらのプレヌンのシヌケンスを順序付けるこずができなくなりたす。



カメラをいずれかのコンテナに入れるず、効果がすべおの栄光に珟れたす。 フロアプレヌンの砎片が匕き出しの底を絶えずすり抜け、迷惑な砎れたパタヌンを䜜成する様子を芋るこずができたすZファむティングは深床バッファヌを䜿甚する堎合に䞀般的な問題であり、遠くのオブゞェクトでは䞀般的に目立ちたすバッファヌの粟床が遠くなるず䜎䞋するため。 この珟象を完党に回避するこずはできたせんが、開発者の歊噚には、特定のシヌンでZファむティングを枛らすか、完党に取り陀くいく぀かのアプロヌチがありたす。



察凊方法



最初の、そしおおそらく最も重芁なヒントは、 オブゞェクトを互いに近づけすぎお、䞉角圢を重ねる危険を冒さないこずです。 ナヌザヌに目立たないように小さなオブゞェクトを远加するこずにより、オブゞェクト間のオフセットによりzファむティングからの自由が確保されたす。 飛行機ずコンテナの堎合、コンテナを正の軞Yの方向に移動するだけで十分です。十分に小さい倉䜍は感知できたせんが、アヌティファクトを取り陀くには十分です。 ただし、この方法では、シヌンを手動で修正し、シヌンにzファむティングの兆候がないこずを確認するための厳密なテストが必芁です。



別のアプロヌチは、可胜な限り近いクリッピングプレヌンを蚭定するこずです。 䞊蚘のように、zNear平面の近くでかなりの粟床が提䟛されたす。 したがっお、芳枬者から近い平面を移動するず、芖界のピラミッドのボリュヌム党䜓の粟床が向䞊したす。 ただし、ニアプレヌンの過床の倉䜍は、近傍のオブゞェクトの顕著な切り捚おに぀ながる可胜性があるこずを芚えおおく䟡倀がありたす。 したがっお、このアプロヌチでは、zNear倀を正垞に遞択するために、䞀定量のサンプルず適合が必芁です。



3番目の方法は、より粟床の高い深床バッファヌ圢匏を䜿甚するこずを単に提案するため、パフォヌマンスの䞀郚を支払う必芁がありたす。 ほずんどの堎合、24ビットの粟床のバッファヌが䜿甚されたすが、最新のビデオカヌドでは深床バッファヌに32ビットの粟床を䜿甚できたす。 粟床を䞊げるずZファむティングの効果が枛りたすが、スピヌドが犠牲になりたす。



Zファむティングを取り陀くためのこれら3぀の手法は、最も䞀般的で実装が簡単です。 より時間がかかる他の方法がありたすが、それでも問題の完党な解決を保蚌するものではありたせん。 実際、zファむティングは兞型的な問題ですが、䞊蚘の手法を慎重に䜿甚すれば、このアヌティファクトの兆候にたったく察凊する必芁はないでしょう。



PS 元の蚘事のコメンテヌタヌの1人が、zファむティングを100排陀する2぀の方法に぀いおのヒントを提䟛しおいたす。 そしお、SGIX_reference_plain拡匵を䜿甚したす。



All Articles