web-dev-qa-db-fra.com

Meilleures pratiques OpenGL VAO

Je fais face à un problème que je crois dépendre de VAO, mais je ne suis pas sûr ..

Je ne suis pas sûr de l'utilisation correcte d'un VAO, ce que je faisais pendant l'initialisation GL était une simple

glGenVertexArrays(1,&vao)

suivi d'un

glBindVertexArray(vao)

et plus tard, dans mon pipeline de dessin, je viens d'appeler glBindBuffer (), glVertexAttribPointer (), glEnableVertexAttribArray () et ainsi de suite .. sans se soucier du VAO lié initialement

est-ce une bonne pratique?

75
user815129

Les VAO agissent de la même manière que les VBO et les textures en ce qui concerne la façon dont ils sont liés. Avoir un seul VAO lié pour toute la durée de votre programme n'apportera aucun avantage en termes de performances, car vous pourriez tout aussi bien effectuer un rendu sans VAO. En fait, cela peut être plus lent selon la façon dont l'implémentation intercepte les paramètres d'attribut de sommet lorsqu'ils sont dessinés.

Le but d'un VAO est d'exécuter toutes les méthodes nécessaires pour dessiner un objet une fois lors de l'initialisation et de supprimer tous les frais supplémentaires d'appel de méthode pendant la boucle principale. Le but est d'avoir plusieurs VAO et de basculer entre eux lors du dessin.

En termes de bonnes pratiques, voici comment organiser votre code:

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

Cela évite le gâchis de la liaison/dissociation des tampons et de la transmission de tous les paramètres pour chaque attribut de sommet et le remplace par un seul appel de méthode, liant un VAO.

87
Robert Rouhani

Non, ce n'est pas ainsi que vous utilisez VAO. Vous devez utiliser VAO de la même manière que vous utilisez VBO ou des textures ou des shaders. Configurez-le d'abord. Et lors du rendu, ne les liez que sans les modifier.

Ainsi, avec VAO, vous procédez comme suit:

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

Voir aussi ces liens:

24
Mārtiņš Možeiko

est-ce une bonne pratique?

Oui, c'est parfaitement légal et valable. Est-ce bien? Bien...

Il y a eu tests de performance informels sur ce genre de chose. Et il semble, au moins sur le matériel NVIDIA où cela a été testé, l'utilisation "correcte" des VAO (c'est-à-dire: ce que tout le monde préconisait) est en réalité plus lente dans de nombreux cas. Cela est particulièrement vrai si la modification des VAO ne change pas les tampons liés.

À ma connaissance, aucun test de performance similaire n'a eu lieu sur le matériel AMD. En général, à moins que quelque chose ne change avec eux, il s'agit d'une utilisation acceptable des VAO.

9
Nicol Bolas

La réponse de Robert ci-dessus a fonctionné pour moi lorsque je l'ai essayée. Pour ce qu'il vaut ici, c'est le code, dans Go, d'utiliser plusieurs objets d'attribut de sommet:

// 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()

Ensuite, dans votre boucle principale, vous pouvez les utiliser comme tels:

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

Si vous voulez voir la source complète, elle est disponible sous forme de Gist et dérivée des exemples de go-gl:

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

Merci à tous pour les réponses originales, j'avais la même question que ECrownofFire.

3
Marek