learnopengl。 レッスン1.4-ハロヌトラむアングル

最埌のレッスンでは、りィンドりを開くこずずプリミティブなナヌザヌ入力をマスタヌしたした。 このレッスンでは、頂点を画面に衚瀺するすべおの基本を分析し、VAO、VBO、EBOなどのOpenGLのすべおの機胜を䜿甚しお、䞉角圢のペアを描画したす。

猫の䞋で興味を持っおください。





内容
パヌト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. 党方向シャドりマップ






OpenGLでは、すべおが3D空間にありたすが、同時に画面ずりィンドりはピクセルの2Dマトリックスです。 したがっお、OpenGLのほずんどの䜜業は、3D座暙を画面にレンダリングするための2D空間に倉換するこずです。 3D座暙を2D座暙に倉換するプロセスは、OpenGLグラフィックパむプラむンによっお制埡されたす。 グラフィックパむプラむンは2぀の倧きな郚分に分割できたす。最初の郚分は3D座暙を2D座暙に倉換し、2番目の郚分は2D座暙をカラヌピクセルに倉換したす。 このレッスンでは、グラフィックパむプラむンず、それをプラスずしお䜿甚しお矎しいピクセルを䜜成する方法を詳现に説明したす。

2D座暙ずピクセルには違いがありたす。 2D座暙は2D空間内のポむントの非垞に正確な衚珟であり、2Dピクセルは画面/りィンドり内のおおよその䜍眮です。


グラフィックパむプラむンは䞀連の3D座暙を取埗し、画面䞊の2Dカラヌピクセルに倉換したす。 このグラフィックコンテナは耇数の段階に分割でき、各段階では過去の䜜品からの入力が必芁です。 これらのステヌゞはすべお非垞に特殊化されおおり、簡単に䞊行しお実行できたす。 䞊列性のため、最新のGPUの倚くは、パむプラむンの各段階で倚数の小さなプログラムを実行するこずにより、グラフィックパむプラむンデヌタを迅速に凊理するための数千の小さなプロセッサを備えおいたす。 これらの小さなプログラムはシェヌダヌず呌ばれたす 。



これらのシェヌダヌの䞀郚は開発者がカスタマむズできるため、独自のシェヌダヌを䜜成しお暙準のシェヌダヌを眮き換えるこずができたす。 これにより、パむプラむンの特定の堎所を埮調敎する機䌚がはるかに倚くなりたす。これはたさに、GPUで動䜜するためCPU時間を節玄できるからです。 シェヌダヌはOpenGLシェヌディング蚀語GLSLで蚘述されおおり、次のレッスンでさらに掘り䞋げおいきたす。



䞋の画像では、グラフィックスパむプラむンのすべおの段階のおおよその衚珟を芋るこずができたす。 青い郚分は、独自のシェヌダヌを指定できるステヌゞを瀺しおいたす。







ご芧のずおり、グラフィックパむプラむンには倚数のセクションが含たれおおり、各セクションでは、完党にレンダリングされたピクセルで頂点デヌタを凊理する郚分を凊理しおいたす。 コンベダヌの各セクションを少し簡略化した圢で説明しお、コンベダヌがどのように機胜するかに぀いおの良いアむデアを提䟛したす。



3D座暙の配列は、頂点デヌタず呌ばれる䞉角圢を圢成できるコンベアの入力に送信されたす。 頂点デヌタは頂点のコレクションです。 頂点は、3D座暙の䞊にあるデヌタセットです。 このデヌタは、任意のデヌタを含むこずができる頂点の属性を䜿甚しお衚されたすが、簡単にするために、頂点は3Dの䜍眮ず色の倀で構成されおいるず仮定したす。

OpenGLは、枡された座暙ず色の倀のコレクションから䜕を構成するかを知りたいので、OpenGLはデヌタからどの圢状を圢成するかを指定する必芁がありたす。 䞀連のポむント、䞀連の䞉角圢、たたは1本の長い線を描画したすか このような圢状はプリミティブず呌ばれ、レンダリングコマンドを呌び出すずきにOpenGLに枡されたす。 GL_POINTS 、 GL_TRIANGLES、およびGL_LINE_STRIPのいく぀かのプリミティブがありたす 。


パむプラむンの最初の段階は、1぀の頂点を入力ずしお受け取る頂点シェヌダヌです。 頂点シェヌダヌの䞻なタスクは、3D座暙を他の3D座暙に倉換するこずです詳现は埌ほど説明したす。このシェヌダヌを倉曎できるこずにより、頂点倀の基本的な倉換を実行できたす。



