菜鸟-创作你的创作

使用feDisplacementMap+feImage滤镜实现水波纹效果(计算动态值)

好的,阿杰。下面给你一个完整的 SVG + feDisplacementMap + feImage 水波纹动态效果示例,并讲解如何 计算动态值来驱动水波纹动画
这个方法利用 滤镜位移图 + 动态动画帧 来实现波纹效果,非常适合网页 H5、Canvas 替代方案或 SVG 动画。


1️⃣ 原理概述


2️⃣ 简单 SVG 水波纹示例

<svg width="400" height="300">
  <!-- 原始图片 -->
  <image id="source" href="your-image.jpg" width="400" height="300"></image>

  <!-- 定义滤镜 -->
  <filter id="ripple" x="0" y="0" width="100%" height="100%">
    <!-- 位移源图片,可以是噪声图 -->
    <feImage id="noise" href="noise.png" result="displacementMap" x="0" y="0"/>
    <!-- DisplacementMap -->
    <feDisplacementMap in="SourceGraphic" in2="displacementMap"
      scale="20" xChannelSelector="R" yChannelSelector="G"/>
  </filter>

  <!-- 应用滤镜 -->
  <image href="your-image.jpg" width="400" height="300" filter="url(#ripple)"></image>
</svg>

参数说明

属性说明
scale位移幅度,数字越大波纹越明显
xChannelSelector / yChannelSelector使用哪一个通道控制偏移(R/G/B/A)
in / in2in 是原图,in2 是位移图
feImage href位移源图,可以是噪声图

3️⃣ 动态计算波纹偏移值(JavaScript 动态修改 scalefeImage 偏移)

<svg id="svg" width="400" height="300">
  <defs>
    <filter id="ripple" x="0" y="0" width="100%" height="100%">
      <feImage id="noise" href="noise.png" result="displacementMap" x="0" y="0"/>
      <feDisplacementMap id="dispMap"
        in="SourceGraphic" in2="displacementMap"
        scale="0" xChannelSelector="R" yChannelSelector="G"/>
    </filter>
  </defs>

  <image href="your-image.jpg" width="400" height="300" filter="url(#ripple)"></image>
</svg>

<script>
const dispMap = document.getElementById('dispMap');
let t = 0;

// 动态水波纹
function animate() {
  // 使用正弦函数计算 scale,实现波动
  const scale = 10 + 10 * Math.sin(t * 0.1); 
  dispMap.setAttribute('scale', scale);

  // 可以同时动态改变 feImage x/y 偏移
  const noise = document.getElementById('noise');
  noise.setAttribute('x', 20 * Math.sin(t * 0.05));
  noise.setAttribute('y', 20 * Math.cos(t * 0.05));

  t++;
  requestAnimationFrame(animate);
}
animate();
</script>

✅ 关键点

  1. 动态 scale
    使用 Math.sinMath.cos 产生周期性变化,模拟水波上下浮动。
  2. 动态移动位移图
    改变 feImagexy 可以让波纹方向、流动速度更自然。
  3. requestAnimationFrame
    每帧更新,平滑动画,性能更好。
  4. 噪声图选择
    • 可以是灰度随机噪声图
    • 或者用 Canvas 动态生成噪声图 → toDataURLfeImage href 动态替换,实现复杂水波纹效果。

4️⃣ 高级技巧


5️⃣ 总结

太好了,阿杰!下面给你一个 完整可运行的 SVG 水波纹网页 Demo
特点如下:

你可以直接复制到 HTML 文件里打开预览。


<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SVG 水波纹动效 Demo</title>
<style>
  html, body {
    margin: 0;
    padding: 0;
    overflow: hidden;
    width: 100%;
    height: 100%;
    background: #000;
  }
  svg {
    width: 100%;
    height: 100%;
    display: block;
  }
</style>
</head>
<body>

<svg id="rippleSVG" width="100%" height="100%">
  <defs>
    <!-- 动态噪声位移图 -->
    <filter id="rippleFilter" x="0" y="0" width="100%" height="100%">
      <feImage id="noiseImage" href="" result="displacementMap" x="0" y="0" preserveAspectRatio="none"/>
      <feDisplacementMap id="dispMap" in="SourceGraphic" in2="displacementMap"
                         scale="0" xChannelSelector="R" yChannelSelector="G"/>
    </filter>
  </defs>

  <!-- 背景图片 -->
  <image href="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&w=800&q=80" 
         width="100%" height="100%" filter="url(#rippleFilter)"/>
</svg>

<script>
// 创建 Canvas 用作动态噪声
const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');

const noiseImage = document.getElementById('noiseImage');
const dispMap = document.getElementById('dispMap');

let t = 0;

function generateNoise() {
  const imgData = ctx.createImageData(canvas.width, canvas.height);
  for(let i=0;i<imgData.data.length;i+=4){
    const val = Math.floor(Math.random() * 255);
    imgData.data[i] = val;     // R
    imgData.data[i+1] = val;   // G
    imgData.data[i+2] = val;   // B
    imgData.data[i+3] = 255;   // A
  }
  ctx.putImageData(imgData, 0, 0);
  noiseImage.setAttribute('href', canvas.toDataURL());
}

function animateRipple() {
  t++;

  // 生成动态噪声
  generateNoise();

  // 动态 scale 模拟水波起伏
  const scale = 15 + 10 * Math.sin(t * 0.1);
  dispMap.setAttribute('scale', scale);

  // 动态偏移噪声图,实现波动方向
  const xOffset = 20 * Math.sin(t * 0.05);
  const yOffset = 20 * Math.cos(t * 0.05);
  noiseImage.setAttribute('x', xOffset);
  noiseImage.setAttribute('y', yOffset);

  requestAnimationFrame(animateRipple);
}

// 启动动画
animateRipple();

// 可根据窗口大小动态调整 Canvas
window.addEventListener('resize', () => {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
});

</script>

</body>
</html>


✅ 特性说明

  1. 动态水波纹
    • dispMap.scale 动态变化模拟波纹起伏
    • noiseImage x/y 动态偏移,波纹方向自然流动
  2. 全屏背景图
    • SVG <image> 作为背景
    • 可替换 href 为你自己的图片 URL
  3. 移动端/桌面端兼容
    • SVG + Canvas 动态生成噪声
    • 不依赖外部库
  4. 可扩展
    • 替换噪声生成算法可实现涟漪、波浪、液化等效果
    • 可叠加多个 feDisplacementMap 增强真实感
退出移动版