Du code au réel — Tutoriel p5JS : Vague de cercle multicolore

Vincent Largillet
6 min readFeb 28, 2022

--

Dernier article de ce plan d’apprentissage : le tutoriel !

Ici, je vais me servir de l’éditeur web de p5JS, accessible ici : https://editor.p5js.org/

L’objectif du tutoriel sera de recréer ceci : un effet de vague sur une grille de cercle multicolore.

— Créer la grille

En premier, on va définir les variables qui nous serviront par la suite.

Dans l’ordre :

  • wCanvas accueillera la valeur pour la largeur du Canvas p5JS.
  • hCanvas accueillera la valeur pour la hauteur du Canvas p5JS.
  • rMin, pour rayon Min, sera la valeur du rayon du cercle la plus petite possible.
  • rMax, à l’inverse, sera la valeur du rayon du cercle la plus grande possible.
  • stkW sera la valeur qui va gérer l’épaisseur de la bordure de notre cercle, ici une épaisseur de 2.
  • dBase sera la valeur de base du diamètre de notre cercle, soit Rayon fois 2 (ici la valeur de rayon maximum fois 2).

Ensuite, on va passer dans la fonction setup() de l’éditeur. Cette fonction permet d’initialiser notre Canvas, mais aussi des valeurs qu’on peut réutiliser plus tard, setup() n’étant appelé qu’une fois au lancement du programme.

À l’intérieur, je vais définir wCanvas et hCanvas avec les valeurs windowWidth et windowHeight, qui sont des variables fournis par p5JS, qui récupèrent la taille de la fenêtre, en largeur et en hauteur respectivement.

Pour créer le Canvas, on appelle la méthode createCanvas, en lui passant d’abord la largeur puis la hauteur en paramètres.

function setup() {
wCanvas = windowWidth
hCanvas = windowHeight
createCanvas(wCanvas, hCanvas)
}

Pour compléter cette fonction setup(), je vais définir le mode de couleur sur HSB grâce à la fonction colorMode. Cela simplifiera par la suite la création de notre effet multicolore. Le mode de couleur HSB est un peu différent du RGB. HSB signifie Hue/Saturation/Brightness (Teinte, Saturation, Luminosité). La première valeur sera notre couleur, allant de 0 à 360, et suivant les couleurs du spectre du visible.

Saturation, valeur allant de 0 à 100, va gérer si notre couleur sera plus ou moins saturé. Plus on est proche de 0, moins la couleur sera vive. À l’inverse, plus on est proche de 100, plus la couleur sera vive.

Brightness, valeur allant de 0 à 100, va gérer la “luminosité de la couleur”. Si la saturation est à 0, la brightness va gérer la nuance de gris de la couleur, qu’importe sa teinte. 0 de luminosité sera tout le temps noir, 100 de luminosité va donner du blanc si la saturation est à 0. Sinon, on gère si la couleur est plus ou moins vive et lumineuse.

Pour le moment, on ne doit rien avoir sur notre Canvas. C’est normal, et on va justement passer à l’affichage des cercles.

Magnifique preview n’est-ce pas ?

La fonction draw(), là où toute la magie va opérer et où on va pouvoir créer notre mer de cercle.

On commence par appeler background, et lui passer les paramètres (0, 0, 0), ce qui correspond à du noir en HSB. (Sinon, on remonte juste un peu, pour voir que 0 de brightness = du noir)

Pour créer notre grille, on va passer par deux boucles for, une pour gérer les lignes, une autre pour les colonnes :

for(let x = 0; x < width; x += dBase) {
for(let y = 0; y < height; y += dBase) {
}
}

On passe d’abord dans la première boucle, qui va gérer les colonnes, puis dans la deuxième, qui va créer les lignes en fonction de la hauteur. À chaque passage, on augmente la valeur de base de dBase, pour que nos cercles ne se chevauchent pas, et tout cela jusqu’à atteindre la hauteur ou la largeur, selon la boucle.

