svg滤镜详解之feDisplacementMap滤镜

  我们前面讲述的svg的各种滤镜,有图像模糊,添加阴影,修改图像颜色,增加光照,图像合成叠加滤镜。前面的滤镜均不会改变像素自身的位置。feDisplacementMap滤镜是修改像素的位置。常见的应用是为元素添加水波为效果。这篇文章通过一步一步带大家通过实现水波纹效果,来认识这个滤镜。先上效果:

动画.gif

下面来讲一下具体的实现。feDisplacementMap滤镜是使用一个输入源的颜色值,对另外一个输入源的元素位置进行像素平移。feDisplacementMap滤镜的语法:
scale:平移比例比例越大,平移距离就越大。
in:需要改变元素位置的输入源。
in2:使用该输入的颜色值改变in输入的位置。
xChannelSelector:x轴的使用的偏移颜色可取值R,G,B,A。
yChannelSelector:y轴的使用的偏移颜色可取值R,G,B,A。
俗话说纸上得来空觉浅,绝知此事要躬行,下面我们通过实例来一起研究一下这个属性。
下面我们使用:

water.png

这个图片对我们的风景图片:

fj.png测试该滤镜,代码如下:

<svg width="500" height="300">
    <defs>
       <filter id="filter-ripple">
            <feImage result="pict2" xlink:href="../img/water.png" ></feImage>
            <feDisplacementMap
              scale="20"
              color-interpolation-filters="sRGB" 
              xChannelSelector="R" 
              yChannelSelector="R"  
              in="SourceGraphic" 
              in2="pict2">
            </feDisplacementMap>
      </filter>    
    </defs>
    <image xlink:href="../img/fj.png" x="0" y="0" width="500" height="300" style="filter:url(#filter-ripple)"></image>
</svg>

效果如图:

截图_选择区域_20221206172720.png

如果我们将scale修改为10效果如下:

截图_选择区域_20221206173911.png

可能有好奇的同学确实对具体的偏移逻辑感兴趣,通过查看mdn知道偏移公式如下:

P'(x,y) ← P( x + scale * (XC(x,y) - 0.5), y + scale * (YC(x,y) - 0.5))

在实际使用过程中不用知道太详细,我们到能根据颜色值对图像偏移,并且能控制偏移比例就行了。

到这里我们发现,我们要做的是水波纹的扩散效果。这个滤镜对整个图片做了处理,我们怎么能处理图片的一部分呢?当然我们首先想到的是改变in2输入源的大小,代码如下:

<svg width="500" height="300">
    <defs>
       <filter id="filter-ripple">
            <feImage result="pict2" xlink:href="../img/water.png" x="0" y="0" width="200" height="120"></feImage>
            <feDisplacementMap
              scale="10"
              color-interpolation-filters="sRGB" 
              xChannelSelector="R" 
              yChannelSelector="R"  
              in="SourceGraphic" 
              in2="pict2">
            </feDisplacementMap>
      </filter>    
    </defs>
    <image xlink:href="../img/fj.png" x="0" y="0" width="500" height="300" style="filter:url(#filter-ripple)"></image>
</svg>

这样能不能满足我们的需求呢?看下效果:

截图_选择区域_20221206175227.png

我们看到这并不是我们想要的效果,只把滤镜处理的一部分显示出来了。图片剩余的部分并未显示。那接下来怎么做呢?这时候有的同学就想起了我们上一篇文章讲的两个滤镜:feblend和feComposite,具体该使用哪一个呢?可以看到们的这个效果明显有一个阴影,并且随着位置改变阴影会变化:例如:

<svg width="500" height="300">
    <defs>
       <filter id="filter-ripple">
            <feImage result="pict2" xlink:href="../img/water.png" x="50" y="50" width="200" height="120"></feImage>
            <feDisplacementMap
              result="partImg"
              scale="20"
              color-interpolation-filters="sRGB" 
              xChannelSelector="R" 
              yChannelSelector="R"  
              in="SourceGraphic" 
              in2="pict2">
            </feDisplacementMap>
      </filter>    
    </defs>
    <image xlink:href="../img/fj.png" x="0" y="0" width="500" height="300" style="filter:url(#filter-ripple)"></image>
</svg>

就变成了下面的样子:

截图_选择区域_20221206182138.png

至于为什么会出现这样的阴影背景,我也不知道,可能是svg本身就是这么设计的。所以现在我们需要一个滤镜将这个效果裁剪一下,正好用到了我们上一节讲的滤镜:feComposite,我们可以使用波纹图片最输入源将这个结果裁剪,去掉后面的背景:代码如下:

<svg width="500" height="300">
    <defs>
       <filter id="filter-ripple">
            <feImage result="pict2" xlink:href="../img/water.png" x="50" y="50" width="200" height="120"></feImage>
            <feDisplacementMap
              result="partImg"
              scale="20"
              color-interpolation-filters="sRGB" 
              xChannelSelector="R" 
              yChannelSelector="R"  
              in="SourceGraphic" 
              in2="pict2">
            </feDisplacementMap>
            <feComposite in="partImg" in2="pict2" operator="in"/>
      </filter>    
    </defs>
    <image xlink:href="../img/fj.png" x="0" y="0" width="500" height="300" style="filter:url(#filter-ripple)"></image>
</svg>

效果如图:

1670322408170.png

这就达到我们想要的效果了,然后我们可以将这个滤镜效果叠加到原图片上,就可以做出部分水波纹效果,代码如下:

<svg width="500" height="300">
    <defs>
       <filter id="filter-ripple">
            <feImage result="pict2" xlink:href="../img/water.png" x="50" y="50" width="200" height="120"></feImage>
            <feDisplacementMap
              result="partImg"
              scale="40"
              color-interpolation-filters="sRGB" 
              xChannelSelector="R" 
              yChannelSelector="R"  
              in="SourceGraphic" 
              in2="pict2">
            </feDisplacementMap>
            <feComposite result="resutPart" in="partImg" in2="pict2" operator="in"/>
            <feComposite in="resutPart" in2="SourceGraphic" operator="over"/>
      </filter>    
    </defs>
    <image xlink:href="../img/fj.png" x="0" y="0" width="500" height="300" style="filter:url(#filter-ripple)"></image>
</svg>

1670322758317.png

  但是仔细看会发现贴图的位置不对,向上发生了偏移。经过测试发现:图片偏移的位置和feDisplacementMap滤镜的sacle成正比,也就是scale值越大偏移距离越大。有兴趣的同学可以调试一下。所以我们做水波纹效果的时候,可以将动画效果由大变小,最后变为0。并且在动画过程中人眼很难捕捉到这些细小的差异,就能实现一个冒牌的水波纹动画效果。当然这个水波纹效果是有矩形边界的的,换一个波纹图片就好了。大家可以根据需要自行制作。
  有了上面的效果我们下面就可以制作动画了。具体的代码这里就不写了。大家可以查看源码:水波纹动画效果。当然这个神奇的滤镜还有很多用途等待大家开发,我这里抛砖引玉,谢谢大家观看。下一节我们介绍svg的最后一滤镜。feTurbulence。看看他能造出来那些神奇的效果。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容