Skip to Content
路漫漫其修远兮,吾将上下而求索
Content时间基 vs 帧基动画对比

时间基 vs 帧基动画对比

实际对比

左边是帧基动画(固定每帧旋转 2π/60 弧度,以60Hz为基准一秒转一圈),右边是时间基动画(2π 弧度/秒,一秒转一圈)。

帧基动画 (Frame-based)

Loading...

60Hz: 1秒/圈 | 120Hz: 0.5秒/圈 | 240Hz: 0.25秒/圈

时间基动画 (Time-based)

Loading...

任何刷新率: 恒定1秒/圈

核心区别

帧基动画

// 每帧旋转固定角度 const autoRotationSpeed = Math.PI * 2 / 60 // 60Hz基准:一秒转一圈 function animate() { requestAnimationFrame(animate) loadedModel.rotation.y += autoRotationSpeed renderer.render(scene, camera) }

问题

  • 60Hz 屏幕:每秒旋转约 2π 弧度(1圈)
  • 120Hz 屏幕:每秒旋转约 4π 弧度(2圈,速度翻倍
  • 240Hz 屏幕:每秒旋转约 8π 弧度(4圈,速度翻4倍

时间基动画

// 根据实际时间间隔计算旋转量 const autoRotationSpeed = Math.PI * 2 // 2π 弧度/秒(一秒转一圈) let lastTime = performance.now() function animate() { requestAnimationFrame(animate) const currentTime = performance.now() const deltaTime = Math.min((currentTime - lastTime) / 1000, 0.1) // 封顶 100ms lastTime = currentTime loadedModel.rotation.y += autoRotationSpeed * deltaTime renderer.render(scene, camera) }

关键代码对比

帧基版本

let animationId: number const autoRotationSpeed = Math.PI * 2 / 60 // 60Hz基准:一秒转一圈 const animate = () => { animationId = requestAnimationFrame(animate) if (loadedModel) { loadedModel.rotation.y += autoRotationSpeed } renderer.render(scene, camera) } animate()

时间基版本

let animationId: number let lastTime = performance.now() const autoRotationSpeed = Math.PI * 2 // 2π 弧度/秒(一秒转一圈) const animate = () => { animationId = requestAnimationFrame(animate) const currentTime = performance.now() const deltaTime = Math.min((currentTime - lastTime) / 1000, 0.1) // 封顶 100ms lastTime = currentTime if (loadedModel) { loadedModel.rotation.y += autoRotationSpeed * deltaTime } renderer.render(scene, camera) } animate()

时间基的额外保护

const deltaTime = Math.min((currentTime - lastTime) / 1000, 0.1)

Math.min(..., 0.1) 封顶非常重要:

  1. 标签页切换:用户切走时 rAF 暂停,切回来时时间差可能很大
  2. 显示器刷新率切换:外接显示器从 60Hz 切换到 144Hz
  3. 系统休眠唤醒:长时间休眠后恢复

适用场景

场景推荐方式原因
3D 模型旋转时间基需要一致的速度体验
游戏动画时间基物理模拟依赖真实时间
UI 微交互帧基可接受轻微速度差异不明显
数据可视化图表时间基需要精确的动画时长

总结

// ❌ 帧基 - 速度依赖刷新率(60Hz下1秒/圈,240Hz下0.25秒/圈) rotation += Math.PI * 2 / 60 // ✅ 时间基 - 速度恒定(任何刷新率都是1秒/圈) const deltaTime = (currentTime - lastTime) / 1000 rotation += Math.PI * 2 * deltaTime // ⚠️ 时间基 + 封顶 - 防止标签页切换后跳跃 const deltaTime = Math.min((currentTime - lastTime) / 1000, 0.1) rotation += Math.PI * 2 * deltaTime

结论:除非明确知道动画不需要恒定速度,否则都应该使用时间基动画。

Last updated on