Bezier 曲线的妙用
贝塞尔曲线在设计软件中很常见,它可以根据控制点来得出一条平滑的曲线。不仅可以用作运动路径,还能作为时间插值使用。 本文介绍一下贝塞尔曲线在代码中的使用,以 JavaScript 为例。
二阶曲线
这是一个二阶贝塞尔函数,它需要传入 3 个点坐标,描述一个物体的运动曲线,然后根据时间 progress 计算出当前进度下的物体位置:
function bezier(x1,y1,x2,y2,x3,y3, progress) {
let px1=(x2-x1)*t+x1;
let py1=(y2-y1)*t+y1;
let px2=(x3-x2)*t+x2;
let py2=(y3-y2)*t+y2;
return[(px2-px1)*t+px1,(py2-py1)*t+py1]
}
用法如下:传入 3 个点的坐标,传入 progress 进度(取值 0 ~ 1)
let [cx, cy] = bezier(80,250, 200,30, 300,370, progress)
1.在 React 中使用
在 React 中,你可以用 setInterval(),结合状态做到动画。
export function Widget() {
// 定义 progress 状态
const [progress, setProgress] = useState(0)
useEffect(() => {
let frame = 0
let interval = setInterval(() => {
// 每帧(16ms)刷新一次
setProgress( ((frame++ * 16) % 5000) / 5000 )
}, 16)
// 组件卸载时记得清理定时器
return () => { clearInterval(interval) }
}, []);
// 计算小球位置
let [cx, cy] = bezier(80,250, 200,30, 300,370, progress)
return (
<svg width={400} height={400}>
{/* 绘制小球 */}
<circle cx={ cx } cy={ cy } r={10} fill="#FFD93FFF"/>
</svg>
)
}
效果如下
2.在 AE 中使用
在 AE 表达式中,可以通过 time 属性 + linear() 函数来获得 progress。
// 在 3秒 ~ 5秒 的时候,进度从 0 进行到 1
let progress = linear(time, 3, 5, 0, 1);
有了 progress 之后就和之前一样好办了,只需要调用 bezier() 计算出坐标,然后给到图层的位置属性就可以了。
可以给图层的位置属性设置表达式:
// 在 3秒 ~ 5秒 的时候,进度从 0 进行到 1
let progress = linear(time, 3, 5, 0, 1);
// 复制bezier函数到这里
function bezier(){ ... }
// 调用它
let pos = bezier(.../*自行设置*/, progress);
// 返回坐标
[pos[0], pos[1]];
3.在 Remotion 中使用
在 Remotion 中可以使用 useCurrentFrame() 结合 interpolate() 来映射时间范围到 progress。
// 获取当前时间(帧)
const frame = useCurrentFrame()
// 在第 30 到 90帧 的时候,进度从 0 进行到 1
const progress = interpolate(frame, [30, 90], [0,1])
之后就和 React 中使用没有差别了。
三阶曲线
三阶贝塞尔曲线,待补充。
最后修改:2025年09月03日