2012-01-14 14 views
7

私はこの質問から来た:私は、OpenGL 3.3を使用し、非推奨の機能を使用しません可動部分を持つモデル用のVAO/VBOのOpenGL構造?

opengl vbo advice

。私のブレンダーモデルをインポートするためにAssimpを使用しています。しかし、私は少しVAOとVBOの面でそれらを分割すべきかについて少し混乱しています。

まずは小さな質問です。私はglDrawElementsを使用します。つまり、頂点の属性をインターリーブすることはできませんか、またはVAVはglVertexAttribPointerとglDrawElementsオフセットを使用して頂点の位置を知ることができますか?

主な質問私は、VAO/VBOを複数の可動部分を持つモデルと複数のメッシュprでモデル化するにはどうすればいいのかと思います。部。

assimpの各ノードは、各メッシュがテクスチャ、頂点、法線、マテリアルなどを持つ複数のメッシュを含むことができます。assimpのノードには変換が含まれます。私はそれに大砲の砲塔を持つ船を持っていると言う。私は砲台を起伏させたい。これは、船のノードに属性(または複数のVBOなど)が含まれている各メッシュに対して、別々のVAOとVBOを作成することを意味します。 は、私は完全にUBO(ユニフォームバッファオブジェクト)をまだ理解していない

draw(ship); //call to draw ship VAO 
pushMatrix(turretMatrix) //updating uniform modelview matrix for the shader 
draw(turret); //call to draw turret VAO 

ようにそれが行くと思いますが、それは私が中に可動部品との完全なモデルが含まれているのに役立ちます、私は複数の制服を渡すことができそうです単一のVAO?

答えて

13

最初に、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の初期化中にこれを結合しない

+0

クールな私は考えます私はインタリーブでそれを得る、それを試してみる必要があります。しかし、私はあなたがそれを理解したように、頂点位置の最初のglVertexAttribPointerを決定するのに間違いを犯したと思います。頂点の位置はvbo [0]できつく詰まっています。彼らがインターリーブされていないので、ストライドは位置のためにゼロでなければならない。 – CodeMonkey

+0

私はシェーダのメッシュIDについてのアイデアが好きで、属性として渡しますが、シェーダ(均一な配列のような)に多くの行列を解析するにはどうすればいいですか?これは、UBOを使って10の異なるタレットの10種類の変換行列を渡し、シェーダ内の正しい行列を検索するための属性として解析されたインデックスを使用することができますか? これは、glMultiDrawElements/Arrays関数を使用して、複数のパーツをすべて1つの船で描画することも可能になりますか? – CodeMonkey

+0

こんにちは、ストライドとの良好な観察。しかしそれは誤りではない。いずれか私はストライド0を残すことができ、OpenGLは、私は3D GL_FLOATSのストリームを持っていることを知っています(したがって、サイズは3 * sizeof(float)です)、または私はそれのためのストライドを計算することができます。それには何も問題ありません。ストライドは、2つの連続した頂点のアドレス間の距離であり、それらの間のスペースではない(したがって、0は、頂点間に未使用のバイトがないことを意味しない。つまり、OpenGLは、および使用されるデータタイプ)。 –

0

@theswine

は、私のプログラムがクラッシュしますが、VAOを結合した後、それを結合することは、正しく実行する原因となります。これはVAOに保存されていませんか?

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO 

(BTW:!昔の話題を持ち出すため申し訳ありませんが、私は、これは他の人に役立つ可能性が考えられ、このポストを確認してください、あなたに感謝を思い出すた(だった!!))

+0

こんにちは。私はあなたが '@ login'で始まる回答を投稿したときに通知を受け取らないので、偶然これを見ました(OPだけに通知されます)。あなたは私の答えにコメントを残しておくべきです、私はそれが通知されるでしょう。新しい質問を開始し、クラッシュを再現する最小限のコードを投稿することをお勧めします。それは可能でしょうか?それでは、このコメントの下に '@ login'コメントを残すことができます。私はあなたの問題を調べます。 –

+0

申し訳ありませんが、評判が悪いため投稿にコメントできませんでした。しかし、あなたがチェックアウトするために何かを一緒に投げようとしますか? – luveti

+0

これは通常、スワップされたインデックスまたは絡んだバインディングです。最高のことが起こります。場合によっては、要素配列(インデックス)バッファが特にインテルグラフィックカードで問題を引き起こすことがあります。 –

関連する問題