html5滤镜怎样加动态波纹_html5动态波纹滤镜法【步骤】

9次阅读

html5 canvas 实现动态波纹滤镜需用 requestAnimationFrame 驱动像素级 UV 偏移:预分配 createImageData 内存,按距离衰减正弦公式计算偏移量,结合鼠标事件触发扰动,并适配 devicePixelRatio。

html5滤镜怎样加动态波纹_html5动态波纹滤镜法【步骤】

html5 Canvas 如何用 requestAnimationFrame 实现动态波纹滤镜

css 无法实现真正的动态波纹(如水波扩散、点击扰动),必须结合 Canvas + javaScript 计算像素偏移。核心是用 getImageData 读取原图,对每个像素按正弦/衰减函数做 UV 偏移,再用 putImageData 渲染——关键在偏移量随时间变化。

常见错误是直接操作 dom 图片元素加 Filter: url(#wave),那只是 svg 滤镜的静态定义,不支持时间变量;也有人误用 filter: blur()hue-rotate(),这些和波纹无关。

  • 波纹本质是「纹理坐标扰动」,不是颜色变换,必须走 Canvas 像素级操作
  • 每次帧更新需重置偏移相位(如 time += 0.02),否则动画卡死
  • 为避免性能爆炸,建议限制画布尺寸(如最大 800×600),或用 ctx.drawImage 缩放原始图像后再处理

怎样用 createImageData 预分配内存避免频繁 GC

每帧都调 getImageData 会触发大量内存分配,导致卡顿。正确做法是提前用 createImageData 创建缓冲区,复用同一块内存:

const canvas = document.getElementById('wave-canvas'); const ctx = canvas.getContext('2d'); const width = canvas.width; const height = canvas.height; // 预分配一次 const imageData = ctx.createImageData(width, height); const data = imageData.data; // 直接引用像素数组

后续每一帧只需修改 data 数组值,再 ctx.putImageData(imageData, 0, 0) 输出,跳过重复创建开销。

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

  • 不要在动画循环里写 ctx.getImageData(0, 0, w, h) —— 这是典型性能雷区
  • data 是长度为 width × height × 4 的 Uint8ClampedArray,索引 i 对应 RGBA 四字节,修改时注意边界(i+0 是 R,i+1 是 G…)
  • 若需叠加原图纹理,得先用 ctx.drawImage(img, 0, 0) 绘制底图,再读取 ctx.getImageData 获取初始像素

波纹公式怎么写:用 math.sin + 距离衰减模拟真实水波

简单正弦偏移(dx = Math.sin(x + time) * amp)看起来生硬。真实波纹需满足:中心扰动强、向外快速衰减、多频率叠加。推荐这个轻量公式:

const dx = Math.sin(dist * 0.05 - time * 2) * amp / (dist + 1); const dy = Math.cos(dist * 0.07 - time * 1.5) * amp / (dist + 1);

其中 dist = Math.sqrt((x - cx)**2 + (y - cy)**2) 是到波源点(如鼠标位置 cx, cy)的距离。

  • / (dist + 1) 是关键衰减项,没它波纹会平铺全图
  • 两组不同频率(0.05 vs 0.07)和相位(time*2 vs time*1.5)叠加,避免单调感
  • 鼠标点击触发时,把 cx, cy 设为点击坐标,并重置 time = 0,否则新波和旧波干涉混乱

为什么webgl 更合适但多数人该先用 Canvas

Canvas 方案在 1080p 下帧率易掉到 30fps 以下,尤其多波源时。WebGL 理论上更优:用 fragment shader 直接计算偏移,GPU 并行处理百万像素。但代价是学习曲线陡峭、调试困难、移动端兼容性差(部分 android webview 不支持 WEBGL_depth_texture 扩展)。

除非你已在用 Three.js 或需要同时跑 5+ 动态波源,否则 Canvas + 上述优化已够用。真正容易被忽略的是:Canvas 波纹效果依赖设备像素比(window.devicePixelRatio),在 Retina 屏上若没缩放 canvas.style.width/height,图像会模糊——必须显式设置 canvas.width = width * dprctx.scale(dpr, dpr)

text=ZqhQzanResources