Tech
贝塞尔曲线及其背后的逻辑
概要:
贝塞尔曲线广泛应用于网页和图形设计中,用于实现平滑的曲线效果。理解曲线背后的基本逻辑,可以更好地应用它。贝塞尔曲线由多个控制点定义,通过这些控制点及其控制手柄,可以精确控制曲线的形状和方向。曲线上的每个点,可以通过多次线性插值计算获得。三次贝塞尔曲线在SVG和CSS动画中很常见。SVG路径可以利用三次贝塞尔曲线命令画出复杂曲线;CSS中的三次贝塞尔缓动函数可以自定义复杂的动画效果。学习透彻贝塞尔曲线的原理,可以丰富网页动效的创作手段,获得更大的自由度。代码与数学结合,可以产生无限的艺术创作可能。
贝塞尔曲线一直是我前端工程职业生涯中的一个重复主题。我在工作中广泛使用它们——在插图、图标的动画和SVG路径中。然而,我直到最近才对支配它们行为的基本逻辑产生兴趣。这为我消除了与曲线相关的路径命令的神秘感,并让我对网页动画有了更深刻的理解。在本文中,我将分享关于贝塞尔曲线的有趣发现。
在CSS动画中,缓动函数指定属性随时间变化的速率。有三种类型的缓动函数——线性、阶跃和三次贝塞尔。
线性缓动:线性通常用于以恒定速率/速度对属性进行动画处理。
阶跃缓动:阶跃用于以相等的时间间隔对属性进行动画处理。
三次贝塞尔缓动:三次贝塞尔用于以可变速率/速度对属性进行动画处理。
如ease、ease-in、ease-out和ease-in-out等预定义的CSS缓动以及常用的平滑缓动如以正弦为基础的缓入和以三次方为基础的缓入都是三次贝塞尔缓动函数的例子。自定义缓动也可以通过三次贝塞尔缓动函数生成。
CSS中的缓动函数计算动画的加速和减速方式。生成的动画路径可以在缓动图中表示,其中x轴是动画的进度,y轴是变化的程度。三次贝塞尔缓动函数在(0,0)和(1,1)处有固定的锚点,对应于动画的开始和结束点。三次贝塞尔曲线函数cubic-bezier(<x1>, <y1>, <x2>, <y2>)中的两个控制点设置了定义动画平稳加速和减速的曲线。通过将这些控制点设置为与固定锚点相同的值cubic-bezier(0, 0, 1, 1),可以使用三次贝塞尔缓动函数生成线性路径动画。
与CSS动画类似,视觉元素具有线性和曲线路径。几个连接的贝塞尔曲线用于为字体、图标、插图、数据可视化图表、3D对象和其他视觉元素中的简单和复杂形状添加曲线。直线仅由起点和终点定义,而贝塞尔曲线除了起点和终点之外,还由一个或多个控制点定义。贝塞尔曲线方程的最高次确定点的数量。顾名思义,二次贝塞尔曲线的次数为2(3个点),三次曲线的次数为3(4个点)。
二次贝塞尔有3个控制点,三次贝塞尔有4个控制点。
在连接的贝塞尔曲线中,控制点经常有两个从中延伸出来的控制柄。这些控制柄可精确控制曲线的方向。
贝塞尔控制柄
控制柄的角度和长度可以是对称的、不对称的,甚至是不连接的,以定义所需的形状。每一种模式都会对连接点产生不同的行为。
Photoshop和Figma等设计工具提供在这些控制柄模式之间切换的灵活性,允许用户快速创建更复杂的形状和图案。
当对称时,控制柄的角度和长度始终对称,使相连的曲线在大多数情况下保持平滑。
SVG路径和HTML canvas可用于在网页上绘制平滑曲线。它们都有二次和三次贝塞尔曲线命令和功能。在本文的其余部分,我将关注SVG中的三次贝塞尔曲线。
SVG路径元素用于创建复杂形状。路径由其d属性定义,该属性包含指示如何在viewport中绘制它的命令。可以使用Q(二次)或更复杂的C(三次)命令绘制曲线路径。三次命令C x1 y1,x2 y2,x y需要3个点 - p1、p2和p3。p0始终是路径中前一个命令的终点。
SVG视口
SVG视口由width和height属性设置,定义了SVG的边界。在200 x 200的视口中,一个d属性为M C 的路径会生成一条起点在()结束于()的曲线。
超出视口的形状通常是隐藏的,但可以通过将SVG溢出设置为visible来公开。
复杂的向量是通过路径和其他SVG元素的组合创建的。单个路径通常包含多个连接的三次贝塞尔曲线。这在图标、logo和插图中很常见。
在试图理解沿着贝塞尔曲线路径派生点的方式时,我了解到贝塞尔曲线(以法国工程师皮埃尔·贝塞尔的名字命名),在上世纪60年代被用来为雷诺汽车的车身设计曲线。有几种方法可以获得贝塞尔曲线中的点,但我最喜欢的解法是Casteljau算法,下面简要解释一下。
让我们开始计算起点p0和终点p1之间直线上的点。每个点都有相应的x轴和y轴值,直线的进度可以表示为t,它在0(开始)和1(结束)之间。我们可以使用线性插值函数lerp(p0,p1,t)= p0 + (p1 - p0)* t,在任何给定的t值获取直线上一点的坐标。
对于p0在(0,0)、p1在(0,30)的直线,中点即t=0.5是(0,15),这是0 + (0 - 0)* 0.5 = 0和0 + (30 - 0)* 0.5 = 15的结果。
与直线类似,贝塞尔曲线的进度也可以由t定义。使用卡斯蒂艾姆算法,我们可以在给定的t处获得三次贝塞尔曲线路径的点坐标。
p4 = lerp(p0, p1, t)
p5 = lerp(p1, p2, t)
p6 = lerp(p2, p3, t)
p7 = lerp(p4, p5, t)
p8 = lerp(p5, p6, t)
bt = lerp(p7, p8, t)
我们通过对三次贝塞尔曲线的控制点和锚点的线性插值函数输出进行嵌套线性插值,来实现这一点。
了解贝塞尔曲线背后的逻辑让我在实验SVG路径和三次贝塞尔缓动函数方面有了更多尝试,我在为本文构建交互组件时(查看原文可以看到交互图例)应用了这些知识。这种知识为我解锁了创作可能性,我希望这能激发你去创造下一个有趣的作品。
本文译自 Richard Ekwonye,由 BALI 编辑发布。