了解如何使用功能强大的feTurbulence SVG滤镜基元来创建自己的纹理和变形效果。

拟议的系列文章“ SVG过滤效果 ”,作者:Sara Soueidan,是自由UI / UX界面开发人员,并且是黎巴嫩的许多技术文章的作者,重点关注SVG过滤器的工作,并包括以下文章:
SVG过滤效果
- SVG过滤效果。 第1部分。SVG过滤器101
- SVG过滤效果。 第2部分。 用词形学概述文本
- SVG过滤效果。 第3部分。使用feComponentTransfer的图像后代化效果
- SVG过滤效果。 第4部分 。 带feComponentTransfer的两色图像 。
- SVG过滤效果。 第5部分。使用feDisplacementMap将文本与表面纹理匹配
- SVG过滤效果。 第6部分。使用feTurbulence创建纹理
feTurbulence是最强大的SVG过滤器原语之一。 规范对此原语的定义如下:
该滤镜基元使用Perlin湍流函数创建图像。 它可以合成人造纹理,如云层或大理石。 [...]
生成的图像将填充此滤镜基元的滤镜基元的整个子区域。
换句话说, feTurbulence滤波器原语生成并显示Perlin噪声。 这种噪声对于模拟几种自然现象(例如云,火和烟)以及生成复杂的纹理(例如大理石或花岗岩)很有用。 与feFlood一样, feTurbulence原语用新内容填充过滤区域。
在本文中,我们将研究如何使用feTurbulence产生噪声,以及如何使用该噪声使图像和文本变形,就像我们在上一篇文章中对feDisplacementMap纹理所做的那样。 然后,我们研究如何将生成的噪声与SVG照明效果结合使用,以为粗糙的纸张创建简单的纹理。
但首先,让我们回顾一下feTurbulence及其属性,看看它们各自如何影响所产生的噪声。
用feTurbulence产生湍流和分形噪声
当我打算编写本系列文章时,我决定尽可能避免使用有关过滤器基元的原始技术细节。 这就是为什么我们不讨论用于生成Perlin噪声的功能的技术细节的原因。
在阅读了构成噪声基础的功能之后,我发现当为实验设置原语时,它根本没有帮助。 最后,我们将使用随机噪声发生器。 因此,在大多数情况下,您会发现创建纹理将成为实验和调整的主题,直到获得所需的结果。 随着时间的流逝,预测纹理的外观将变得稍微容易一些。
我发现玩feTurbulence原语并可视化其属性是了解它们的最佳方法,并帮助我理解了这些属性的作用。 因此,我们使用视觉方法通过一些交互式演示来了解feTurbulence 。
现在, FeTurbulence使用Perlin的湍流函数生成噪声。 它具有5个控制该功能的主要属性,因此也可以控制其视觉效果:
- 类型 ;
- baseFrequency ;
- numOctaves ;
- 种子 ;
- itchTiles 。
我们将检查这些属性中的每一个如何影响视觉效果,而无需深入研究该功能的技术细节。 您会发现在大多数情况下,您只需要担心以下三个属性: type , baseFrequency和numOctaves 。
基本频率
为了产生噪声,仅需要baseFrequency属性。 baseFrequency影响生成的噪声的大小(或比例)和颗粒度。
当对基础频率进行可视化和动画处理时,可以最好地理解其效果。 这就是为什么我创建了下一个演示的原因。 使用滑块,您可以更改所用基本频率的值,并实时查看它如何影响所产生的噪声。 您会注意到,当增加或减小baseFrequency属性的值时,生成的模式将保持稳定,分别变小或变大 ,并且看起来像已缩放并退出左上角的源 。
降低baseFrequency值(例如0.001)会生成较大的模式,而将值增大至0.5+会生成较小的模式。 值从0(无频率==无模式)开始并更高。 不允许使用负值。 正如Michael Mullani指出的那样 :“ 0.02到0.2的值是大多数纹理的有用起点。”
请注意,产生的噪音没有背景色。 这意味着,如果删除SVG上的白色背景色,则可以通过噪声看到黑体背景。
baseFrequency属性也采用两个值。 如果您指定两个值,则第一个将用于X轴的基本频率,第二个将与Y轴相对应。通过提供两个不同的值,您可以生成垂直或水平噪声,可用于实现一些奇妙的效果,我们将看到在下一节中。
再次使用此演示中的baseFrequency值,并注意如果为它提供不同的值,它将沿X和Y轴变化。 该演示以良好的水平噪声开始。 x-baseFrequency值为 0.01相对较小,这会使水平图案变大(拉伸时)。 如果将其进一步减小,例如减小到0.001,您将看到水平图案将变得更像线条。 试试看
类型
顾名思义, type属性用于指示由feTurbulence原语生成的噪声的类型。 有两种类型:
- 湍流 ,这是默认设置;
- fractalNoise 。
fractalNoise可以创建更加朦胧且平滑的图案;这是创建气态纹理(如云)的良好基础。 湍流产生更多的线条来模拟波纹,因此适合作为流体纹理的基础。

