OpenGL VAO最佳实践

我面临一个问题,我认为是VAO依赖,但我不知道..

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

glGenVertexArrays(1,&vao) 

其次是一个

 glBindVertexArray(vao) 

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

这是一个正确的做法吗?

VAO与维也纳各组织和组织的行为方式类似,如何约束。 有一个单一的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 

这样可以避免绑定/解除绑定缓冲区的混乱,并为每个顶点属性传递所有的设置,并用一个方法调用replace它,绑定一个VAO。

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

另请参阅这些链接:

这是一个正确的做法吗?

是的,这是完全合法和有效的。 好吗? 好…

对这类事情进行了一些非正式的性能testing 。 看起来,至less在NVIDIA硬件上进行了testing,在很多情况下,“正确”使用VAO(即:其他人所主张的)其实是比较慢的 。 如果更改VAO不会更改绑定的缓冲区,则更是如此。

就我所知,在AMD硬件上没有发生类似的性能testing。 一般来说,除非有什么变化,否则这是VAO的可接受的使用。

罗伯特上面的答案在我尝试的时候为我工作。 在这里值得一提的是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。