好的,阿杰。下面给你一个完整的 SVG + feDisplacementMap + feImage 水波纹动态效果示例,并讲解如何 计算动态值来驱动水波纹动画。
这个方法利用 滤镜位移图 + 动态动画帧 来实现波纹效果,非常适合网页 H5、Canvas 替代方案或 SVG 动画。
1️⃣ 原理概述
feDisplacementMap
将一张灰度图(或噪声图)作为位移源,对目标图像进行像素偏移,实现扭曲效果。feImage
用作位移图(displacement map),可以用噪声图或动态生成的噪声纹理。- 动态水波纹
通过改变feImage的x/y偏移或滤镜属性,或者用<animate>或 JS 动态改变滤镜参数,实现动画效果。
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 / in2 | in 是原图,in2 是位移图 |
feImage href | 位移源图,可以是噪声图 |
3️⃣ 动态计算波纹偏移值(JavaScript 动态修改 scale 或 feImage 偏移)
<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>
✅ 关键点
- 动态 scale
使用Math.sin或Math.cos产生周期性变化,模拟水波上下浮动。 - 动态移动位移图
改变feImage的x、y可以让波纹方向、流动速度更自然。 - requestAnimationFrame
每帧更新,平滑动画,性能更好。 - 噪声图选择
- 可以是灰度随机噪声图
- 或者用 Canvas 动态生成噪声图 →
toDataURL→feImage href动态替换,实现复杂水波纹效果。
4️⃣ 高级技巧
- 多层滤镜叠加
通过多个feDisplacementMap叠加不同频率噪声,实现更真实水波纹。 - 基于 Canvas 动态生成噪声图
const canvas = document.createElement('canvas'); canvas.width = 400; canvas.height = 300; const ctx = canvas.getContext('2d'); const imgData = ctx.createImageData(400, 300); for(let i=0;i<imgData.data.length;i+=4){ const v = Math.random()*255; imgData.data[i] = v; // R imgData.data[i+1] = v; // G imgData.data[i+2] = v; // B imgData.data[i+3] = 255; // A } ctx.putImageData(imgData,0,0); noise.setAttribute('href', canvas.toDataURL()); - 结合 CSS / JS
可把 SVG 放到<div>背景中,实现网页全屏水波纹动态效果。
5️⃣ 总结
- 使用
feDisplacementMap + feImage可以实现 SVG 水波纹。 - 动态计算:
scale = base + amplitude * sin(t * speed)feImage x/y 偏移 = amplitude * sin/cos
- 可以通过 JS 每帧更新
requestAnimationFrame动态变化,实现真实波动效果。 - 高级场景可结合 Canvas 噪声图 + 多层滤镜叠加,生成更逼真的水波纹。
太好了,阿杰!下面给你一个 完整可运行的 SVG 水波纹网页 Demo,
特点如下:
- 全屏背景图片
- 使用
feDisplacementMap + feImage实现水波纹 - JS 动态计算波纹参数
- 支持连续动画
- 支持移动端/桌面端
你可以直接复制到 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>
✅ 特性说明
- 动态水波纹
dispMap.scale动态变化模拟波纹起伏noiseImage x/y动态偏移,波纹方向自然流动
- 全屏背景图
- SVG
<image>作为背景 - 可替换
href为你自己的图片 URL
- SVG
- 移动端/桌面端兼容
- SVG + Canvas 动态生成噪声
- 不依赖外部库
- 可扩展
- 替换噪声生成算法可实现涟漪、波浪、液化等效果
- 可叠加多个
feDisplacementMap增强真实感
发表回复