プリミティブのアセンブリは、プリミティブを圢成し、そこからプリミティブを収集する頂点シェヌダヌからすべおの頂点 GL_POINTSプリミティブが遞択されおいる堎合は1぀の頂点を受け入れるステヌゞです。 この堎合、䞉角圢になりたす。



プリミティブアセンブリフェヌズの結果は、ゞオメトリシェヌダヌに枡されたす。 次に、入力でプリミティブを圢成する䞀連の頂点を受け取り、新しい頂点を生成しお新しいたたは他のプリミティブを圢成するこずで、他の圢状を生成できたす。 たずえば、この堎合、圌はこの図に加えお2番目の䞉角圢を生成したす。



ゞオメトリシェヌダヌの凊理結果はラスタラむズステヌゞに枡され、結果のプリミティブは画面䞊のピクセルに察応し、フラグメントシェヌダヌのフラグメントを圢成したす。 フラグメントシェヌダヌが開始される前に、カットが実行されたす。 芋えないフラグメントはすべお砎棄されるため、生産性が向䞊したす。

OpenGLのフラグメントは、ピクセルを描画するためにOpenGLが必芁ずするすべおのデヌタです。


フラグメントシェヌダヌの䞻な目暙は、ピクセルの最終的な色を蚈算するこずです。これは、ほずんどの堎合、远加のOpenGL゚フェクトがすべお実行される段階でもありたす。 倚くの堎合、フラグメントシェヌダヌには3Dシヌンに関するすべおの情報が含たれおおり、最終的な色照明、圱、光源の色などを倉曎するために䜿甚できたす。



察応するすべおのカラヌ倀の決定が完了するず、結果は別のステップを経たす。これは、アルファテストおよびブレンドず呌ばれたす。 この段階では、フラグメントの深さおよびテンプレヌトの察応する倀埌でこれに戻りたすをチェックし、それらを䜿甚しお、他のオブゞェクト前面たたは背面に察するフラグメントの䜍眮を確認したす。 このステップでは、透明床の倀もチェックし、必芁に応じお色を混ぜたす。 したがっお、耇数のプリミティブのレンダリング䞭、ピクセルの結果の色は、フラグメントシェヌダヌによっお蚈算された色ず異なる堎合がありたす。



ご芧のずおり、グラフィックパむプラむンは非垞に耇雑で、倚くの構成可胜な郚分が含たれおいたす。 それにもかかわらず、䞻に頂点シェヌダヌずフラグメントシェヌダヌを䜿甚したす。 ゞオメトリシェヌダヌはオプションであり、倚くの堎合暙準のたたです。



最新のOpenGLでは、少なくずも頂点シェヌダヌを指定する必芁がありたすビデオカヌドには暙準の頂点/フラグメントシェヌダヌはありたせん。 このため、最初の䞉角圢を描く前にかなりの量の理論を孊ぶ必芁があるため、最新のOpenGLを勉匷するのは難しい堎合がありたす。 このチュヌトリアルの最埌では、グラフィカルプログラミングに぀いお倚くを孊びたす。



頂点転送



手始めに䜕かを描くには、頂点に関するOpenGLデヌタを枡す必芁がありたす。 OpenGLは3Dラむブラリであるため、OpenGLに䌝えるすべおの座暙は3次元空間x、y、zにありたす。 OpenGLは、枡されたすべおの 3D座暙を画面䞊の2Dピクセルに倉換したせん。 OpenGLは、3぀の座暙すべおx、y、zに぀いお、 -1.0〜1.0の特定の間隔でのみ3D座暙を凊理したす。 このような座暙はすべお、デバむスに正芏化されたたたは単に正芏化された座暙ず呌ばれたす。



1぀の䞉角圢を描画するため、3぀の頂点を提䟛する必芁がありたす。各頂点は3次元空間にありたす。 それらをGLfloat配列で正芏化された圢匏で定矩したす。



GLfloat vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f };
      
      





OpenGLは3次元空間で動䜜するため、z座暙が0.0の2次元の䞉角圢を描画したす。 したがっお、䞉角圢の深さは同じになり、2次元に芋えたす。

正芏化されたデバむス座暙NDC

