Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Qt Discussion :

La 3D avec le module OpenGL de Qt


Sujet :

Qt

  1. #1
    Inactif  
    La 3D avec le module OpenGL de Qt
    Bonjour,

    Les processeurs graphiques (GPU) sont devenus en quelques années un des composants majeurs des ordinateurs. Leur puissance de calcul, en croissance constante, est souvent utilisée dans les jeux vidéos 3D pour permettre aux joueurs de s'immerger dans un environnement toujours plus réaliste et riche en détails. Mais la 3D est présente également dans d'autres types d'applications, par exemple pour la représentation de données scientifiques complexes.

    Qt fournit depuis quelques temps un module dédié à la 3D, intégré par défaut dans le SDK : le module QtOpenGL. Ce module fournit les éléments de base pour créer une vue OpenGL avec QGLWidget mais également des outils avancés comme la gestion des shaders avec QGLShader.

    De nombreuses personnes réclamaient un tutoriel sur le sujet. Voici la chose faite : La 3D avec le module OpenGL de Qt

    Se basant sur un exemple simple de heightmap, ce tutoriel décrit en détails la création d'une vue 3D, l'envoi de données aux GPU, la programmation des shaders, la gestion des lumières et des textures, la création de textures dynamiques (rendu off-screen) et l'affichage d'éléments 2D sur une vue 3D (overpainting). Ce tutoriel s'accompagne de plusieurs codes exemples, directement exécutables dans Qt Creator.

    Cette première partie sur la 3D sera suivie par une partie sur le calcul sur carte graphique (GPU Computing) avec OpenCL (en cours de relecture) puis une partie sur le module Qt3D, qui devrait être intégré dans Qt 4.8. D'autres chapitres seront progressivement ajoutés, en fonction des demandes (et de mes envies ).



    Bonne lecture.

  2. #2
    Membre régulier
    Super intéressant félicitation !

    C'est assez rare de trouver des tutoriaux à jour sur le sujet,
    et encore plus des tutoriaux complets et pas simplement des bouts de codes, vous avez fait les 2

    Bon courage et vivement la suite !

  3. #3
    Membre confirmé
    Merci pour ce superbe article !
    Il est complet, détaillé et bien fait.
    Grâce à cet article, je vais mieux maîtriser l'utilisation de QtOpenGL.

    Juste une critique négative concernant la compatibilité du code de exemples :
    Le compilateur de Microsoft$ n'a pas connaissance de M_PI
    Donc, c'est dommage, mais il n'est pas possible de tester les exemples avec ce compilateur de ... Qui est malheureusement très utilisé.

    Donc, pour qu'un maximum de personnes puissent tester les exemples, je te conseillerais de modifier leures sources.
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  4. #4
    Nouveau membre du Club
    Hi!
    Merci pour cet article qui semble tomber pile poil au moment où j'en ai besoin!
    La compilation des 4 sources proposées ne pose aucun problème.
    Cependant c'est à l'exécution que çà se gâte!

    OpenGL-minimal et OpenGL-buffers : ok

    OpenGL-shader (voir screenshot) : ko
    le "menu" est caché en partie
    sur les commandes proposées, seule la commande "espace" semble avoir un effet perceptible.

    OpenGL-offscreen (voir screenshot) : ko
    l'application avorte en générant un message

    OS : windows seven 32 bits
    Qt : version 4.7.0

  5. #5
    Inactif  
    Hum... j'ai testé aussi Win 7 32b mais avec Qt 4.7.3 et MingW32 et ça fonctionnait.
    Il faudra que je regarde. Tu as lancé en mode débug pour voir à ça plantait ?

  6. #6
    Responsable 2D/3D/Jeux

    Bonjour,

    Excellent tutoriel Qt que j'utilise pour un certain défi . Je le trouve très complet, malgré que je regrette le manque d'information sur ce qui est utilisable en OpenGL ES 1 / 2 ou encore OpenGL 1 / 2 / 3 / 4. En effet vous dites juste:
    Cette transition s'est effectuée en 2001-2002, avec l'arrivée de DirectX8 et des OpenGL Shader extensions. L'utilisation du pipeline fixe est donc déconseillée, la plupart des fonctions utilisées dans la partie précédente sont dépréciées. Ces fonctions ne sont plus supportées sur OpenGL ES 2.0 (version d'OpenGL destinée aux systèmes embarqués).
    Mais vous ne précisez pas lesquels et on ne sait pas vraiment pourquoi on parle d'OpenGL ES 2 et non de OpenGL 3 par exemple.
    Un exemple pour mes propos, c'est que les blocs glBegin() / glEnd() n'ont jamais existé dans OpenGL ES 1. Par contre, les Vertex Array existe (et je crois que dans cette version d'OpenGL ES c'est la seule méthode pour envoyer les données).
    Bien sur, l'utilisation des VBO est la meilleure des techniques ... même si elle a quelques défauts, du genre que la mémoire de la puce graphique peut être brutalement surchargés si on a une multitude d'objets différents dans la scène (compromis entre la bande passante CPU -> GPU / et la mémoire disponible sur la puce graphique). Enfin bref ... le tuto est tout de même excellent. Merci pour l'écriture de celui-ci.

    Un autre point que je trouve contestable (mais je chipote facilement): c'est le code source. En effet j'utilise le tuto pour apprendre à faire un dessin OpenGL avec l'aide des classes de Qt. Dans le code source on se retrouve avec 4 méthodes de dessins mélangées dans le même source. Peut être aurait été il plus logique de faire de multiple classes ... (enfin, c'est vraiment du chipotage, je l'admet).

    Finalement, j'ai un problème sur ma machine.
    J'ai récemment installé Qt 4.7.3 sur un Windows XP. J'embarque une Geforce FX 5200 (oui, j'ai de très vieilles machines). Je me retrouve avec des bugs bizarres lors de l'écriture des infos de la scène (voir pièce jointe). Je dois dire, je n'ai pas cherché pour connaître la source du problème ...
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  7. #7
    Inactif  
    Oui, j'avais pensé à faire le tour des fonctions utilisées et donner pour quelles versions d'OpenGL elles étaient disponibles.
    En pratique, Qt crée un contexte par défaut (1.x sur windows je crois, ES 2 sur mobile, etc.) puis charge les fonctions dynamiquement. Donc, en gros, il suffit juste que la carte graphique prenne en charge la fonctionnalité, peut importe que contexte (qui est encapsulé de toute façon dans Qt). Et dans le cas où le fonctionnalité n'est pas supporté par la carte graphique, en général Qt réalise le travail en utilisant d'autres méthodes (par exemple en utilisant le Raster pour réaliser le rendu 2D)

    Pour le code source, je suis d'accord avec toi : on a codé pour mettre tous dans la même classe et ce n'est pas très respectueux de la POO. A ne pas reproduire en vrai. Par contre, pour un tutoriel, c'était mieux de rassembler le code similaire ensemble.

    Pour le bug avec la Geforce FX 5200, je pense à une fonctionnalité non prise en charge et utilisation du rendu en mode "dégradé" (normalement, Qt converti le dessin 2D en directive 3D dans un contexte OpenGL, pour ne pas avoir à changer de contexte ; sauf si les fonctionnalités ne sont pas dispo)

    Merci pour les critiques. Ce n'est pas un tutoriel destiné à ne plus changer. On complétera/corrigera en fonction des remarques

  8. #8
    Responsable 2D/3D/Jeux

    Citation Envoyé par gbdivers Voir le message
    Oui, j'avais pensé à faire le tour des fonctions utilisées et donner pour quelles versions d'OpenGL elles étaient disponibles.
    En pratique, Qt crée un contexte par défaut (1.x sur windows je crois, ES 2 sur mobile, etc.) puis charge les fonctions dynamiquement. Donc, en gros, il suffit juste que la carte graphique prenne en charge la fonctionnalité, peut importe que contexte (qui est encapsulé de toute façon dans Qt). Et dans le cas où le fonctionnalité n'est pas supporté par la carte graphique, en général Qt réalise le travail en utilisant d'autres méthodes (par exemple en utilisant le Raster pour réaliser le rendu 2D)
    Hum...
    La réponse des contextes ne me plait guère. Tout d'abord, sous Windows, oui c'est bien un contexte OpenGL 1.x qui est en place (malheureusement). Mais sous GNU/Linux on a facilement accès a un contexte 2.x ... et j'ose croire que dans 5 ans nous aurons un contexte 3.x de base (notamment, car Khronos a déprécié tout ce qui était avant OpenGL 2 (et peut être même une grande partie du 2)). En pratique, une fonction déprécié devrait être évité à tout pris (en effet, peut être que demain, elle ne fonctionnera plus du tout). Donc il est préférable de dire ce qui a été déprécié, un peu plus clairement (juste dire que la technique 1 est dépréciée me va, c'est que pour le moment, vous ne le dites pas assez précisément à mon gout )
    Et puis, si Qt fait des trucs à la mains (O_o) et bah, il y aura grosse perte de performances. Au final, cela voudrait dire, voilà, j'ai une machine OpenGL 1.1 uniquement, je voulais faire des VBO et comme je n'en avais pas, Qt m'a overkiller mon application pour pouvoir le faire ...). Alors que en général, c'est le programmeur qui met des vérifications pour savoir si son programme fonctionnera assez ou pas. Et s'il n'a pas la fonctionnalité, il peut toujours passer par un chemin moins couteux ou une plus vieille technique ...
    Le dernier problème sur ce genre de truc, c'est que la moitié du temps, on joue avec des pointeurs de fonctions. Deux cas arrivent, soit le programme ne compile pas, car le driver n'a pas les fonctions voulus (cas de l'installation des shaders avec Windows, et on a recourt à GLEW / Qt ou autre). Soit on a une fonction qui nous retourne un pointeur sur la fonction (getProcAddress) et qu'il faut vérifié, sinon crash.
    Enfin bref, je demandais juste de rajouter une petite phrase du genre, oui la technique du bloc glBegin/glEnd, bien que très pratique pour dessiner nos axes et a évité.


    Pour le bug avec la Geforce FX 5200, je pense à une fonctionnalité non prise en charge et utilisation du rendu en mode "dégradé" (normalement, Qt converti le dessin 2D en directive 3D dans un contexte OpenGL, pour ne pas avoir à changer de contexte ; sauf si les fonctionnalités ne sont pas dispo)
    Sauf que cela n'arrive pas partout. En fait, cela arrive sur le '5' le '7' et quelques autres caractères. Je commençais a douter du cast qui est effectué autour du QString . Il faut que je vérifie sur mes autres machines
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  9. #9
    Nouveau membre du Club
    Hi!

    Je m'excuse pour ma réponse plutôt tardive, mais étant tout nouveau sur Developpez.com, je m'attendais, un peu naïvement j'en conviens, à recevoir un mail m'annonçant l'arrivée de nouveaux messages sur cette page de discussion.

    Bref, après avoir rajouté "CONFIG += console debug" dans les .pro et compilé en mode "debug", la console me délivre les messages suivants :

    concernant l'application "OpenGL-shader" :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    QGLShader::compile: "ERROR: 2:17: 'texture' : no matching overloaded function found (using implicit conversion)
    ERROR: 2:17: 'assign' :  cannot convert from 'const float' to 'varying 4-component vector of float'
    "
    QGLShader::link: "Fragment shader contains a user varying, but is linked without a vertex shader."
    QGLShader::link: "Fragment shader contains a user varying, but is linked without a vertex shader."
    QGLShaderProgram::uniformLocation( ambiant_color ): shader program is not linked
    QGLShaderProgram::uniformLocation( light_direction ): shader program is not linked
    QGLShader::link: "Fragment shader contains a user varying, but is linked without a vertex shader."
    QGLShaderProgram::uniformLocation( matrixpmv ): shader program is not linked
    QGLShaderProgram::uniformLocation( light_direction ): shader program is not linked
    QGLShader::link: "No errors."
    QGLShader::link: "No errors."
    QGLShader::link: "No errors."
    QGLShader::link: "No errors."
    QGLShader::link: "Fragment shader contains a user varying, but is linked without a vertex shader."
    QGLShaderProgram::uniformLocation( matrixpmv ): shader program is not linked
    QGLShaderProgram::uniformLocation( light_direction ): shader program is not linked


    concernant l'application "OpenGL-offscreen" :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    QGLShaderProgram::uniformLocation( pbuffer_size ): shader program is not linked
    QGLShaderProgram::release: program is not valid in the current context.


    Pour mémoire, je rappelle ma configuration :

    OS : Windows seven 32 bits
    Qt : version 4.70
    Compilation : mingw32 version 3.81

  10. #10
    Responsable 2D/3D/Jeux

    Citation Envoyé par opossum_farceur Voir le message
    Hi!

    Je m'excuse pour ma réponse plutôt tardive, mais étant tout nouveau sur Developpez.com, je m'attendais, un peu naïvement j'en conviens, à recevoir un mail m'annonçant l'arrivée de nouveaux messages sur cette page de discussion.
    Vous pouvez configurer, dans le "Tableau de bord" afin que le forum vous abonne à chaque conversation que vous répondez.

    OS : Windows seven 32 bits
    Qt : version 4.70
    Compilation : mingw32 version 3.81
    Dans une application de ce type, le plus important, c'est d'indiquer quelle est la carte graphique et sa version du pilote.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  11. #11
    Nouveau membre du Club
    Hi!
    Merci pour votre réactivité (c'est pas comme la mienne!)

    Vous pouvez configurer, dans le "Tableau de bord" afin que le forum vous abonne à chaque conversation que vous répondez.
    C'est chose faite.

    Concernant ma "carte graphique" (dans mon cas "chipset" serait plus approprié), voila les infos que j'ai récupérées à l'adresse :
    http://www.intel.com/support/siu.htm

    GRAPHICS INFORMATION
    Graphics Product [1] : Intel® G41 Express Chipset
    Graphics Driver Version : not detected
    3D Acceleration : Yes
    Hardware Transform & Lighting Support : Yes
    Video Memory : 1.5 GB
    Vertex Shader Support : 4.0
    Pixel Shader Support : 4.0
    Microsoft DirectX* Version : 11.0

  12. #12
    Responsable 2D/3D/Jeux

    Intel a toujours été reconnu comme étant une bête noire dans le support d'OpenGL et de tout ce qui est 3D (bon ok, surtout OpenGL).

    Ainsi, par exemple, plein de chipset OpenGL, non pas de framebuffer (FBO). Ce qui devient réellement gênant (technique de blur, ou deferred rendering).

    Après, il peut aussi y avoir que les shaders ne soit pas analyser comme chez NVidia / AMD et que du coup, la compilation foir complêtement.
    Finalement, d'après les erreurs vu, il se peut aussi que ce soit juste l'auteur qui ne savait pas qu'il faut linker un shader avant d'envoyer certaine information. Enfin, je dis ça, on va surtout voir la réaction du pro, je parle bien de Monsieur gbdivers
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  13. #13
    Inactif  
    Non, pas de problème dans le link (sinon, ça poserait problème sur d'autres plateformes aussi).
    Le problème est que le fonction texture(sampler2D, vec2) n'est pas trouvé lors de la compilation du vertex shader (les autres erreurs de compilation et de link en découlent). Je dirais que c'est un problème de prise en charge d'OpenGL.

    Donc achète une carte NVIDIA

    Sinon, essaie avec la fonction texture2D dans le vertex shader. Remplace
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    texture_color = texture(texture2d, texture_coordonnees);

    par
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    texture_color = texture2D(texture2d, texture_coordonnees);


    EDIT : par contre, l'erreur dans mon code est de ne pas avoir testé les extensions OpenGL avant de les avoir utilisée (comme je suis sur un carte NVIDIA récente, je n'ai pas de problème de compatibilité)
    Tu peux poster la liste de tes extensions opengl supporté ?

  14. #14
    Nouveau membre du Club
    Hi!

    Encore merci pour votre expertise!

    Donc achète une carte NVIDIA
    J'ai déjà consulté un catalogue, mais je ne suis pas sûr que cette solution me convienne car mon application doit pouvoir tourner sur un pc ordinaire et non pas le dernier cri en matière d'accélération graphique.

    remplacer
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    texture_color = texture(texture2d, texture_coordonnees);

    par
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    texture_color = texture2D(texture2d, texture_coordonnees);

    désolé mais dans les sources fournies avec le tuto, je n'ai trouvé nulle part trace d'une méthode/fonction "texture" se présentant sous cette forme. Pour en avoir le coeur net, je les ai retéléchargées, pensant qu'elles aient pu entre temps être mises à jour : mais non!

    Tu peux poster la liste de tes extensions opengl supporté ?
    A l'aide de l'utilitaire downloadé à l'adresse :
    http://www.realtech-vr.com/glview/download.html
    j'ai récupéré le .xml attaché à ce message et qui contient, entre autre, la liste des extensions.

  15. #15
    Candidat au Club
    Bonjour,

    Tout d'abord merci et bravo pour ce tutoriel.

    Je viens de finir de le parcourir récemment, et j'ai toutefois un comportement que je n'arrive pas à expliquer.

    Comme des images valent mieux que des mots maladroits, je met en pièce jointe deux illustrations du comportement :

    Lorsqu'on utilise le FBO pour un rendu offscreen, si l'on réduit la fenêtre, le rendu dans le FBO s'en trouve découper. (ce n'est pas le cas pour les autres mode de rendu offscreen).

    Si quelqu'un peut m'éclairer sur le pourquoi de ce comportement, je lui en serais reconnaissant.

    merci d'avance.

  16. #16
    Inactif  
    J'ai déjà consulté un catalogue, mais je ne suis pas sûr que cette solution me convienne car mon application doit pouvoir tourner sur un pc ordinaire et non pas le dernier cri en matière d'accélération graphique.
    C'était bien sur une plaisanterie
    Par contre, si tu veux une compatibilité avec du vieux matériel, il est préférable peut être de travailler en vieux OpenGL (sans shaders ?) et d'utiliser le mode compatibilité pour le matériel récent (avec perte de performance) dans un premier temps. Ensuite, tu ajoutes le code nécessaire pour prendre en charge les nouvelles fonctionnalités dans un second temps.

    désolé mais dans les sources fournies avec le tuto, je n'ai trouvé nulle part trace d'une méthode/fonction "texture" se présentant sous cette forme. Pour en avoir le coeur net, je les ai retéléchargées, pensant qu'elles aient pu entre temps être mises à jour : mais non!
    J'ai oublié de préciser : tu trouveras la fonction dans le fichier de shader "vertex.glsl"

    j'ai récupéré le .xml attaché à ce message et qui contient, entre autre, la liste des extensions.
    Manifestement, le problème est que la version prise en charge est le GLSL 1.2 "intel build"... (j'ai testé pour du GLSL 3.x).
    Sur le site de Khronos, tu as les spécifications pour le GLSL pour chaque version. Il faut aller voir dans le pdf correspondant spécifiquement à ta version (ici dans ton cas). Pour le GLSL 1.2, la fonction texture() surchargée n'existe pas, il faut appeler la fonction texture2D() (voir page 64 du pdf)

    Lorsqu'on utilise le FBO pour un rendu offscreen, si l'on réduit la fenêtre, le rendu dans le FBO s'en trouve découper. (ce n'est pas le cas pour les autres mode de rendu offscreen).
    Si quelqu'un peut m'éclairer sur le pourquoi de ce comportement, je lui en serais reconnaissant.
    Bravo, tu as découvert une fonctionnalité caché du programme d'exemple... qui a dit un bug ? Bande de méchants !
    Je regarde les sources pour modifier cette fonctionnalité...

    EDIT : pour le problème de FBO, je ne l'ai pas (Ubuntu 11.04, NVIDIA 8600M GT 512 Mo, driver 285.03, OpenGL 3.3.0). Tu peux donner les caractéristiques de ta carte (et la taille de ta RAM GPU) ?
    Je pense à un problème de buffer saturé...

  17. #17
    Nouveau membre du Club
    Hi!
    J'ai oublié de préciser : tu trouveras la fonction dans le fichier de shader "vertex.glsl"
    Autant pour moi, ayant parcouru la partie "shader" du tutoriel en diagonale, j'avais pas capté que les .glsl contenaient du code.
    Bon, dans les fichiers de shader "vertex.glsl" j'ai remplacé
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    texture_color = texture(texture2d, texture_coordonnees.st);
    par
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    texture_color = texture2D(texture2d, texture_coordonnees.st);


    L'appli OpenGL-shader fonctionne correctement.

    L'appli OpenGL-offscreen quant à elle, n'a pas bougé d'un poil, elle avorte après avoir envoyé à la console un fort désobligeant :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    QGLShaderProgram::uniformLocation( pbuffer_size ): shader program is not linked
    QGLShaderProgram::release: program is not valid in the current context.

  18. #18
    Candidat au Club
    Citation Envoyé par gbdivers Voir le message

    pour le problème de FBO, je ne l'ai pas (Ubuntu 11.04, NVIDIA 8600M GT 512 Mo, driver 285.03, OpenGL 3.3.0). Tu peux donner les caractéristiques de ta carte (et la taille de ta RAM GPU) ?
    Je pense à un problème de buffer saturé...
    D'un point de vue caractéristique de la CG, j'ai une ATI Radeon HD 4870 X2, 2Go de RAM en GDDR5 (1 pour chaque proc)

    Driver :
    Driver Packaging Version 8.881-110728a-124445C-ATI
    Catalyst Version 11.8

    glGetString(GL_VERSION) donne : "3.3.11005 Compatibility Profile Context"

    Sinon, je suis sous windows7 SP1, avec QtCreator/MinGW. je ne sais pas si ça peut jouer.

  19. #19
    Membre à l'essai
    Super tuto. Bravo.

    Juste une petite remarque :

    Dans le paragraphe 4, vous dites: "un exemple de Geometry Shader (uniquement à partir de la version 4.7 de Qt) sera présenté dans le chapitre suivant. "
    Or, il semble que l'exemple n'arrive finalement pas.

    Mais cela n'enlève rien au mérite de ce beau tuto.

  20. #20
    Inactif  
    Citation Envoyé par Dedew Voir le message
    D'un point de vue caractéristique de la CG, j'ai une ATI Radeon HD 4870 X2, 2Go de RAM en GDDR5 (1 pour chaque proc)

    Driver :
    Driver Packaging Version 8.881-110728a-124445C-ATI
    Catalyst Version 11.8

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    glGetString(GL_VERSION) donne : "3.3.11005 Compatibility Profile Context"


    Sinon, je suis sous windows7 SP1, avec QtCreator/MinGW. je ne sais pas si ça peut jouer.
    Désolé, je n'ai pas fait attention à ta réponse. Mais j'ai aucune idée du problème

    Citation Envoyé par lolo_bobo
    Super tuto. Bravo.

    Juste une petite remarque :

    Dans le paragraphe 4, vous dites: "un exemple de Geometry Shader (uniquement à partir de la version 4.7 de Qt) sera présenté dans le chapitre suivant. "
    Or, il semble que l'exemple n'arrive finalement pas.

    Mais cela n'enlève rien au mérite de ce beau tuto.
    Un oubli ? Cette partie a du sauter lors des différentes réécritures. La partie sur les shaders geometry permettait d'afficher les vecteurs normaux. Je rétablirai lors d'une prochaine mise à jour du tutoriel