Avant de t'attaquer à ce défi, on te conseille de compléter les défis suivants:

  1. P5JS - Prédiction
  2. Ça va bien aller
  3. Bulles de savant
  4. P5JS - 10 Print

On va commencer par une animation très simple, un simple carré qui tourne autour de soi même. Bien sûr, il n'y a pas de 3D dans cela, mais elle sera très facile à rajouter!

Pour commencer, on va introduire la "dimension" WEBGL. Plutôt que de définir un canvas 400x400 comme normalement, on va ajouter une 3e composante: La composante WEBGL.


              createCanvas(400, 400, WEBGL);
            

Cette nouvelle dimension correspond en fait à la profondeur, mais cela ne fait pas vraiment sens d'ajouter une taille à la profondeur, on se satisfait de préciser qu'il y a une profondeur.

En introduisant ce WEBGL, on a accès à de nouvelles fonctions, qui vont nous aider grandement. Par exemple, on peut maintenant définir un carré en utilisant plane(). Le paramètre indique la taille du carré. Comme c'est bien fait, il sera centré au milieu de l'écran!

On veut maintenant créer une animation. Rien de plus simple! On va se servir de la fonction rotateX() qui fait une rotation au carré. Le paramètre indique l'angle.

Crée une variable angle, auquel tu ajoutes un certain nombre chaque fois que draw() s'execute, et mets cet angle dans la fonction rotateX().


                  let angle = 0;
                  
                  function draw() {
                    background(220);
                    angle += 0.02;
                    rotateX(angle);
		    plane(70);
                  }
                

Une remarque importante: Il est important de dessiner le carré APRÈS de faire la rotation, sinon on ne verra rien.

Comme tu l'as surement deviné, tu peux utiliser les fonctions rotateY() et rotateZ() aussi. Tu peux même les combiner, et mettre différents angles comme paramètres.

Si tu veux faire tourner une cube plutôt qu'un carré, tu peux utiliser la fonction box(), de nouveau avec paramètre la taille.

Et pour toutes les autres figures possibles, c'est aussi facile! En effet, il y a 7 figures dites "primitives" que tu peux utiliser. Les voici:

  • plane()
  • box()
  • sphere()
  • ellipsoid()
  • cone()
  • cylinder()
  • torus()

Pas tous ne prennent qu'un seul paramètre, tu peux essayer lesquels en prennent combien. Certains ont plusieurs options: Par exemple, la fonction plane() peut en prendre 1 (Comme on a vu plus tôt), ou 2 (Hauteur et Largeur). Similairement, la fonction box() peut en prendre 1 ou 3.

Pour l'instant on a des figures blanches qui flottent dans l'espace. C'est joli, certes, mais si on ajoutait des couleurs?

Te souviens tu comment tu faisais pour colorier un carré normal? Tu peux reutiliser cela ici!


                  fill("red");
                

Mais on a d'autres façons de colorier, qui viennet avec WEBGL. La plus facile est normalMaterial(). Il existe d'autres façons, mais on ne va pas les explorer comme elles sont plutôt compliquées et qu'on ne s'en servira pas.

Essaie de dessiner plusieurs figures ensembles. Elles vont se mettre les unes sur les autres et cela ne sera pas super beau... Heureusement, on a des solutions!

Les nouvelles functions qu'on a introduites ne prennent pas comme paramètres les positions. Elles sont simplement placées au milieu de l'écran. Donc pour les bouger, on va utiliser des translations.

La fonction translate() prend 2 paramètres, un pour le décallage en X et l'autre pour le décallage en Y. Essaie de décaler ta figure plus vers le coin en haut à gauche.

Une chose est claire: Il faut mettre cette fonction avant de dessiner notre figure. Sinon cela ne s'appliquera pas sur la figure... Mais faut-il placer la fonctiona avant ou après les fonctions rotateX(), rotateY(), rotateZ()?

Essaie les deux! Normalement, les deux fonctionnent, mais donnent des résultats très différents!

Si tu places le translate() après les rotate(), alors tu vas faire bouger ta figure mais pas le centre de rotation, donc le figure bouge dans tous les sens. Si tu le places avant, tu vas bouger la figure et le centre de rotation, donc la figure va bouger "normalement" mais à un autre moment.

Il est donc clair qu'on va utiliser la seconde option comme elle est moins "bordélique". Le code pour déplacer ta figure ressemble donc à ceci:


              function draw() {
                background(220);
                angle += 0.02;
              
                translate(-100, -100);

                rotateX(angle);
                rotateY(angle);
                rotateZ(angle);
                            
                normalMaterial();

                box(70);
              }
            