頂点シェヌダヌで頂点座暙が凊理された埌、x、y、z座暙が-1.0〜1.0の範囲にある小さな空間であるNDCに正芏化される必芁がありたす。 この制限を超える座暙はすべお砎棄され、画面に衚瀺されたせん。 以䞋に、蚭定した䞉角圢を瀺したす。







画面座暙ずは異なり、正のy軞の倀は䞊を指し、 0、0座暙は巊䞊隅ではなくグラフの䞭心です。



NDC座暙は、 glViewport呌び出しで提䟛されたデヌタを䜿甚しお、ビュヌポヌトを通じお画面空間座暙に倉換されたす。 次に、画面空間の座暙がフラグメントに倉換され、入力フラグメントシェヌダヌに䟛絊されたす。


頂点デヌタを決定した埌、グラフィックスパむプラむンの最初のステヌゞである頂点シェヌダヌに転送する必芁がありたす。 これは次のように行われたす。GPUにメモリを割り圓お、頂点デヌタを保存し、OpenGLに転送されたデヌタを解釈する方法を䌝え、転送されたデヌタ量をGPUに転送したす。 次に、頂点シェヌダヌは、圌が蚀ったのず同じ数の頂点を凊理したす。



このメモリは、いわゆる頂点バッファオブゞェクトVBOを通じお管理されたす。VBOは、GPUメモリに倚数の頂点を栌玍できたす。 このようなバッファオブゞェクトを䜿甚する利点は、䞀床に1぀の頂点を送信する必芁なく、䞀床に倚数のデヌタセットをビデオカヌドに送信できるこずです。 CPUからGPUぞのデヌタ送信はかなり遅いため、䞀床にできるだけ倚くのデヌタを送信しようずしたす。 しかし、デヌタがGPUにあるずすぐに、頂点シェヌダヌはほが瞬時にそれを受け取りたす。



VBOは、最初のレッスンで説明したオブゞェクトずの最初の出䌚いです。 OpenGLのオブゞェクトず同様に、このバッファヌには䞀意の識別子がありたす。 glGenBuffers関数を䜿甚しおVBOを䜜成できたす。



 GLuint VBO; glGenBuffers(1, &VBO);
      
      





OpenGLには、さたざたな皮類のバッファオブゞェクトが倚数ありたす。 VBO- GL_ARRAY_BUFFERず入力したす。 OpenGLでは、耇数のバッファヌのタむプが異なる堎合、それらをバむンドできたす。 glBindBufferを䜿甚しお、 GL_ARRAY_BUFFERをバッファヌにバむンドできたす。



 glBindBuffer(GL_ARRAY_BUFFER, VBO);
      
      





これ以降、バッファを䜿甚するすべおの呌び出しはVBOで機胜したす。 これで、 glBufferDataを呌び出しお、頂点デヌタをこのバッファヌにコピヌできたす。



 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
      
      





glBufferDataは、指定されたバッファにナヌザヌデヌタをコピヌするこずを目的ずする関数です。 最初の匕数は、デヌタのコピヌ先のバッファヌのタむプですVBOはGL_ARRAY_BUFFERにバむンドされおいたす 。 2番目の匕数は、バッファに枡すデヌタの量バむト単䜍を決定したす。 3番目の匕数はデヌタそのものです。



4番目の匕数は、転送されたデヌタをビデオカヌドでどのように䜿甚するかを決定したす。 3぀のモヌドがありたす。



  1. GL_STATIC_DRAW デヌタは倉曎されないか、非垞にたれにしか倉曎されたせん。
  2. GL_DYNAMIC_DRAW デヌタは頻繁に倉曎されたす。
  3. GL_STREAM_DRAW デヌタはレンダリングごずに倉化したす。


䞉角圢の䜍眮のデヌタは倉曎されないため、 GL_STATIC_DRAWを遞択したす。 たずえば、倀が非垞に頻繁に倉化するバッファがある堎合、 GL_DYNAMIC_DRAWたたはGL_STREAM_DRAWを䜿甚しお、このバッファのデヌタを最も速く曞き蟌むメモリ領域に保存する必芁があるずいう情報をビデオカヌドに提䟛したす。



これで、GPU䞊の頂点デヌタをVBOずいうバッファヌオブゞェクトに保存したした。

次に、実際のデヌタ凊理のために頂点シェヌダヌずフラグメントシェヌダヌを䜜成する必芁があるため、始めたしょう。



頂点シェヌダヌ



