OpenGL:VBOを指定せずにVAOを使用できますか


12

VAO(頂点配列オブジェクト)に関するすべてのチュートリアルで、頂点属性を構成し、VBO(頂点バッファーオブジェクト)をバインドすることにより、VAOの使用方法を示しています。しかし、各バッファーが同じデータパターン(頂点、uv、色など)を使用する固定シェーダーと組み合わせて、VBOのセット用に構成されるVAOを作成します。したがって、1つのシェーダーを使用して描画される複数のVBOに対して1つのVAOを作成します。

これに関するデモが見つからなかったため、試してみることにしました。しかし、それは機能せず、glDrawArray呼び出し時にクラッシュします。VBOがバインドされていないようです。私が使用しているコードは次のとおりです。

レンダリング:

/* Prepare vertex attributes */
glBindVertexArrayOES(vao);

/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());

/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);

glBindVertexArrayOES(0);

VAO作成:

glBindVertexArrayOES(vao);

glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);

glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));

glBindVertexArrayOES(0);

属性の場所を保持lsするシンプルな場所はどこですかstruct

レンダリングの部分では、glBindBufferとそのglBindVertexArrayOES周りを交換しても機能しませんでした。

だから、問題はそうすることさえ可能ですか、それとも各バッファにVAOを作成する必要がありますか?また、VBOごとにVAOを作成する必要がある場合、VAOとglBufferSubData組み合わせて使用してVBOのデータを更新することはできますか?

回答:


18

VAOには、GL_ELEMENT_ARRAY_BUFFERバインド状態を除き、「glBindBuffer」状態は含まれません。あなたが理解していないことはそれglBindBuffer(GL_ARRAY_BUFFER) は何もしないということです。レンダリングに関する限り、何もしません。それを試してみてください; glDraw *を呼び出す直前にcall glBindBuffer(GL_ARRAY_BUFFER, 0); レンダリングはうまく機能します。

道のglVertexAttribPointer作品は、それがGL_ARRAY_BUFFERにバインドされているものを見ていることである時にglVertexAttribPointer呼ばれます。レンダリング時ではありません。後でありません。まさにその瞬間。そこにあったバッファオブジェクトをすべて取得し、VAO内にカプセル化された別のOpenGL状態に格納します。

一般に、2つのオプションがありますが、そのうちの1つは新しく、おそらく現時点では使用すべきではありません。

最初のオプションは、同じ頂点フォーマット(つまり、バッファオブジェクトとオフセットを除くすべて)を使用するすべてのオブジェクトを同じバッファオブジェクトに配置することです。基本的に、同じ形式を使用するすべてのオブジェクトのすべての頂点を含む巨大な配列を作成します。

レンダリングするときが来たら、頂点の一部をレンダリングできます。glDrawArraysレンダリングする要素の範囲を取りglDrawElements、同じようにインデックスを調整できます。または、を使用glDrawElementsBaseVertexて頂点バイアスをかけ、各インデックスにオフセットを追加できます。このオフセットは、大きな配列内のその頂点の前の頂点の数です。

もう1つの方法は、GL 4.3で追加された比較的新しい形式の属性分離システムを使用することです。フォーマットをリセットせずにバッファを変更できます。したがって、単一のVAOをバインドし、必要に応じてで異なるバッファーに置き換えるだけglBindVertexBufferです。これはES 3.1でも利用可能です。


1
NV GL4.3ドライバーは現在完全なリリースです。
マキシマスミニマス

glVertexAttribPointerの動作を説明していただき、ありがとうございます。それは啓発的であり、それがなぜそしてどのように機能するかを説明しています。
マルティンクルトー

5

VAOはglVertexAttribPointer状態を保存します。VAOを変更しても、現在のglBindBufferには影響せず、glBindBufferを変更してもVAOには影響しません。glVertexAttribPointer呼び出しのみが、呼び出しで使用中のバッファーを記録することにより、VAOに影響します。

あなたの質問に対する答えはノーです。

オブジェクトの数を減らしたい場合の1つのオプションは、すべてのメッシュデータを1つの大きなVBOに配置し、「first」引数と「count」引数を使用してglDrawArrays呼び出しでメッシュデータがVBOのどこにあるかを指定することです。


VAOに関するインターネット上のすべての記事は、VAOをバインドするとVBOが自動的にバインドされることを示しています。したがって、VAOはglVertexAttribPointer状態 glBindBuffer状態の両方を保持する構成だと思います。はい、VAOがバインドされているときにVBOをバインドすると、VAOが変更されます。私がこれをテストしているので、私はこれを言っています、そしてそれは効果的にします。この情報はどこから来たのですか?
マルティンクルトー

2
@MartijnCourteaux:「VAO に関するインターネット上のすべての記事は、VAOをバインドするとVBOが自動的にバインドされることを示しています。」いいえ、そうではありません。頂点仕様に関するOpenGL Wikiはサポートしていません。確かに、VAOをバインドすることによって以外のglBindBuffer状態が変更されるという、インターネット上の記事を1つ表示してください。 GL_ELEMENT_ARRAY_BUFFER
ニコルボーラス

もう1つの答えは、glVertexAttribPointerメソッドがどのように機能するかを説明しました。その時点でバインドされたVBOを使用します。あなたが正しいです!ありがとう、私は今理解しています。
マルティンクルトー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.