html5滤镜怎么加水波荡漾_html5水波滤镜应用法【技巧】

6次阅读

html5 canvas 水波效果靠手动模拟位移映射,核心是 requestAnimationFrame + getImageData/putImageData 实时逐像素正弦偏移,关键三步:控制幅度(2–8px)、频率、相位推进速度。

html5滤镜怎么加水波荡漾_html5水波滤镜应用法【技巧】

html5 canvas 实现水波荡漾效果靠的是什么

不是 Filter css 属性,也不是 WebGPU 或 webgl 高级 API —— 纯 HTML5 水波效果几乎全靠 Canvas 2D 手动模拟位移映射(displacement map),核心是逐像素计算正弦扰动偏移量。

常见误区:以为加个 filter: url(#water) 就能出水波。svg 滤镜虽支持 ,但浏览器对动态噪声 + 动画的支持极差,且无法响应鼠标/触摸交互。

真正可用的路径只有一条:用 requestAnimationFrame + getImageData/putImageData 做实时像素重采样。

Canvas 水波滤镜的关键三步怎么写

水波本质是「把原图每个像素的采样坐标,按正弦函数横向/纵向偏移」。实现时必须控制好三个变量:扰动幅度、频率、相位推进速度。

立即学习前端免费学习笔记(深入)”;

  • amplitude(幅度)设太大图像撕裂,建议 2–8 像素;设太小(
  • frequency(频率)决定波纹疏密,0.01–0.03 较自然;值越大越像高频抖动而非水波
  • phase(相位)每帧递增,如 phase += 0.02;过快会晕眩,过慢像卡顿

示例片段(简化版):

const ctx = canvas.getContext('2d'); const imgData = ctx.getImageData(0, 0, w, h); const data = imgData.data; 

for (let y = 0; y < h; y++) { for (let x = 0; x < w; x++) { const offsetX = Math.sin(x freq + phase) amplitude; const offsetY = Math.cos(y freq + phase 0.7) amplitude; const srcX = Math.max(0, Math.min(w - 1, x + offsetX)); const srcY = Math.max(0, Math.min(h - 1, y + offsetY)); const srcIdx = (srcY w + srcX) 4; const dstIdx = (y w + x) * 4; data[dstIdx] = data[srcIdx]; // R data[dstIdx + 1] = data[srcIdx + 1]; // G data[dstIdx + 2] = data[srcIdx + 2]; // B data[dstIdx + 3] = data[srcIdx + 3]; // A } } ctx.putImageData(imgData, 0, 0);

为什么直接用 getImageData 会卡顿甚至崩溃

因为每次读写都是全图内存拷贝,1920×1080 图像单次操作就要处理约 800 万像素,CPU 压力极大。Chrome 下连续调用 getImageData 容易触发 DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D' 错误。

缓解方法:

  • 缩小绘制区域:只对局部区域(如鼠标 hover 区域)应用水波,用 canvas.width/height 控制画布尺寸,而非撑满屏幕
  • 降帧率:不用 requestAnimationFrame 满帧,改用 setTimeout(..., 60) 锁 16ms 以上间隔
  • 避免重复创建 ImageData:复用同一块内存,用 ctx.createImageData(w, h) 预分配
  • 禁用抗锯齿:ctx.imageSmoothingEnabled = false,防止缩放采样额外开销

有没有更轻量的替代方案

有,但要接受效果妥协。如果只是需要「看起来像水波」而非物理模拟,可考虑:

  • CSS backdrop-filter: blur(2px) + 微动画 transform: translateX(1px) 模拟晃动感(仅适用于背景透明容器)
  • 播放预渲染的水波遮罩视频(MP4/WebM),叠加在目标元素上,opacity 设为 0.15–0.3
  • Three.js 加载简单水面 Shader(如 MeshStandardMaterialnormalMap),但已超出纯 HTML5 范畴

真正零依赖、可交互、跨浏览器稳定的水波,还是得回到 Canvas 像素循环 —— 只是别忘了把幅度、频率、相位这三个数调到人眼舒服的区间,否则再准的算法也像故障显示器。

text=ZqhQzanResources