So erzeugen Sie den Liquid-Glass-Effekt mit HTML-Canvas

Was ist Brechung?

Wenn Licht durch eine Linse mit abgerundeten Kanten, wie ein Wassertropfen oder eine konvexe Linse, tritt, bewirkt das Phänomen der Brechung, dass die Lichtstrahlen je nach Eintrittspunkt in die Linse unterschiedlich gebogen werden.

In der Mitte ist die Oberfläche fast flach, sodass die Strahlen nur wenig abgelenkt werden und das Bild relativ scharf und originalgetreu erscheint. Aber zu den Rändern hin nimmt die Krümmung zu: Die Lichtstrahlen treten in einem steileren Winkel zur Normalen (der Linie, die senkrecht zur Oberfläche steht) ein und werden stärker abgelenkt. Dies führt zu einem Effekt des Dehnens, Biegens und ungleichmäßigen Vergrößerns des darunterliegenden Bildes.

💡 Wie es reproduziert wird

Um den Brechungseffekt einer Linse mit abgerundeten Kanten technisch zu reproduzieren, wird eine Technik des Pixel-Remappings basierend auf der Entfernung vom Rand verwendet.

Hintergrund erfassen: Das darunterliegende Bild wird in einem Puffer (boardBufferData) gespeichert. Dies dient dazu, die Originalpixel zu lesen, die dann vom Tropfen "verzerrt" werden.

Form der Linse: Die Form der Linse wird definiert, zum Beispiel ein Rechteck mit abgerundeten Ecken. Nur die Pixel innerhalb dieser Form werden modifiziert.

Berechnung der Entfernung vom Rand: Für jedes Pixel innerhalb der Linse berechnet der Code, wie nah es am Rand ist. Je näher das Pixel am Rand ist, desto intensiver ist der Brechungseffekt.

Verzerrungsfaktor: Ein kubisches Easing (Math.pow(1 - norm, 3)) wird verwendet, um eine natürliche Abschwächung vom Rand zur Mitte zu erzeugen. Dies erzeugt eine "physikalischere" Krümmung, ähnlich der, die bei einem echten Tropfen beobachtet wird.

Pixel-Remapping: Jeder Punkt auf der Linse wird proportional zurück zur Mitte verschoben, um die Ablenkung der Lichtstrahlen zu simulieren. Es ist, als ob jedes Pixel basierend auf der Krümmung vom Zentrum "gezogen" wird.

Endgültiges Rendering: Der verzerrte Puffer wird auf einer sekundären Leinwand gezeichnet und dann auf die Hauptleinwand projiziert. Dazu kommen dynamische Reflexionen und ein Fresnel-Effekt an den Rändern, um das Licht zu simulieren, das sich biegt.

Ein wenig Code:

// Abmessungen des Tropfens
const W  = /* Breite des Tropfens */ 300;  
const H  = /* Höhe des Tropfens */ 150;  

// Innerer Radius zur Dämpfung der Verzerrung (in Pixel)
const R  = /* Radius */ Math.min(W, H) / 3;  

// Verzerrungskoeffizient (z.B. –0.3 für konvexe Linse)
const k  = /* lensStrength */ -0.3;  

// Koordinaten des Mittelpunkts des Tropfens im Ausgabepuffer
const cx = W / 2;  
const cy = H / 2;  

// src: 2D-Matrix der Hintergrundpixel (buffer.getImageData)
const src = backgroundPixelArray;  

// dst: 2D-Matrix der Pixel für den Tropfen (erstellt mit createImageData)
const dst = dropletPixelArray;  

// Schleife über jedes Pixel des Tropfens
for (let j = 0; j < H; j++) {
  for (let i = 0; i < W; i++) {
    // 1. Normalisierte Entfernung vom Rand (0 am Rand, 1 in der Mitte)
    let norm = Math.min(i, W - i, j, H - j) / R;

    // 2. Verzerrungsfaktor: größer an den Rändern, null in der Mitte
    let f = 1 + k * Math.pow(1 - norm, 2);

    // 3. "Gebrochene" Koordinaten im Hintergrundpuffer
    let sx = Math.round(cx + (i - cx) * f);
    let sy = Math.round(cy + (j - cy) * f);

    // 4. Kopiere das gebrochene Pixel, wenn es innerhalb der Grenzen liegt
    if (sx >= 0 && sx < canvasWidth && sy >= 0 && sy < canvasHeight) {
      dst[j][i] = src[sy][sx];
    }
  }
}

// Am Ende, wende dst mit putImageData auf das Canvas an

Zusammengefasst simuliert der Code die Brechung, indem er die Abtastkoordinaten der Pixel verändert, anstatt echte Lichtstrahlen zu verwenden, und imitiert genau das, was passiert, wenn Licht durch ein transparentes, gekrümmtes Objekt tritt.

🔍 Bonus 1 – HD-Qualität mit skaliertem Canvas

Das interne Canvas hat eine sehr hohe Auflösung, wird jedoch in HTML kleiner dargestellt. Dieser Trick ermöglicht es, das Bild auch bei Verzerrungen scharf zu halten und vermeidet den pixeligen Effekt, insbesondere an den Rändern des Tropfens.

⚙️ Bonus 2 – Hohe Leistung

Der Hintergrund wird nur einmal in einem Puffer gezeichnet, sodass er nicht jedes Mal neu berechnet werden muss. Zudem wird nur der Bereich des Tropfens aktualisiert, was die Arbeitslast reduziert und den Effekt flüssig und leicht hält.

Ich hoffe, Ihnen hat das Tutorial gefallen. Wenn Sie Fragen oder Anregungen haben, schreiben Sie uns gerne!