🎬 开场白
前几章我们已经让立方体旋转得像勤劳的小村民🧱、粒子飘得像天上的蒲公英🌬️、球体上下蹦跶得像村口的小兔子🐇。可是,你有没有想过,这些“动作背后的小秘密”到底是什么?为什么模型们能动?为什么它们看起来又自然又炫酷✨?今天,我们就要揭开 Three.js 动画的魔法面纱🪄。
首先,时间是模型的灵魂⏳。Clock 就像新手村的日晷🕰️,告诉每个模型:“嘿,该动啦!”
然后,requestAnimationFrame 就是贴身小助理🤖,提醒模型每一帧都要更新动作,不让它们卡住或掉队🚀。
最后,旋转、位移、粒子漂移这些动作,就像舞步设计师💃精心安排的舞蹈,让每个模型都有自己的专属节奏🎵。
想象一下,当立方体不再只是旋转,而是随着音乐节奏轻轻晃动🎶,球体上下起伏像在做热身操🤸,粒子像小烟花🎇般跳跃——整个新手村就像开了蹦迪派对🕺!而你,就是那位幕后 DJ🎧,控制节奏、指挥舞步,让模型们尽情炫技💥。
| 特性 | requestAnimationFrame | THREE.Clock |
|---|---|---|
| 角色 | 贴身小助理🤖 | 新手村的日晷🕰️ |
| 功能 | 每一帧提醒浏览器“该渲染啦!” | 精确记录时间,告诉模型“你该动多少啦!” |
| 控制对象 | 场景刷新、渲染循环 | 动画 Mixer、模型动作更新 |
| 更新频率 | 与屏幕刷新率同步(通常 60fps) | 根据 deltaTime 计算每帧动作增量 |
| 优点 | 自动节省 CPU、平滑动画、不丢帧 | 精确掌控动画节奏,动画与时间解耦 |
| 使用场景 | 渲染循环、游戏主循环 | 动画 Mixer 更新、基于时间的动作控制 |
| 幽默比喻 | “小助理喊你起床啦,每一帧都不让你赖床!” | “日晷告诉你现在几时,该走几步舞蹈啦!” |
| 经典用法 | requestAnimationFrame(animate) | const delta = clock.getDelta(); mixer.update(delta) |
💡 小结:
requestAnimationFrame是循环的节拍器,每一帧都敲鼓提醒模型更新画面。THREE.Clock是时间计量器,让每个动作按照真实时间的节奏移动,而不是盲目“跳舞”。
想象一下,如果没有 requestAnimationFrame,模型就像缺少 DJ 的舞蹈班,动作可能乱套;
如果没有 Clock,模型就像跟随错乱的节拍跳舞,或者快慢不一,看起来奇怪又滑稽😆。
在接下来的篇章里,我们将带你从基础动作升级到 综合舞步秀💃🕺,教你如何用几行代码,让模型们旋转、跳跃、漂浮、闪烁,彻底嗨翻新手村🎉!
准备好了吗?让我们给模型们开个 炫酷舞蹈课堂🪩,动次打次,开始吧!
requestAnimationFrame 使用指南
1:基础认知
requestAnimationFrame的触发频率通常和显示器的刷新率保持同步。
也就是说,如果你的屏幕是 60Hz,那么rAF理论上每秒会触发 60 次;如果是144Hz 屏幕,就可能达到 144 次。
这比用setInterval(fn, 16)来模拟 60 FPS 更精准,因为 rAF 会和浏览器的渲染节奏对齐。
2:浏览器机制
不过,这并不意味着
rAF就一定和刷新率完全相等。
浏览器在调度rAF时,还要看主线程是否空闲:
如果JavaScript执行太慢,导致一帧没来得及渲染,下一帧rAF就会掉帧。
所以在 144Hz 屏幕上,如果代码性能不足,实际FPS可能还是 60 或更低。
3:性能与优化
rAF相比setInterval的一个优势是:
它只会在页面可见时运行;后台标签页会自动降速甚至暂停,节省性能。
而setInterval则会傻傻地不停执行,浪费资源。
此外,rAF的回调会在浏览器 重绘之前 执行,这保证了动画和渲染同步,避免出现“撕裂”或卡顿。
4:深入探究
从底层来看,
rAF的回调是和浏览器渲染管线对齐的。
浏览器会等待显示器的 VSync信号 (垂直同步),在下一帧真正绘制前统一调用rAF的回调。
所以可以理解为:显示器刷新 → 浏览器捕获VSync→ 调用rAF回调 → 执行JS更新动画 → 浏览器绘制 → 下一帧。
这就是为什么rAF的动画通常比setInterval更流畅、更稳定。
🎯 总结
requestAnimationFrame的触发频率取决于浏览器的渲染管线,它会尽量和显示器刷新率保持同步(例如 60Hz ≈ 60FPS),但也会受到主线程性能和浏览器优化机制影响。它的优势在于帧同步和节能优化,是实现流畅动画的最佳实践。
⏱THREE.Clock 使用指南
| 属性/方法 | 作用 | 返回值 | 使用场景 | 幽默比喻 |
|---|---|---|---|---|
clock.getDelta() | 获取自上次调用以来的时间间隔(秒) | Number | 动画更新:计算模型移动、旋转的步幅 | “告诉舞者,上次摇摆多久啦,该换步伐了!” |
clock.getElapsedTime() | 获取 Clock 启动到现在的总运行时间(秒) | Number | 用于控制动画进度或时间相关效果 | “日晷说:你已经在场景里蹦了多久啦?” |
clock.start() | 启动 Clock(从 0 或上次暂停处计时) | 无 | 初始化动画计时器 | “给日晷上弦,滴答滴答开始计时!” |
clock.stop() | 停止 Clock,暂停计时 | 无 | 暂停动画或调试 | “让日晷休息一会儿,暂停跳舞派对。” |
clock.elapsedTime(只读) | 内部属性,记录总计时 | Number | 通常不直接使用,偏调试 | “偷偷看看日晷的总滴答数。” |
使用小贴士 💡
- Clock 本身不控制动画,它只是提供时间信息。
- 动画是否活跃、播放、暂停,需要通过
AnimationMixer或自定义逻辑判断。 requestAnimationFrame就是你每天叫醒模型、让它们动起来的小助理,每一帧都提醒 Clock 看看时间到了没,再让舞者跳舞。
📢 新手村村长的动画通告
村民们注意啦!接下来要聊的是让模型蹦迪的三大流派。每个流派都有自己的风格,就像学跳舞,有人自嗨,有人跟着健身操,还有人干脆上舞蹈学院。下面开始点名!
🥁 1. 手动驱动流派:自嗨型选手
- 原理:直接在
requestAnimationFrame里一帧一帧地修改属性,比如位置、旋转、缩放。 - 风格:像自己在家开迪厅,没人管你,动作随心所欲。
- 优点:超自由,想让立方体翻跟头还是侧空翻,全凭你喊口令。
- 缺点:每个动作都得你手写,写久了容易变成“代码健身操”。
function animate() {
requestAnimationFrame(animate); // 一帧一帧叫醒立方体
// 🎉 动作随心所欲
cube.rotation.x += 0.05; // 翻跟头
cube.rotation.y += 0.03; // 侧空翻
cube.position.y = Math.sin(Date.now() * 0.005) * 1; // 上下蹦跶,像蹦床高手
renderer.render(scene, camera); // 渲染当前帧
}
💃 2. Tween补间流派:请个健身教练
啊哈,Tween 是动画领域的一个小明星,通俗点说,它就是 “帮你在两种状态之间平滑过渡的小精灵😎” 。
- 原理:设定起点和终点,库(如
GSAP)自动帮你把中间的动作补齐。 - 风格:像去上健身操,你只要说“我要从沙发走到冰箱,用 2 秒”,教练会让你走得优雅还带节奏感。
- 优点:代码简洁,动作平滑,炫酷效果手到擒来。
- 缺点:复杂动作多了,像同时上十节健身课,排程容易乱。
// GSAP 旋转动画
let rotateTween;
function rotateCube() {
rotateTween = gsap.to(cube.rotation, {
x: "+=6.28",
y: "+=6.28",
duration: 4,
repeat: -1,
ease: "power1.inOut",
});
}
点击可以重置动画哦
🎤 3. 骨骼动画流派:专业舞团登场
想象你有一个玩具娃娃,你不可能直接抓着手让它摆各种姿势而看起来自然。
但是,如果娃娃有内部骨架,你就能控制每个关节,轻松让它做“空翻、手舞足蹈、比心动作”,甚至拍成微电影!
这就是骨骼动画:小骨头控制大身躯,动作自然又酷炫,而你只需要当导演就行。
- 原理:模型内部有“骨头”,通过
AnimationMixer控制,每个关节都能动。 - 风格:这是职业舞团级别的,能跳科目三、街舞甚至钢管舞。
- 优点:超自然,角色能像真人一样活动。
- 缺点:门槛高,新手可能一看骨头就想逃课。
📢 在 Three.js 中,你看到的模型之所以会动,不是魔法,而是因为它本身就“自带剧本”。这些模型在建模软件里被赋予了骨骼和动作——每个动作其实就是一段关键帧动画(AnimationClip),像给模型写好的舞蹈教程。Three.js 的 AnimationMixer 就像舞蹈老师,把这些动作讲给模型听,让它按照指令动起来。后续我们会详细拆解这些动作是如何产生、如何导出,以及如何在 Three.js 中播放和混合,让模型从静止变得活灵活现。
⏱ 动画工具对比表
| 工具 | 用途 | 类型 | 优点 | 小幽默 |
|---|---|---|---|---|
requestAnimationFrame(callback) | 每帧触发动画 | 函数 | 自动与浏览器刷新同步,省电、不卡顿 | “小助理在耳边喊:嘿,该动啦!” |
THREE.Clock | 记录时间流逝 | 对象 | 精准计算 deltaTime,适合统一动画节奏 | “新手村的日晷告诉你:现在该旋转多少度了!” |
clock.getElapsedTime() | 获取总运行时间 | 数字 | 判断动画进度、循环控制 | “看看模型跳了多久,够不够炫酷?” |
clock.getDelta() | 获取两帧间隔 | 数字 | 平滑动画、时间步控制 | “每帧都不差分毫,模型跳得更稳!” |
🌟 结尾
恭喜你!模型终于学会动次打次、旋转、跳跃、甩头发了。
你现在已经是 Three.js 动画大师,连村口的大妈看到模型也会惊呼:“哎哟,这跳得比我孙子还灵活!”
更妙的是,你在练动画的时候,还顺带练了 节奏感、时间观念 和幽默感。
下一章,我们要给它们加上 互动魔法——鼠标点一点、拖一拖、点开一开,它们都会乖乖听话,做出酷炫动作!🎮✨
准备好让新手村里的模型们 从蹦迪派对 🕺 到炫酷表演舞台 💃 吗?
你的指挥棒已经就位,音乐响起,舞台属于你和你的模型们!💥