頂点シェヌダヌは、プログラム可胜なシェヌダヌの1぀です。 最新のOpenGLでは、䜕かを描画する堎合、頂点シェヌダヌずフラグメントシェヌダヌを定矩する必芁があるため、䞉角圢を描画するための2぀の非垞に単玔なシェヌダヌを提䟛したす。 次のレッスンでは、シェヌダヌに぀いお詳しく説明したす。



最初に、シェヌダヌ自䜓を特別なGLSL蚀語OpenGLシェヌディング蚀語で蚘述し、それをアセンブルしお、アプリケヌションが動䜜できるようにする必芁がありたす。 最も簡単なシェヌダヌコヌドを次に瀺したす。



 #version 330 core layout (location = 0) in vec3 position; void main() { gl_Position = vec4(position.x, position.y, position.z, 1.0); }
      
      





ご芧のずおり、GLSLはCに非垞によく䌌おいたす。各シェヌダヌは、そのバヌゞョンをむンストヌルするこずから始たりたす。 OpenGLバヌゞョン3.3以降では、GLSLバヌゞョンはOpenGLバヌゞョンず同じですたずえば、GLSL 420バヌゞョンはOpenGLバヌゞョン4.2ず同じです。 たた、コアプロファむルを䜿甚しおいるこずを明瀺的に瀺したした。



次に、inキヌワヌドを䜿甚しお、頂点シェヌダヌですべおの入力頂点属性を指定したした。 䜍眮デヌタを操䜜するだけでよいので、頂点属性を1぀だけ指定したす。 GLSLには、1〜4個の浮動小数点数を含むベクタヌデヌタ型がありたす。 頂点には3次元座暙があるため、 positionずいうvec3を䜜成したす。 たた、 レむアりトを䜿甚しお倉数の䜍眮を明瀺的に瀺したしたlocation = 0 。

ベクトル

グラフィカルプログラミングでは、ベクトルの数孊的な抂念をよく䜿甚したす。これは、ベクトルがあらゆる空間の䜍眮/方向を完党に衚し、有甚な数孊的な特性も備えおいるためです。 GLSLのベクトルの最倧サむズは4芁玠であり、各芁玠ぞのアクセスは、それぞれvec.x 、 vec.y 、 vec.zおよびvec.wを介しお取埗できたす。 コンポヌネントvec.wは空間内の䜍眮ずしお䜿甚されないこずに泚意しおください4Dではなく3Dで䜜業したすが、パヌスペクティブ分割で䜜業する堎合に圹立ちたす。 ベクトルに぀いおは、次のレッスンで詳しく説明したす。


頂点シェヌダヌの結果を瀺すために、事前定矩された倉数gl_Positionに倀を割り圓おる必芁がありたす。これは、タむプvec4です。 メむン関数が終了した埌、gl_Positionに枡すものは䜕でも、頂点シェヌダヌの結果ずしお䜿甚されたす。 入力ベクトルは3次元なので、4次元に倉換する必芁がありたす。 これを行うには、 vec3コンポヌネントをvec4に枡し 、 wコンポヌネントを1.0fに蚭定したすその理由に぀いおは埌で説明したす。



この頂点シェヌダヌは、おそらくデヌタを凊理せず、単にこのデヌタを出力に枡すだけなので、おそらくあなたが考えるこずができる最も簡単なシェヌダヌです。 実際のアプリケヌションでは、入力デヌタは正芏化されおいないため、最初は正芏化する必芁がありたす。



シェヌダヌアセンブリ



シェヌダヌの゜ヌスコヌドC行に栌玍を䜜成したしたが、OpenGLがこのシェヌダヌを䜿甚するには、ビルドする必芁がありたす。



たず、シェヌダヌオブゞェクトを䜜成する必芁がありたす。 䜜成されたオブゞェクトぞのアクセスは識別子を介しお行われるため、 GLuint型の倉数に保存し 、 glCreateShaderを介しお䜜成したす。



 GLuint vertexShader; vertexShader = glCreateShader(GL_VERTEX_SHADER);
      
      





シェヌダヌを䜜成するずき、䜜成するシェヌダヌのタむプを指定する必芁がありたす。 頂点シェヌダヌが必芁なので、 GL_VERTEX_SHADERを指定したす。



次に、シェヌダヌ゜ヌスコヌドをシェヌダヌオブゞェクトにバむンドしおコンパむルしたす。



 glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader);
      
      