图_1。 像湍流一样的噪声在左边,而分形噪声在右边。
在以下演示中更改type属性的值,以查看创建的模式如何变化:
numOctaves
numOctaves缩写为“八度音阶数”,代表噪声细节的级别。
在音乐中,八度是两个音符之间的音调差异,其中一个音符的频率是另一个音符的两倍。 因此,八度音阶越高,频率越高。 在feTurbulence中 ,八度的数量越多,您可以在它产生的噪音中看到更多的细节。 默认情况下,生成的噪声为一个八度,这意味着numOctaves属性的默认值为1。
在以下演示中拖动滑块,以查看增加八度数对生成的纹理的影响:
您会注意到,从numOctaves =“ 5”开始,添加八度的效果几乎变得不可见。
种子
规范中定义的谷物为“伪随机数生成器的起始编号”。 换句话说,它为用于生成随机噪声的随机函数提供了不同的种子。
从视觉上,您将看到这会影响“波纹线”的生成位置和生成方式。 当您看到这如何影响两个相邻矩形中产生的噪声时,也可以更好地理解这一点。
当两个相邻的矩形使用相同的初始值时,用于通过两个矩形创建噪声的函数是连续的,并且沿这两个矩形的边缘的“波纹线”的连续性将在视觉上反映出来。

图_2。 可以使用相同的初始值在两个矩形的边缘看到生成随机噪声的函数的连续性。
在下一个演示中试用种子属性的值,查看它如何影响所产生的噪声,并注意,噪声沿两个矩形使用相同的初始值连续出现。
标题
可以使用stitchTiles在噪声的“平铺”之间创建拼接效果。 此属性的效果与种子效果非常相似,这意味着当您有两个相邻的噪声区域(或“平铺”)时,此效果最为明显。
正如规范所提到的,有时产生噪声的结果会在图块边界处显示明显的中断。 您可以告诉浏览器尝试展平结果,以使两个图块看起来“被缝合”在一起,我真的很喜欢将该属性及其效果与缝合进行比较。
默认情况下,不做任何尝试在包含湍流功能的图纸边框上实现平滑过渡,因为StitchTiles的默认值为noStitch 。 如果要创建缝合效果,可以将值更改为。
为了将stitchTiles的结果与seed的结果进行比较,在下一个演示中,我将相同的seed值应用于在两个矩形中生成的噪声。 您已经可以看到它们之间的噪声似乎是连续的。 将stitchTiles选项切换为“ on ”,将其值更改为stitch,以查看噪声如何改变其在边缘周围的位置。
如前所述,只有三个属性,您很可能会使用type , baseFrequency和numOctaves 。 因此,我们将重点关注这三个方面,并向前迈进。
使用feTurbulence噪声使内容失真
从这里开始乐趣。 以及我们如何开始使用产生的噪声。 实际上,仅用噪声填充滤波区域本身是没有用的。
在上一篇文章中,我们使用feDisplacementMap使一段文本与外部图像的纹理保持一致。 而且我们提到feDisplacementMap使用一幅图像的颜色信息来扭曲另一幅图像。 用作位移图的图像可以是任意图像。 这意味着它可以是外部图像,也可以是在SVG中生成的图像,例如渐变图像或图案...井,或噪声纹理。
换句话说,如果与feDisplacementMap一起应用,我们使用feTurbulence生成的噪声也可以用于扭曲内容。 在以下示例中,我们使用feTurbulence的出口与feDisplacementMap一起偏移图像。 我通过为baseFrequency属性提供两个不同的值来使用水平噪声模型,这与我们之前所做的类似。
<svg viewBox="0 0 180 100"> <filter id="noise" x="0%" y="0%" width="100%" height="100%"> <feTurbulence baseFrequency="0.01 0.4" result="NOISE" numOctaves="2" /> <feDisplacementMap in="SourceGraphic" in2="NOISE" scale="20" xChannelSelector="R" yChannelSelector="R"></feDisplacementMap> </filter> <image xlink:href="..." x="0" y="0" width="100%" height="100%" filter="url(#noise)"></image> </svg>
feDisplacementMap上的sale属性指示了湍流使图像失真的强度。 我非常重视使效果看起来更加生动。
现在,基于这个简单的应用程序,我们可以为组合这些事实提供更多的可能性:
- SVG过滤器也可以应用于HTML内容。
- baseFrequency值是数字,因此可以设置动画效果。
不到两年前, Adrien Denat写了正确的文章,在其中他尝试了将类似的效果应用于HTML按钮。 我们将打破并重新创建以下按钮单击效果:

