阴影扩散上的照明

2020-09-08 07:18:44

从今天开始,您可以调整Figma中矩形、椭圆、框架背景和组件背景上的阴影扩散,就像使用CSS方框阴影一样。

我最初计划在菲格玛最近的制造者周期间建立这个项目,当时我们给公司的每个人留出时间,探索他们日常职责之外的项目。我可以在几天内解决的看似简单的特性变成了长达一周的算法思想之旅、W3C规范的兔子洞和细致入微的产品决策。在这里,我将分享更多关于我们如何在一个(看似)简单的用户请求上做出艰难权衡的信息。

为共同制造产品的团队创建一个健壮的基于Web的设计平台需要做很多工作。我们提供的系统可以帮助您开发和理解复杂设计系统的价值,为世界各地的团队成员实现实时协作,甚至可以改进像可靠的钢笔工具这样的旧备用工具。所以,你可能会问:那么,在用户第一次在Spectrum上提问的958天里,为什么不支持阴影扩散,这是CSS的方框阴影的一个基本特性?我们真的很难,嗯,做一个影子,就是…。更大?

如果你问图形工程师这个问题,实际上答案是响亮的。阴影的扩散值表示阴影在所有方向上扩展或收缩的距离。要理解何时会变得复杂,我们将首先考虑如何绘制阴影。这里有几个简单的投影:

如您所见,投影的形状看起来很熟悉。要创建这样的投影,我们复制对象的几何体,用一种颜色填充它,使其模糊,然后在节点本身下面渲染它。

它可能看起来像使用扩散值渲染阴影一样简单,只需放大阴影的几何体即可。这确实适用于矩形,但对于任何更复杂的东西来说就不是那么有效了-比如,Figma的徽标,它到处都是洞:

如果我们考虑阴影扩散的定义-将阴影在每个方向上从几何体向外(或向内)扩展一定数量的像素-我们会想要更多这样的东西:

但没有人告诉我,在我决定在5月份菲格玛制作周的一天下午尝试解决阴影传播问题之前,没有人告诉我这一点。在Maker Week期间,我天真地通过“错误”的方法进行了猛烈抨击,意识到了问题所在,然后冲锋在前,决心解决这个问题。我想,这不是火箭科学。我们可以想出如何渲染2D形状的阴影。

的确,有几种有趣的算法方法可以做到这一点,但这些方法都不能很好地整合到我们现有的渲染系统中。也可以通过非算法的方式来实现这一点-通过利用笔划来模拟具有扩散距离的阴影-但我很快意识到这也不是一个选择;我们在笔划中处理某些顶点角度的方式与您希望用于阴影扩散的方式不同,并且我们的原型渲染器中没有笔划生成代码。不知何故,我们需要找到一种方法,在不向两个不同的呈现代码库添加大量复杂的几何代码的情况下,实现这一点。

如果有一件事比调试渲染错误更让我喜欢的话,那就是阅读有关互联网技术的规范。(问问我去年在Figma实现GIF支持时了解到的关于GIF89a的所有奇怪事情。)。我开始盘问我们对阴影扩散的假设。我们知道,现在的Figma用户实现了变通方法,并且在涉及阴影扩散值时包括单独维护的开发人员移交文档。如果我们构建阴影扩散是因为我们想要减少开发人员移交过程中的摩擦,那么CSS应该引导我们的约束。我们真的需要为有洞的图形标志画出完美的阴影扩散吗?我们甚至可以在CSS中做到这一点吗?!

事实上,我们不能。关于长方体阴影的事情是,它只适用于渲染长方体的阴影(以及其他类似长方体的东西,如果你把角半径弄对了,包括椭圆)。长方体阴影不会将Figma徽标的阴影呈现为徽标的副本,而是呈现一个方框。

(顺便说一句:在这个过程中的每一步,有人告诉我,“实际上,Filter:Drop-Shadow()中支持扩散值”,并将我指向一个MDN页面,该页面错误地暗示扩散值包含在规范中,只是浏览器还不支持它。不幸的是,正如W3C规范中明确指出的那样,这从来都不是真的。我们知道!我们也很难过。)。

在与我们的设计师倡导者讨论后,他们确信只要在矩形和椭圆形上提供阴影扩散就可以覆盖很大比例的用例,并进一步巩固了CSS遵从性应该激励我们在这里做出决定的想法,我们决定是否可以呈现一个Figma形状的徽标并不重要。我们决定毫不留情地确定优先级:我们至少要做CSS能做的事情。

为了实现这一点,我们决定仅在应用长方体阴影的形状上实现类似CSS的阴影扩散参数:矩形、椭圆、框架背景和组件背景。这似乎可以通过做简单的事情来实现,或多或少-生成原始节点的更大或更小版本。它不像拉伸节点那样简单,因为这会在圆角之类的东西上分解。尽管如此,在我们的两个渲染引擎中生成新的矩形几何图形还是很容易的。

当然,没有什么事情像我们预期的那样直截了当。这个计划有几个问题:我们如何生成正确的椭圆?(椭圆的真正扩散阴影将不再是明确的椭圆;我们的椭圆生成代码不会生成非椭圆,椭圆上任一方向的简单变换都将保持其椭圆属性。)。当展开距离应用于圆角矩形时,我们将如何渲染圆角?(W3等级库定义了有关变换拐角半径的一般规则,以及用于较大跨接值的特定公式。)。我们如何在仅限笔划的节点上渲染阴影扩散,这在CSS中是一种未定义的行为?

我们用在CodePen中捣碎按钮的久经考验的科学解决了其中的一些问题,并观察了浏览器的功能。有趣的是,浏览器不会通过生成展开斑点来实现带有展开的椭圆阴影;它们只是简单地生成一个较大的椭圆。在决定主要做CSS做的事情之后,我们也这样做。

更令人惊讶的是,在遵循了W3C关于大扩散值阴影的角半径的特定立方规则(这是一个经过仔细考虑的规则!)之后,将我们的结果与快速CodePen进行了比较,结果表明,截至本出版物,浏览器根本没有实现这一点。要为圆角矩形创建阴影扩散,浏览器-以及现在的Figma-总是简单地添加或减去扩散值和原始角半径。

但是CodePen在为仅限笔划的节点定义阴影扩散行为方面没有任何帮助,因为我们的阴影方法已经与这里的CSS有了很大的不同。即使是完全透明的填充,也会在CSS中加入并遮蔽他们自己的阴影(尽管不是其他阴影);Figma采用了一种更接近于基于物理的渲染方法,允许用户通过透明和半透明填充看到阴影,而不包括阴影中不可见的几何图形。

下面,CSS(左)和Figma(右)中的相同矩形(零不透明度填充,带有描边和投影):

虽然很容易了解如何渲染具有填充的节点的阴影(左下),但您可能会想象以几种方式解释笔划的阴影扩散:

A.以跨页开始笔划,使笔划保持恒定B.将跨页添加到笔划宽度的外侧。c.将跨页添加到笔划宽度,居中使其分布在任一侧D。将跨页添加到笔划宽度的每个边缘,最终将2*跨页添加到笔划宽度。

在考虑了这些选项后,我们得出了D:我们认为当切换对象填充的可见性时,阴影的外部足迹应该保持不变,这就去掉了C。在剩下的选项中,D似乎最符合阴影扩散的概念:一个阴影,通过扩散沿着每个点挤出。

构建一个新功能并不总是像看起来那么简单。在解释功能请求时,重要的是要考虑该请求背后的动机,并考虑前面的人所做的权衡,这一点很重要。在这种情况下,在经历了一段曲折的调查和探索之旅之后,我们很高兴能推出一项广受欢迎的功能,希望它能让设计师和开发人员的生活变得更容易。查看我们的游乐场文件,了解阴影扩散的可能性!