阅读 333

云破月来花弄影-SVG多种技术组合实现

天仙子·水调数声持酒听

【宋】张先

水调数声持酒听,午醉醒来愁未醒。送春春去几时回?临晚镜,伤流景,往事后期空记省。
沙上并禽池上暝,云破月来花弄影。重重帘幕密遮灯,风不定,人初静,明日落红应满径。

昨天七夕,下班在地铁里面看到了各种恩爱撒狗粮的,不禁想起当年情窦初开的时候,非常喜欢宋词。而张先,因为“影”字用的好,被称为“张三影”,这首词就是三影之一(不是火影)。回到家,小孩和老婆都睡了(996害死人啊),但心中的火却旺的很,右手也不安份。我想到今天多少对情侣在那啥,我却只能一个人,心中躁动不已,艺术之魂熊熊燃烧,我控制住右手,强行挪开了点击某hub网站的冲动,点开了另一个某hub网站,开始了我的艺术创作。

1、月来

用svg做个月亮还是很简单的,只要画一个发光的大圆饼就好了,上代码。

<circle id="whitemoon" cx="420" cy="160" r="60" fill="white" />复制代码

上帝说,要有光,那就来个光

<filter id="blur-moon">
                <feGaussianBlur in="SourceGraphic" stdDeviation="3" />
</filter>复制代码

用feGaussianBlur模糊后的作为月亮的光,和大圆饼合起来,就是一个发光的月亮了

<use xlink:href="#whitemoon" />
<use xlink:href="#whitemoon" filter="url(#blur-moon)" />复制代码

这个月亮圆也很圆,亮也很亮,但是作为一个现代人,我知道月亮上是有环形山的,这么洁白无暇的月亮太假了,所以还要加点黑影。

<circle id="greymoon" cx="420" cy="170" r="45" fill="grey" fill-opacity="0.15"
                filter="url(#filter-greymoon)" />
<filter id="filter-greymoon" >
                <feTurbulence type="fractalNoise" baseFrequency="0.03" numOctaves="9" seed="3" />
                <feDisplacementMap in="SourceGraphic" scale="120" />
            </filter>复制代码

看过前面做云文章的朋友都知道,feTurbulence和feDisplacementMap的组合用来做纹理和腐蚀效果是很好的,这里也用来做月亮的黑影,这里需要说明一个知识点,这个问题之前其实困扰了我很久。

我们使用filter特效的时候,如果效果超出了图形本身的矩形框范围,那么效果会在矩形框范围直接切断,比如上面这个greymoon,显示出来是这样的

明显可以看出左边切掉了一块,非常影响效果,去掉边界的限制在哪呢?就在filter的属性,这个例子里面,我改成这样就好了

<filter id="filter-greymoon" height="250%" width="250%" x="-100%" y="-100%">复制代码

把filter的width,hegith加宽加高,单这样还不行,因为width,height只能影响图形的右边和下边,结果效果只是这样

可以看到,左边和上边仍然被无情的截取了,所以必须把x,y参数加上去,因为是向左和向上,在坐标原点前,所以是负数,最终的效果如下

最后把阴影加到大月亮上去,就能看到最终效果了

<circle id="whitemoon" cx="420" cy="160" r="60" fill="white" />
            <circle id="greymoon" cx="420" cy="170" r="30" fill="grey" fill-opacity="0.25"
                filter="url(#filter-greymoon)" />
<filter id="filter-greymoon" width="350%" height="250%" x="-100%" y="-100%">
                <feTurbulence type="fractalNoise" baseFrequency="0.03" numOctaves="9" seed="3" />
                <feDisplacementMap in="SourceGraphic" scale="120" />
            </filter>
<g id="moon">
                <use xlink:href="#whitemoon" />
                <use xlink:href="#whitemoon" filter="url(#blur-moon)" />
                <use xlink:href="#greymoon" filter="url(#blur-greymoon)" />
</g>
<use xlink:href="#moon" />复制代码

一个比较真实的月亮就做好了(不要和我提阴影和真实的月面情况不一样,我又不是华为手机的AI拍摄,能自动把真实月面给P出来)。

2、云破

月亮做出来了,我们开始做云。之前在做云的文章里面其实已经很详细的讲了做云的方法,所以我这边就不详细讲了。不过这次我们搞点新花样,不用css的box-shadow来做,直接使用svg来做,代码会更简洁。

<defs>
<ellipse id="cloudback" cx="260" cy="230" rx="280" ry="70" fill="white" fill-opacity="0.9"
                filter="url(#blur-cloud)" />
            <ellipse id="cloudmid" cx="260" cy="240" rx="220" ry="55" fill="#9EA8B3" fill-opacity="0.5"
                filter="url(#blur-cloud)" />
            <ellipse id="cloudfront" cx="260" cy="260" rx="170" ry="30" fill="black" fill-opacity="0.2"
                filter="url(#blur-cloud)" />
