如何用Three.js做3DHTML5动画_Three.js基础入门【3D教程】

6次阅读

Three.js 动画本质是手动管理 requestAnimationFrame 循环并更新物体属性再渲染;可用 TWEEN.js 实现精准补间,或用 GLB+AnimationMixer 加载预设动画。

如何用 Three.js 做 3DHTML5 动画_Three.js 基础入门【3D 教程】

Three.js 本身不提供“动画时间轴”或“关键帧编辑器”,它只负责把每一帧渲染出来;要做可控的 3D HTML5 动画,核心是自己管理 requestAnimationFrame 循环 + 修改物体属性(如 positionrotationscale),或用 TWEEN.js / GSAP 补间库驱动。

怎么让一个立方体转起来(最简可运行动画)

Three.js 的动画本质就是「在每帧里改状态,再调 renderer.render()」。没有自动播放、暂停、倒放——这些都得你写逻辑。

  • 必须手动调用 requestAnimationFrame(animate) 启动循环
  • 每次回调里要更新物体,比如 mesh.rotation.y += 0.01
  • 必须显式调用 renderer.render(scene, camera),否则画面不会变
  • 别忘了在 animate() 结尾再调一次 requestAnimationFrame,否则只执行一帧
function animate() {   requestAnimationFrame(animate);   mesh.rotation.y += 0.01;   renderer.render(scene, camera); } animate();

为什么 用 TWEEN.js 而不是手写 time += delta?

手算时间增量(delta)容易出错:帧率波动时,time += 0.016 这类固定步进会导致快慢不均;TWEEN 把起止值、缓动函数、持续时间封装好,自动按实际帧间隔插值,更稳也更易控制。

  • TWEEN.update() 必须在 requestAnimationFrame 回调里调用
  • 每个动画实例需手动 .start(),否则不触发
  • 默认使用 Date.now(),若需精确同步多个动画,建议传入统一时间戳给 TWEEN.update(timestamp)
  • 缓动函数名是字符串,比如 "easeInOutQuad",拼错不报错但没效果
const tween = new TWEEN.Tween(mesh.rotation)   .to({y: Math.PI * 2}, 2000)   .easing(TWEEN.Easing.Quadratic.InOut); tween.start(); 

function animate(t) {requestAnimationFrame(animate); TWEEN.update(t); // 传入时间戳 renderer.render(scene, camera); }

常见卡顿 / 掉帧原因和检查点

Three.js 动画卡,90% 不是代码写法问题,而是渲染层压力过大。浏览器 开发者 工具 的 Performance 面板能直接看到 requestAnimationFrame 是否超时、GPU 是否瓶颈。

立即学习 前端免费学习笔记(深入)”;

  • 每帧创建新材质(new MeshBasicMaterial())→ 内存泄漏 + GPU 上传开销剧增
  • 频繁修改几何体顶点(geometry.attributes.position.array)且没调 .needsUpdate = true → 渲染结果不更新或崩溃
  • 未启用 renderer.setAnimationLoop()(新版推荐)而用裸 requestAnimationFrame → 在页面切到后台时仍持续占用 CPU
  • 用了 OrbitControls 却没在动画循环里调 controls.update() → 拖拽后视角不动

动画导出与复用:GLB 比手搭更可靠

纯代码搭动画适合简单旋转平移,但复杂动作(角色骨骼、路径移动、多对象协同)建议用 Blender 做好后导出 GLB。Three.js 的 GLTFLoader 可直接加载带内嵌动画的 GLB,并用 mixer.clipAction() 控制播放。

  • Blender 导出时务必勾选「Include > Animations」和「Embed Textures」
  • mixer.update(delta) 是关键,delta 必须是秒为单位(如 clock.getDelta()
  • 多个动画同时播需分别 .play(),用 mixer.stopAllAction() 清场
  • GLB 里的动画轨道名(如 "Walk")需和代码中 clipAction("Walk") 严格一致,大小写敏感

真正难的不是让东西动起来,而是动得准、停得稳、切得顺——尤其是混合多个动画、响应用户交互、适配不同设备帧率时,手写逻辑很快失控。GLB + AnimationMixer 是生产环境更可持续的选择。

text=ZqhQzanResources