内容简介:原文:这是作者最终实现的效果:......哦,不,应该是这张:
原文: Drawing Realistic Clouds with SVG and CSS
这是作者最终实现的效果:
......哦,不,应该是这张:
在线查看效果:cloud demo正文开始啦~
希腊神话讲述了一个关于宙斯创造云女神涅斐勒的故事。和其他希腊神话一样,这个故事极其怪异并且有点限制级。下面的表述则是一个比较简短且含蓄的版本( 限制级,非战斗人员请撤离 )。
涅斐勒(云神) ,据说是宙斯按照自己美丽妻子的形象创造的。传说有个凡人遇见了涅斐勒,一见钟情爱上了她并且在一起了,后来她们一起睡了一个觉,然后奇怪的事情发生了,一朵云生下了一个半人半马的小孩,传说这就半人马的祖先。
很不可思议对吗?就我个人而言,我搞不懂。但庆幸的是,浏览器中创建云的过程要简单得多,也没有那么不可描述。
这是@袁川画的云demo最近,我发现开发者 @袁川 已经用代码实现了仿真的云烟。对我来说,在浏览器中实现一直是个神话。
通过简单扫一下这个demo里面的代码,我们可以现象,逼真而又独特的云朵是可以通过使用 css
的 box-shadow
和一个包含两个元素的SVG过滤器 <filter>
去实现。
我们想要的仿真效果是通过 feTurbulence
和 feDisplacementMap
之间的微妙混合来实现的。SVG过滤器功能强大、复杂,并且提供了令人非常兴奋的功能(还包括奥斯卡获奖算法)。然而,在它的底层,它们的复杂性可能有点吓人!
译者:奥斯卡获奖算法,这么牛逼?无知限制了我的想象。
虽然SVG的物理特性超出了本文的范畴,但是在MDN和w3.org上有大量的文档。一个免费的关于 feTurbulence
和 feDisplacement
非常有用的页面(同时被作为这本惊奇的书的一个章节)
对于本文,我们专注学习如何使用SVG的过滤器实现惊人的效果。我们不需要深入研究其底层的算法,正如艺术家不需要了解分子的结构也能绘出令人惊叹的风景一样。
先从一些基础开始
CSS的 box-shadow
属性有五个值需要搞懂:
box-shadow: <offsetX> <offsetY> <blurRadius> <spreadRadius> <color>; 复制代码
让我们把这些值调高(可能比任何理智的开发人员调得都要高):
#cloud-square { background: turquoise; box-shadow: 200px 200px 50px 0px #000; width: 180px; height: 180px; } #cloud-circle { background: coral; border-radius: 50%; box-shadow: 200px 200px 50px 0px #000; width: 180px; height: 180px; } 复制代码
会得到下面的效果图:
你曾经应该也玩过或者看过影子木偶对吗?像下面这样:
译者:看见这个,想起小时候自己也玩过, 两个拇指叉在一块能摆出鸽子的投影。
就像一只手改变形状可以改变投影一样,我们改变HTML的“源形状”也可以使渲染在浏览器中的投影变形。 box-shadow
复制了原始尺寸和 border-radius
上的“渐变”特性,SVG过滤器则同时应用于元素及其阴影。
<svg width="0" height="0"> <filter id="filter"> <feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="10" /> <feDisplacementMap in="SourceGraphic" scale="10" /> </filter> </svg> 复制代码
这是我们目前的SVG代码,它不会被渲染,因为我们还没有定义任何可见的东西。它唯一的目的就是保存我们为 SourceGraphic
(也就是我们的 <div>
)提供的过滤器。
我们借助SVG过滤器的 ID
,通过添加CSS规则将HTML元素( #cloud-circle
)和SVG过滤器进行关联:
#cloud-circle { filter: url(#filter); box-shadow: 200px 200px 50px 0px #fff; } 复制代码
嗯!很棒,就是这样
在线查看demo别急!我们只是了解了皮毛,还有很多好东西要看。
尝试使用feDisplacementMap的scale属性
使用这一属性进行一些非科学试验可以产生显著的效果。现在,我们保持 feTurbulence
的值不变,简单调整 feDisplacementMap
的 scale
属性值。
随着 scale
的增加(以30为增量),我们的源 <div>
变得扭曲,投射的阴影反应出天空中云出现的随机形式。
<feDisplacementMap in="SourceGraphic" scale="180"/> 复制代码在线查看demo
好了,我们有进展了!让我们稍微改变颜色,以形成更具说服力的云。
body { background: linear-gradient(165deg, #527785 0%, #7FB4C7 100%); } #cloud-circle { width: 180px; height: 180px; background: #000; border-radius: 50%; filter: url(#filter); box-shadow: 200px 200px 50px 0px #fff; } 复制代码
现在,我们越来越接近真实的云朵效果了!
修改box-shadow的模糊度
下面一套图片展示了 box-shadow
属性的模糊度作用的效果,这里,我们以10px递增模糊值:
为了增加一点积云的效果,我们可以稍微扩宽源 <div>
的宽度:
#cloud-circle { width: 500px; height: 275px; background: #000; border-radius: 50%; filter: url(#filter); box-shadow: 200px 200px 60px 0px #fff; } 复制代码很好,我们的源元素开始碍事了
:tired_face:
等等,我们扩宽了源元素的宽度,但它现在遮挡在我们云层(白色阴影)的上方。让我们在更远的位置重新投影,这样我们的云就不会再被源图像遮挡了(你可以想象成把你的手往远离墙的方向移动,这样它就不会挡住你的影子木偶的视线了)。
这点我们通过CSS定位可以很好地实现。 <body>
是父元素,默认是静态定位的,我们给源 <div>
添加绝对定位。最初地,这也会重新定位我们的阴影,因此我们还需要增加阴影和元素之间的距离。
#cloud-circle { width: 500px; height: 275px; background: #000; border-radius: 50%; filter: url(#filter); box-shadow: 400px 400px 60px 0px #fff; /* 增加投影位移 */ position: absolute; top: -320px; left: -320px; } 复制代码
是的,我们已经实现了一个极具说服力的云:这里查看
浏览器上展示的已经是一个相当完美的云了,但我不确定......这片云真的能公正地描述云女神涅斐勒吗?我相信我们还可以做得更好!
通过层次传达深度
这是我们想要的效果:
从这张照片中云层的深度、纹理和丰富性来看,宙斯一定是读过艺术专业的。至少,他一定读过《通用设计法则》,这本书阐述了一个强大而又普通的概念:
照明偏差在深度和自然度的解释中起着重要作用,设计师可以通过多种方式操纵照明偏差,利用明暗区域之间的对比度来改变深度的外观。
这段话给了我们一个提示,我们可以将不同形状、大小和颜色的图层堆叠在一起,可以实现像参考图片中那样具有高保真度的云。我们要做的也只是多次调用SVG过滤器。
使用三个SVG过滤器绘制前中后三朵云:
<svg width="0" height="0"> <!-- 后层 --> <filter id="filter-back"> <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" /> <feDisplacementMap in="SourceGraphic" scale="170" /> </filter> <!-- 中层 --> <filter id="filter-mid"> <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" /> <feDisplacementMap in="SourceGraphic" scale="150" /> </filter> <!-- 前层 --> <filter id="filter-front"> <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" /> <feDisplacementMap in="SourceGraphic" scale="100" /> </filter> </svg> 复制代码
通过分层的应用,我们有机会去探索 feTurbulence
并认识它的多样性。我们选择了较为平滑的类型: fractalNoise
,对于 numOctaves
的值最高只调到了6。
上面这些意味着什么?我们来看一下 baseFrequency
这个属性,下面几张图片是不同 baseFrequency
值下的效果:
从效果看,介于0.005~0.01的值比较符合我们想要的积云效果。
用numOctaves添加细节
增加 numOctaves
值允许我们以更细的粒度去渲染图像,这个过程需要大量的计算,因此需要注意:高值会严重影响性能。
幸运的是我们不需要为达到精细的效果而设置太高的值,介于4~5就够了。
最后的效果
用seed属性进行无限变形
关于 seed
属性有很多可以说,但就我们的目的而言, seed
的作用可以归结为: 不同的值,不同的形状 。
柏林噪音函数 使用这个值作为其随机数生成器的起点。选择不包含此属性则将 seed
值默认为0;当包含时,无论我们设置何值,都不需要担心会影响性能。
seed
值,对应生成不同的形状。
上面的GIF代表了 seed
作用的效果。请记住,每个云都是分层的复合云(虽然我调整了每一层的属性,但我保持了它们的 seed
值一致)。
仔细观察上面这张参考图片,我将3个云层 <div>
堆砌在一个基础的 div
上,通过反复试验不同的 seed
值,最终得到了与图中比较相似的形状。如下图:
天空的极限
显然,认为我们用 <div>
在浏览器上绘制的云比涅斐勒高级是很荒谬的。
但是,我们能够梳理出CSS和SVG过滤器的神秘感越多,我们就越有能力去创造在视觉上令人惊叹的东西,并且高度保真于雷神的创作。那么,我们可以做进一步的试验了!
在这篇文章中,我们刚刚涉足了一个充满力量和复杂性的知识海洋,SVG过滤器通常看起来复杂地难以理解。
不过,就像A Single Div Project和Smith's绘画技术中的例子一样,有趣和实验性的方法总会给人惊艳的效果。
我希望这篇文章能让你对web上进行摄影写实开发感到兴奋,欢迎下方评论交流你的想法~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。