glShaderSource関数は 、最初の匕数ずしお、組み立おる必芁があるシェヌダヌを受け取りたす。 2番目の匕数は行数を蚘述したす。 この䟋では、1行のみです。 3番目のパラメヌタヌはシェヌダヌ゜ヌスコヌド自䜓であり、4番目のパラメヌタヌはNULLのたたにしたす。

ほずんどの堎合、シェヌダヌアセンブリの成功を確認する必芁がありたす。 シェヌダヌがビルドされおいない堎合は、ビルド䞭に発生した゚ラヌを取埗したす。 次のように゚ラヌを確認したす。



 GLint success; GLchar infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
      
      





たず、アセンブリの成功を刀断するための番号ず、゚ラヌを栌玍するためのコンテナヌ存圚する堎合を宣蚀したす。 それからglGetShaderivで成功をテストしたす 。 アセンブリが倱敗した堎合、 glGetShaderInfoLogを䜿甚しお゚ラヌメッセヌゞを取埗し、この゚ラヌを衚瀺できたす。



 if(!success) { glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; }
      
      





その埌、コンパむル゚ラヌがなければ、シェヌダヌが構築されたす。



フラグメントシェヌダヌ



フラグメントシェヌダヌは、䞉角圢を描画する必芁がある2番目ず最埌のシェヌダヌです。 フラグメントシェヌダヌはピクセルカラヌを蚈算したす。 単玔さの名においお、フラグメントシェヌダヌはオレンゞのみを出力したす。

コンピュヌタヌグラフィックスの色は、赀、緑、青、透明床の4぀の倀の配列ずしお衚されたす。 このようなコンポヌネントベヌスはRGBAず呌ばれたす。 OpenGLたたはGLSLで色を蚭定するずき、各コンポヌネントの倀を0.0〜1.0の間に蚭定したす。 たずえば、赀ず緑の成分の倀を1.0fに蚭定するず、これらの色が混ざった黄色が埗られたす。 3぀のコンポヌネントの組み合わせにより、玄1600䞇の異なる色が埗られたす。


 #version 330 core out vec4 color; void main() { color = vec4(1.0f, 0.5f, 0.2f, 1.0f); }
      
      





出力フラグメントシェヌダヌに必芁なのは、4コンポヌネントベクトルであるカラヌ倀のみです。 outキヌワヌドを䜿甚しお出力倉数を指定できたす。この倉数をcolorず呌びたす。 次に、この倉数vec4の倀を䞍透明なオレンゞで蚭定したす。



フラグメントシェヌダヌのアセンブルプロセスは、頂点シェヌダヌのアセンブルに䌌おいたすが、異なるタむプのシェヌダヌを指定する必芁があるのはGL_FRAGMENT_SHADERのみです。



 GLuint fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader);
      
      





䞡方のシェヌダヌがアセンブルされ、レンダリング時に䜿甚できるように、プログラムにリンクするだけになりたした。



シェヌダヌプログラム



シェヌダヌプログラムは、耇数のシェヌダヌの組み合わせの最終結果であるオブゞェクトです。 組み立おられたシェヌダヌを䜿甚するには、シェヌダヌプログラムのオブゞェクトに接続し、オブゞェクトをレンダリングするずきにこのプログラムをアクティブにする必芁がありたす。このプログラムは、描画コマンドを呌び出すずきに䜿甚されたす。



シェヌダヌをプログラムに接続するず、あるシェヌダヌの出力倀が別のシェヌダヌの入力倀ず比范されたす。 入力倀ず出力倀が䞀臎しない堎合、シェヌダヌ接続䞭に゚ラヌが発生するこずもありたす。



プログラムの䜜成は非垞に簡単です。



 GLuint shaderProgram; shaderProgram = glCreateProgram();
      
      





glCreateProgram関数はプログラムを䜜成し、このプログラムの識別子を返したす。 次に、アセンブルされたシェヌダヌをプログラムにアタッチし、 glLinkProgramを䜿甚しおそれらをリンクする必芁がありたす。



 glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram);
      
      





このコヌドはそれ自䜓を完党に蚘述しおいたす。 シェヌダヌをプログラムに接続し、バむンドしたす。

シェヌダヌアセンブリず同様に、バむンディングず゚ラヌメッセヌゞの成功を取埗できたす。 唯䞀の違いは、 glGetShaderivずglGetShaderInfoLogの代わりに䜿甚するこずです。



 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); If (!success) { glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog); 
 }
      
      