En créant une ellipse à l’intérieur de la deuxième boucle for, avec x en premier paramètre, y en deuxième et rMax en dernier, on devrait se retrouver avec quelque chose comme ça dans la preview :

Plein de petits ronds !

Or, comme vu sur l’objectif en haut, on veut que chaque ellipse soit vide à l’intérieur, et juste avoir une bordure.
Pour ça, on va ajouter juste après le background la fonction strokeWeight(), en lui passant stkW comme valeur, ce qui va définir la taille de notre bordure, et aussi la fonction noFill(), pour pas que notre ellipse se remplisse.

function draw() {
background(0, 0, 0)

noFill()
strokeWeight(stkW)
for(let x = 0; x < width; x += dBase) {
for(let y = 0; y < height; y += dBase) {
ellipse(x, y, rMax*2)
}
}
}

Mais là, le noir complet. Plus rien dans la preview. C’est tout à fait normal. p5JS remplit par défaut de blanc, mais ne définit pas par défaut une couleur de bordure. Pour ça, on va ajouter stroke(0, 0, 100), juste avant notre ellipse, pour obtenir un beau blanc.

function draw() {
background(0, 0, 0)

noFill()
strokeWeight(stkW)
for(let x = 0; x < width; x += dBase) {
for(let y = 0; y < height; y += dBase) {
stroke(0, 0, 100)
ellipse(x, y, rMax*2)
}
}
}

— Animation du rayon des cercles

Pour ça, on va utiliser plusieurs fonctions imbriquées les unes dans les autres, que je vais expliquer une à une.

let wave = map(sin(radians((frameCount + x * y))), -1, 1, rMin, rMax)

La base de tout ça, c’est le calcul à l’intérieur de la fonction radians. frameCount est la variable qui va s’incrémenter à chaque fois que le Canvas se rafraîchit (de manière générale, 60 fois par seconde, mais on peut choisir moins avec la fonction frameRate()). À ça, on ajoute une multiplication de la position en x et y. La fonction radians() va transformer ce calcul, en transformant le résultat de degrés en radians. On passe tout ça dans la fonction sin(), qui est la fonction pour récupérer la valeur sinus.

On utilise uniquement ça pour avoir cet effet de vague, qui va osciller entre -1 et 1. Sauf que -1 et 1, c’est très peu pour le rayon de nos cercles. C’est là qu’intervient la fonction map(). Elle permet de lui donner une valeur, de spécifier son min et son max par défaut (ici une fonction sinus, donc entre -1 et 1) et de “remapper” la valeur dans un nouvel intervalle. Ici on choisi d’aller de rMin à rMax.

Concrètement, si la valeur de notre sinus est proche de -1, on aura une valeur “remapper” proche de rMin, et à l’inverse, si la valeur de notre sinus est proche de 1, on aura une valeur “remapper” proche de rMax.

Remplacer la valeur gérant le diamètre de l’ellipse de rMax*2 par wave*2 et on devrait avoir du mouvement apparaître dans notre Canvas.

Bien, il ne manque plus que la couleur !

Juste après la définition de notre vague gérant le rayon par rapport à la position, on ajoute une nouvelle variable que l’on va nommer hue. Cette valeur sera “mapper” à partir de notre variable wave, et la nouvelle valeur sera comprise entre 0 et une addition de la position x et y, modulo 360 (la valeur max de Hue dans le mode de couleur HSB).

On change ensuite la fonction stroke(), pour lui passer hue en premier paramètre, et changer la saturation à 100, ce qui devrait donner ce code :

let hue = map(wave, rMin, rMax, 0, (x + y)%360)

stroke(hue, 100, 100)

Et voilà ! On retrouve notre résultat comme montrer au début de cet article.

Lien du sketch p5JS: https://editor.p5js.org/VincentLrg/sketches/octyUjLq5

--

--

Vincent Largillet

Writing about my journey learning creative development (in French) Student at Gobelins - Front developer at My Little Paris