第 5 课:时间与动画
动画是位置与时间的函数
Shader 中不必“移动一张图”才能做动画。只要颜色函数同时接受位置和时间,color = f(uv,time),每一帧给相同位置算出的颜色就会改变。本课从滚动条纹和颜色脉冲开始,逐步组合水流、雷达、心跳、电视雪花与点击涟漪。
JS 的渲染循环每帧接收 dt,以秒累加到 uTime。uTime 是 uniform:这一帧的每个顶点和片元读到同一个数。绘制时 GPU 根据它重新计算片元颜色。公共运行时会把异常大的单帧 dt 限到 0.05 秒,避免页面从后台回来时效果突然跳过很长一段;它是演示用的动画时间,不等同于严格的墙钟时间。实际项目若需要和音频或服务器时间同步,应选择相应时间源。
周期、相位与速度
sin(x) 的一个完整周期是 2π 弧度。sin(uTime * 2.0) 中的 2.0 是角速度,周期约为 2π/2 = 3.14 秒。若需要 2 秒一轮,可用角速度 2π/2 = π。第 2 题把 sin 的 -1–1 映射成 0–1,以此混合暗色和亮色。
滚动条纹把 uTime 加进空间相位:
float phase = fract(vUv.x * 7.0 + uTime * 0.25);
float stripe = step(0.5, phase);
vUv.x*7 是七个空间周期,每个周期有深浅两条,共十四条。+uTime 让保持相同相位的位置向左移动;换为减号则向右。移动速度取决于时间系数除以空间频率:这里约为 0.25/7 个 UV 单位每秒。只看时间系数容易误判实际位移速度。
把基础函数组合成常见效果
- 水流:先让
uv.y += amplitude*sin(uv.x*frequency-uTime*speed),把平直条带弯曲;再让采样相位随时间移动。幅度控制弯曲距离,频率控制波峰密度。 - 呼吸光环:半径
r(t)=base+amplitude*sin(ωt),片元以abs(length(p)-r(t))判断是否靠近圆环。时间改半径,距离决定轮廓,两者职责分开。 - 雷达扫描:
atan(p.y,p.x)把位置转换成角度,再减去旋转时间并用mod(...,2π)限到一圈。与半径遮罩相乘,避免扇形扩展到画布角落。 - 心跳:
pow(max(sin(phase),0),8)把正弦峰压窄,exp(-phase*k)提供较慢的余辉。高次幂先max到非负,避免对负值做不合适的幂运算。 - 扩散波纹:
sin((distance-speed*time)*frequency)的等相位曲线会随着时间向外移动;使用半径渐弱遮罩,可以让远处波纹逐渐消失。 - 电视雪花:把 UV 量化成小格,用
floor(uTime*18)生成离散帧号。随机函数对同一格和同一帧给出同一灰度,对下一帧给出新灰度,画面才像电视雪花,而不是每个像素连续缓慢闪烁。
第 9 题在画布 pointerdown 时,JS 读取画布的 getBoundingClientRect(),把指针坐标转成 0–1 UV,Y 轴再翻转,传入 uClick,并把 uAge 清零。片元以 length(vUv-uClick) 求到点击点的距离,让波前半径随 uAge 增大,再用指数衰减让它消失。当前版本只保存最近一次点击;若要同时存在多圈,需要维护多组位置和起始时间,可用 uniform 数组、粒子系统或纹理缓冲区。
数据流与工程实践
Three.js 把平面 position、uv 送到顶点 Shader,顶点 Shader 输出位置与 vUv,光栅化阶段插值后片元 Shader 根据 vUv 和 uTime 求颜色。点击题另外从 JS 传入 uClick/uAge。这样 JS 不必逐像素改图片,GPU 并行处理片元;代价是高分辨率、大量数学运算和多层采样会增加片元负载。
渲染循环只更新已有 uniform,不要每帧创建几何体、材质或纹理。时间长期累加会损失浮点小数精度,尤其在移动端 mediump;需要长时间运行的周期效果可在 JS 里对时间取模,或传入已经归一化的相位。sin、fract、mod 的周期边界是否连续取决于最终颜色函数:硬条纹适合接缝,平滑背景则要让周期两端颜色匹配。
排查顺序
动画不动:先查看 main.js 是否按 dt 更新对应 uniform、变量名是否一致;再把 uTime 直接映射到颜色确认值在变。速度异常:检查毫秒与秒、角速度与周期、空间频率与位移速度。鼠标波纹位置不对:检查画布矩形、页面滚动和 Y 轴翻转。图案突然跳变:检查 fract/mod 接缝和页面从后台恢复时的 dt。
练习
| 难度 | 题目 | 可见验收 |
|---|---|---|
| ⭐ | 时间驱动水平滚动条纹 | 条纹连续向左移动 |
| ⭐ | 正弦颜色脉冲 | 颜色平滑明暗变化 |
| ⭐⭐ | UV 扭曲与滚动水流 | 弯曲水纹流动 |
| ⭐⭐ | 半径随时间呼吸的光环 | 圆环周期伸缩 |
| ⭐⭐ | 极坐标雷达扫描 | 扇形持续旋转 |
| ⭐⭐⭐ | 短促心跳与慢速余辉 | 短亮脉冲与衰减 |
| ⭐⭐⭐ | 从中心扩散的波纹 | 同心亮纹向外移动 |
| ⭐⭐⭐⭐ | 时间切片的电视雪花 | 灰度噪点逐帧闪烁 |
| ⭐⭐⭐⭐ | 点击位置产生衰减涟漪 | 点击处扩散并渐隐 |