SVG滤镜用来增加对SVG图形的特殊效果。多种滤镜巧妙结合起来可以实现很棒的视觉效果。下面利用svg的feTurbulence滤镜和feDisplacementMap来模拟真实的水波倒影特效。效果如下图
代码并不复杂,首先设置两张图片:
<div class="container">
<div class='wrap'>
<img src="./p.jpg"><br/>
</div>
<div class='wrap'>
<img src="./p.jpg" class="reflect">
</div>
</div>
设置样式,将倒影图旋转,调整到合适的位置:
<style type="text/css">
.reflect{
transform:scaleY(-1);
margin-top:-5px;
filter:url(#displacementFilter);
}
.container {
width: -moz-fit-content;
width: fit-content;
clip-path: inset(10px);
background-color: #0E6CAA;
}
</style>
重点是滤镜的样式:filter:url(#displacementFilter);
在文档中定义svg滤镜:
<svg width="0" height="0" style="posiotion:absolute;">
<filter id="displacementFilter">
<feTurbulence type="turbulence" baseFrequency="0.01 .1" numOctaves="1" result="turbulence" seed="53" />
<feDisplacementMap in2="turbulence" in="SourceGraphic" scale="20" xChannelSelector="R" yChannelSelector="B" />
</filter>
</svg>
此时,得到的效果是静态的 ,但已经得到了倒影的效果。
下面通过设置动画让倒影波动起来,添加动画:
<script type="text/javascript">
var img = document.querySelector("#displacementFilter feTurbulence");
var frames = 0;
var rad = Math.PI / 180;
function AnimateBaseFrequency() {
var bf = "0.01 .1";
bfx = Number(bf.split(" ")[0]);
bfy = Number(bf.split(" ")[1]);
frames += .5
bfx += 0.001 * Math.cos(frames * rad);
bfy += 0.005 * Math.sin(frames * rad);
bf = bfx.toString() + ' ' + bfy.toString();
img.setAttributeNS(null, 'baseFrequency', bf);
requestAnimationFrame(AnimateBaseFrequency);
}
window.requestAnimationFrame(AnimateBaseFrequency);
</script>
至此,整体效果达成。
简短的代码实现了真实的水波效果,这主要归功于svg的强大滤镜功能。SVG滤镜用来增加对SVG图形的特殊效果。这里重点说说我们用到的两个滤镜feTurbulence和feDisplacementMap。
feTurbulence滤镜
该滤镜利用 Perlin 噪声函数创建了一个图像。它实现了人造纹理比如说云纹、大理石纹的合成。除了svg滤镜的通用属性外,该滤镜支持5种专属属性的设置:
属性 | 默认值 | 说明 |
---|---|---|
baseFrequency | 0 | 柏林噪波函数的基频参数 |
numOctaves | 1 | 柏林噪波函数的八度音阶数。 |
seed | 0 | 柏林澡波函数生成的伪随机数的开始数字。 |
stitchTiles | noStitch | 柏林噪波瓷砖在边界处的行为。 |
type | turbulence | 以噪声函数还是湍流函数执行过滤 |
以上参数看起来很抽象,我们通过示例来体验每个参数的作用:
baseFrequency
<svg viewBox="0 0 420 200" xmlns="http://www.w3.org/2000/svg">
<filter id="noise1" x="0" y="0" width="100%" height="100%">
<feTurbulence baseFrequency="0.025" />
</filter>
<filter id="noise2" x="0" y="0" width="100%" height="100%">
<feTurbulence baseFrequency="0.05" />
</filter>
<rect x="0" y="0" width="200" height="200" style="filter: url(#noise1);" />
<rect x="0" y="0" width="200" height="200" style="filter: url(#noise2); transform: translateX(220px);" />
</svg>
效果:
如果提供两个数字,第一个数字表示水平方向上的基频,第二个数字表示垂直方向上的基频。如果提供了一个数字,则该值同时用于x和y。不支持使用负值。
numOctaves
当我们设置了这个属性之后,算法会在原来的噪声函数上叠加若干个频率不同的他自己,形成细节更加丰富的噪声,看一下numOctaves增加时的动态效果。倍频程是由其频率和振幅定义的噪声函数。湍流是通过增加频率和降低振幅来累积几个八度音阶而形成的。八度音阶越高,噪音看起来就越自然。
<svg viewBox="0 0 420 200" xmlns="http://www.w3.org/2000/svg">
<filter id="noise1" x="0" y="0" width="100%" height="100%">
<feTurbulence baseFrequency="0.025" numOctaves="1" />
</filter>
<filter id="noise2" x="0" y="0" width="100%" height="100%">
<feTurbulence baseFrequency="0.025" numOctaves="3" />
</filter>
<rect x="0" y="0" width="200" height="200" style="filter: url(#noise1);" />
<rect x="0" y="0" width="200" height="200" style="filter: url(#noise2); transform: translateX(220px);" />
</svg>
效果:
seed
seed是种子的意思,这是每一个随机数算法都需要用到的一个输入,所有的伪随机数算法中,当输入的种子一样的时候,输出总是一致的。
stitchTiles
该属性定义了对平铺边界处实现平滑过渡,可选值为noStitch | stitch。
<svg viewBox="0 0 420 200" xmlns="http://www.w3.org/2000/svg">
<filter id="noise1" x="0" y="0" width="100%" height="100%">
<feTurbulence baseFrequency="0.025" stitchTiles="noStitch" />
</filter>
<filter id="noise2" x="0" y="0" width="100%" height="100%">
<feTurbulence baseFrequency="0.025" stitchTiles="stitch" />
</filter>
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise1);" />
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise1); transform: translate(100px, 0);" />
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise1); transform: translate(0, 100px);" />
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise1); transform: translate(100px, 100px);" />
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise2); transform: translate(220px, 0);" />
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise2); transform: translate(320px, 0);" />
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise2); transform: translate(220px, 100px);" />
<rect x="0" y="0" width="100" height="100" style="filter: url(#noise2); transform: translate(320px, 100px);" />
</svg>
效果:
type
可选值 fractalNoise
| turbulence
turbulence是指将柏林函数进行合成时,只取函数的绝对值,合成后的函数在0处不可导,其图像会有一些尖锐效果,形似湍流。fractalNoise则是在原来的噪声中叠加白噪声,让最终的结果呈现出高斯模糊的效果。
feDisplacementMap滤镜
映射置换滤镜,该滤镜用来自图像中从in2 (en-US)
到空间的像素值置换图像从in
到空间的像素值。
属性 | 默认值 | 取值 | 说明 | |
---|---|---|---|---|
in | SourceGraphic | SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | 自定义的滤镜的原始引用 | in 属性标识输入的源 | |
in2 | 第一个过滤器原语的源图形,否则为上一个过滤器原形的结果 | SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | 自定义的滤镜的原始引用 | in2属性标识给定过滤器原语的第二输入。它的工作原理与in属性完全相同。 | |
scale | 0 | 缩放比例 通常使用正数值处理,值越大,偏移越大 | ||
xChannelSelector | A | R | G | B | A | 使用in2中的哪个颜色通道沿x轴置换像素。 | |
yChannelSelector | A | R | G | B | A | 属性指示使用in2中的哪个颜色通道沿y轴置换像素。 |
feDisplacementMap
是一个位置替换滤镜,就是改变元素和图形的像素位置的。遍历原图形的所有像素点,使用feDisplacementMap
重新映射替换一个新的位置,形成一个新的图形。feDisplacementMap
滤镜在业界的主流应用是对图形进行形变,扭曲。
P'(x,y) ← P( x + scale * (XC(x,y) - 0.5), y + scale * (YC(x,y) - 0.5))
-
P'(x,y)
指的是转换之后的x, y
坐标。 -
x + scale * (XC(x,y) - 0.5), y + scale * (YC(x,y) - 0.5)
指的是具体的转换规则。 -
XC(x,y)
表示当前x,y坐标像素点其X轴方向上设置的对应通道的计算值,范围是0~1。 -
YC(x,y)
表示当前x,y坐标像素点其Y轴方向上设置的对应通道的计算值,范围是0~1。 - -0.5是偏移值,因此
XC(x,y) - 0.5
范围是-0.5~0.5
,YC(x,y) - 0.5
范围也是-0.5~0.5
。 -
scale
表示计算后的偏移值相乘的比例,scale
越大,则偏移越大。
简单讲就是根据设定的通道颜色对原图的x, y
坐标进行偏移。
最后,欢迎小伙伴关注: