OpenGL VAO最佳实践

时间:2012-01-19 08:42:55

标签: opengl opengl-3 vao

我面临一个我认为依赖VAO的问题,但我不确定......

我不确定VAO的正确用法,我在GL初始化过程中所做的事情很简单

glGenVertexArrays(1,&vao)

后跟

glBindVertexArray(vao)

之后,在我的绘图管道中,我只调用 glBindBuffer(),glVertexAttribPointer(),glEnableVertexAttribArray()等等,而不关心初始绑定的VAO

这是正确的做法吗?

4 个答案:

答案 0 :(得分:87)

VAO与VBO和纹理的行为方式类似。将单个VAO绑定到程序的整个长度将不会产生任何性能优势,因为您可能只是在没有VAO的情况下进行渲染。事实上,它可能会更慢,具体取决于实现如何在绘制顶点属性设置时截取它们。

VAO的目的是在初始化期间运行一次绘制对象所需的所有方法,并在主循环期间删除所有额外的方法调用开销。关键是要有多个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。

答案 1 :(得分:24)

不,那不是你如何使用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(..)
}

另见这些链接:

答案 2 :(得分:9)

  

这是正确的做法吗?

是的,这是完全合法且有效的。好吗?嗯......

在这类事情上有一些informal performance testing。似乎,至少在测试过的NVIDIA硬件上,在许多情况下,VAO的“正确”使用(即:其他所有人都提倡的)实际上是更慢。如果更改VAO不会更改绑定的缓冲区,则尤其如此。

据我所知,在AMD硬件上没有进行过类似的性能测试。一般情况下,除非事情发生变化,否则这是VAO的可接受用途。

答案 3 :(得分: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)
    }
}

如果你想看到完整的源代码,它可以作为一个Gist,并从go-gl中的例子中得到:

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

感谢大家的原始答案,我和ECrownofFire有同样的问题。

相关问题