gKit2 light
|
cf tuto4GL.cpp
pour dessiner des triangles, il faut décrire les informations associées aux sommets, indiquer ou les trouver, leur organisation mémoire, et indiquer à quelles entrées du vertex shader elles sont associées.
le cas simple permettant de dessiner quelques triangles est présenté dans afficher plusieurs triangles, modifier les paramètres uniform d'un shader program.
c'est un objet openGL, appelé vertex array object, qui stocke la description du format de sommets.
la création des objets openGL utilise des fonctions de la forme glGenXXX( int n, GLuint *names ). cette famille de fonctions permet de créer plusieurs objets en même temps et renvoye un tableau d'identifiants des nouveaux objets. pour en créer un seul, on peut utiliser :
il ne reste plus qu'à le sélectionner pour configurer le pipeline :
les informations des sommets, les attributs, sont stockées dans un ou plusieurs vertex buffers, qui ne sont que des tableaux alloués dans la mémoire de la carte graphique. cf vertex buffers et index buffer pour les créer et leur affecter des données.
le vertex array object stocke, pour chaque attribut déclaré par le vertex shader :
l'indexation des sommets (l'index buffer) peut aussi être associé à un vertex array objet.
la configuration se fait en plusieurs étapes :
exemple : le cas classique, le vertex buffer, identifiant buffer, contient les positions des sommets. le vertex shader déclare : in vec3 position;
exemple : si le maillage est décrit par des sommets partagés, l'index buffer stocke des triplets d'indices pour décrire chaque triangle. Les opérations sont les mêmes que pour un vertex buffer, par contre, il faut sélectionner le buffer sur GL_ELEMENT_ARRAY_BUFFER :
remarque : nettoyage / revenir à l'état par défaut
il y a en général un index buffer et un vertex buffer sélectionné ainsi que le vao. quelle est la bonne manière de les désélectionner :
rappel : certains paramètres sont implicites... le vao en cours de configuration, par exemple
il faut décrire chaque attribut déclaré.
exemple : position_buffer contient les positions, normal_buffer contient les normales des sommets, et les attributs sont déclarés comme : in vec3 position; in vec3 normal;
dans le vertex shader :
exemple complet : tuto4GL_normals.cpp
pour récupérer la liste des attributs déclarés par le vertex shader et vérifier qu'ils sont bien associés à un buffer, cf récupérer les uniforms et les attributs utilisés par un shader program
le compilateur et le linker des shaders sont capables de déterminer qu'un attribut n'est pas nécessaire pour exécuter un shader. par exemple :
la couleur des fragments est constante, elle ne depend pas de la normale calculée par le vertex shader, et glGetAttibLocation( ... "normal" ) renvoie -1 dans ce cas, alors que l'attribut normal est correctement déclaré.
si le fragment shader est modifié pour utiliser la normale :
glGetAttribLocation( ... "normal" ) renverra bien un identifiant valide dans ce cas. il faut prévoir les 2 cas dans le programme, il y a 2 manières de le gérer,
remarque : les attributs peuvent être numérotés directement par le vertex shader, et dans ce cas l'utilisation de glGetAttribLocation( ) n'est pas nécessaire, cf la section et sans utiliser glGetAttribLocation( ) ?.
les paramètres stride et offset de glVertexAttribPointer( ) permettent d'organiser les données assez librement :
remarque : stride = 0 est interprété comme l'organisation par défaut, les valeurs se suivent, c'est équivalent à stride= sizeof()
exemple : position et normale dans le même buffer, toutes les positions, puis toutes les normales : PPPPPPPPNNNNNNNN
exemple : alterner les donnees, position + normale sommet 0, position + normale sommet 1, etc : PNPNPNPNPNPNPN
cf exemple : utiliser un seul buffer pour stocker les attributs et configurer le vao pour un exemple complet de création.
les buffers sont des tableaux alloués dans la mémoire de la carte graphique, il faut leur donner une dimension (en octets) et transférer des données, cf glBufferData( ).
on peut également modifier le contenu d'un buffer à n'importe quel moment, cf glBufferSubData( ). en fonction de la fréquence de modifications, il faut choisir l'option correspondante lors de la création, cf le paramètre usage de glBufferData( ). l'option par défaut est GL_STATIC_DRAW qui indique que le buffer est utilisé par glDraw( ) et que son contenu ne devrait pas changer.
mais bien sur, il faut commencer par créer l'objet openGL, cf glGenBuffers( ) :
pour pouvoir manipuler un buffer, il faut le sélectionner, comme les autres objets openGL, cf glBindBuffer( ) :
exemple : créer un vertex buffer pour stocker les positions d'un mesh, cf Mesh::vertex_buffer() et Mesh::vertex_buffer_size(), pour récupérer les infos nécessaires :
exemple : créer un vertex buffer, le dimensionner et changer son contenu
le buffer est remplit avec toutes les positions, suivies de toutes les texcoords, et enfin toutes les normales :
il suffit de donner l'identifiant directement dans le source du vertex shader avec layout(location= id) in vec3 attribute;
:
l'exemple de création de buffer / configuration de vao précédent suppose que position est l'attribut 0, texcoord est l'attribut 1 et normal est l'attribut 2, ce qui se déclare comme ça :
et la création des buffers / configuration du vao peut etre simplifiée, puisque l'on connait les identifiants des attributs. cf l'exemple précédent exemple : utiliser un seul buffer pour stocker les attributs et configurer le vao.