feDisplacementMap 是 SVG 滤镜中最强大的滤镜之一。也是最具破坏性的滤镜之一。
他和 PS 中的置换滤镜的原理是一样的,都是通过一个图像的颜色值来改变另一个图像的像素位置。
他可以利用一张图(通常是纹路或者噪声)的颜色信息,来推挤另外一张图的像素,从而产生扭曲、液化、变形、故障、手绘等风格。
他的参数如下:
in: 要被变形的原始图像。in2: 置换图(Displacement Map),通常是噪点或特定的梯度图。scale: 变形的强度。值越大,拉伸/扭曲越严重。xChannelSelector / yChannelSelector: 指定用置换图的哪个颜色通道(R, G, B, A)来控制 X 轴或 Y 轴的偏移。通常设置:R 控制 X,G 控制 Y滤镜会遍历 in 的每一个像素,查看 in2 对应位置的颜色值
feTurbulence 可以在不基于任何图像的情况下,生成噪点纹理。从云彩、大理石、水波,到如今设计圈大火的“噪点渐变”和“磨砂质感”,核心全是它。本文中的案例,也会大量借助他来实现。
他的关键参数如下
baseFrequency: 控制噪点的频率。值越大,噪点越密集。
numOctaves: 控制噪点的层数,即细节丰富度
type: 类型,有两种:
turbulence: 湍流噪点,产生随机、不规则的噪点,适合火焰、爆炸等效果fractalNoise: 分形噪点,产生更自然的条纹,适合云雾、柔和过渡的场景最常见的用法是结合 feTurbulence 生成的噪点来实现水波纹效果。
我们让噪点在 baseFrequency 上进行动画,从而带动置换效果的流动。
10<filter id="demo1-ripple">20{/* 1. 生成大尺度的湍流噪点,模拟水波 */}30<feTurbulence40type="turbulence"50baseFrequency="0.01 0.015" // X方向高频 (0.01) => 密集的噪点,Y方向低频 (0.015) => 拉伸的长条60numOctaves="2"70result="noise"80>90{/* 让噪点动起来 */}10<animate attributeName="baseFrequency" values="0.01 0.015;0.01 0.025;0.01 0.015" dur="10s" repeatCount="indefinite" />11</feTurbulence>1213{/* 2. 使用噪点置换原图 */}14<feDisplacementMap15in="SourceGraphic"16in2="noise"17scale="20"18xChannelSelector="R" // 使用红色通道控制X偏移19yChannelSelector="G" // 使用绿色通道控制Y偏移20/>21</filter>
通过控制噪点的频率(X 轴高频,Y 轴低频),我们可以制造出水平方向的撕裂效果,非常适合赛博朋克风格的故障文字。
10<filter id="demo2-glitch">20<feTurbulence30type="fractalNoise" // 使用分形噪点,产生更自然的条纹40baseFrequency="0.5 0.005" // X方向高频 (0.5) => 密集的噪点,Y方向低频 (0.005) => 拉伸的长条50numOctaves="2" // 噪点层数,层数越多,条纹越明显60result="noise"70/>8090<feDisplacementMap10in="SourceGraphic"11in2="noise"12scale="20"13xChannelSelector="R"14yChannelSelector="G"15/>16</filter>
利用高频噪点进行细微的像素置换,可以模拟磨砂玻璃的粗糙表面。这实际上是一种高级的模糊,比 feGaussianBlur 更有质感。
10<filter id="demo3-frost">20<feTurbulence30type="fractalNoise" // 使用分形噪点,产生更自然的条纹40baseFrequency={baseFrequency} // 高频噪点,产生细小的颗粒感50numOctaves="3" // 噪点层数,层数越多,颗粒感越强60stitchTiles="stitch"70result="noise"80/>90<feDisplacementMap10in="SourceGraphic"11in2="noise"12scale="10"13xChannelSelector="R"14yChannelSelector="G"15/>16</filter>
给规则的几何图形或文字添加低频噪点的置换,可以让线条变得不规则,模仿手绘的颤抖线条效果。
10<filter id="demo4-sketch">20<feTurbulence30type="fractalNoise" // 使用分形噪点,产生更自然的条纹40baseFrequency="0.04" // 低频噪点,产生规则的条纹50numOctaves="3" // 噪点层数,层数越多,条纹越明显60result="noise"70/>80<feDisplacementMap90in="SourceGraphic"10in2="noise"11scale="5"12xChannelSelector="R"13yChannelSelector="G"14/>15</filter>
结合 React 的状态管理,我们可以动态改变 scale 属性。
鼠标悬停时瞬间增大 scale,可以制作出“受到干扰”或“全息投影不稳定”的酷炫交互效果。
10'use client'20import { useState } from 'react'3040export default function App() {50const [scale, setScale] = useState(0)6070return (80<div90className="w-full h-full flex flex-col items-center justify-center bg-gray-900 rounded-xl p-8 relative overflow-hidden"10onMouseEnter={() => setScale(30)}11onMouseLeave={() => setScale(0)}12>13<svg className='w-full max-w-[400px] cursor-pointer' viewBox="0 0 400 250">14<defs>15<filter id="demo5-interact">16<feTurbulence17type="fractalNoise" // 使用分形噪点,产生更自然的条纹18baseFrequency="0.1 0.01" // X方向高频 (0.1) => 密集的噪点,Y方向低频 (0.01) => 拉伸的长条19numOctaves="2" // 噪点层数,层数越多,条纹越明显20result="noise"21>22<animate attributeName="baseFrequency" values="0.1 0.01; 0.1 0.04; 0.1 0.01" dur="0.2s" repeatCount="indefinite" />23</feTurbulence>2425<feDisplacementMap26in="SourceGraphic"27in2="noise"28scale={scale} // 变形的强度。值越大,拉伸/扭曲越严重。29xChannelSelector="R" // 使用红色通道控制X偏移30yChannelSelector="G" // 使用绿色通道控制Y偏移31className="transition-all duration-300"32/>33</filter>34</defs>3536<g filter="url(#demo5-interact)">37<rect x="20" y="20" width="360" height="210" rx="15" fill="#6366f1" />38<text x="50" y="80" fontFamily="sans-serif" fontSize="24" fill="white" fontWeight="bold">HOVER CARD</text>39</g>40</svg>41</div>42)43}
通过控制噪点的频率(X 轴高频,Y 轴低频),我们可以制造出水平方向的撕裂效果,非常适合赛博朋克风格的故障文字。
1<filter id="melt-filter">2{/* 定义两个维度的噪声,Y轴频率稍低,模拟重力下垂感 */}3<feTurbulence type="turbulence" baseFrequency="0.02 0.08" numOctaves="3" seed="5" result="noise">4{/* SVG 动画让流体动起来 */}5<animate attributeName="baseFrequency" dur="10s" values="0.02 0.08;0.02 0.1;0.02 0.08" repeatCount="indefinite"/>6</feTurbulence>7{/* 使用噪点置换原图 */}8<feDisplacementMap in="SourceGraphic" in2="noise" scale="30" xChannelSelector="R" yChannelSelector="G" />9</filter>
feDisplacementMap 的核心在于 in2 (置换图) 的设计:
1<filter id="ripple-filter">2{/* 低频噪声,模拟缓和的水波 */}3<feTurbulence type="turbulence" baseFrequency="0.02 0.02" numOctaves="2" seed="2" result="ripple">4<animate attributeName="baseFrequency" dur="5s" values="0.01 0.01;0.02 0.04;0.01 0.01" repeatCount="indefinite" />5</feTurbulence>6{/* 稍微增加一点 scale */}7<feDisplacementMap in="SourceGraphic" in2="ripple" scale="20" xChannelSelector="R" yChannelSelector="G" />8</filter>