第 6 章 · 传动装置:动画与交互 章节摘要:本章给沙盘装上传动装置:渲染循环是整条产线的心跳,一切动画都在心跳上跑;动画剪辑与混合器负责让模型的骨骼动起来;手写缓动负责让物件与机位优雅移动;射线拾取负责把用户的点击翻译成场景里的命中事件。 一条主线 沙盘静态验收全过,客户的下一句话是标准的:"能不能动?"——叉车要能开一圈、传送带要能转、点一下货箱要能弹出信息卡。这三件事在 Three.js 里共用同一个底层装置:每一帧重算并渲染。动画不是"播放一个视频",交互也不是"响应一个事件"——它们都是"每帧根据时间与状态重新摆好场景",区别只是谁在摆:动画系统按剪辑摆、手写代码按缓动摆、物理引擎按仿真摆。 主线从心跳的节拍谈起。1.
章节摘要:本章给沙盘装上传动装置:渲染循环是整条产线的心跳,一切动画都在心跳上跑;动画剪辑与混合器负责让模型的骨骼动起来;手写缓动负责让物件与机位优雅移动;射线拾取负责把用户的点击翻译成场景里的命中事件。
沙盘静态验收全过,客户的下一句话是标准的:"能不能动?"——叉车要能开一圈、传送带要能转、点一下货箱要能弹出信息卡。这三件事在 Three.js 里共用同一个底层装置:每一帧重算并渲染。动画不是"播放一个视频",交互也不是"响应一个事件"——它们都是"每帧根据时间与状态重新摆好场景",区别只是谁在摆:动画系统按剪辑摆、手写代码按缓动摆、物理引擎按仿真摆。
主线从心跳的节拍谈起。1.2 节的工装底座里已有 setAnimationLoop,但"每帧做什么、按什么节奏做、帧率不稳怎么办"三个问题从未展开。本章 6.1 先把节拍器校准(时间增量 dt 的意义、帧率无关动画的写法),6.2 再接传动系统(官方动画系统与手写缓动两条传动链各自适合什么活),最后 6.3 把交互这根操纵杆接进传动箱(射线拾取如何把屏幕坐标反投影成场景射线)。
第一站 6.1 传动轴:渲染循环与时钟。Clock 的增量时间与累计时间各是什么、为什么旋转要乘 dt、动画逻辑与渲染调用在循环里的先后纪律。这一站的产出是一条"帧率无关"的心跳——同一份代码在 144 帧电竞屏与 30 帧办公机上转速一致。
第二站 6.2 动画系统:剪辑、混合与手写缓动。外协模型自带的动画片段(第 5 章转交来的 clips)如何用 AnimationMixer 播放、多条剪辑怎么混合过渡;自制的属性动画(浮沉、变色、缩放脉冲)如何用缓动函数写出手感。两条传动链的分工表是本站的核心交付。
第三站 6.3 拾取交互:射线检测与命中处理。Raycaster 把屏幕上的一个点反投影成场景中的一条射线,命中列表按距离排序;过滤策略决定"点得准不准",命中分层决定"点了之后走哪条业务"。点击、悬停、拖拽三类交互在同一套射线上长出来。
本章的认观转折在 6.1 的"帧率无关":写 cube.rotation.x += 0.01 这类代码时,动画速度实际与帧率绑定——高刷屏转得飞快、低配机慢如老牛。乘上 dt 之后,速度单位从"每帧"变成"每秒",任何设备上一致。这是从"会跑"到"专业"的分水岭,成本只是一个乘法。
第二个转折在 6.2 的分工:官方动画系统强在"时间轴上的编排"——剪辑、过渡、混合都是它的母语;手写缓动强在"状态间的插值"——两个数值之间走出优雅曲线。模型自带的骨骼动画交给前者,界面级的属性动画交给后者,硬用一套去干另一套的活,代码立刻扭曲。
传动装置是全册的汇聚点:心跳与 dt 来自第 1 章的工装底座,动画剪辑来自第 5 章的片段转交,运镜缓动与第 4 章的一键特写共用同一套插值思路,拾取命中接的业务层(信息卡、机位特写)把第 4 章的交互闭环补完。它同时也是第 7 章的上游:物理引擎的每帧 step、粒子的逐帧更新,全都要挂在 6.1 校准好的心跳上——心跳不稳,精装修全是歪的。倒读的读者可以从 6.1 入手,那是理解全书所有"每帧"类代码的总开关。
传动装好,沙盘已"能玩"。下一章进精装修工段:自定义着色器给表面换装、后期处理链给画面抛光、粒子与物理给场景加戏——每一样都好看,每一样都费预算,所以它们在品质环节,不在主体装配线。