2012-01-19 56 views
69

进出口面临的一个问题,我认为是VAO依赖,但林不知道..的OpenGL VAO最佳实践

我不知道有关VAO,正确用法是我用GL初始化过程中做在一个简单的

glGenVertexArrays(1,&vao) 

接着是

glBindVertexArray(vao) 

,后来在我的绘图管线,我只是叫glBindBuffer(),glVertexAttribPointer(),glEnableVertexAttribArray()等。不关心初始界限VAO

这是一个正确的做法吗?

+27

我不知道为什么这个问题得到-1 ..它不显示任何努力和不明确?我在发布之前花了3天的时间与规格,维基和论坛争论,并没有得到任何真正的原因,我应该使用VAO .. meh .. – user815129

+17

因为对于酷兄弟来说,只要他们有剪切和粘贴,方便,为什么要理解的东西打扰?作为上述答案的 – mlvljr

回答

77

VAOs作用类似于维也纳组织和质感方面他们如何约束。将一个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。

+0

啊,是的,事实上我根本没有使用VAO ......直到GL规范开始抱怨如果没有VAO绑定,可能(并将会)抛出错误。谢谢 – user815129

+1

是否真的有必要解除绑定VAO?我发现了不同的做法 – user815129

+3

这不是必要的,但我通常会这样做,以防一些其他对象决定不使用VAO(调试绘图/字体渲染库/等)渲染,因为(就我所知)替换属性当前绑定的VAO的设置。 –

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(..) 
} 

参见以下链接:

+0

,清楚并具有说明性。谢谢 – user815129

+0

这个答案应该更高。它特别修复了一个难以追踪我的错误。 – abarax

+1

'glEnableVertexAttribArray(...)'应该在'glVertexAttribPointer(...)'之前调用。有些司机(包括我的)_really_不喜欢这种方式。 – RecursiveExceptionException

10

这是正确的做法吗?

是的,这是完全合法和有效的。好吗?那么...

在这种事情上已经有一些informal performance testing。看起来,至少在NVIDIA硬件上进行了测试,在很多情况下,“正确”使用VAO(即:其他人都主张的)实际上是较慢的。如果更改VAO不会更改绑定的缓冲区,则更是如此。

据我所知,在AMD硬件上没有发生类似的性能测试。一般来说,除非他们有所改变,否则这是VAO的可接受使用。

+0

当然,一旦每个VAO有足够多的跟踪状态,在渲染循环中手动切换缓冲区和属性将需要很多调用,那么我们将开始看到使用VAO的性能有所提高? –

+0

不幸的是,链接已经死亡。 –

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) 
    } 
} 

如果你想看到完整的源代码,它可以作为一个精髓,源自于去-GL的例子:

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

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

+3

在绑定vao2之前,您不需要解除绑定vao1,只需绑定vao2即可。 – havokentity