我们将从创建噪波纹理开始。 这是按钮变形的状态,然后,一旦获得它,我们便会将按钮的初始状态设置为此变形状态的动画,然后通过单击返回。
我们的目标是使按钮水平变形。 即 我们将使用并调整上一个演示中的水平噪声。 它对图像的失真影响甚至太强,因此首先,我将通过将湍流值从(0.01 0.4)更改为(0 0.2)来拨打代码:
<filter id='noise' x='0%' y='0%' width='100%' height='100%'> <feTurbulence type="turbulence" baseFrequency="0 0.2" result="NOISE" numOctaves="2" /> <feDisplacementMap in="SourceGraphic" in2="NOISE" scale="30" xChannelSelector="R" yChannelSelector="R"></feDisplacementMap> </filter>
效果变得更好一点,但是按钮仍然比我们想要的失真得更多:

我们希望失真不那么剧烈。 请记住,我们可以通过将噪声类型从默认湍流切换为更平滑的fractalNoise来立即降低噪声影响。 这样做之后,我们将看到失真效果也将得到平滑:

看起来好多了。
现在我们有了满意的失真效果,我们将以一个过滤器开始演示,该过滤器最初几乎什么都不做:
<filter id='noise' x='0%' y='0%' width='100%' height='100%'> <feTurbulence type="fractalNoise" baseFrequency="0 0.000001" result="NOISE" numOctaves="2" /> <feDisplacementMap in="SourceGraphic" in2="NOISE" scale="30" xChannelSelector="R" yChannelSelector="R"></feDisplacementMap> </filter>
我们将将此过滤器应用于CSS中的按钮:
button { -webkit-filter: url(#noise); filter: url(#noise); }
此时,按钮仍不会出现变形。
接下来,我们将使用Adrien的代码 ,尽管它是经过稍微修改的版本,该版本使用GSAP将baseFrequency属性的值动画化为 (0 0.2),然后通过单击将其返回到feTurbulence基元内部:
var bt = document.querySelectorAll('.button')[0], turbVal = { val: 0.000001 }, turb = document.querySelectorAll('#noise feTurbulence')[0], btTl = new TimelineLite({ paused: true, onUpdate: function() { turb.setAttribute('baseFrequency', '0 ' + turbVal.val); } }); btTl.to(turbVal, 0.2, { val: 0.2 }) .to(turbVal, 0.2, { val: 0.000001 }); bt.addEventListener('click', function() { btTl.restart(); });
实际上,这就是所需要的。 您可以在此处进行演示 :
在撰写本文时,该演示可在Chrome和Firefox中运行。 这些是Safari当前版本中的错误,但是该问题将在下一版本中得到解决,因为Safari Tech Preview显示该演示工作正常。
尽管这在MS Edge中不起作用,但是按钮根本不会变形,这意味着缺少支持不会影响使用它的能力。 这很棒,因为您仍然可以将此效果用作增强 。 如果不支持该效果,则该按钮的外观和行为类似于没有效果的常规按钮。
Adrian的文章还包含其他一些按钮失真效果 ,这些效果使用了我们刚刚看过的相同原理,绝对值得一试。 每个人都需要学习一两个好的技巧。
使用feTurbulence的波浪文字
我最喜欢feturbulence的用途之一是Lucas Beber的波浪文字效果。 在他的演示中,卢卡斯使用了几个feTurbulence函数:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <defs> <filter id="squiggly-0"> <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="0" /> <feDisplacementMap id="displacement" in="SourceGraphic" in2="noise" scale="6" /> </filter> <filter id="squiggly-1"> <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="1" /> <feDisplacementMap in="SourceGraphic" in2="noise" scale="8" /> </filter> <filter id="squiggly-2"> <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="2" /> <feDisplacementMap in="SourceGraphic" in2="noise" scale="6" /> </filter> <filter id="squiggly-3"> <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="3" /> <feDisplacementMap in="SourceGraphic" in2="noise" scale="8" /> </filter> <filter id="squiggly-4"> <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="4" /> <feDisplacementMap in="SourceGraphic" in2="noise" scale="6" /> </filter> </defs> </svg>
...并通过CSS动画将它们通过CSS应用于一段HTML文本,从一个动画到另一个动画:
@keyframes squiggly-anim { 0% { -webkit-filter: url("#squiggly-0"); filter: url("#squiggly-0"); } 25% { -webkit-filter: url("#squiggly-1"); filter: url("#squiggly-1"); } 50% { -webkit-filter: url("#squiggly-2"); filter: url("#squiggly-2"); } 75% { -webkit-filter: url("#squiggly-3"); filter: url("#squiggly-3"); } 100% { -webkit-filter: url("#squiggly-4"); filter: url("#squiggly-4"); } }
...从而产生波浪效果。
同样,所使用的文字是真实的,即 它可用于搜索,选择,访问和编辑(使用contenteditable属性)。 观看现场演示 ,但请注意 该演示占用大量资源,您可能不必在手机上打开Codepen。

因此,本节有一些有用的结论:
- feTurbulence产生的噪声可用于使SVG和HTML内容失真。
- baseFrequency的值可以设置为动画。
- 您可以通过调整baseFrequency中的值并使用fractalNoise类型平滑噪声来降低失真量。
- 尽管通常可以为SVG过滤器设置动画,但是通常建议不要过度使用它,因为它们可能会占用大量资源。 尽量将动画限制在小范围内; 动画区域越大,消耗的资源越多。
feTurbulence原语很少(如果有的话)单独使用。 其他过滤器原语几乎总是使用它来实现单独的效果。
在本节中,我们将其用作feDisplacementMap中的置换图。 让我们看看您还能用它做什么。
用feTurbulence模仿自然纹理
使用feTurbulence产生的噪声的另一种有用方法是模拟自然纹理。 如果您曾经在After Effects中使用过噪声生成插件,那么您可能已经遇到过此功能和示例。

图_7。 使用Fractal Noise插件在After Effects中创建的示例纹理。 ( 来源 )
feTurbulence为每个分量R,G,B和A生成噪声(随机值)。您可以更改每个分量的值以获得不同的噪声变化。 为了模拟纹理,我们通常只需要这样做:调整R / G / B / A组件(取消组件,使其他组件饱和等)。以获得所需的结果。 在其他情况下,我们需要做的只是对此有所了解。 从字面上看。
在本节中,我们将看一看Michael Mullany创建的粗糙纸张纹理效果 。 为了创建此纹理,我们需要使用SVG光源照亮feTurbulence生成的噪声的纹理。
SVG中的光源
SVG方便地提供了几种可用于照亮对象或图像的原语。
有两个过滤器原语用于指示所需的光的类型:
- feDiffuseLighting ,指示来自外部光源的间接光,最适合用于日光的影响;
- feSpecularLighting ,定义从反射表面返回的二次光。
两个原语都使用该图像的Alpha通道作为地形图来照亮对象或图像。 透明值保持平坦,而不透明值增加以形成峰值,并被更明显地照亮。
换句话说,光源滤镜使用输入的Alpha通道来获取深度信息:不透明度较高的区域会出现在观察者身上,而不透明度较小的区域则会从该处移开。 这意味着将输入中像素的alpha值用作z维度中该像素的高度,并且滤镜使用该高度来计算虚拟表面,该虚拟表面将反射来自光源的一定量的光。 这是非常强大的功能!
两种类型的光都接受一个称为surfaceScale的属性,该属性实际上是z索引因子。 随着该值的增加,表面纹理的“斜率”变得更陡峭。
“由于feTurbulence生成的Alpha通道充满了从0到1的噪声值,因此它形成了一个不错的Z曲面变量,当我们在其上发光时会产生眩光。” -迈克尔·穆兰尼
确定光源类型后,您需要选择一个光源。 SVG中有三种类型的光源 :
- feDistantLight :是一个远距所需的远程光源,因此根据其与目标的倾斜角度确定。 这是最适合表示阳光的方式。
- fePointLight :代表从特定点发出的点光,以X / Y / Z三维坐标表示。 它看起来像是房间内或场景内的光源。
- feSpotLight :是一种聚光灯,其行为类似于点光源,但其光束可以缩小为圆锥形,并且该光源可以转向其他目标。
这三个光源中的每一个都有其自己的属性,这些属性用于通过指示光源在3D空间中的位置来调整其生成的光。 属性超出了本文的范围,但是您可以在本规范中了解更多有关它们的信息。
要创建并应用照明效果,您需要将光源附加到照明类型上。 因此,您首先要选择所需的照明类型,然后选择照明源。 最后,您需要指定照明的颜色。 Lighting-color属性用于确定feDiffuseLighting和feSpecularLighting的光源颜色。
在考虑了光源的基础之后,我们现在来看我们的示例。
对于粗糙纸张的质地,我们将使用阳光。 这意味着我们将使用来自遥远光源的白色漫射照明。 转换为代码后,我们的代码如下所示:
<feDiffuseLighting lighting-color="white" surfaceScale="2" in=".." result=".."> <feDistantLight azimuth="45" elevation="60" /> </feDiffuseLighting>
方位角和仰角属性确定光源在三维空间中的位置。 拉斐尔·庞斯(Rafael Pons ) 的一篇文章令人惊奇,它以一种简单易懂的方式解释了这两个概念,并提供了有助于说明的精美方便的插图。 我强烈建议您看一下。
现在我们有了灯光,我们需要创建噪音以便用该灯光照亮它。 我们将分阶段演示该示例,以了解如何创建它。
我们需要从某个地方开始,我们将首先生成随机的基本噪声作为纹理的基础:
<feTurbulence baseFrequency='0.04' result='noise' />
我们的噪音看起来像这样:

然后,我们向他阐明了自己的观点,然后从那里出发:
<feTurbulence baseFrequency='0.04' result='noise' /> <feDiffuseLighting in='noise' lighting-color='white' surfaceScale='2'> <feDistantLight azimuth='45' elevation='60' /> </feDiffuseLighting>
噪声的明亮照明使我们具有以下纹理:

这不是我们要寻找的纹理的结果。 我们在这里注意到的第一件事是纹理中存在许多尖锐的线条。 我们希望摆脱它们,因为纸张表面上没有锐利的线条。 我们需要平滑这些线。 这可以通过将生成的噪声的类型更改为fractalNoise来完成 :
<feTurbulence type="fractalNoise" baseFrequency='0.04' result='noise' /> <feDiffuseLighting in='noise' lighting-color='white' surfaceScale='2'> <feDistantLight azimuth='45' elevation='60' /> </feDiffuseLighting>
这将从我们的纹理中删除所有这些尖锐的对齐边缘:

现在,我们离粗糙的纸张纹理又近了一步。
但是,上述纹理不够粗糙。 她缺乏必要的“粗糙度”。 小零件数量的增加应使其更粗糙。 为此,我们将增加numOctaves的值。 我们发现大约5是获得所需粗糙度级别的一个好数目:
<feTurbulence type="fractalNoise" baseFrequency='0.04' numOctaves="5" result='noise' /> <feDiffuseLighting in='noise' lighting-color='white' surfaceScale='2'> <feDistantLight azimuth='45' elevation='60' /> </feDiffuseLighting>
现在,我们的纸张纹理如下所示:

太好了!
您可以在此处进行演示:
该演示可在所有主要浏览器(包括MS Edge)上运行。
如果需要,您可以根据光源和光源的距离进一步调整效果。 例如, 将光源的高度从60降低到40应该会增加纹理中的小山之间的对比度。 然后纹理将如下所示:

我强烈建议您尝试使用光源和噪声源的属性值,并查看它们如何影响最终的纹理。
结论
feTurbulence原语是最有趣且功能最强大的SVG操作之一。 结合其他图元和动画,他能够创造出非常有趣和有吸引力的效果,纹理和交互。
我假设feTurbulence是您想尝试或解析其他人的代码以便更好地研究它的那些过滤器之一。 但是,我想我正在猜测一段时间后纹理的外观。 而且由于我们仅用一种纹理就可以完成很多工作,因此如果将其与其他基元一起使用,则可以用它创建几乎无数种可能的效果。 我强烈建议您查看他人的工作并将其拆开,以便更好地学习。
在几个月前我谈论 SVG过滤器之后,Yoksel正在尝试 Codepen SVG过滤 器 。 因此,您可以在他的Codepen个人资料中找到很多要解析和学习的效果。

图_13。 Yoksel最近使用feTurbulence使用SVG滤波器进行的实验之一 。
希望本文能激发您的灵感,并为您的想象力打开一扇新门,以便您了解使用SVG过滤器可以做什么。
在本系列的最后一篇文章中,我将分享一些其他资源和工具,以帮助您继续使用SVG过滤器并开始自己构建。 和我们在一起。