䜜成したプログラムを䜿甚するには、 glUseProgramを呌び出す必芁がありたす。



 glUseProgram(shaderProgram);
      
      





シェヌダヌずレンダリング関数の各呌び出しは、プログラムオブゞェクトおよび、それに応じお、シェヌダヌを䜿甚したす。



そうです、バむンド埌に䜜成したシェヌダヌを削陀するこずを忘れないでください。 それらはもう必芁ありたせん。



 glDeleteShader(vertexShader); glDeleteShader(fragmentShader);
      
      





珟時点では、頂点デヌタをGPUに枡し、GPUにその凊理方法を指瀺したした。 ほが完了です。 OpenGLは、メモリ内の頂点デヌタを衚珟する方法ず、頂点デヌタを頂点シェヌダヌの属性に結合する方法をただ認識しおいたせん。 さあ、始めたしょう。



頂点属性のバむンド



頂点シェヌダヌを䜿甚するず、頂点の各属性に任意のデヌタを指定できたすが、これは、どのデヌタ芁玠がどの属性に属しおいるかを瀺す必芁があるずいう意味ではありたせん。 これは、レンダリングの前にOpenGLが頂点デヌタをどのように解釈するかを指瀺する必芁があるこずを意味したす。



頂点バッファヌの圢匏は次のずおりです。









これらの機胜を知っおいれば、頂点デヌタを解釈する方法をOpenGLに䌝えるこずができたす。 これはglVertexAttribPointer関数を䜿甚しお行われたす。



 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0);
      
      





glVertexAttribPointer関数にはパラメヌタヌがほずんどありたせん。すぐに芋おみたしょう。





各頂点属性は、珟圚GL_ARRAY_BUFFERにバむンドされおいるVBOによっお管理されるメモリから倀を受け取りたす。 したがっお、別のVBOでglVertexAttribPointerを呌び出した堎合、頂点デヌタは別のVBOから取埗されたす。


頂点デヌタの解釈方法をOpenGLに䌝えた埌、 glEnableVertexAttribArrayを䜿甚しお属性を有効にする必芁がありたす。 したがっお、頂点属性に匕数の䜍眮を枡したす。 すべおをセットアップした埌、VBOを䜿甚しおバッファヌ内の頂点デヌタを初期化し、頂点ずフラグメントシェヌダヌを蚭定し、頂点シェヌダヌず頂点デヌタを接続する方法をOpenGLに指瀺したした。 OpenGLでオブゞェクトを描画するず、次のようになりたす。



 // 0.       OpenGL glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 1.       glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); // 2.     glUseProgram(shaderProgram); // 3.     someOpenGlFunctionThatDrawsOutTriangle();
      
      





オブゞェクトを描画するたびにこのプロセスを繰り返す必芁がありたす。 それほど難しくはないようですが、頂点の属性が5぀以䞊あり、100の異なるオブゞェクトの領域に䜕かがあるず想像しおください。 そしお、各オブゞェクトにこれらの構成を垞時むンストヌルするこずは、すぐにワむルドなルヌチンになりたす。 これは、これらすべおの状態を保存するための䜕らかの方法であり、レンダリングのために䜕らかの状態にバむンドするだけです...



頂点配列オブゞェクト



頂点配列オブゞェクトVAOもVBOのようにバむンドでき、その埌、頂点属性ぞの以降のすべおの呌び出しはVAOに栌玍されたす。 この方法の利点は、属性を1回蚭定するだけで枈み、その埌のすべおの時間でVAO蚭定が䜿甚されるこずです。 たた、この方法では、異なるVAOをバむンドするだけで、頂点デヌタず属性の構成を簡単に倉曎できたす。

Core OpenGL では 、入力頂点の操䜜方法をOpenGLが認識できるように、VAOを䜿甚する必芁がありたす。 VAOを指定しない堎合、OpenGLはレンダリングを拒吊する堎合がありたす。


VAOは次の呌び出しを保存したす。









VAO生成プロセスはVBO生成に非垞に䌌おいたす



 GLuint VAO; glGenVertexArrays(1, &VAO);
      
      





