我面临一个我认为依赖VAO的问题,但我不确定......
我不确定VAO的正确用法,我在GL初始化过程中所做的事情很简单
glGenVertexArrays(1,&vao)
后跟
glBindVertexArray(vao)
之后,在我的绘图管道中,我只调用 glBindBuffer(),glVertexAttribPointer(),glEnableVertexAttribArray()等等,而不关心初始绑定的VAO
这是正确的做法吗?
答案 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)
// 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有同样的问题。