Comment pourrait-on dessiner plusieurs figures du coup? Une idée assez simple serait de reproduire le code 2 fois, cela marche en géneral... Mais que fait-il reproduire? On n'a pas besoin de re-dessiner l'arrière-plan, et on n'a pas besoin de changer l'angle de nouveau. Mais on doit certainement de nouveau utiliser la fonction translate(), sinon nos deux figures se superposent. Faut-il aussi re-utiliser les fonctions rotate()? Essaie de créer 2 figures qui tournent "joliment" autour d'elles mêmes de façon indépendantes!

On pourrait donc s'imaginer quelque chose comme ceci:


              function draw() {
                background(220);
                angle += 0.02;
              
                normalMaterial();

                // Figure 1
                translate(-100, -100);

                rotateX(angle);
                rotateY(angle);
                rotateZ(angle);       

                box(70);

                // Figure 2
                translate(200, 200);

                rotateX(angle);
                rotateY(angle);
                rotateZ(angle);       

                box(70);
              }
            

Tu as du mal? C'est normal! Laisse moi t'expliquer pourquoi: Pour ta première figure, tu déplaces le centre de rotation pour que la première figure tourne bien autour d'elle même. Pour la deuxième figure, tu déplaces de nouveau le centre de rotation, mais ta deuxième figure va aussi subir la première rotation. Donc elle part dans tous les sens. C'est un peu technique, et on pourrait l'expliquer de façon plus rigoureuse, mais ce n'est pas bien important. L'important est de conclure que cela ne marche pas.

Mais comment fait-on alors? On va utiliser des fonctions qui s'appellent push() et pop(). Elles font un peu peur au début, mais elles sont SUPER utiles! Tu vas voir ;-)

Pour définir une figure, on encadre tout son code par des push() /* ... */ pop(). Cela veut dire qu'avant notre figure, on place un push(), et après, on place un pop(). Cela va ressembler à ceci pour une figure:


              function draw() {
                background(220);
                angle += 0.02;
              
                normalMaterial();

                // Figure 1
                translate(-100, -100);

                push();

                rotateX(angle);
                rotateY(angle);
                rotateZ(angle);       

                box(70);
                pop();
              }
            

Remarque comment on garde le translate() en dehors des push(), pop(). C'est parce que le translate ne fait pas partie de notre figure, il indique simplement où il se trouve. Maintenant il indique où l'ensemble entre le push() et le pop() se trouve!

Tu peux ainsi créer plusieurs figures qui tournent indépendamment des autres. C'est super!!

On va maintenant s'attaquer à une animation plus compliquée! Tu peux voir le résultat ici. Es-tu prêt?!

Je vais commencer un nouveau projet. Tu peux continuer sur ton ancien si tu en as envie, mais je te conseille de reprendre dès le début.

Commençons par ce que l'on connaît déjà. On sait qu'il faut ajouter une nouvelle "dimension" lorsqu'on crée le canvas, la "dimension" WEBGL.

On sait aussi qu'on veut dessiner une boîte. Pour ce faire, on peut se servir d'une des fonctions primitives de WEBGL. Sais-tu laquelle serait très bonne pour notre cas?

Cette boîte devrait avoir une hauteur qui change avec le temps. On doit donc définir une variable pour déterminer la hauteur. Cette hauteur peut être utilisée dans ton code.

Essaie déjà de code cela!


                  let hauteur = 20;

                  function setup() {
                    createCanvas(400, 400, WEBGL);
                  }

                  function draw() {
                    background(220);
                    box(100, 100, hauteur);

                    // Faire changer la hauteur
                    // ...
                  }
                

Pour le moment, on voit juste la boîte de côté. Pour la voir de côté, on peut simplement faire une rotation à angle fixe. Par exemple (À toi de déterminer les valeurs)


              rotateX(20);
              rotateY(10);
            

Notre boîte ne bouge pas, mais on voit bien que c'est une boîte 3D parce qu'on la voit en perspective. Super!

On aimerait alors adapter la hauteur de la boîte à la fin de chaque fois que draw() s'execute. On va donc placer le code pour adapter la taille à la fin de draw().

Notre boîte doit s'agrandir jusqu'à un certain point, puis elle doit diminuer, puis elle doit s'agrandir etc. On va donc devoir jouer avec des conditions.

L'idée est d'avoir une nouvelle variable qui s'appelle "Grandir" (Ou quelque chose dans le style). Lorsque la hauteur est plus grande que 50 (par exemple), cette variable devient négative, et lorsque la hauteur est plus petite que 0, elle redevient positive. L'idée se fonde sur le fait qu'on change la hauteur par cette variable à chaque tour. Voic un exemple:


              if(hauteur > 50) {
                grandir = -2;
              } 
              if(hauteur < 0) {
                grandir = 3;
              }
              hauteur += grandir;
            

On peut alors ajouter une couleur à notre boîte en utilisant la fonction normalMaterial().

Finalement, tu peux faire tourner la boîte autour d'elle même aussi si tu le souhaites. Tu peux également changer la boîte en une autre figure primitive. Tu peux même ajouter plusieurs figures! Sois créatif ;-)