Come ricreare l'effetto Liquid glass usando canvas HTML
Cos'è la rifrazione?
Quando la luce attraversa una lente con bordi arrotondati, come una goccia d’acqua o una lente convessa, il fenomeno della rifrazione fa sì che i raggi di luce si pieghino in modo diverso a seconda di dove entrano nella lente.
Al centro, la superficie è quasi piatta, quindi i raggi vengono deviati poco e l’immagine appare abbastanza nitida e fedele. Ma verso i bordi, la curvatura aumenta: i raggi di luce entrano con un angolo più inclinato rispetto alla normale (la linea perpendicolare alla superficie) e vengono deviati di più. Questo provoca un effetto di stiramento, piegamento e ingrandimento non uniforme dell’immagine sottostante.
💡 Come si riproduce
Per riprodurre tecnicamente l'effetto di rifrazione di una lente con bordi arrotondati, si sfrutta una tecnica di pixel remapping basata sulla distanza dal bordo.
Cattura lo sfondo: l’immagine sottostante viene salvata in un buffer (boardBufferData). Questo serve per leggere i pixel originali che verranno poi “distorti” dal droplet.
Forma della lente: si definisce la forma della lente, per istanza un rettangolo con angoli arrotondati. Solo i pixel interni a questa forma verranno modificati.
Calcolo della distanza dal bordo: per ogni pixel dentro la lente, il codice calcola quanto è vicino al bordo. Più il pixel è vicino al bordo, più l’effetto di rifrazione sarà intenso.
Fattore di distorsione: viene usato un easing cubico (Math.pow(1 - norm, 3)) per dare un’attenuazione naturale dal bordo verso il centro. Questo genera una curvatura più “fisica” simile a quella osservata in una vera goccia.
Remapping dei pixel: ogni punto sulla lente viene spostato indietro verso il centro in modo proporzionale, simulando la deviazione dei raggi di luce. È come se ogni pixel venisse "tirato" dal centro in base alla curvatura.
Rendering finale: il buffer distorto viene disegnato su un canvas secondario, e poi proiettato sul canvas principale. A questo si aggiungono riflessi dinamici e un effetto Fresnel ai bordi per simulare la luce che si piega.
Un po' di codice:
// Dimensioni della droplet
const W = /* width della droplet */ 300;
const H = /* height della droplet */ 150;
// Raggio interno usato per smorzare la distorsione (in pixel)
const R = /* radius */ Math.min(W, H) / 3;
// Coefficiente di distorsione (es. –0.3 per lente convessa)
const k = /* lensStrength */ -0.3;
// Coordinate del centro della droplet nel buffer di output
const cx = W / 2;
const cy = H / 2;
// src: matrice 2D di pixel dello sfondo (buffer.getImageData)
const src = backgroundPixelArray;
// dst: matrice 2D di pixel per la droplet (creata con createImageData)
const dst = dropletPixelArray;
// Loop su ogni pixel della droplet
for (let j = 0; j < H; j++) {
for (let i = 0; i < W; i++) {
// 1. Distanza normalizzata dal bordo (0 al bordo, 1 al centro)
let norm = Math.min(i, W - i, j, H - j) / R;
// 2. Fattore di distorsione: maggiore ai bordi, zero al centro
let f = 1 + k * Math.pow(1 - norm, 2);
// 3. Coordinate “rifratte” sul buffer di sfondo
let sx = Math.round(cx + (i - cx) * f);
let sy = Math.round(cy + (j - cy) * f);
// 4. Copia il pixel rifratto se entro i limiti
if (sx >= 0 && sx < canvasWidth && sy >= 0 && sy < canvasHeight) {
dst[j][i] = src[sy][sx];
}
}
}
// Alla fine, applica dst con putImageData sul canvas
In poche parole, invece di usare veri raggi di luce, il codice simula la rifrazione modificando le coordinate di campionamento dei pixel, imitando esattamente cosa succede alla luce che attraversa un oggetto trasparente curvo.
🔍 Bonus 1 – Qualità HD con canvas scalato
Il canvas interno ha una risoluzione molto alta, ma viene mostrato più piccolo in HTML. Questo trucco permette di mantenere l’immagine nitida anche quando viene distorta, evitando l’effetto pixelato soprattutto sui bordi della goccia.
⚙️ Bonus 2 – Alte prestazioni
Lo sfondo viene disegnato una sola volta in un buffer, così da non calcolarlo ogni volta. Inoltre, solo l’area della goccia viene aggiornata, riducendo il carico di lavoro e mantenendo l’effetto fluido e leggero.
Spero ti sia piaciuto leggere il tutorial, se hai domande o suggerimenti scrivici pure!