Le problème que Perlin a résolu

En 1983, Ken Perlin travaillait sur le film Tron et avait besoin de générer des textures naturelles — nuages, fumée, terrain — qui semblent organiques plutôt que mécaniques. random() ne suffisait pas : les valeurs aléatoires pures créent du bruit blanc, sans cohérence spatiale. Un pixel peut valoir 0.1 et son voisin 0.9 — aucune transition, aucun motif naturel.

Sa solution : un bruit pseudo-aléatoire cohérent. Deux points proches dans l'espace ont des valeurs proches. L'espace des valeurs est continu, pas chaotique. Perlin a reçu un Oscar scientifique pour cette invention.

La différence en une image mentale

Imaginez random() comme un dé lancé à chaque pas : chaque valeur est indépendante de la précédente. Imaginez noise() comme la courbe de température d'une journée : les variations sont douces, continues, prévisibles à court terme mais jamais identiques d'un jour à l'autre.

Comment ça marche (sans maths)

noise(x) prend un argument de position et renvoie une valeur entre 0 et 1. Ce qui compte : si x varie lentement, la valeur varie lentement. Si vous passez de noise(0) à noise(1), vous traversez une transition douce. Si vous passez de noise(0) à noise(100), vous traversez des centaines de variations.

Donc : pour un mouvement lent et organique, faites varier x lentement. Pour un mouvement rapide et nerveux, faites varier x vite.

Les 3 usages fondamentaux en p5.js

1. Position animée


let t = 0;
function draw() {
  t += 0.005; // vitesse de variation
  let x = noise(t) * width;
  let y = noise(t + 100) * height; // offset pour éviter que x et y bougent pareil
  ellipse(x, y, 10, 10);
}

L'offset + 100 est une astuce classique : noise(t) et noise(t + 100) donnent des valeurs différentes mais toutes deux lisses.

2. Champ de vecteurs


function draw() {
  for (let i = 0; i < particles.length; i++) {
    let p = particles[i];
    let angle = noise(p.x * 0.005, p.y * 0.005, frameCount * 0.003) * TWO_PI * 2;
    p.x += cos(angle) * 1.5;
    p.y += sin(angle) * 1.5;
  }
}

Ici, noise prend trois arguments : position x, position y, et le temps. Deux particules proches suivent des directions similaires, créant des lignes de flux cohérentes.

3. Terrain 2D


function draw() {
  for (let x = 0; x < width; x++) {
    let h = noise(x * 0.008, frameCount * 0.005) * height;
    line(x, height, x, height - h);
  }
}

Le paramètre caché : l'échelle

Le facteur multiplicatif appliqué à x (0.005, 0.008, etc.) détermine l'échelle du bruit. Petit facteur = transitions lentes = motifs larges. Grand facteur = transitions rapides = motifs serrés. C'est le paramètre que vous ajusterez le plus souvent pour obtenir le rendu souhaité.

Bruit fractal : plusieurs octaves

En superposant plusieurs couches de bruit à des échelles différentes (moitié d'amplitude, double de fréquence à chaque couche), on obtient un bruit fractal plus riche. p5.js n'implémente pas nativement les octaves, mais on peut les coder manuellement :


function fbm(x, y) {
  let val = 0, amp = 1, freq = 1, max = 0;
  for (let i = 0; i < 4; i++) {
    val += noise(x * freq, y * freq) * amp;
    max += amp; amp *= 0.5; freq *= 2;
  }
  return val / max;
}

Résumé en 3 règles

1. Faites varier l'argument de noise() lentement pour obtenir un mouvement lent

2. Utilisez des offsets différents pour des dimensions indépendantes

3. Jouez avec le facteur d'échelle pour contrôler la densité du motif

Explorer le tuto interactif → · Parler de votre projet →