我遇到了一个问题,我认为它是依赖VAO的,但我不确定。
我不太清楚如何正确使用VAO,在GL初始化期间我通常会做简单的以下操作:
glGenVertexArrays(1,&vao)
跟随着一个
glBindVertexArray(vao)
后来,在我的绘图管线中,我只是调用了glBindBuffer()、glVertexAttribPointer()、glEnableVertexAttribArray()等函数...而不关心最初绑定的VAO。
这种做法正确吗?
我遇到了一个问题,我认为它是依赖VAO的,但我不确定。
我不太清楚如何正确使用VAO,在GL初始化期间我通常会做简单的以下操作:
glGenVertexArrays(1,&vao)
跟随着一个
glBindVertexArray(vao)
后来,在我的绘图管线中,我只是调用了glBindBuffer()、glVertexAttribPointer()、glEnableVertexAttribArray()等函数...而不关心最初绑定的VAO。
这种做法正确吗?
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。
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(..)
}
以下是相关链接:
glVertexAttribPointer(...)
ن¹‹ه‰چه؛”该ه…ˆè°ƒç”¨glEnableVertexAttribArray(...)
م€‚ن¸€ن؛›é©±هٹ¨ç¨‹ه؛ڈ(هŒ…و‹¬وˆ‘çڑ„)éه¸¸ن¸چه–œو¬¢è؟™ن¸¤ن¸ھه‡½و•°çڑ„调用é،؛ه؛ڈé¢ ه€’م€‚ - RecursiveExceptionException这是正确的做法吗?
是的,这是完全合法且有效的。好吗?嗯…
已经有一些非正式的性能测试针对这种情况进行了。至少在测试了NVIDIA硬件的情况下,“正确”使用VAOs(即其他人都提倡的方式)在许多情况下实际上是更慢的。特别是如果更改VAOs不会更改绑定的缓冲区。
据我所知,在AMD硬件上尚未进行类似的性能测试。一般来说,除非有变化,否则这是VAOs的可接受用途。
当我尝试时,Robert上面的答案对我有用。以下是使用多个顶点属性对象的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)
}
}