私はこのチュートリアルから今日OpenGLを学び始めました: http://openglbook.com/the-book/
第2章に進み、三角形を描き、VAO以外のすべてを理解しました(この頭字語は大丈夫ですか?)。チュートリアルには次のコードがあります。
glGenVertexArrays(1, &VaoId);
glBindVertexArray(VaoId);
私はコードが必要であることを理解していますが、それが何をするのか見当がつきません。この点を超えてVaoIdを使用することはありませんが(破棄する場合を除く)、コードはそれなしでは機能しません。これはバインドする必要があるためだと思いますが、その理由はわかりません。この正確なコードは、すべてのOpenGLプログラムの一部である必要がありますか?チュートリアルでは、VAOを次のように説明しています。
頂点配列オブジェクト(またはVAO)は、頂点属性が頂点バッファーオブジェクト(またはVBO)に格納される方法を記述するオブジェクトです。つまり、VAOは頂点データを格納する実際のオブジェクトではなく、頂点データの記述子です。頂点属性は、glVertexAttribPointer関数とその2つの姉妹関数glVertexAttribIPointerおよびglVertexAttribLPointerで記述できます。最初の関数については、以下で詳しく説明します。
VAOが頂点属性をどのように説明するのか理解できません。私はそれらを決して説明していません。 glVertexAttribPointerから情報を取得しますか?これだと思う。 VAOはglVertexAttribPointerからの情報の単なる宛先ですか?
補足として、私がフォローしているチュートリアルは受け入れられますか?気をつけるべきことや従うべきより良いチュートリアルはありますか?
「頂点配列オブジェクト」は、愚かな名前のOpenGL ARB小委員会によってもたらされます。
ジオメトリオブジェクトと考えてください。 (昔のSGI Performerプログラマーとして、私はそれらをジオセットと呼びます。)オブジェクトのインスタンス変数/メンバーは、頂点ポインター、通常のポインター、カラーポインター、属性Nポインター、...です。
VAOが最初にバインドされたときに、これらのメンバーを呼び出すには
glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer...;
glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer...;
等々。どの属性が有効になっており、指定したポインターはVAOに保存されています。
その後、VAOを再度バインドすると、これらの属性とポインターもすべて最新になります。したがって、1回のglBindVertexArray
呼び出しは、すべての属性を設定するために以前必要だったすべてのコードと同等です。独自の構造体やオブジェクトを作成せずに、関数やメソッド間でジオメトリを渡すのに便利です。
(一度セットアップすると、複数使用がVAOを使用する最も簡単な方法ですが、属性をバインドし、より多くの有効化/ポインター呼び出しを行うだけで属性を変更することもできます。VAOは定数ではありません。)
パトリックの質問への回答の詳細:
新しく作成されたVAOのデフォルトは、空(AFAIK)です。ジオメトリも頂点もありません。したがって、描画しようとすると、OpenGLエラーが発生します。 「すべてをFalse/NULL /ゼロに初期化する」のように、これは合理的です。
必要なことは、セットアップ時にglEnableClientState
だけです。 VAOは、各ポインターの有効/無効状態を記憶しています。
はい、VAOはglEnableVertexAttribArray
とglVertexAttrib
を保存します。古い頂点、法線、色、...配列は、属性配列、頂点==#0などと同じです。
頂点配列オブジェクトは、ワードプロセッシングプログラムなどのmacrosに似ています。良い説明が見つかりました here 。
マクロだけrememberこの属性をアクティブにする、そのバッファーをバインドするなど、実行したアクション。glBindVertexArray( yourVAOId )
を呼び出すと、単にreplaysこれらの属性ポインターバインディングとバッファバインディング。
したがって、次に描画するための呼び出しは、VAOによってバインドされたものを使用します。
VAOはvertex dataを保存しません。いいえ。頂点データは頂点bufferまたはクライアントメモリの配列に格納されます。
VAOは、OpenGLパイプラインの頂点フェッチステージを表すオブジェクトであり、頂点シェーダーに入力を供給するために使用されます。
このような頂点配列オブジェクトを作成できます
_GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);
_
最初に簡単な例を見てみましょう。シェーダーコードでこのような入力パラメーターを検討する
_layout (location = 0) in vec4 offset; // input vertex attribute
_
この属性を埋めるために使用できます
_glVertexAttrib4fv(0, attrib); // updates the value of input attribute 0
_
頂点配列オブジェクトはこれらの静的属性値を保存しますが、もっと多くのことができます。
頂点配列オブジェクトを作成した後、その状態の入力を開始できます。 OpenGLに、提供するバッファオブジェクトに保存されているデータを使用して自動的に入力するように要求します。各頂点属性は、いくつかの頂点バッファーバインディングの1つにバインドされたバッファーからデータを取得します。このために、glVertexArrayAttribBinding(GLuint vao, GLuint attribindex, GLuint bindingindex)
を使用します。また、glVertexArrayVertexBuffer()
関数を使用して、バッファーを頂点バッファーバインディングの1つにバインドします。 glVertexArrayAttribFormat()
関数を使用してデータのレイアウトと形式を記述し、最後にglEnableVertexAttribArray()
を呼び出して属性の自動入力を有効にします。
頂点属性が有効になっている場合、OpenGLは、glVertexArrayVertexBuffer()
およびglVertexArrayAttribFormat()
で指定した形式と位置情報に基づいて、頂点シェーダーにデータを送ります。属性が無効な場合、頂点シェーダーには、glVertexAttrib*()
の呼び出しで提供する静的情報が提供されます。
_// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));
// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0);
glEnableVertexArrayAttrib(vao, 0);
_
そして、シェーダーのコード
_layout (location = 0) in vec4 position;
_
結局、glDeleteVertexArrays(1, &vao)
を呼び出す必要があります。
OpenGL SuperBible を読んで理解を深めてください。
私は常に、VAOをOpenGLで使用されるデータバッファーの配列と考えています。最新のOpenGLを使用して、VAOおよび頂点バッファーオブジェクトを作成します。
//vaoB is a buffer
glGenVertexArrays(1, vaoB); //creates one VAO
glBindVertexArray(vao.get(0));
glGenBuffers(vbo.length, vbo, 0); //vbo is a buffer
glBindVertexArray(vao.get(1));
glGenBuffers(vbo1.length, vbo1, 0); //vbo1 is a buffer
glBindVertexArray(vao.get(2));
glGenBuffers(vbo2.length, vbo2, 0); //vbo2 is a buffer
次のステップは、データをバッファにバインドすることです。
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER,vertBuf.limit()*4, vertBuf, GL_STATIC_DRAW); //vertf buf is a floatbuffer of vertices
この時点で、OpenGLは次のことを確認します。
これで、glVertexAttribPointerを使用して、バッファ内のデータが何を表すかをOpenGLに伝えることができます。
glBindBuffer(GL_ARRAY_BUFFER, 0); //bind VBO at 0
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); //each vertex has 3 components of size GL_FLOAT with 0 stride (space) between them and the first component starts at 0 (start of data)
OpenGLはバッファにデータを保持し、データが頂点にどのように編成されているかを認識します。同じプロセスをテクスチャ座標などに適用できますが、テクスチャ座標には2つの値があります。
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER,coordBuf.limit()*4, coordBuf, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
次に、テクスチャをバインドして配列を描画します。VertおよびFragシェーダを作成し、コンパイルしてプログラムに添付します(ここには含まれていません)。
glActiveTexture(textureID); //bind our texture
glBindTexture(GL_TEXTURE_2D, textureID);
glDrawArrays(GL_TRIANGLES,0,6); //in this case 6 indices are used for two triangles forming a square