最初に、VAOは、最後の頂点属性バインディング(および、インデックスバッファ(0,)がある場合はVBOバインディング)のみを「記憶」します。したがって、glDrawElements()
のオフセットを記憶していないので、後でVAOを使用するときに呼び出す必要があります。それは、インターリーブされた頂点配列を使用することを妨げるものではありません。私が説明してみましょう:
int vbo[3];
glGenBuffers(3, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, data0, size0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, data1, size1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data2, size2);
// create some buffers and fill them with data
int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// create a VAO
{
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO
glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); // this is VAO saved state
glEnableVertexAttribArray(0); // this is VAO saved state
// sets up one vertex attrib array from vbo[0] (say positions)
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // not saved in VAO
glVertexAttribPointer(1, 3, GL_FLOAT, false, 5 * sizeof(float), NULL); // this is VAO saved state
glVertexAttribPointer(2, 2, GL_FLOAT, false, 5 * sizeof(float), (const void*)(2 * sizeof(float))); // this is VAO saved state
glEnableVertexAttribArray(1); // this is VAO saved state
glEnableVertexAttribArray(2); // this is VAO saved state
// sets up two more VAAs from vbo[1] (say normals interleaved with texcoords)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // this is VAO saved state
// uses the third buffer as the source for indices
}
// set up state that VAO "remembers"
glBindVertexArray(0); // bind different vaos, etc ...
その後...
glBindVertexArray(vao); // bind our VAO (so we have VAAs 0, 1 and 2 as well as index buffer)
glDrawElements(GL_TRIANGLE_STRIP, 57, GL_UNSIGNED_INT, NULL);
glDrawElements(GL_TRIANGLE_STRIP, 23, GL_UNSIGNED_INT, (const void*)(57 * sizeof(unsigned int)));
// draws two parts of the mesh as triangle strips
だから、あなたは...あなたは、単一のVAOと1つ以上のVBOsを使用してglDrawElements
を使用して、インターリーブ頂点配列を描画することができます参照してください。
質問の第2部分に答えるには、メッシュの異なる部分に異なるVAOとVBOを割り当てることができます(別々の部分を描くのは簡単です)か、すべてを1つのVAO VBOペアに融合することができます最初のglDrawElements()
が船を描画し、2番目が砲塔を描画すると仮定して、呼び出し間でいくつかの行列の一様性を更新するだけである)を使用して、メッシュの個々の部分を描画します(glBind*()
)。
シェイダーは、ユニフォームの複数のモデルビュー行列を含むことができるため、別の頂点属性としてメッシュIDをエンコードし、頂点シェーダーにこの属性に基づいて頂点の変換に使用するマトリックスを選択させることもできます。このアイデアは、単一の頂点ごとに複数の行列を使用することにも拡張でき、各行列にいくつかの重みが割り当てられます。これは、プレイヤーキャラクターなどの有機物をアニメーション化するときによく使用されます(スキンニングを参照)。
均一なバッファオブジェクトがあるので、唯一の利点は、たくさんのデータをパックすることができ、シェーダ間で簡単に共有できることです(UBOを使用できるシェーダにバインドするだけです)。あなたが1000個の行列を持つオブジェクトを持っている場合を除いて、あなたのためにそれらを使用することに本当の利点はありません。
また、私は上記のソースコードをメモリから書きました。いくつかのエラー/問題がある場合、私に教えてください... VAOの初期化中にこれを結合しない
クールな私は考えます私はインタリーブでそれを得る、それを試してみる必要があります。しかし、私はあなたがそれを理解したように、頂点位置の最初のglVertexAttribPointerを決定するのに間違いを犯したと思います。頂点の位置はvbo [0]できつく詰まっています。彼らがインターリーブされていないので、ストライドは位置のためにゼロでなければならない。 – CodeMonkey
私はシェーダのメッシュIDについてのアイデアが好きで、属性として渡しますが、シェーダ(均一な配列のような)に多くの行列を解析するにはどうすればいいですか?これは、UBOを使って10の異なるタレットの10種類の変換行列を渡し、シェーダ内の正しい行列を検索するための属性として解析されたインデックスを使用することができますか? これは、glMultiDrawElements/Arrays関数を使用して、複数のパーツをすべて1つの船で描画することも可能になりますか? – CodeMonkey
こんにちは、ストライドとの良好な観察。しかしそれは誤りではない。いずれか私はストライド0を残すことができ、OpenGLは、私は3D GL_FLOATSのストリームを持っていることを知っています(したがって、サイズは3 * sizeof(float)です)、または私はそれのためのストライドを計算することができます。それには何も問題ありません。ストライドは、2つの連続した頂点のアドレス間の距離であり、それらの間のスペースではない(したがって、0は、頂点間に未使用のバイトがないことを意味しない。つまり、OpenGLは、および使用されるデータタイプ)。 –