IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Apprendre OpenGL moderne

Quatrième partie : OpenGL avancé


précédentsommairesuivant

VII. Données avancées

Depuis le début, nous avons intensément utilisé les tampons OpenGL pour stocker des données. Il existe d’autres façons de manipuler les tampons et d’autres méthodes pour transférer de nombreuses données aux shaders, notamment grâce aux textures. Dans ce tutoriel, nous allons voir quelques fonctions intéressantes à propos des tampons.

En OpenGL, un tampon n’est qu’un objet qui gère un morceau de mémoire et rien d’autre. Nous donnons un sens à ce tampon lorsque nous le lions à une cible. Un tampon n’est qu’un tableau de sommets lorsque vous le liez comme un GL_ARRAY_BUFFER, mais vous pouvez aussi le lier comme un GL_ELEMENT_ARRAY_BUFFER. En interne, OpenGL stocke un tampon par cible et, suivant la cible, traite le tampon différemment.

Jusqu’à présent, nous avons rempli la mémoire gérée par un objet tampon grâce à glBufferData() qui alloue un morceau de mémoire et ajoute ces données dans la mémoire. Si nous passions NULL comme argument pour les données, la fonction ne ferait que l’allocation de mémoire. C’est pratique si vous souhaitez d’abord réserver une certaine partie de la mémoire et la remplir plus tard, petit à petit.

Au lieu de remplir l’intégralité du tampon avec un seul appel, vous pouvez remplir des régions de ce tampon grâce à la fonction glBufferSubData(). Cette fonction attend une cible de tampon, un décalage, la taille et les données à insérer. Ainsi, avec cette fonction, il est possible de spécifier à partir de quel endroit nous souhaitons remplir le tampon. Cela nous permet d’insérer/mettre à jour certaines parties de la mémoire. Notez que le tampon doit être alloué avec assez de mémoire grâce à glBufferData() avant d’appeler la fonction glBufferSubData().

 
Sélectionnez
glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // remplir la zone [24, 24 + sizeof(data)]

Vous pouvez aussi obtenir les données d’un tampon en demandant un pointeur sur sa mémoire et copier directement les données vers ce tampon vous-même. En appelant glMapBuffer(), OpenGL retourne un pointeur associé à la mémoire du tampon sur lequel vous pouvez travailler :

 
Sélectionnez
float data[] = {
  0.5f, 1.0f, -0.35f
  ...
};
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// obtenir le pointeur
void *ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// copier les données en mémoire
memcpy(ptr, data, sizeof(data));
// assurez-vous d’indiquer à OpenGL que vous avez terminé avec ce pointeur
glUnmapBuffer(GL_ARRAY_BUFFER);

En indiquant à OpenGL que nos opérations sont finies avec glUnmapBuffer(), OpenGL peut reprendre possession de cette mémoire. Le pointeur devient invalide et la fonction retourne GL_TRUE si OpenGL a pu mettre vos données dans le tampon.

La fonction glMapBuffer() est pratique pour mettre vos données directement dans un tampon sans devoir les stocker temporairement. Ainsi, il est possible de lire vos données directement du disque pour les placer dans la mémoire du tampon.

VII-A. Mise en lot des attributs de sommets

Grâce à la fonction glVertexAttribPointer() nous pouvons spécifier la disposition du contenu des tableaux de sommets. Dans celui-ci, nous intercalons les attributs, c’est-à-dire la position, la normale, la ou les coordonnées de texture pour chaque sommet. Maintenant que nous maîtrisons mieux les tampons, nous pouvons utiliser une autre approche.

Nous pouvons mettre en lot toutes les données dans de grand morceau de mémoire par type d’attribut au lieu de les intercaler. Ainsi, au lieu d’avoir un agencement 123123123123, nous aurions 111122223333.

Lors du chargement des données des sommets, nous récupérons un tableau de position, un tableau de normales et un ou plusieurs tableaux de coordonnées de texture. Cela peut être pénible de réarranger ces tableaux afin d’avoir des données agencées différemment. La mise en lot offre une solution plus simple à implémenter, grâce à la fonction glBufferSubData() :

 
Sélectionnez
float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// fill buffer
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);

De cette façon, nous pouvons transférer directement les tableaux d’attributs en une seule fois sans avoir besoin de les traiter. Nous pouvons aussi remplir le tampon avec glBufferData(), mais la fonction glBufferSubData() correspond parfaitement à ce genre de tâches.

Nous devons aussi mettre à jour nos attributs de sommets ainsi :

 
Sélectionnez
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);  
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(sizeof(positions)));  
glVertexAttribPointer(
  2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(sizeof(positions) + sizeof(normals)));

Remarquez que le paramètre stride est égal à la taille des attributs, car le prochain attribut se trouve directement après les 3 (ou 2) composantes.

Cela nous donne une nouvelle approche pour définir les attributs de sommets. L’utilisation d’une approche ou d’une autre n’a pas d’intérêt immédiat en OpenGL. C’est principalement une façon d’organiser les attributs de sommets. L’approche à utiliser repose uniquement sur vos préférences et le type d’application.

VII-B. Copie des tampons

Une fois que vos tampons sont remplis avec vos données, vous pouvez souhaiter les partager avec d’autres tampons ou même copier un tampon dans un autre. La fonction glCopyBufferSubData() nous permet de copier les données d’un tampon vers un autre. Le prototype de la fonction est le suivant :

 
Sélectionnez
void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset,
                         GLintptr writeoffset, GLsizeiptr size);

Les paramètres readtarget et writetarget définissent les tampons de source et de destination. Nous pouvons, par exemple, copier du tampon VERTEX_ARRAY_BUFFER vers un tampon VERTEX_ELEMENT_ARRAY_BUFFER en spécifiant ces cibles pour la lecture et l’écriture, respectivement. Les tampons actuellement liés à ces cibles seront alors affectés.

Comment faire si nous souhaitons lire et écrire dans deux tampons qui sont tous les deux des tableaux de sommets ? Nous ne pouvons pas lier deux tampons en même temps à la même cible. Pour cela, OpenGL nous donne deux autres cibles : GL_COPY_READ_BUFFER et GL_COPY_WRITE_BUFFER. Nous souhaitons alors lier les tampons de notre choix à ces deux nouvelles cibles en les passants en paramètre readtarget et writetarget.

glCopyBufferSubData() lit alors les size données à partir de readoffset pour les écrire dans le tampon indiqué par writetargetbuffer à partir de writeoffset. Voici un exemple montrant comment copier le contenu de deux tableaux de sommets :

 
Sélectionnez
float vertexData[] = { ... };
glBindBuffer(GL_COPY_READ_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));

Nous pouvions aussi le faire en liant le tampon writetarget à l’un des nouveaux types :

 
Sélectionnez
float vertexData[] = { ... };
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, sizeof(vertexData));

Grâce à ces nouvelles connaissances sur la manipulation des tampons, nous sommes prêts à les utiliser de manière intéressante. Plus vous allez en profondeur dans OpenGL, plus ces nouvelles méthodes vont devenir utiles. Dans le prochain tutoriel, nous allons voir les objets de tampons uniformes (uniform buffer objects) et faire bon usage de glBufferSubData().

VII-C. Remerciements

Ce tutoriel est une traduction réalisée par Alexandre Laurent dont l’original a été écrit par Joey de Vries et qui est disponible sur le site Learn OpenGL.


précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2019 Joey de Vries. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.