Bonjour, après avoir suivi le tuto de Boouh, je souhaiterais afficher plusieurs fois la même forme (un grand nombre de fois), j'ai vu qu'il fallait utiliser la fonction glDrawArraysInstanced. Du coup j'ai réservé de la place sur GPU avec
// Version du GLSL
#version 150 core
// Entrées
in vec3 in_Vertex;
in vec2 in_TexCoord0;
in vec3 in_Offset;
// Uniform
uniform mat4 projection;
uniform mat4 modelview;
// Sortie
out vec2 coordTexture;
// Fonction main
void main()
{
// Position finale du vertex en 3D
gl_Position = projection * modelview * vec4(in_Vertex + in_Offset, 1.0);
// Envoi des coordonnées de texture au Fragment Shader
coordTexture = in_TexCoord0;
}
Et le résultat n'est pas bon, je vous laisse en juger
glDrawInstanced ne requiert pas d'allouer un grand nombre de données à l'intérieur d'un VBO.
L'idée est la suivante : tu crées 2 VBO :
Un premier VBO qui contient les données de ton cube (grossièrement 8 sommets (positions, normal, texture, couleur etc)).
Un second VBO (ou un UBO) qui contient les matrices. Si tu choisis l'option VBO, là tu dois utiliser glVertexAttribDivisor mais n'oublie pas que tu dois fournir tes matrices à ton shader. Du coup tu te retrouverais à avoir quelque chose comme ça :
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoord;
layout(location = 3) in mat4 worldMatrix;
// jusqu'à location 6
void main() {
gl_Position = perspecive * view * worldMatrix * vec4(position, 1.0);
}
En gros, avant de vouloir faire fonctionner ton code sur de l'instancé : fais le fonctionner surr du normal (car la base de code sera la même) et ensuite tu rajoutes l'instancing. Toi j'ai l'impression que tu veux stocker les sommets de tout tes cubes dans un VBO, alors que le but de l'instancing est justement d'éviter de faire ça : tu stockes ton cube dans un VBO, et les informations de position dans des buffers annexe (SSBO, UBO, ou VBO avec divisor;) )
http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
Merci de ta réponse mais je ne comprends pas bien ce qu'est worldMatrix dans ton exemple. Dans le tuto, on stocke bien les données du cube dans un vbo, mais les matrices sont transmises dans la fonction dessiner. Ce que j'ai fait c'est de rajouter dans le vbo un tableau de vecteurs de translation (en les envoyant 1 par 1, donc 3 floats à chaque fois, enfin j'espère) et après dans le shader j'ajoute à la position la translation en question. Je link le code de la fonction chager
if (glIsBuffer(m_vboID) == GL_TRUE)
glDeleteBuffers(1, &m_vboID);
glGenBuffers(1, &m_vboID);
// Verrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
// Allocation de la mémoire vidéo
glBufferData(GL_ARRAY_BUFFER, m_verticesSize_Bytes + m_coordTextureSize_Bytes + m_nbCube*sizeof(glm::vec3), 0, GL_STATIC_DRAW);
// Transfert des données
glBufferSubData(GL_ARRAY_BUFFER, 0, m_verticesSize_Bytes, m_vertices);
glBufferSubData(GL_ARRAY_BUFFER, m_verticesSize_Bytes, m_coordTextureSize_Bytes, m_coordTexture);
glBufferSubData(GL_ARRAY_BUFFER, m_coordTextureSize_Bytes, m_nbCube*sizeof(glm::vec3), m_translations);
// Déverrouillage de l'objet
glBindBuffer(GL_ARRAY_BUFFER, 0);
if (glIsVertexArray(m_vaoID) == GL_TRUE)
glDeleteVertexArrays(1, &m_vaoID);
glGenVertexArrays(1, &m_vaoID);
//Verrouillage du VAO
glBindVertexArray(m_vaoID);
//Verrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, m_vboID);
// Accès aux vertices dans la mémoire vidéo
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(0);
// Accès aux couleurs dans la mémoire vidéo
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(m_verticesSize_Bytes));
glEnableVertexAttribArray(2);
//Accès aux offsets
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), BUFFER_OFFSET(m_coordTextureSize_Bytes));
glEnableVertexAttribArray(3);
glVertexAttribDivisor(3, 1);
// Déverrouillage du VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
//Déverrouillage du VAO
glBindVertexArray(0);
pour le 16*sizeof(float) je n'en suis pas sûr je me dis que c'est pour associer une seule modelview à chaque vertex, par exemple si j'avais mis 0 ça aurait considérer que la position 4 était un float ? Aussi, le tuto que j'ai vu pour gérer ce genre de cas (en 2D) est ici
EDIT : je viens de me rendre compte que j'envoie une translation pour chaque vertex et pas pour chaque cube mais du coup je ne sais pas le faire...
Alors en gros faudrait appeler 4 fois glVertexAttribPointer pour envoyer les 4 colonnes de ta matrice oui.
Et pour pas envoyer chaque colonnes de ta matrice à chaque vertex, faut utiliser le divisor ;).
Dans ton exemple, tu restes sur un VBO qui contient les informations du cube. Tu créés un VBO qui contient tes translations pour lequel tu appliques un divisor (afin qu'il soit envoyé à chaque instance et non pas à chaque vertex ).
http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
Du coup comme le cube est composé de 36 vertices et que j'envoie le vecteur translation une fois toutes les 36 instances, il devrait y avoir une translation par cube ? Merci.
Quand tu bind ton vao avec le VBO2. Pourquoi tu fais commencé ton buffer par un offset ? Ton buffer de translation commence à l'offset 0, pas à l'offset m_coordTextureSize_Bytes...
Tu n'as pas compris la fonction glVertexAttribDivisor. Tu ne comprends pas non plus le mot instance.
Un cube = 8 sommets. Un cube = 6 faces de 2 triangles = 12 faces = "36 sommets" à "traiter" par la carte graphique.
Une instance d'un cube c'est un cube. 2 instances signifie donc 2 cubes. 3 instances 3 cubes etc.
glVertexAttribDivisor attend en entrée le nombre d'instance à sauter. Dans ton cas tu lui dis d'avancer tout les 36 instances. C'est à dire que les 36 premières instances sont dessiné avec la même translation, les 36 suivants sont dessinés avec la translation d'après etc.
tu devrais donc donné glVertexAttribDivisor(3, 1);
Si tu veux que la même valeur soit assigné à 4 cubes par exemple, tu écris glVertexAttribDivisor(3, 4); Toi dans ton cas, c'est tout les 36 cubes qu'elle change
D'ailleurs je viens de capter que tu utilises le numéro 0 2 3. Pourquoi ne pas utiliser plutôt 0 1 2 ?
Dans tes conventions de nommage VBOID VBOID2 ça veut rien dire. nomme tes variables correctement : cubeSommetVBO. TranslationVBO par exemple.
http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
Pour l'offset c'est une erreur de c/c, j'avais bien compris mais je parlais d'instance de vec3, je croyais que ça traitait pour chaque vertice donc à faire 1 fois sur 36, d'ailleurs comment sait-il qu'il faut attendre que les 36 vertices soient traités si on met 1, comment ferait-on si on voulait que cela soit fait tous les 2 vertices dans le cube par exemple (et pas 2 cubes) ? Est-ce que c'est lié au 3e paramètre de la fonction glDrawArraysInstanced ? Pour les numéros 0 2 3, j'utilise 1 pour les couleurs . Dans shaper.cpp j'ai rajouté une ligne
Parce qu'en réalité je me suis mal exprimé. Une instance = une instance de triangle. Il y a 12 triangles par cube, donc une instance d'un cube = une instance des 12 triangles (12 petites instances si tu veux). Tu peux pas faire en fonction de 2 vertices et c'est normal car ça n'aurait aucun sens. Ou alors ce serait via un GL_LINES et pas un GL_TRIANGLES.
Pour glDrawArrayInstanced il suffit de regarder la doc :
le troisième paramètre c'est le nombre de sommet à processer donc surement 36 pour toi, et le quatrième paramètre c'est le nombre d'instance.
Qu'est ce qui ne marche pas? Peux tu me montrer ton code entier plutôt que des brides?
Tu ne devrais pas utiliser glBindAttribLocation, mais layout location à la place
layout(location = 0) in vec3 in_Vertex;
layout(location = 1) in vec4 in_Color;
layout(location = 2) in vec2 in_TexCoord;
layout(location = 3) in vec3 in_Offset;
Comme ça ton code utilisant glBindAttribLocation n'est pas utile et tu gères tes locations directement dans le shader.
http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
// Version du GLSL
#version 150 core
// Entrées
in vec3 in_Vertex;
in vec2 in_TexCoord0;
in vec3 in_Offset
// Uniform
uniform mat4 projection;
uniform mat4 modelview;
// Sortie
out vec2 coordTexture;
// Fonction main
void main()
{
// Position finale du vertex en 3D
gl_Position = projection * modelview * vec4(in_Vertex + in_Offset, 1.0);
// Envoi des coordonnées de texture au Fragment Shader
coordTexture = in_TexCoord0;
}
Désolé d'avance pour le manque de lisibilité je ferai un truc propre quand ça marchera Si j'utilise
layout(location = 0) in vec3 in_Vertex;
layout(location = 1) in vec4 in_Color;
layout(location = 2) in vec2 in_TexCoord;
layout(location = 3) in vec3 in_Offset;
à la place des glBindAttribLocation ça ne m'affiche plus la texture correctement, mais une sorte de moyenne des couleurs, en bref c'est marron clair mais pas uniforme.
Ok ya vraiment un truc que je comprends pas. Je te demande de m'envoyer le code entier, tu me renvoies un code que je ne peux pas tester, pour lequel il manque la class Cube etc... je ne comprends toujours pas pourquoi tu t'entête à utiliser des color en unité 1 alors que tu ne t'en sers jamais.
Je ne comprends pas non plus pourquoi tu écris du C avec des classes ... Tu es en C++ pas en C, donc n'utilise jamais de malloc, de tableau à la C : (float tableau[72] = {}) et pleins d'autre trucs.
Pour ton problème en utilisant layout(location) c'est bizarre. A mon avis ça vient du faire que couleur n'est pas utilisé, mais je n'affirme pas.
Pour le reste je n'ai pas di'dée malheureusement...
Qu'est ce qu'il se passe si tu écris ça dans ton shader plutôt que ta ligne actuel ? :
Comme j'ai une seule classe shader et qu'elle spécifie quels sont les numéros pour vertex couleur texture etc je pense que je ne peux pas mettre les textures en 1 par exemple quand je le veux. Ça marcherait bien si je pouvais le gérer indépendamment dans le shader mais bon... Pour le tableau temporaire de texture je n'ai pas vraiment le choix.
Ton code est inutilement compliqué je pense. Je m'explique : ton but c'est de tester l'instancing. Pourquoi veux tu afficher un cube texturé. Contente toi d'afficher un cube coloré le code ce sera moins compliqué et vu qu'il y aura probablement moins de code, plus simple à debugger (remarque à ne pas prendre méchanmment, mais vu que tu cherches à tester une features, isole là au maximum ).
Ensuite rien que le fait que d'utiliser gl_InstanceID ne fonctionne pas, c'est qu'il y a un problème en amont à mon avis. Je n'ai pas vu d'erreur grossière à côté en tout cas, après j'ai pas testé.
Je t'encourage déjà de cleaner ton code un maximum pour pouvoir tester uniquement la partie instantiation.
Ensuite, vu qu'on est sur le forum de C++, je me permet de te faire des remarques :
En C++ on utilise pas delete, ni new (enfin pour new c'est à prendre avec des pincettes, mais étant donné que tu me sembles être débutant, considère new comme interdit sauf dans les bibliothèques où il y a une gestion de la mémoire à la parent enfant à l'instar de Qt. On utilise des pointeurs intelligents.
En C++ on utilise pas malloc ou autre joyeuseté pour les tableaux dynamique. On utilise std::vector.
En C++ on utilise pas de tableau statique à la C. On utilise std::array.
Ensuite sur ta partie organisation de code. Tu sembles attaché une importance particulière à glBindAttribLocation. Lorsque tu vas faire des vrais shaders : tone mapper, gestion des lumières, et autres, tu comptes toujours avoir les même variables? Non, il faut que tu te sépares de ton approche et te forcer à utiliser layout(location) comme spécifié plus haut (btw, c'est l'approche hautement recommandé pour Vulkan).
Tu devrais développer une classe pour la gestion de tes buffers. Car là tu fais du copier coller en boucle c'est pas bon.
Tu n'as pas forcément besoin de sélectionner le buffer "0" comme tu le fais régulièrement.
Tu essaies de penser à la gestion des erreurs (pointeur null etc) c'est une très bonne chose ! Par contre tu le fais mal et tu risques d'avoir des fuites mémoires avec ta façon de faire.
Tu fais un héritage entre TexturedCube et Cube. C'est pas une mauvaise approche en sois étant donné que TexturedCube IS A Cube. En revenche j'aurais préféré une relation de type Cube avec une texture, ça t'aurait évité de recopier du code en masse.
On utilise pas 0 ou NULL en C++, mais nullptr.
Voilà, pour revenir à ton problème, avant de passer par un VBO / UBO de translation, je t'encourage à tester POURQUOI la version avec gl_InstanceID ne fonctionne pas. Ce n'est pas normal. Es tu sûre que c'est bien ce shader là qui est pris en compte? (si tu enlèves un ";" et que ça marche toujours, poses toi des questions ).
Simplifie également ton shader pour la 52ème fois : tu te sers pas des couleurs (ou pas des textures avec ma remarque ci dessus), enlève donc les parties qui ne sont pas intéressantes pour toi.
Voilà voilà, bon courage...
PS : tu peux peut être utiliser renderdoc pour voir ce qu'il se passe étape par étape
http://cpp-rendering.io : Vous trouverez tout ce dont vous avez besoin sur Vulkan / OpenGL et le rendu 3D !
Pour le code, c'est juste un c/c du tuto présent sur ce site, étant donné que je cherche à voir comment marche opengl je n'y ai pas touché (ou pas bcp). Je ne me force pas à utiliser glBindAttribLocation c'est juste que ça ne marchait pas avec les layout(location), mais du coup oui il y a bien un problème au niveau de la classe shader car il n'est pas pris en compte... Je vais regarder ça de plus près, en revanche il est probable que je ne fasse pas d'apparition sur le post pendant un petit moment. Merci bcp.
EDIT : Me revoilà plus tôt que prévu, en fait c'était un problème de version de shader : il faut minimum la version 330. Du coup je vais essayer de faire un petit truc propre avec ce que tu m'as dit. Merci beaucoup
Le résultat ne change pas.