SVG 滤镜效果:使用 <feTurbulence> 创建纹理 (2019)

Lobsters Hottest 工具

摘要

本文介绍如何使用 SVG 的 feTurbulence 滤镜图元来创建纹理和扭曲图像,并提供交互式演示用于视觉实验。

<p><a href="https://lobste.rs/s/jxloti/svg_filter_effects_creating_texture_with">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/24 01:25

# SVG 滤镜效果:使用 `feTurbulence` 创建纹理 | Codrops 来源:https://tympanus.net/codrops/2019/02/19/svg-filter-effects-creating-texture-with-feturbulence/ `feTurbulence` 是最强大的 SVG 滤镜基元之一。规范对此基元的定义如下: > 此滤镜基元使用 Perlin 湍流函数创建图像。它允许合成人工纹理,如云彩或大理石纹理。[...] 生成的图像将填充此滤镜基元的整个滤镜基元子区域。 换言之,`feTurbulence` 滤镜基元生成并渲染 Perlin 噪声。这种噪声在模拟多种自然现象(如云彩、火焰和烟雾)以及生成复杂纹理(如大理石或花岗岩纹理)方面非常有用。与 `feFlood` 类似,`feTurbulence` 用新内容**填充滤镜区域**。 在本文中,我们将探讨如何使用 `feTurbulence` 创建噪声,以及如何利用这些噪声来扭曲图像和文本——这与我们在上一篇文章 (https://tympanus.net/codrops/2019/02/12/svg-filter-effects-conforming-text-to-surface-texture-with-fedisplacementmap/) 中使用 `feDisplacementMap` 纹理的方式类似。接着,我们将了解如何将生成的噪声与 SVG 光照效果结合使用,以创建简单的粗糙纸张纹理。但首先,让我们概览一下 `feTurbulence` 及其属性,并了解每个属性如何影响生成的噪声。 ## 使用 `feTurbulence` 创建湍流和分形噪声 当我开始撰写本系列文章时,我决定尽可能避免涉及滤镜基元背后复杂的细节。这就是为什么我们不会深入探讨用于生成 Perlin 噪声 (https://en.wikipedia.org/wiki/Perlin_noise) 的函数的技术细节。在阅读了噪声生成所依据的函数后,我发现当我进行基元实验时,这些知识并没有太大帮助。毕竟,我们在这里处理的是一个随机噪声发生器。因此,大多数时候,你会发现生成纹理是一个不断试验和调整以达到期望效果的过程。随着时间的推移,预测纹理*可能*的样子会变得容易一些。我发现通过*视觉上*操作 `feTurbulence` 并调整其属性,是了解它们的最佳方式,这帮助我理解了每个属性的作用。因此,我们将采用视觉方法来理解 `feTurbulence`,并辅以一些交互式演示。 现在,`feTurbulence` 使用 Perlin 湍流函数 (https://en.wikipedia.org/wiki/Perlin_noise) 生成噪声。它有 5 个主要属性来控制该函数,从而控制函数的视觉结果: - `type` - `baseFrequency` - `numOctaves` - `seed` - `stitchTiles` 我们将讨论每个属性如何影响视觉结果,而不深入探讨该函数的技术细节。你会发现,大多数时候,你只需要关注其中三个属性:`type`、`baseFrequency` 和 `numOctaves`。 ### `baseFrequency` 为了生成噪声,只需要 `baseFrequency` 属性。`baseFrequency` 影响生成噪声的大小(或比例)和颗粒度。 `baseFrequency` 的效果在可视化和动画化时最容易理解。这就是我创建以下实时演示的原因。使用滑块,你可以更改基准频率的值,并实时查看它如何影响生成的噪声。你会注意到,随着你增加或减少 `baseFrequency` 属性的值,生成的图案**在变小或变大的过程中保持完整**,并且**看起来像是在左上角原点处进行缩放**。 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence: baseFrequency。 较低的 `baseFrequency` 值(例如 0.001)生成较大的图案,而较高的值(0.5+)生成较小的图案。值从 0(无频率 == 无图案)开始,不允许负值。正如 Michael Mullany 提到的 (https://www.creativebloq.com/netmag/how-go-beyond-basics-svg-filters-71412280),“*对于大多数纹理,0.02 到 0.2 范围内的值是有用的起点*。” 请注意,生成的噪声没有背景颜色。也就是说,如果你移除 SVG 上的白色背景色,你将能够透过噪声看到深色主体的背景。 `baseFrequency` 属性也接受两个值。当你提供两个值时,第一个用于 x 轴的基准频率,第二个对应于 y 轴。通过提供两个不同的值,你可以生成垂直或水平噪声,从而实现一些奇妙的效果,我们将在后续章节中看到。 在此实时演示中再次尝试 `baseFrequency` 的值,并注意当你为其提供不同值时,它如何沿 X 轴和 Y 轴变化。演示以一个不错的水平噪声开始。0.01 的 x 基准频率值相对较小,这使得水平图案较大(就像被拉伸开一样)。如果你进一步减小它(例如到 0.001),你会看到水平图案变得更像线条。试试看。 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence: x & y baseFrequency。 ### `type` 顾名思义,`type` 属性用于指定 `feTurbulence` 生成的噪声类型。有两种可用类型: - `turbulence`,这是默认值 - `fractalNoise` `fractalNoise` 生成更云状、更平滑的图案,是创建气体类纹理(如云彩)的合适基础。`turbulence` 生成更多模拟波纹的线条,因此适合作为液体纹理的基础。 ![左侧为 turbulence 类型噪声,右侧为 fractalNoise 类型](此处应有图片) 在以下演示中更改 `type` 属性的值,看看生成的图案如何变化: 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence: stitchTiles。 ### `numOctaves` `numOctaves` 是“倍频程数量”的缩写,代表噪声的细节级别。在音乐中,倍频程是两个音符之间的音高差,其中一个的频率是另一个的两倍。因此,倍频程越高,频率越高。 在 `feTurbulence` 中,倍频程数量越高,你能在生成的噪声中看到的细节就越多。默认情况下,生成的噪声有一个倍频程,这意味着 `numOctaves` 属性的默认值为 1。 拖动以下演示中的滑块,查看增加倍频程数量对生成纹理的影响: 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence: numOctaves。 你会注意到,从 `numOctaves="5"` 开始,添加更多倍频程的效果实际上变得难以察觉。 ### `seed` 如规范 (https://www.w3.org/TR/filter-effects-1/#feTurbulenceElement) 中所定义,`seed` 是“伪随机数生成器的起始数”。换句话说,它为用于生成随机噪声的随机函数提供了一个不同的起始数。从视觉上看,你会看到它影响“波纹线”的生成位置和方式。当你看到它如何影响两个相邻矩形中生成的噪声时,会更容易理解它。 当两个相邻的矩形使用相同的 `seed` 时,用于在两个矩形上生成噪声的函数是**连续的**,这将在视觉上通过两个矩形边缘“波纹线”的连续性反映出来。 ![使用相同 `seed` 值时,两个矩形沿边界的随机噪声生成函数是连续的](此处应有图片) 在以下演示中尝试 `seed` 属性的值,看看它如何影响生成的噪声,并注意在使用相同 `seed` 值的两个矩形边界上,噪声是如何连续的。 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence: seed。 ### `stitchTiles` `stitchTiles` 可用于在噪声“图块”之间创建拼接效果。此属性的效果与 `seed` 非常相似,意味着当你有两个相邻的噪声区域(或“图块”)时,它最为明显。 正如规范所提到的,有时噪声生成的结果会在图块边界显示明显的断点。你可以告诉浏览器尝试平滑结果,以便两个图块看起来像是“缝合”在一起的。(我真的很喜欢这个属性及其效果被比作*缝合*。) 默认情况下,对于包含湍流函数的图块边界,不会尝试实现平滑过渡,因为 `stitchTiles` 的默认值是 `noStitch`。如果你想创建那种拼接效果,可以将值更改为 `stitch`。 为了比较 `stitchTiles` 与 `seed` 的效果,我在以下演示中为两个矩形生成的噪声应用了相同的 `seed` 值。你已经可以看到噪声在两个矩形之间似乎是连续的。切换 `stitchTiles` 选项为“开启”(将其值更改为 `stitch`),看看噪声如何改变以适应边界。 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence: stitchTiles。 正如我之前提到的,你最有可能使用的三个属性是 `type`、`baseFrequency` 和 `numOctaves`。因此,我们将重点讨论这三个属性。 ## 使用 `feTurbulence` 生成的噪声扭曲内容 *这*才是乐趣的开始。也是我们开始利用生成的噪声的地方。毕竟,仅仅用噪声填充滤镜区域本身并无用处。 在上一篇文章 (https://tympanus.net/codrops/2019/02/12/svg-filter-effects-conforming-text-to-surface-texture-with-fedisplacementmap/) 中,我们使用了 `feDisplacementMap` 使一段文本与外部图像中的纹理相符。我们提到 `feDisplacementMap` 使用一个图像中的颜色信息来扭曲另一个图像。用作置换贴图的图像可以是*任何*图像。这意味着它可以是外部图像或在 SVG 内生成的图像,例如渐变图像、图案……或者噪声纹理。 换句话说,我们使用 `feTurbulence` 生成的噪声也可以用于扭曲内容,如果它与 `feDisplacementMap` 一起使用的话。 在以下演示中,我们使用了 `feTurbulence` 的输出,通过 `feDisplacementMap` 来置换图像。我通过为 `baseFrequency` 属性提供两个不同的值来使用水平噪声模式,类似于我们之前的做法。 ```xml <filter id="noise"> <feTurbulence type="fractalNoise" baseFrequency="0.01 0.4" numOctaves="1" result="turbulence"/> <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="30"/> </filter> ``` 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence as a displacementMap。 湍流扭曲图像的强度由 `feDisplacementMap` 上的 `scale` 属性指定。我使用了一个较大的值,以使效果看起来更戏剧化。 现在,从这个简单的应用出发,我们可以开启更多的可能性,因为我们结合了以下事实: - SVG 滤镜可以应用于 HTML 内容, - 并且 `baseFrequency` 的值是*数字*,因此可以被动画化。 不到两年前,Adrien Denat (https://tympanus.net/codrops/author/grsmto/) 在 Codrops (https://tympanus.net/codrops/2016/05/11/distorted-button-effects-with-svg-filters/) 上撰写了一篇文章,在其中他尝试了将类似效果应用于 HTML `button`。我们将分解并重现以下按钮点击效果: ![按钮点击扭曲效果](此处应有图片) 我们将从创建噪声纹理开始。我们将从最终状态开始——即按钮被扭曲的状态,然后,一旦达到该状态,我们将在点击时将按钮的初始状态动画化到该扭曲状态并返回。我们的目标是水平扭曲按钮。因此,我们将使用并稍微调整上一个演示中的水平噪声。它对图像的扭曲效果有点太强了,所以我要首先通过将湍流值从 `0.01 0.4` 改为 `0 0.2` 来调低它: ```xml <filter id="noise"> <feTurbulence type="fractalNoise" baseFrequency="0 0.2" numOctaves="1" result="turbulence"/> <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="30"/> </filter> ``` 效果好了一点,但按钮仍然比我们希望的扭曲得更厉害: ![扭曲仍然有点强](此处应有图片) 我们希望扭曲不那么剧烈。一个有用的技巧是:**我们可以通过将噪声类型从默认的 `turbulence` 切换到更平滑的 `fractalNoise` 来瞬间减弱噪声的效果。**一旦我们这样做,就会看到扭曲效果也被“平滑”了: ![切换到 fractalNoise 后效果更平滑](此处应有图片) 这看起来好多了。现在我们已经得到了一个满意的扭曲效果,我们将以一个初始时几乎不起作用的滤镜开始我们的演示: ```xml <filter id="noise"> <feTurbulence type="fractalNoise" baseFrequency="0" numOctaves="1" result="turbulence"/> <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="30"/> </filter> ``` 我们将在 CSS 中将该滤镜应用于我们的 `button`: ```css button { -webkit-filter: url(#noise); filter: url(#noise); } ``` 此时,按钮看起来仍未扭曲。接下来,我们将使用(略微修改版的)Adrien 的代码,该代码使用 GSAP (https://greensock.com/) 在点击时将 `feTurbulence` 的 `baseFrequency` 内的值动画化到 `0 0.2` 并返回: ```javascript 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(); }); ``` 真的就这么简单。你可以在这里玩这个实时演示: 请查看 CodePen 上由 Sara Soueidan (@SaraSoueidan) 创建的 Pen feTurbluence on BUTTONs。 https://greensock.com/ 在撰写本文时,该演示在 Chrome 和 Firefox 中有效。在当前版本的 Safari 中存在错误,但在下一个版本中该问题已解决,因为 Safari 技术预览版显示该演示运行完美。它在 MS Edge 中不起作用,*但*按钮根本没有扭曲,这意味着缺乏支持并不影响按钮的可用性。这很棒,因为**你仍然可以将此效果用作增强功能。**如果效果不被支持,按钮将只是看起来和行为像一个普通的、无效果的按钮。 Adrien 的文章还包括相当多 (https://greensock.com/) 的其他按钮扭曲效果 (https://tympanus.net/Development/DistortedButtonEffects/),它们使用了我们刚刚涵盖的相同原理,绝对值得查看和分解。每个效果都有一两个不错的技巧可以学习。 ### 使用 `feTurbulence` 制作波浪形文本 我最喜欢的 `feTurbulence` 实际应用示例之一是 Lucas Bebber 的 Squiggly Text (https://codepen.io/lbebber/pen/KwGEQv) 效果。在他的演示中,Lucas 使用了多个 `feTurbulence` 函数: ```xml <filter id="squiggly-0"> <feTurbulence baseFrequency="0.02" numOctaves="3" result="noise" seed="0"/> <feDisplacementMap in="SourceGraphic" in2="noise" scale="2"/> </filter> <!-- ... 更多具有不同种子的滤镜 --> ``` ...然后通过 CSS 动画将它们应用于一段 HTML 文本,从一个动画化到另一个: ```css @keyframes squiggly-anim { 0% { filter: url(#squiggly-0); } 25% { filter: url(#squiggly-1); } 50% { filter: url(#squiggly-2); } 75% { filter: url(#squiggly-3); } 100% { filter: url(#squiggly-4); } } ``` ...从而创建波浪效果。再次说明,使用的文本是真实的,这意味着它是可搜索的、可选择的、可访问的且可编辑的(使用 `contenteditable` 属性)。 查看实时演示 (https://codepen.io/lbebber/pen/KwGEQv?editors=1100),但请注意该演示资源消耗较大,因此你可能希望避免在移动设备上打开 Codepen。 Lucas 的波浪形文本演示的动画截图。 --- 因此,本节的一些**有用要点**:

相似文章

使用CSS进行抖动处理

Hacker News Top

本文演示如何使用CSS滤镜和SVG feTurbulence对图像应用抖动效果,以保持一致的视觉风格。

一个无需光栅化即可投影纹理的3D SVG渲染器

Lobsters Hottest

一位开发者描述了一个用原生TypeScript编写的3D转SVG渲染器,该渲染器通过将图像细分为带裁剪路径的仿射变换多边形来近似透视纹理效果,而无需光栅化,旨在用于在React中渲染电路板。

纯CSS实现阳光透过窗户洒入的效果

Lobsters Hottest

一个纯CSS实现的阳光透过窗户洒入的效果,包含渐进模糊、带有SVG滤镜的飘动树叶,以及日出/日落过渡。包含每个视觉效果的详细代码解释。