Comment recréer l'effet Liquid Glass en utilisant le canvas HTML

Qu'est-ce que la réfraction ?

Lorsque la lumière traverse une lentille aux bords arrondis, comme une goutte d'eau ou une lentille convexe, le phénomène de réfraction fait que les rayons de lumière se courbent différemment selon l'endroit où ils pénètrent dans la lentille.

Au centre, la surface est presque plate, donc les rayons sont peu déviés et l'image apparaît assez nette et fidèle. Mais vers les bords, la courbure augmente : les rayons de lumière entrent avec un angle plus incliné par rapport à la normale (la ligne perpendiculaire à la surface) et sont davantage déviés. Cela provoque un effet d'étirement, de courbure et d'agrandissement non uniforme de l'image sous-jacente.

💡 Comment le reproduire

Pour reproduire techniquement l'effet de réfraction d'une lentille aux bords arrondis, on utilise une technique de remappage de pixels basée sur la distance au bord.

Capture de l'arrière-plan : l'image sous-jacente est sauvegardée dans un tampon (boardBufferData). Cela sert à lire les pixels originaux qui seront ensuite "déformés" par la goutte.

Forme de la lentille : on définit la forme de la lentille, par exemple un rectangle avec des coins arrondis. Seuls les pixels à l'intérieur de cette forme seront modifiés.

Calcul de la distance au bord : pour chaque pixel à l'intérieur de la lentille, le code calcule sa proximité avec le bord. Plus le pixel est proche du bord, plus l'effet de réfraction sera intense.

Facteur de distorsion : un easing cubique (Math.pow(1 - norm, 3)) est utilisé pour donner une atténuation naturelle du bord vers le centre. Cela génère une courbure plus "physique" similaire à celle observée dans une véritable goutte.

Remappage des pixels : chaque point sur la lentille est déplacé vers le centre de manière proportionnelle, simulant la déviation des rayons de lumière. C'est comme si chaque pixel était "tiré" depuis le centre en fonction de la courbure.

Rendu final : le tampon déformé est dessiné sur un canvas secondaire, puis projeté sur le canvas principal. À cela s'ajoutent des reflets dynamiques et un effet Fresnel aux bords pour simuler la lumière qui se courbe.

Un peu de code :

// Dimensions de la goutte
const W  = /* largeur de la goutte */ 300;  
const H  = /* hauteur de la goutte */ 150;  

// Rayon interne utilisé pour atténuer la distorsion (en pixels)
const R  = /* rayon */ Math.min(W, H) / 3;  

// Coefficient de distorsion (ex. –0.3 pour lentille convexe)
const k  = /* force de la lentille */ -0.3;  

// Coordonnées du centre de la goutte dans le tampon de sortie
const cx = W / 2;  
const cy = H / 2;  

// src : matrice 2D de pixels de l'arrière-plan (buffer.getImageData)
const src = backgroundPixelArray;  

// dst : matrice 2D de pixels pour la goutte (créée avec createImageData)
const dst = dropletPixelArray;  

// Boucle sur chaque pixel de la goutte
for (let j = 0; j < H; j++) {
  for (let i = 0; i < W; i++) {
    // 1. Distance normalisée au bord (0 au bord, 1 au centre)
    let norm = Math.min(i, W - i, j, H - j) / R;

    // 2. Facteur de distorsion : plus fort aux bords, zéro au centre
    let f = 1 + k * Math.pow(1 - norm, 2);

    // 3. Coordonnées "réfractées" sur le tampon de l'arrière-plan
    let sx = Math.round(cx + (i - cx) * f);
    let sy = Math.round(cy + (j - cy) * f);

    // 4. Copier le pixel réfracté si dans les limites
    if (sx >= 0 && sx < canvasWidth && sy >= 0 && sy < canvasHeight) {
      dst[j][i] = src[sy][sx];
    }
  }
}

// À la fin, appliquez dst avec putImageData sur le canvas

En résumé, au lieu d'utiliser de véritables rayons de lumière, le code simule la réfraction en modifiant les coordonnées d'échantillonnage des pixels, imitant exactement ce qui se passe avec la lumière traversant un objet transparent courbé.

🔍 Bonus 1 – Qualité HD avec canvas redimensionné

Le canvas interne possède une résolution très élevée, mais est affichée plus petite en HTML. Cette astuce permet de conserver l'image nette même lorsqu'elle est déformée, évitant l'effet pixélisé surtout sur les bords de la goutte.

⚙️ Bonus 2 – Haute performance

Le fond est dessiné une seule fois dans un tampon, évitant ainsi de le recalculer à chaque fois. De plus, seule la zone de la goutte est mise à jour, réduisant la charge de travail et maintenant l'effet fluide et léger.

J'espère que vous avez apprécié lire ce tutoriel, si vous avez des questions ou des suggestions, n'hésitez pas à nous écrire !