OpenGLを孊びたす。 レッスン4.9-幟䜕孊的なシェヌダヌ

OGL3

幟䜕孊シェヌダヌ



頂点シェヌダヌずフラグメントシェヌダヌのステヌゞの間には、ゞオメトリシェヌダヌを実行するために蚭蚈されたオプションのステヌゞがありたす。 ゞオメトリシェヌダヌの入力には、OpenGLで蚱容されるプリミティブポむント、䞉角圢などの1぀を圢成する䞀連の頂点がありたす。 その䜜業の結果、ゞオメトリシェヌダヌは、次のシェヌダヌステヌゞに転送する前に、この䞀連の頂点を自由裁量で倉換できたす。 同時に、ゞオメトリシェヌダヌの最も興味深い機胜に泚目する䟡倀がありたすその䜜業の過皋で、入力頂点のセットを倉換しお完党に異なるプリミティブを衚すこずができ、入力デヌタに基づいお完党に新しい頂点を生成し、頂点の総数を増やすこずもできたす。



内容
パヌト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 ミラヌ露光。




長い間利甚せず、すぐにゞオメトリシェヌダヌの䟋に戻りたす。



#version 330 core layout (points) in; layout (line_strip, max_vertices = 2) out; void main() { gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0); EmitVertex(); gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0); EmitVertex(); EndPrimitive(); }
      
      





シェヌダヌコヌドの先頭で、頂点シェヌダヌステヌゞからデヌタを取埗するプリミティブのタむプを指定する必芁がありたす。 これは、inキヌワヌドの前にあるレむアりト指定子を䜿甚しお行われたす。 指定子で瀺されるプリミティブのタむプは、頂点シェヌダヌによっお凊理されるプリミティブのタむプに察応する次の倀のいずれかを取るこずができたす。





結果ずしお、 glDrawArraysのようなレンダリング関数ぞの受け枡しに有効な、事実䞊すべおのタむプのプリミティブがここにリストされたす。 GL_TRIANGLESを䜿甚しおレンダリングする堎合、 トラむアングルパラメヌタヌを指定子で指定する必芁がありたす。 ここの括匧内の数字は、1぀のプリミティブに含たれる頂点の最小数を意味したす。



次に、このシェヌダヌの出力プリミティブのタむプも指定する必芁がありたす。 したがっお、これはoutキヌワヌドの前にレむアりト指定子を介しお行われたす。 この䟋では、最倧2぀の頂点を持぀line_stripが出力で生成されたす。



忘れた堎合 ラむンストリッププリミティブはセット内のポむントを接続し、セット内の2぀のポむントから始たる連続したラむンを圢成したす。 2぀を超えるポむントが远加されるたびに、新しいポむントから前のポむントたで䌞びる別の線セグメントが䜜成されたす。 以䞋は、5ポむントセグメントの画像です。









瀺されおいるシェヌダヌの䟋では、プリミティブの頂点の最倧数を明瀺的に2に蚭定しおいるため、個々の盎線セグメントのみを生成できたす。



シェヌダヌが䜕か有甚なこずを行えるようにするには、前のシェヌダヌステヌゞの出力からデヌタを取埗する必芁がありたす。 GLSLには組み蟌み倉数gl_inが甚意されおおり、次の構造で衚すこずができたす。



 in gl_Vertex { vec4 gl_Position; float gl_PointSize; float gl_ClipDistance[]; } gl_in[];
      
      





したがっお、この倉数は最埌のレッスンで説明したむンタヌフェむスブロックに䌌おおり、頂点シェヌダヌの結果ずしお蚭定された頂点䜍眮ベクトルを含むgl_Positionがいく぀かのフィヌルドを含んでいたす。

ほずんどのプリミティブには耇数の頂点が含たれおおり、ゞオメトリシェヌダヌのステヌゞは凊理されたプリミティブのすべおの頂点を入力ずしお受け取るため、この倉数は配列であるこずに泚意しおください。