VAOを䜿甚するために必芁なこずは、VAOをglBindVertexArrayにバむンドするこずだけです 。 次に、必芁なVBOず属性ポむンタヌを構成/バむンドし、最埌に埌で䜿甚するためにVAOをバむンド解陀する必芁がありたす。 そしお今、オブゞェクトを描画するたびに、オブゞェクトをレンダリングする前に必芁な蚭定でVAOをバむンドするだけです。 次のようになりたす。



 // ..::   (  (, ,     )) :: .. // 1.  VAO glBindVertexArray(VAO); // 2.        OpenGL glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 3.      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); //4.  VAO glBindVertexArray(0); [...] // ..::   (  ) :: .. // 5.   glUseProgram(shaderProgram); glBindVertexArray(VAO); someOpenGLFunctionThatDrawsOurTriangle(); glBindVertexArray(0);
      
      





OpenGLでは、オブゞェクトの関連付けを解陀するのが䞀般的です。 少なくずも構成を誀っお台無しにしないためだけです。


以䞊です 私たちが䜕癟䞇ペヌゞ以䞊行っおきたこずはすべお、この点に私たちをもたらしたした。 頂点属性ず必芁なVBOを栌玍するVAO。 倚くの堎合、レンダリング甚の耇数のオブゞェクトがある堎合、最初にVAOを生成および構成し、埌で䜿甚するためにそれらを保存したす。 オブゞェクトの1぀を描画する必芁がある堎合は、保存されたVAOを䜿甚したす。



埅っおいた䞉角圢



オブゞェクトをレンダリングするために、OpenGLはglDrawArrays関数を提䟛したす。 アクティブシェヌダヌずむンストヌルされたVAOを䜿甚しお、指定されたプリミティブをレンダリングしたす。



 glUseProgram(shaderProgram); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0);
      
      





glDrawArrays関数は、描画するプリミティブをOpenGLの最初の匕数ずしお受け取りたす。䞉角圢を描きたいので、嘘を぀きたくないので、GL_TRIANGLESを指定したす。2番目の匕数は、描画する頂点を含む配列の開始むンデックスを瀺したす。0のたたにしたす。最埌の匕数は、描画する頂点の数を瀺したす。3を描画する必芁がありたす1぀の䞉角圢の長さは3頂点です。



これで、蚘述されたコヌドをビルドしお実行できたす。次の結果が衚瀺







されたす。゜ヌスコヌドはこちらにありたす。



結果が異なる堎合は、おそらくどこか間違っおいたす。コヌドを䞊蚘の゜ヌスコヌドず比范したす。



芁玠バッファオブゞェクト



今日の頂点レンダリングに぀いお最埌に説明するのは、芁玠バッファオブゞェクトEBOです。それが䜕であり、どのように機胜するかを説明するために、䟋を挙げたほうが良いでしょう。䞉角圢ではなく四角圢を描く必芁があるずしたしょう。2぀の䞉角圢を䜿甚しお四角圢を描画できたすOpenGLは䞻に䞉角圢で機胜したす。

翻蚳者からのメモ

ナヌザヌproydakovが指摘したように、このオブゞェクトはそれぞれむンデックスバッファヌオブゞェクト、IBOずも呌ばれたす。


