利用SVG滤镜实现水波倒影效果

        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种专属属性的设置:

feTurbulence参数
属性默认值说明
baseFrequency0柏林噪波函数的基频参数
numOctaves1柏林噪波函数的八度音阶数。
seed0柏林澡波函数生成的伪随机数的开始数字。
stitchTilesnoStitch柏林噪波瓷砖在边界处的行为。
typeturbulence以噪声函数还是湍流函数执行过滤

以上参数看起来很抽象,我们通过示例来体验每个参数的作用:

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到空间的像素值。
 

属性默认值取值说明
inSourceGraphicSourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | 自定义的滤镜的原始引用in 属性标识输入的源
in2 

第一个过滤器原语的源图形,否则为上一个过滤器原形的结果

SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | 自定义的滤镜的原始引用in2属性标识给定过滤器原语的第二输入。它的工作原理与in属性完全相同。
scale0缩放比例 通常使用正数值处理,值越大,偏移越大
xChannelSelectorAR | G | B | A使用in2中的哪个颜色通道沿x轴置换像素。
yChannelSelectorAR | 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.5YC(x,y) - 0.5范围也是-0.5~0.5
  •  scale表示计算后的偏移值相乘的比例,scale越大,则偏移越大。

 简单讲就是根据设定的通道颜色对原图的x, y坐标进行偏移。

最后,欢迎小伙伴关注:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值