頂点シェヌダヌの出力から頂点デヌタを受け取ったら、新しいデヌタの生成を開始できたす。これは、ゞオメトリシェヌダヌの2぀の特別な関数EmitVertexおよびEndPrimitiveを䜿甚しお実行されたす。 コヌドでは、出力ずしお宣蚀された少なくずも1぀のプリミティブを生成するこずが期埅されおいたす。 この䟋では、少なくずも1぀のline_stripタむプのプリミティブを返す必芁がありたす。



 void main() { gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0); EmitVertex(); gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0); EmitVertex(); EndPrimitive(); }
      
      





EmitVertexを呌び出すたびに、 gl_Position倉数の珟圚の倀が珟圚のプリミティブむンスタンスに远加されたす。 EndPrimitiveを呌び出すず、生成されたすべおの頂点が最終的​​にプリミティブの指定された出力タむプにバむンドされたす。 EmitVertexの 1぀以䞊の呌び出しの埌にEndPrimitiveの呌び出しを繰り返すこずにより、プリミティブの新しいむンスタンスを䜜成し続けるこずができたす。 具䜓的には、この䟋では、2぀の頂点が生成され、入力頂点の䜍眮から少し距離を移動しおから、 EndPrimitive呌び出しが行われ 、これら2぀の生成された頂点から2぀の頂点を含む1぀のラむンストリップを圢成したす。



したがっお、理論的にはゞオメトリシェヌダヌの仕組みを知っおいれば、おそらくこの䟋の効果が䜕であるかをすでに掚枬しおいるでしょう。 入力時に、シェヌダヌはポむントプリミティブを受け取り、それに基づいお入力ラむンがちょうど真ん䞭にある氎平線を䜜成したす。 そのようなシェヌダヌを䜿甚したプログラムの出力を以䞋に瀺したす。









あたり印象的ではありたせんが、1回の描画呌び出しを実行するだけでこのような結果が埗られたこずを考えるず、すでに興味深いものです。



 glDrawArrays(GL_POINTS, 0, 4);
      
      





この䟋は非垞に単玔ですが、重芁な原則を瀺しおいたす。幟䜕孊的シェヌダヌを䜿甚しお新しい圢状を動的に䜜成する機胜です。 埌ほど、ゞオメトリシェヌダヌに基づいお実装されたいく぀かの興味深い゚フェクトを芋おいきたすが、今のずころは、単玔なシェヌダヌを䜿甚しお基本的な䜜業を行いたす。



ゞオメトリシェヌダヌを䜿甚する



ゞオメトリシェヌダヌの䜿甚方法を瀺すために、デバむスの正芏化された座暙NDCでXoY平面にある4぀のポむントをレンダリングする簡単なプログラムを䜿甚したす。 ポむント座暙



 float points[] = { -0.5f, 0.5f, // - 0.5f, 0.5f, // - 0.5f, -0.5f, // - -0.5f, -0.5f // - };
      
      





頂点シェヌダヌはシンプルです-ポむントを目的のプレヌンにマップするだけです



 #version 330 core layout (location = 0) in vec2 aPos; void main() { gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); }
      
      





フラグメントシェヌダヌも簡単で、フラグメントにハヌドコヌドされた色を䜿甚したす。



 #version 330 core out vec4 FragColor; void main() { FragColor = vec4(0.0, 1.0, 0.0, 1.0); }
      
      





プログラムコヌドでは、通垞どおり、頂点デヌタのVAOずVBOを䜜成し、 glDrawArraysを呌び出しおレンダリングしたす。



 shader.use(); glBindVertexArray(VAO); glDrawArrays(GL_POINTS, 0, 4);
      
      





その結果、画面には完党な暗闇ず4぀のほずんど芋えない緑色のドットがありたす。









このような憂鬱な写真を撮るためだけに倚くのこずを孊んだのは、ちょっず悲しいこずです。 そのため、すぐにシヌンに介入し、ゞオメトリックシェヌダヌの機胜を䜿甚しおこの悲芳的な人を薄めたす。



しかし、最初に、トレヌニングの目的で、 ゚ンドツヌ゚ンドのゞオメトリシェヌダヌがどのように機胜するかを䜜成しお把握する必芁がありたす。これは、入力プリミティブのデヌタを取埗し、倉曎せずに送信したす。



 #version 330 core layout (points) in; layout (points, max_vertices = 1) out; void main() { gl_Position = gl_in[0].gl_Position; EmitVertex(); EndPrimitive(); }
      
      





珟時点では、ヒントなしでシェヌダヌコヌドを既に理解できたす。 ここでは、頂点シェヌダヌから取埗した䜍眮に頂点を生成し、同じポむントプリミティブを生成したす。



ゞオメトリシェヌダヌには、頂点シェヌダヌずフラグメントシェヌダヌず同様に、コンパむルずプログラムオブゞェクトぞのリンクが必芁です。 ただし、今回はシェヌダヌのタむプずしおGL_GEOMETRY_SHADERが指定されたシェヌダヌオブゞェクトが䜜成されたす 。



 geometryShader = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(geometryShader, 1, &gShaderCode, NULL); glCompileShader(geometryShader); ... glAttachShader(program, geometryShader); glLinkProgram(program);
      
      





実際、コンパむルコヌドは他の皮類のシェヌダヌずたったく同じです。 コンパむルおよびリンク゚ラヌのチェックを忘れないでください



実行するず、おなじみの画像が埗られたす









幟䜕孊的シェヌダヌなしの堎合ず同じものが埗られたした...退屈です ただし、ドットはただ衚瀺されおいるので、少なくずもシェヌダヌが機胜しおいるこずず、より興味深いものに進むこずができるこずを確認しおいたす。



家を建おる



単玔な線ず点を描くこずは、私たちが期埅したものずはたったく異なりたす。したがっお、少し創造性を远加し、入力頂点によっお䞎えられた点に家を描きたす。 これを行うには、出力プリミティブのタむプをtriangle_stripに倉曎し、3぀の䞉角圢を描画する必芁がありたす。2぀は正方圢のベヌスを䜜成し、1぀は屋根に䜿甚したす。



OpenGLプリミティブTriangle Stripは、入り口で必芁な頂点が少ない䞉角圢を描くためのより効率的な方法です。 最初の䞉角圢をレンダリングした埌、埌続の各頂点は、前の䞉角圢に隣接する別の䞉角圢を䜜成したす。 6぀の頂点が䞉角圢ストリップの䞀郚ずしお䞎えられた堎合、結果は次の䞉角圢のシヌケンスになりたす1,2,3、2,3,4、3,4,5および4,5,6 4぀の描かれた䞉角圢にあふれたす。 このプリミティブでは、レンダリングを成功させるために少なくずも3぀の頂点を蚭定する必芁がありたす。 䞀般的な堎合、N-2個の䞉角圢が導出されたす。 以䞋に瀺すように、6぀の頂点がある6-2 = 4の䞉角圢が埗られたした。









䞉角圢のストリップを䜿甚するず、3぀の隣接する䞉角圢から目的の圢状を簡単に圢成し、正しい順序で蚭定できたす。 次の画像は、目的の䞉角圢を取埗するために頂点を描画する順序を瀺しおいたす。 青い点は、入力頂点の䜍眮を瀺しおいたす。









結果の幟䜕孊的シェヌダヌ



 #version 330 core layout (points) in; layout (triangle_strip, max_vertices = 5) out; void build_house(vec4 position) { gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0); // 1:bottom-left EmitVertex(); gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0); // 2:bottom-right EmitVertex(); gl_Position = position + vec4(-0.2, 0.2, 0.0, 0.0); // 3:top-left EmitVertex(); gl_Position = position + vec4( 0.2, 0.2, 0.0, 0.0); // 4:top-right EmitVertex(); gl_Position = position + vec4( 0.0, 0.4, 0.0, 0.0); // 5:top EmitVertex(); EndPrimitive(); } void main() { build_house(gl_in[0].gl_Position); }
      
      





シェヌダヌは、入力頂点の䜍眮からオフセットした䜍眮に5぀の頂点を䜜成し、それらをすべお䞉角圢ストリップタむプの1぀のプリミティブに配眮したす。 次に、このプリミティブがラスタラむズのために送信され、フラグメントシェヌダがその衚面を緑色にペむントしたす。 各゚ントリポむントに1぀のグリヌンハりスを取埗したす。









ここでは、各家が実際に3぀の䞉角圢で構成されおいるこずがわかりたす。これらはすべお、入力デヌタの単䞀ポむントに基づいお構築されおいたす。



しかし、ただ少し退屈に芋えたす それぞれの家を独自の色で色付けしおみたしょう。 これを行うために、頂点に関する色情報を保存する別の頂点属性を敎理したす。 頂点シェヌダヌは、頂点の属性倀を読み取り、ゞオメトリシェヌダヌに枡したす。ゞオメトリシェヌダヌは、色の倀をフラグメントシェヌダヌに向けたす。



曎新された頂点デヌタは次のずおりです。



 float points[] = { -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // - 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // - 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // - -0.5f, -0.5f, 1.0f, 1.0f, 0.0f // - };
      
      





次に、むンタヌフェむスブロックを䜿甚しお、ゞオメトリシェヌダヌに色属性を枡すための頂点シェヌダヌコヌドを指定したす。



 #version 330 core layout (location = 0) in vec2 aPos; layout (location = 1) in vec3 aColor; out VS_OUT { vec3 color; } vs_out; void main() { gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); vs_out.color = aColor; }
      
      





明らかに、ゞオメトリシェヌダヌで同じタむプのただし名前は異なるむンタヌフェむスナニットを定矩する必芁がありたす。



 in VS_OUT { vec3 color; } gs_in[];
      
      





ゞオメトリシェヌダヌは入力頂点のセット党䜓で実行されるため、単䞀の頂点が入力される堎合でも、その入力パラメヌタヌは垞に配列です。

実際、ゞオメトリブロックにデヌタを転送するためにむンタヌフェむスブロックを䜿甚する必芁はありたせん。 頂点シェヌダヌがout vec3 vColorずしお色を持぀ベクトルを枡した堎合、次のように蚘述できたす。



 in vec3 vColor[];
      
      





ただし、䞀般に、特に幟䜕孊的なシェヌダヌでは、むンタヌフェむスナニットの操䜜ははるかに簡単です。 実際には、ゞオメトリシェヌダヌの入力パラメヌタヌは、かなり倧きなデヌタセットで衚されるこずが倚く、それらを配列で衚される単䞀のむンタヌフェむスナニットに結合するこずは、完党に予想されるステップです。


たた、色デヌタをフラグメントシェヌダヌに送る出力倉数を宣蚀する必芁がありたす。



 out vec3 fColor;
      
      





フラグメントシェヌダヌは単䞀の補間されたカラヌ倀を想定しおいるため、カラヌベクトルの配列を送信しおも意味がありたせん。 それが、ここでfColorが配列ではなく、単䞀のベクトルである理由です 。 頂点をスポヌンするず、それらはそれぞれ、フラグメントシェヌダヌの呌び出しのためにfColor倉数にあった最埌の倀を蚘憶したす。 したがっお、家の堎合、頂点シェヌダヌステヌゞから取埗した色でfColorを䞀床だけ塗り぀ぶしお、家党䜓の色を蚭定できたす。



 fColor = gs_in[0].color; //  gs_in[0]        gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0); // 1:- EmitVertex(); gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0); // 2:- EmitVertex(); gl_Position = position + vec4(-0.2, 0.2, 0.0, 0.0); // 3:- EmitVertex(); gl_Position = position + vec4( 0.2, 0.2, 0.0, 0.0); // 4:- EmitVertex(); gl_Position = position + vec4( 0.0, 0.4, 0.0, 0.0); // 5: EmitVertex(); EndPrimitive();
      
      





その結果、生成されたすべおの頂点には、頂点属性の色に察応するfColor倉数の色の倀が栌玍されたす。 珟圚、各家は独自の色で塗装されおいたす。









もう少し創造性を远加し、仮想の冬をアレンゞしお、家の屋根に雪を振りかけたす。 この最埌の頂点に察しお、癜色を個別に割り圓おたす。



 fColor = gs_in[0].color; gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0); // 1:- EmitVertex(); gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0); // 2:- EmitVertex(); gl_Position = position + vec4(-0.2, 0.2, 0.0, 0.0); // 3:- EmitVertex(); gl_Position = position + vec4( 0.2, 0.2, 0.0, 0.0); // 4:- EmitVertex(); gl_Position = position + vec4( 0.0, 0.4, 0.0, 0.0); // 5: fColor = vec3(1.0, 1.0, 1.0); EmitVertex(); EndPrimitive();
      
      





その結果、次のこずができたす。









アプリケヌションコヌドを䟋ず比范できたす。



この時点で、幟䜕孊的なシェヌダヌは、単玔なプリミティブを䜿甚しおも、十分な創造的可胜性を提䟛するこずは既に明らかだず思いたす。 ゞオメトリはGPUの超高速コア内で動的に䜜成されるため、頂点バッファヌを䜿甚しお同じゞオメトリを指定するよりもはるかに効率的です。 ゞオメトリシェヌダヌは、ボクセルレンダリング甚のキュヌブやオヌプンスペヌスシヌンの草の茎など、単玔で頻繁に繰り返される圢状のレンダリングを最適化するための十分な機䌚を提䟛したす。



オブゞェクトを爆発させたす



もちろん、家を描くこずは玠晎らしいこずですが、私たちがしばしば協力しなければならないものではありたせん。 したがっお、熱を加えお、3次元モデルの爆発に盎行しおください うヌん、おそらくこれをあたり頻繁に行う必芁はないでしょうが、幟䜕孊的シェヌダヌの機胜の優れたデモンストレヌションずしお圹立ちたす。



オブゞェクトを爆砎するずいうこずは、貎重なピヌクの文字通りの砎壊を意味するのではなく、時間の経過に䌎う通垞の方向に沿った各䞉角圢の動きを意味したす。 その結果、この効果はオブゞェクトの爆発のように芋え、法線ベクトルの方向に移動する別々の䞉角圢に分割したす。 以䞋は、ナノスヌツモデルに適甚される効果です。









泚目すべきは、ゞオメトリシェヌダヌを䜿甚するず、その耇雑さに関係なく、任意のオブゞェクトで゚フェクトを䜿甚できるこずです。



法線ベクトルに沿っお䞉角圢をシフトする必芁があるため、最初に蚈算する必芁がありたす。 具䜓的には、䞉角圢の衚面に垂盎で、頂点が3぀しかないベクトルを芋぀ける必芁がありたす。 倉換のレッスンから、他の2぀に垂盎なベクトルは倖積挔算を䜿甚しお取埗できるこずをおそらく芚えおいるでしょう。 䞉角圢の衚面に平行な2぀のベクトルaずbを芋぀けるこずができた堎合、衚面に垂盎なベクトルは単玔にそれらのベクトル積の結果になりたす。 実際、以䞋のゞオメトリシェヌダヌコヌドはそれを実行したす。入力䞉角圢の3぀の頂点を䜿甚しお法線ベクトルを蚈算したす。



 vec3 GetNormal() { vec3 a = vec3(gl_in[0].gl_Position) - vec3(gl_in[1].gl_Position); vec3 b = vec3(gl_in[2].gl_Position) - vec3(gl_in[1].gl_Position); return normalize(cross(a, b)); }
      
      





ここでは、枛算を䜿甚しお、䞉角圢の衚面に平行な2぀のベクトルaずbを取埗したす。 ベクトルを枛算するず、元の2぀のベクトルの差である別のベクトルが埗られたす。 3぀の頂点はすべお䞉角圢の平面にあるため、䞉角圢の頂点を衚すベクトルの差により、䞉角圢の衚面に平行なベクトルが生成されたす。 cross関数の゚クスポヌトでのパラメヌタヌの順序に泚意しおください。aずbを亀換するず、法線ベクトルの方向は逆になりたす。



手持ちの法線を芋぀ける方法ができたら、 explode関数の実装に進むこずができたす。この関数は、法線ベクトルず頂点の䜍眮ベクトルを受け入れ、法線に沿っおシフトした新しい頂点䜍眮を返したす。



 vec4 explode(vec4 position, vec3 normal) { float magnitude = 2.0; vec3 direction = normal * ((sin(time) + 1.0) / 2.0) * magnitude; return position + vec4(direction, 0.0); }
      
      





コヌドはかなり明癜です。 sin関数は、珟圚の時間に関連付けられた時間倉数に䟝存し、間隔[-1。、1.]の倀を定期的に返したす。 内向きの爆発内砎の効果は私たちにずっお興味深いものではないため、 sinの倀を区間[0.、1.]に制限したす。 さらに、埗られた倀ず倧きさ制埡定数は、最終方向ベクトルの蚈算で法線ベクトルをスケヌリングするために䜿甚されたす。 このベクトルは、新しいオフセット䜍眮を取埗するために、頂点䜍眮の入力パラメヌタヌに远加されたす。



察応するレッスンの3Dモデルファむルのレンダリングコヌドを䜿甚する堎合の爆発効果のゞオメトリシェヌダヌの完党なコヌドを以䞋に瀺したす。



 #version 330 core layout (triangles) in; layout (triangle_strip, max_vertices = 3) out; in VS_OUT { vec2 texCoords; } gs_in[]; out vec2 TexCoords; uniform float time; vec4 explode(vec4 position, vec3 normal) { ... } vec3 GetNormal() { ... } void main() { vec3 normal = GetNormal(); gl_Position = explode(gl_in[0].gl_Position, normal); TexCoords = gs_in[0].texCoords; EmitVertex(); gl_Position = explode(gl_in[1].gl_Position, normal); TexCoords = gs_in[1].texCoords; EmitVertex(); gl_Position = explode(gl_in[2].gl_Position, normal); TexCoords = gs_in[2].texCoords; EmitVertex(); EndPrimitive(); }
      
      





各頂点を生成する前に、察応するテクスチャ座暙を枡すこずに泚意しおください。



たた、クラむアントコヌドで均䞀な時間の倀を蚭定するこずを忘れないでください。



 shader.setFloat("time", glfwGetTime());
      
      





結果は、定期的に爆発しお元の状態に戻るモデルのあるシヌンです。 䟋はささいなこずですが、幟䜕孊的なシェヌダヌを培底的に䜿甚するこずに぀ながりたす。



結果のコヌドは、䟋ず比范できたす。



法線ベクトルを衚瀺したす



今回は、ゞオメトリシェヌダヌを䜿甚しお、実際に非垞に䟿利なものを実装しようずしたす。レンダリングされたゞオメトリの法線ベクトルを衚瀺したす。 ラむティングアルゎリズムを実装するず、必然的に奇劙な結果ず芖芚的な䞍具合が発生したすが、その原因を特定するのは容易ではありたせん。 ラむティングを操䜜する際の最も䞀般的な゚ラヌの1぀は、頂点デヌタの読み蟌み゚ラヌ、頂点属性の圢匏の蚭定゚ラヌ、たたはシェヌダヌでの単玔な倉換゚ラヌに起因する、䞍正な法線のタスクです。 提䟛された法線の正確さを刀断するツヌルがあるずすばらしいでしょう。法線の芖芚化はそのようなツヌルの1぀であり、幟䜕孊的なシェヌダヌはその実装のために単玔に䜜成されたす。

考え方は単玔です。たず、含たれるゞオメトリシェヌダヌなしで通垞の方法でシヌンをレンダリングし、次に2回目のパスを行いたすが、ゞオメトリシェヌダヌによっお生成された法線のみを衚瀺したす。シェヌダヌは、入力で䞉角圢タむプのプリミティブを取埗し、各頂点の䜍眮で法線ベクトルの方向に3぀のセグメントを䜜成したす。擬䌌コヌドの圢匏では、次のようになりたす。



 shader.use(); DrawScene(); normalDisplayShader.use(); DrawScene();
      
      





今回、ゞオメトリシェヌダヌは、オンザフラむで蚈算するのではなく、頂点属性ずしお指定された法線を䜿甚したす。ゞオメトリシェヌダは、入力ずしおクリップの空間における䜍眮ベクトルかかるクリップ空間ので、我々は、同じ空間に法線ベクトルを倉換しなければなりたせん。しかし、これを行う前に、法線行列の助けを借りお法線ベクトルを倉換する必芁がありたす-これはスケヌリングず回転を考慮する方法ですビュヌずモデル行列によっお䞎えられたす。これはすべお頂点シェヌダヌで行われたす。



 #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; out VS_OUT { vec3 normal; } vs_out; uniform mat4 projection; uniform mat4 view; uniform mat4 model; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0); mat3 normalMatrix = mat3(transpose(inverse(view * model))); vs_out.normal = normalize(vec3(projection * vec4(normalMatrix * aNormal, 0.0))); }
      
      





クリップスペヌスに倉換された法線ベクトルは、むンタヌフェむスナニットを介しお次のシェヌダヌステヌゞに枡されたす。ゞオメトリシェヌダヌは、頂点の属性䜍眮ず法線ベクトルを読み取り、各頂点の䜍眮に法線方向にセグメントを衚瀺したす。



 #version 330 core layout (triangles) in; layout (line_strip, max_vertices = 6) out; in VS_OUT { vec3 normal; } gs_in[]; const float MAGNITUDE = 0.4; void GenerateLine(int index) { gl_Position = gl_in[index].gl_Position; EmitVertex(); gl_Position = gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0) * MAGNITUDE; EmitVertex(); EndPrimitive(); } void main() { GenerateLine(0); //      GenerateLine(1); // ...   GenerateLine(2); // ...   }
      
      





珟時点では、コヌドに远加の説明は必芁ないず思いたす。法線ベクトルはMAGNITUDE定数を䜿甚しおスケヌリングされるこずに泚意しおください。これにより、衚瀺されるセグメントの長さを制限できたすそうでない堎合、わずかに倧きすぎたす。



法線の出力は䞻にデバッグの目的に䜿甚されるため、フラグメントシェヌダヌを䜿甚しお同じ色の線で簡単に衚瀺できたす。



 #version 330 core out vec4 FragColor; void main() { FragColor = vec4(1.0, 1.0, 0.0, 1.0); }
      
      





その結果、通垞のシェヌダヌを䜿甚したモデルレンダラヌず、新しい通垞の可芖化シェヌダヌを䜿甚した再レンダリングの組み合わせにより、次の図が埗られたす。









ナノスヌツがキッチングロヌブの毛むくじゃらの男のように芋えるずいう事実を無芖するず、シヌンで䜿甚されおいるモデルの法線ベクトルの正確さを刀断するための非垞に䟿利な方法を埗るこずができたす。それで、ファヌ゚フェクトを実装するシェヌダヌでも䌌たようなものが䜿甚されおいるこずが明らかになりたした。



この䟋の゜ヌスコヌドはこちらです。



PS転送を調敎するための電報confがありたす。翻蚳を手䌝いたいずいう真剣な願望があれば、倧歓迎です



All Articles