<filter id="blur-cloud" width="350%" height="250%" x="-100%" y="-100%">
                <feGaussianBlur in="SourceGraphic" stdDeviation="15" />
            </filter>
<filter id="filter-back" width="350%" height="250%" x="-100%" y="-100%">
                <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="0" />
                <feDisplacementMap in="SourceGraphic" scale="170" />
            </filter>
            <filter id="filter-mid" width="350%" height="250%" x="-100%" y="-100%">
                <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="0" />
                <feDisplacementMap in="SourceGraphic" scale="150" />
            </filter>
            <filter id="filter-front" width="350%" height="250%" x="-100%" y="-100%">
                <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="0" />
                <feDisplacementMap in="SourceGraphic" scale="100" />
            </filter>
<g id="cloud">
                <use xlink:href="#cloudback" filter="url(#filter-back)" />
                <use xlink:href="#cloudmid" filter="url(#filter-mid)" />
                <use xlink:href="#cloudfront" filter="url(#filter-front)" />
            </g>
</defs>
<use xlink:href="#cloud" />复制代码

最后的效果如下

3、花弄影

在这里我们先需要一堵墙,否则影子在哪显示呢,所以我就上花瓣网找了一堵墙过来。图片地址在这里

针对原图我做了一点处理,主要是把墙面搞暗了一些,把图片的天空部分变成了透明,方便显示月亮和云,使用的同样是svg的图片显示

<image xlink:href="yuanqiang1.png" x="0" y="300" width="400"/>复制代码

然后是花影,要有花影,首先得有花,同样的,我又从花瓣网弄来了一束花。图片地址忘了存,找不到了┐(゚~゚)┌

<image xlink:href="huazhi1.png" x="200"y="690" width="170"></image>复制代码

现在关键来了,花弄影主要是影,我们开始光影的魔法。

<filter id="huazhishadow" x="0" y="0" width="200%" height="200%">
                <feOffset result="offOut" in="SourceAlpha" dx="210" dy="0" />
                <feGaussianBlur result="blurOut" in="offOut" stdDeviation="1" />
                <feBlend in="SourceGraphic" in2="blurOut" mode="darken" />
            </filter>复制代码

先介绍下这几个filter:

feoffset:该输入图像作为一个整体,在属性dx和属性dy的值指定了它的偏移量。说白了就是把原图在离开dx和dy的距离外复制一个一样的图像,活脱脱的拷贝魔法,这就是filter界的旗木卡卡西啊。

feGaussianBlur:老朋友,干模糊化的,略

feBlend:把两个对象组合在一起,使它们受特定的混合模式控制。这类似于图像编辑软件中混合两个图层。它是个粘合剂,把上面两个filter的效果合在一起,并且用mode来控制最后的效果。mode的效果有很多种,我们这边需要的是影子,所以选择了darken,具体的mode说明,请看这里

<image xlink:href="huazhi1.png" x="0" y="600" width="170" filter="url(#huazhishadow)" />复制代码

最后看到的是这样

对话录:

画外音:是不是这样就算做好了

我:当然没有,你没发现我选的这个墙不是平面的吗

画外音:那又怎样

我:这样影子打上去应该是斜的,不是这样平平的影子

画外音:为啥你不选个正平墙的图呢

我:花瓣上没找到啊...

画外音:你为啥要执着于这个影子效果呢,用现在这个就行了

我:不行,我是个严谨的艺术家,我的影子要真实,真实,再真实

画外音:那刚才月亮的阴影你咋不追求真实的月面阴影呢

我:.....,警察叔叔,就是这个声音给我打的诈骗电话,马上抓他去坐牢。

我:让你和我抬杠

画外音:算你狠...

-------------------------------------------------------我是分割线----------------------------------------------

我们需要把花的图片和花的影子分开处理,现在我们把生成影子的花弄出屏幕外

<image xlink:href="huazhi1.png" x="-630" y="720" width="170" filter="url(#huazhishadow)">复制代码

通过x的设置,把花的图像移到 屏幕外,只留下影子

<image xlink:href="huazhi1.png" x="-630" y="720" width="170" filter="url(#huazhishadow)" transform="skewX(29)"/>复制代码

这里要讲下transform:

transform和上面这些filter不同,是SVG元素的属性。作用是设置svg元素的变形,包括位移translate, 旋转rotate, 缩放scale, 斜切skew。今天我们用到的就是斜切(skew)。具体的大家可以去看这篇文章,讲的很详细。最后的花影的效果如下:

4、成品

当我们把月亮,云、院墙和花影组合起来,就可以看到最终的效果了

<image xlink:href="yuanqiang1.png" x="0" y="300" width="400"/>
        <use xlink:href="#moon" />
        <use xlink:href="#cloud" />
        <image xlink:href="huazhi1.png" x="200"y="690" width="170"></image>
        <image xlink:href="huazhi1.png" x="-630" y="720" width="170" filter="url(#huazhishadow)" transform="skewX(29)"/>复制代码

源码地址

在线围观


关注下面的标签,发现更多相似文章
评论