81

VAOに依存していると思われる問題に直面していますが、よくわかりません。

VAOの正しい使用法についてはよくわかりませんが、GLの初期化中に行っていたのは単純なことでした

glGenVertexArrays(1,&vao)

続いて

glBindVertexArray(vao)

その後、描画パイプラインで、最初にバインドされたVAOを気にせずに、glBindBuffer()、glVertexAttribPointer()、glEnableVertexAttribArray()などを呼び出しました。

これは正しい習慣ですか?

4

4 に答える 4

97

VAOは、バインド方法に関してVBOやテクスチャと同様に機能します。プログラムの長さ全体に単一のVAOをバインドしても、VAOをまったく使用せずにレンダリングするだけでもよいため、パフォーマンス上の利点はありません。実際、実装が頂点属性設定を描画するときにそれをインターセプトする方法によっては、処理が遅くなる場合があります。

VAOのポイントは、初期化中にオブジェクトを1回描画するために必要なすべてのメソッドを実行し、メインループ中に余分なメソッド呼び出しのオーバーヘッドをすべて排除することです。重要なのは、複数のVAOを用意し、描画時にそれらを切り替えることです。

ベストプラクティスの観点から、コードを整理する方法は次のとおりです。

initialization:
    for each batch
        generate, store, and bind a VAO
        bind all the buffers needed for a draw call
        unbind the VAO

main loop/whenever you render:
    for each batch
        bind VAO
        glDrawArrays(...); or glDrawElements(...); etc.
    unbind VAO

これにより、バッファのバインド/バインド解除と各頂点属性のすべての設定の受け渡しの混乱が回避され、VAOをバインドする単一のメソッド呼び出しに置き換えられます。

于 2012-01-19T08:53:52.450 に答える
28

いいえ、それはあなたがVAOを使う方法ではありません。VBO、テクスチャ、またはシェーダーを使用するのと同じ方法でVAOを使用する必要があります。最初に設定します。また、レンダリング中は、変更せずにバインドするだけです。

したがって、VAOを使用すると、次のようになります。

void Setup() {
    glGenVertexArrays(..);
    glBindVertexArray(..);
    // now setup all your VertexAttribPointers that will be bound to this VAO
   glBindBuffer(..);
   glVertexAttribPointer(..);
   glEnableVertexAttribArray(..);
}

void Render() {
    glBindVertexArray(vao);
    // that's it, now call one of glDraw... functions
    // no need to set up vertex attrib pointers and buffers!
    glDrawXYZ(..)
}

これらのリンクも参照してください。

于 2012-01-19T08:53:14.777 に答える
11

これは正しい習慣ですか?

はい、これは完全に合法で有効です。いいですか?上手...

この種のものについては、いくつかの非公式のパフォーマンステストが行​​われています。そして、少なくともこれがテストされたNVIDIAハードウェアでは、VAOの「適切な」使用(つまり、他のすべての人が提唱したもの)は実際には多くの場合遅いようです。これは、VAOを変更しても、バインドされているバッファーが変更されない場合に特に当てはまります。

私の知る限り、AMDハードウェアで同様のパフォーマンステストは行われていません。一般に、何かが変更されない限り、これはVAOの許容可能な使用法です。

于 2012-01-19T14:39:09.367 に答える
3

上記のロバートの答えは、私が試したときにうまくいきました。ここで価値があるのは、複数の頂点属性オブジェクトを使用するGoのコードです。

// VAO 1

vao1 := gl.GenVertexArray()
vao1.Bind()

vbo1 := gl.GenBuffer()
vbo1.Bind(gl.ARRAY_BUFFER)

verticies1 := []float32{0, 0, 0, 0, 1, 0, 1, 1, 0}
gl.BufferData(gl.ARRAY_BUFFER, len(verticies1)*4, verticies1, gl.STATIC_DRAW)

pa1 := program.GetAttribLocation("position")
pa1.AttribPointer(3, gl.FLOAT, false, 0, nil)
pa1.EnableArray()
defer pa1.DisableArray()

vao1.Unbind()

// VAO 2

vao2 := gl.GenVertexArray()
vao2.Bind()

vbo2 := gl.GenBuffer()
vbo2.Bind(gl.ARRAY_BUFFER)

verticies2 := []float32{-1, -1, 0, -1, 0, 0, 0, 0, 0}
gl.BufferData(gl.ARRAY_BUFFER, len(verticies2)*4, verticies2, gl.STATIC_DRAW)

pa2 := program.GetAttribLocation("position")
pa2.AttribPointer(3, gl.FLOAT, false, 0, nil)
pa2.EnableArray()
defer pa2.DisableArray()

vao2.Unbind()

次に、メインループでそれらを次のように使用できます。

for !window.ShouldClose() {
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

    vao1.Bind()
    gl.DrawArrays(gl.TRIANGLES, 0, 3)
    vao1.Unbind()

    vao2.Bind()
    gl.DrawArrays(gl.TRIANGLES, 0, 3)
    vao2.Unbind()

    window.SwapBuffers()
    glfw.PollEvents()

    if window.GetKey(glfw.KeyEscape) == glfw.Press {
        window.SetShouldClose(true)
    }
}

完全なソースを確認したい場合は、要点として入手でき、go-glの例から派生しています。

https://gist.github.com/mdmarek/0f73890ae2547cdba3a7

元々の回答をありがとうございました。ECrownofFireと同じ質問がありました。

于 2014-10-24T12:28:36.633 に答える