暗色背景中立着一棵树:树冠由许多深浅不一的三角面拼成,树干是几段暗红的折面,地上有一小片草影,左边挂着一轮白月亮。把鼠标移到树冠附近,靠近指针的那些面会被推开、整棵树跟着倾斜,移开鼠标后它们会一边摆动一边慢慢回到原位,像被风吹过。右上角有一个可折叠的面板,能实时调摆动速度、鼠标感应半径和旋转速度。技术上是原生 Canvas 逐面绘制,只额外用了一个参数面板库。
这棵树是怎么动起来的
每个顶点都记着自己的家。顶点保存原始坐标和当前坐标两套值,受扰后朝原始位置回拉,回拉力与偏离距离成正比,就是最简单的弹簧。
推力按距离衰减。鼠标与顶点的距离小于感应半径时才施加推力,越近推得越远,所以边缘的叶面只是轻轻颤动。
晃动靠阻尼而不是关键帧。速度每帧乘以一个小于一的系数,于是回弹会自然地来回几次再停下,不需要写任何缓动曲线。
低多边形的明暗是怎么来的
树冠没有贴图,每个三角面只填一种颜色,立体感全靠明暗差。源码的做法是给每个面一个基于朝向的固定亮度,朝上的偏亮、朝下的偏暗,再加一点随机抖动避免过于规整。这种做法的代价是光影不会随形变更新——树被推歪时,面的明暗还是原来的。要做到真实的光照,就得每帧重算面的法线,开销会明显上升。作为一个氛围装饰,源码选择了更划算的那一边。
能改的地方
控制面板上的三项可以实时调试,定下来后写回脚本顶部的同名变量。树的形状由一组顶点数据描述,换成别的造型需要替换这组数据;但换配色很容易,树冠、树干、草地、月亮的色值都是独立变量。感应半径调大会让整棵树对鼠标更敏感,调到很小则只有被直接掠过的叶片会动。
常见问题
树不动?
推力只在鼠标进入画布并靠近树冠时产生,先确认指针确实移到了树上。另外感应半径如果被调得过小,远处移动不会有任何反应。
手机上能用吗?
当前监听的是鼠标事件,触摸屏不会触发感应。改成指针事件即可支持触摸,改动只在事件绑定那几行;不过触摸端没有「悬停」,体验会变成点哪里动哪里。
那个控制面板能去掉吗?
能。它来自一个独立的参数面板库,删掉页面里对应的引入和脚本末尾的初始化调用即可,树本身的逻辑不依赖它。
适合用在哪
环保、自然、园艺类站点的首屏装饰,安静风格的个人主页,以及需要一点「可触碰」感的页面留白处。弹簧回弹、距离衰减与低多边形绘制的完整实现都在脚本里,下载后可查看。