web-dev-qa-db-ja.com

頂点配列オブジェクトとは何ですか?

私はこのチュートリアルから今日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からの情報の単なる宛先ですか?

補足として、私がフォローしているチュートリアルは受け入れられますか?気をつけるべきことや従うべきより良いチュートリアルはありますか?

96
Patrick

「頂点配列オブジェクト」は、愚かな名前の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はglEnableVertexAttribArrayglVertexAttribを保存します。古い頂点、法線、色、...配列は、属性配列、頂点==#0などと同じです。

88
Hugh

頂点配列オブジェクトは、ワードプロセッシングプログラムなどのmacrosに似ています。良い説明が見つかりました here

マクロだけrememberこの属性をアクティブにする、そのバッファーをバインドするなど、実行したアクション。glBindVertexArray( yourVAOId )を呼び出すと、単にreplaysこれらの属性ポインターバインディングとバッファバインディング。

したがって、次に描画するための呼び出しは、VAOによってバインドされたものを使用します。

VAOはvertex dataを保存しません。いいえ。頂点データは頂点bufferまたはクライアントメモリの配列に格納されます。

7
bobobobo

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 を読んで理解を深めてください。

5
Yola

私は常に、VAOをOpenGLで使用されるデータバッファーの配列と考えています。最新のOpenGLを使用して、VAOおよび頂点バッファーオブジェクトを作成します。

enter image description here

//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は次のことを確認します。

enter image description here

これで、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)

enter image description here

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
1
vasmos