Reinventing Feathering for the Vectorian Era
标题:为矢量时代重新设计的 Feathering 技术
Products
Community
Learn
PricingDownloads
Rive Blog
为矢量时代重新设计的 feathering 技术
打破僵化、过时的规范,构建首个真正的矢量 feather 的幕后故事。
作者: Chris Dalton
2025 年 4 月 2 日,星期三
这篇来自 Rive 的 Runtime 负责人 Chris Dalton 的文章展示了我们如何从头开始构建一个完全基于矢量的 feathering 系统。它深入探讨了 Rive Renderer,为什么它性能更高,以及它如何解决传统规范无法解决的问题。
2024 年 3 月,GDC。我正在和一位同事聊天,这时我们的增长副总裁 Sarah Warn 走了过来,问道:“嘿,你能做一下发光和阴影效果吗?”她不是随便问问。设计师们已经要求很久了。她知道如果我们实现了它,将会非常受欢迎。
我们的 CEO Guido Rosso 从我第一天上班就一直在推动这件事。Rive CTO Luigi Rosso,他的双胞胎兄弟,曾经开玩笑说,只要 Rive Renderer 发布,我们的首要任务必须是发光和阴影,否则 Guido 就会开始掀桌子。(╯°□°)╯︵ ┻━┻
这件事一直在我脑海里。但我也知道我不想采用传统的方法。
为什么高斯模糊不是一个选项
在设计软件中处理发光和阴影的默认方法是 Gaussian 模糊,但这种方法有一个很大的缺陷。你必须使用图像卷积滤波器,这在计算上非常昂贵。
以下是传统模糊在幕后发生的事情:
- 矢量形状被栅格化为位图。
- 一个卷积滤波器被应用于像素,以模拟柔和的边缘。
- 结果是发光或阴影看起来很漂亮,但在计算上很昂贵,不可扩展,并且不再是真正的矢量。
更重要的是:高斯模糊甚至不是为柔和边缘设计的。
Carl Gauss,19 世纪高斯函数背后的数学家,并没有考虑柔和的阴影或发光效果。他感兴趣的是概率分布和平滑噪声数据。
当高斯模糊在几个世纪后进入图像处理领域时,人们发现它可以用来寻找边缘。通过平滑图像中的精细细节,高斯模糊帮助算法检测一个对象在哪里结束,另一个对象在哪里开始。事实上,许多边缘检测技术,如 Canny Edge detector,首先应用模糊,然后再识别高对比度区域。
荒谬的是,高斯模糊正在解决一个我们从未遇到的问题。我们已经知道了我们的边缘。矢量是由 Bézier 曲线组成的,它以数学精度定义了优雅的边界。
这就像从头开始烤一个蛋糕,然后把它捣碎,让别人找出配料。你一直都有食谱。为什么要破坏信息,然后稍后再猜测它?
这让我思考,“我们为什么要首先栅格化矢量?我们可以从矢量曲线本身计算出柔和的边缘吗?”
高斯模糊依赖于正态分布曲线(钟形曲线)来柔化图像,但它总是在事后应用于栅格化的位图。如果我们不需要那个额外的步骤呢?我们已经知道我们的边缘,所以我们不必近似它们。我们可以不破坏矢量数据后应用模糊,而是可以直接在我们的形状上使用相同的数学方法。
这就是事情变得有趣的地方。
第一个想法很简单。与其在整个栅格化图像上运行昂贵的模糊,为什么不只在矢量的边缘应用卷积滤波器?如果我们已经在处理边缘,我们可以完全绕过卷积滤波器吗?
然后我意识到:Rive Renderer 已经在为抗锯齿做一半的工作了。
我们的 Rive Renderer 是如何工作的
三年前,当我遇到 Rive 的创始人 Guido 和 Luigi 时,我告诉他们我想通过构建一个不受 SVG 限制的渲染器来重新思考矢量渲染。
为什么?SVG 在 2003 年正式确定,但它编纂的矢量图形原理自 20 世纪 60 年代和 70 年代以来就已存在。它没有引入任何特别新的东西——只是将几十年来的想法整合到一个规范中。而且它是在智能手机革命之前,在硬件上完成的,这与我们今天构建的硬件截然不同。
现代 GPU 与矢量图形发明的 GPU 截然不同。现代硬件上的交互式图形和实时设计需要现代算法。一些已确立规范的某些方面无法转化为这个新世界,但是我们可以不继续沿用旧规则,而是可以重写规范。
Guido 和 Luigi 立即理解了我的理由,并希望我为 Rive 构建渲染器。他们知道,为了让 Rive 脱颖而出,他们需要重新构想交互式设计的整个工作流程。为了做到这一点,我们需要我们自己的渲染器。所以,我们一起构建了它。
作为背景,Rive 不仅仅是一个设计工具。它是一个由三个紧密连接的部分组成的完整平台:Editor,.riv 文件格式和我们的开源 Runtimes。Editor 创建交互式图形。.riv 格式包含所有内容——视觉效果、逻辑、状态变化。Runtimes 将它带到你的应用程序、游戏或 Web 体验中。
今天,Rive Renderer 通过基于三角形的覆盖插值来平滑锯齿状边缘,围绕矢量边缘细分三角形以计算覆盖率。根据三角形自然地顺时针或逆时针落入,它会为像素贡献正或负覆盖率。这会产生抗锯齿效果,将矢量混合到背景中。
如果我们扩展该逻辑来解决我们的 feathering 问题呢?
一种更好的 feather 方法
我们可以不使用一个像素宽的抗锯齿斜坡,而是可以根据 feathering 强度将其扩展到任何宽度。而且,我们可以不使用简单的线性覆盖图,而是可以根据正态分布曲线(或钟形曲线,就像高斯模糊背后的曲线一样)来塑造该过渡。
现在,我们可以不盲目地在栅格化图像上应用模糊,而是以程序方式计算覆盖率。任何给定点的 feather 的不透明度都不是近似值。它是正态分布函数的积分。
feather 的中点位于路径的精确边缘上,因此在钟形曲线的一半处,我们达到 50% 的覆盖率。这意味着 feathering 效果在该精确点上的矢量颜色和背景之间混合了一半。没有猜测,没有像素采样,只有纯数学实时塑造效果。
换句话说,我们不是在事后模糊栅格化图像。我们正在源头生成真正的矢量 feather,使用定义形状本身的相同数学方法。
与基于 SVG 的模糊(被视为后期处理效果)不同,Rive 将柔和边缘计算为矢量本身的基本部分。在 SVG 中,一旦应用模糊,它就不再是矢量。它是一个叠加在顶部的栅格化效果。这使得根据实时条件(例如对象移动、缩放或交互)动态调整 feathering 变得昂贵。Rive 通过将柔和边缘视为形状的固有属性来打破这种限制,从而可以进行无限可扩展的实时调整。
这有巨大的优势:
- 完全基于矢量 - 没有栅格化
- 性能友好 - 避免了缓慢的卷积滤波器
- 无限缩放 - 没有质量损失
在这一点上,平坦的边缘和直线 feathered 美丽,但是当我尝试在曲线或角上使用它时,事情变得非常糟糕。
最难的部分:砍掉数学
就像我说的那样,平坦的边缘 feathered 美丽。但是现实世界的形状具有曲率和锐角,如果你尝试使用高斯积分的 1D 采样来渲染它们,会得到一些非常难看的瑕疵。
传统的高斯模糊在整个图像上应用 2D 卷积矩阵,使曲线、角和重叠的边缘自然而美观地柔化。
为了捕捉这种效果,我需要一个处理 2D feathering 的概率分布函数。渲染器必须动态地考虑覆盖率重叠,取消在 feathered 边缘相遇以及像素从两侧的镶嵌中被重复计算的冗余贡献。
这意味着要解决覆盖率如何在 feathering 范围内构建的问题。我一直在回到钟形曲线,其中下方的总面积定义了每个点的不透明度。在平坦的边缘上,在 feather 宽度的正中间,你已经积分了一半的总面积,这意味着你达到了 50% 的覆盖率。但是一旦你引入曲率或角,50% 的比例就会随着曲率的强度而变化。一旦你具有曲率 NOT 在卷积矩阵的确切中心,谁甚至知道会发生什么。🫠
这就是为什么我开始将其视为“通过钟形曲线的一半”。它是精确的平衡点,其中 feathering 效果是不透明和透明之间的一半。它也恰好是建模曲率行为的最干净的点。
但是现实世界的曲线和角使事情变得更加混乱。与高斯模糊(它会涂抹简单的栅格化图像)不同,我们必须分析地解决这个问题,实时计算每个 feathered 边缘如何贡献覆盖率。
我试图通过调整 feather 斜坡来解决这个问题,但它仍然是错误的。然后我意识到我需要一个 2D 积分而不是 1D 斜坡,并且与相邻边缘和角的交互需要以完全的精度来捕获。
完全的噩梦。
我花了几个星期的时间来处理方程式,运行测试用例,并手动调整数学。当三次 Bézier 曲线穿过卷积矩阵时到底会发生什么?我如何捕捉随着曲率强度增加而发生的柔化效果?当两个三次 Bézier 曲线都穿过卷积矩阵时,它们如何相互作用?所有曲线和所有角如何相互作用?“Subtract Path”功能如何与所有这些配合使用?
为了使事情更加复杂,所有这些 Bézier 几何体都被镶嵌成自重叠的三角形补丁。每个单独的三角形对分析覆盖率的贡献是什么(无论是正还是负,取决于它的缠绕方式)?
😵💫😵💫😵💫
… 为什么事情变得如此复杂??我不知道我怎么知道的,但我确实知道这种几何解决方案会起作用,而且数学将会简单而优雅……但是我该如何找到那种数学?🤔
有一次,在我解决了主积分并缩小到解决方案之后,我让 ChatGPT 解决了该积分。它算错了。我不得不坐下来,手动计算并优化数学,最终得出了一个有效的版本。
当我说有效时,我的意思是它看起来与传统的高斯模糊完全相同,但实际上不是。甚至比高斯模糊更好,因为它是在无限可缩放的矢量空间中完成的,而不是在栅格图像中完成的。
矢量 Feathering 的真正魔力在于顺时针填充规则和 Rive Renderer 镶嵌的精美简单的三角形补丁,当它们围绕 Bézier 曲线折叠时,它们自然地以正确的方向(顺时针或逆时针)缠绕。在这些三角形内部完成的数学证明是 相应地优雅。
为什么矢量 Feathering 以前没有完成?
几十年来,矢量图形一直被锁定在相同的僵化规范中。你有两个填充规则,evenOdd 或 nonZero,并且模糊被指定为后期处理高斯模糊效果。
问题在于,这些规范是二十年前为简单的 2D 图形设计的,远早于 GPU 加速渲染出现之前。主要的设计工具一直陷于过时的过程中,有效地阻止了创新。
这些规范还在设计师和开发人员之间建立了一堵墙。设计师在约束范围内工作。工程师实现了它们。没有人说话。但是,这种沉默并不是因为没有想法——而是因为系统不允许更好的沟通。
Rive 采取了不同的方法。它是由设计师和开发人员共同构建的工具,他们共同打破了那堵墙,并构建了一个服务于双方的系统。我们的创始人 Guido 和 Luigi 是双胞胎——一位设计师和一位开发人员,他们始终同步工作。从一开始,这种自然的合作就塑造了 Rive 的愿景:一个图形平台,使创意和技术声音可以轻松地说同一种语言。
我们没有接受这些约束,而是重新思考了整个管道,从 Editor 到 Renderer,以创建一个真正适用于现代硬件的系统。这意味着要丢弃旧规范的某些部分,并构建一个服务于设计师和开发人员的规范。
你在 Rive 的 Editor 中看到的就是你在 Rive 运行的任何地方获得的东西。它是一种真正的、可扩展的矢量效果,没有人可以构建它,因为他们没有控制整个管道。Rive 是第一个将柔和边缘视为矢量图形的固有属性,而不是后期处理效果。
不仅仅是工程师感受到这种差异。设计师告诉我们,许多旧规则感觉像是神秘的遗迹,并且不是特别友好或直观。Rive 的现代方法恢复了他们自 Flash 全盛时期以来就没有感受到的某些创作自由:快速、高效、可用于生产的矢量图形。
接下来是什么?
2.5D 渲染: 矢量图形可以倾斜、旋转并投影到 3D 空间中,而不会失去其清晰度。不再有烘焙的深度效果或静态透视扭曲。
VR-ready UI: VR UI 中的矢量 UI 具有抗锯齿边缘,可在任何比例下保持清晰,而无需高分辨率纹理或 GPU 密集型效果。
Tapered strokes: 目前,笔划在整个路径上的宽度是均匀的。但是,如果笔划宽度本身可以是 Bézier 曲线怎么办?有了这个,你可以使用自然的笔动态进行绘制,创建可变宽度的书法,或实时生成富有表现力的笔划。甚至锥形的 feathers!feather 大小本身将是 Bézier 曲线而不是常量。
一个 15 年的想法变为现实
说实话,自从我在 2011 年在 NVIDIA 实习以来,我一直在思考路径渲染。后来,当我加入 Google 时,我对改进路径渲染有一些想法,但是我们被锁定在 SVG 规范和 W3C 标准中。Rive 不同。反应是,“那是个很酷的想法。让我们构建它!”
Guido 和 Luigi 从一开始就知道,如果我们真的要创新,我们就不能接受现有格式的局限性。他们看到,打破以相同方式做事的心智陷阱将为全新的可能性打开大门,并使 feathering、运动和动态交互更加强大和高效。
这正是发生的事情。
多年来,模糊和阴影一直与妥协有关:栅格化、近似以及性能和规模上的权衡。
我们不再需要妥协了。
开始构建可用于生产的图形 Get Started
加入我们的新闻通讯
获取所有最新的 Rive 新闻发送到你的收件箱。
Product Editor Runtimes Renderer Changelog Community Marketplace Community Bug Reports Feature Requests Discord Experts Learn Documentation Blog Newsletter Features Company Careers Merch Terms Privacy Use Cases Automotive Product UI Game UI Websites Mobile Apps Film + TV Broadcast Runtime Rive vs Lottie © 2025 Rive, Inc. All rights reserved. All trademarks, logos, and brand names are the property of their respective owners.