lorsqu'une application doit dessiner beaucoup d'objets, l'organisation des données à un impact sur les performances. par exemple, dans un code simple, 
les données de chaque objet sont stockées dans un ou plusieurs buffers et la configuration des attributs est stockée dans un vertex array object. pour afficher 
plusieurs objets, on aura donc une boucle qui sélectionne le vao de l'objet avant de le dessiner :
\code
    struct Object
    {
        GLuint vao;
        GLuint program;
        GLuint texture;
        int vertex_count;
        Transform model;
    };
    
    std::vector<Object> scene;
    
    // remplir la description de la scene
    { ... }
    
    // afficher la scene
    Transform vp= { ... };      // composition de view et projection
    for(int i= 0; i < scene.size(); i++)
    {
        glBindVertexArray(scene[i].vao);
        glUseProgram(scene[i].program);
        program_uniform(scene[i].program, "mvpMatrix", vp * scene[i].model);
        program_use_texture(scene[i].program, "diffuseTexture", scene[i].texture);
        
        glDrawArrays(GL_TRIANGLES, 0, scene[i].vertex_count);
    }
\endcode

malheureusement, changer de vao et de shader demande pas mal de travail au driver, et cette solution est très lente.

il est possible de gagner pas mal de temps en stockant toutes les données des objets dans le même buffer et en utilisant un seul vao, ce qui permet
d'écrire la boucle d'affichage de manière plus efficace.
le buffer stocke les sommets des objets, les uns après les autres, il faut donc se rappeller ou commence la description de chaque objet et utiliser le 
paramètre first de glDrawArrays() :
\code
    struct Object
    {
        GLuint program;
        GLuint texture;
        int begin;
        int vertex_count;
        Transform model;
    };
    
    std::vector<Object> scene;
    
    // remplir la description de la scene
    { ... }
    
    // afficher la scene
    glBindVertexArray(vao);
    for(int i= 0; i < scene.size(); i++)
    {
        glUseProgram(program);
        program_uniform(scene[i].program, "mvpMatrix", vp * scene[i].model);
        
        glDrawArrays(GL_TRIANGLES, scenes[i].begin, scene[i].vertex_count);
    }
\endcode

__remarque :__ grosso modo, les changements les plus couteux sont, en ordre décroissant, changer de shader, changer de texture, changer de vao, 
changer de  buffer. changer la valeur d'un uniform est bien plus rapide.

__remarque :__ oui, il est quasi nécessaire de limiter le nombre de shaders utilisés au total dans la scène. une solution courante consiste à trier les objets 
par shader et à les dessiner avec le nombre minimal de glUseProgram()...

__remarque :__ et re-oui, il faut aussi faire la même chose avec les textures, soit trier les objets par paire de (shader, texture), soit packer les textures 
dans une seule grande texture (un atlas de texture), soit utiliser un tableau de textures, cf GL_TEXTURE_2D_ARRAY. tout ca pour limiter le nombre de fois ou 
il faut changer de shader avec glUseProgram() et de texture avec glBindTexture().