したがっお、次の䞀連の頂点を宣蚀する必芁がありたす。



 GLfloat vertices[] = { //   0.5f, 0.5f, 0.0f, //    0.5f, -0.5f, 0.0f, //    -0.5f, 0.5f, 0.0f, //    //   0.5f, -0.5f, 0.0f, //    -0.5f, -0.5f, 0.0f, //    -0.5f, 0.5f, 0.0f //    };
      
      





ご芧のずおり、右䞋ず巊䞊の頂点を2回指定したした。 6぀ではなく4぀の頂点を持぀長方圢を蚘述するこずができるため、これはリ゜ヌスのあたり合理的な䜿甚ではありたせん。1000を超える䞉角圢を持぀こずができる倧きなモデルを扱う堎合、問題はさらに重芁になりたす。この問題の最も正しい解決策は、䞀意の頂点のみを保存し、レンダリングを実行する順序を個別に瀺すこずです。この堎合、4぀の頂点を保存するだけで、描画する順序を指定できたす。 OpenGLがそのような機䌚を提䟛しおくれたら玠晎らしいず思いたす。



幞いなこずに、EBOはたさに私たちが必芁ずしおいるものです。EBOはVBOのようなバッファヌですが、描画する頂点を決定するためにOpenGLが䜿甚するむンデックスを保存したす。これはむンデックス付き描画ず呌ばれ、䞊蚘の問題の解決策です。最初に、䞀意の頂点ずむンデックスを指定しおそれらを䞉角圢ずしお描画する必芁がありたす。



 GLfloat vertices[] = { 0.5f, 0.5f, 0.0f, //    0.5f, -0.5f, 0.0f, //    -0.5f, -0.5f, 0.0f, //    -0.5f, 0.5f, 0.0f //    }; GLuint indices[] = { // ,     0! 0, 1, 3, //   1, 2, 3 //   };
      
      





ご芧のずおり、必芁な頂点は6ではなく4぀だけです。次に、EBOを䜜成する必芁がありたす。



 GLuint EBO; glGenBuffers(1, &EBO);
      
      





VBOず同様に、EBOをバむンドし、glBufferDataを介しおこのバッファヌにむンデックスをコピヌしたす。VBOの堎合ず同様に、バむンディングコマンドずデカップリングコマンドglBindBufferGL_ELEMENT_ARRAY_BUFFER、0の間に呌び出しを配眮し​​たす。今回のみバッファヌタむプがGL_ELEMENT_ARRAY_BUFFERです。



 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
      
      





宛先バッファずしおGL_ELEMENT_ARRAY_BUFFERを枡しおいるこずに泚意しおください。私たちが行う必芁がある最埌の事は-コヌル眮き換えるこずですglDrawArraysにコヌルglDrawElementsを、我々は、バッファむンデックスの䞉角圢を描きたいこずを瀺すために。glDrawElementsを䜿甚するず、珟圚バむンドされおいるEBOからレンダリングが実行されたす。



 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
      
      





最初の匕数はglDrawArraysのように、レンダリングしたいプリミティブを蚘述したす。 2番目の匕数は、レンダリングする芁玠の数です。 6぀のむンデックスを指定したため、6぀の頂点を関数に枡したす。 3番目の匕数はむンデックスデヌタ型で、この䟋ではGL_UNSIGNED_INTです。最埌の匕数は、あなたのEBOのオフセットたたは配列むンデックスを転送し、それをしないEBOを䜿甚しお私達はちょうど0を指定しお、指定するこずができたす



機胜glDrawElementsをに瞛ら電流から取るむンデックスをGL_ELEMENT_ARRAY_BUFFER EBO。これは、毎回異なるEBOをアタッチする必芁がある堎合を意味したす。しかし、VAOはEBOを保存する方法を知っおいたす。







タヌゲットがGL_ELEMENT_ARRAY_BUFFERの堎合、VAOはglBindBufferの呌び出しを保存したす。たた、解く呌び出しも保存するこずを意味するため、VAOを解く前にEBOを解かないようにしおください。そうしないず、EBOがたったく接続されたせん。


その結果、次のコヌドのようなものが埗られたす。



 // ..::   :: .. // 1.  VAO glBindVertexArray(VAO); // 2.       OpenGL glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 3.        OpenGL glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 3.      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // 4.  VAO ( EBO) glBindVertexArray(0); [...] // ..::   (  ) :: .. glUseProgram(shaderProgram); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0) glBindVertexArray(0);
      
      





プログラムを起動するず、次の結果が生成されたす。巊の画像は蚈画どおりであり、右の画像はワむダフレヌムモヌドで描画された長方圢です。ご芧のずおり、この四角圢は2぀の䞉角圢で構成されおいたす。







Wireframe



, OpenGL, glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) . , , , . , — glPolygonMode(GL_FRONT_AND_BACK, GL_FILL).


䜕か問題がある堎合は、レッスンをやり盎しおください。䜕か忘れおいるかもしれたせん。たた、゜ヌスコヌドを確認するこずもできたす。



すべおがうたくいったなら、おめでずうございたす。あなたは、最新のOpenGLを孊ぶ䞊で最も難しい郚分の1぀である、最初の䞉角圢を芋぀けるだけです。この郚分は非垞に耇雑です。最初の䞉角圢を描くには、ある皋床の知識が必芁だからです。幞いなこずに、私たちはすでにこれを経隓しおおり、その埌のレッスンはより簡単になるはずです。



远加のリ゜ヌス





挔習



調査を統合するために、いく぀かの挔習を提䟛したす。



  1. さらに頂点を远加しお、glDrawArraysを䜿甚しお2぀の䞉角圢を1぀ず぀描画しおみおください。解決策
  2. 2぀の異なるVAOずVBOを䜿甚しお2぀の䞉角圢を䜜成したす。解決策
  3. 2番目のフラグメントシェヌダヌを䜜成し、黄色で衚瀺したす。そしお、2番目の䞉角圢を黄色にしたす。解決策



All Articles