零依赖的 Canvas2D / WebGL 动效:一群鸟在三维空间里按 boids 规则群飞,会躲开鼠标。
复刻自 Vanta 的 BIRDS 效果(原实现源自 three.js 示例 canvas_geometry_birds)。
Vanta 的 vanta.birds.min.js 只有 28KB,但它要求你先引入 800KB 的 three.js,而且群集规则跑在 GPGPU 上。这个仓库把那套东西翻译成了不依赖任何库的实现。
index.html 打开就是一个可调参的演示页:拖动滑块即时生效,地址栏同步更新 —— 把链接发给别人,看到的就是同一群鸟。
# 直接双击 index.html 也行(无依赖、无构建、可离线)
open index.html参数全部走 URL:
?color1=b9531c&color2=b9f5bc&colorMode=varianceGradient&quantity=4&birdSize=0.8&wingSpan=25&speedLimit=4&separation=46&alignment=11&cohesion=20
| 参数 | 默认 | 说明 |
|---|---|---|
color1 / color2 |
b9531c / b9f5bc |
调色板两端(六位十六进制,不带 #) |
colorMode |
varianceGradient |
取色方式,见下表 |
quantity |
4 |
鸟数 = (2^quantity)²;4 → 256 只,5 → 1024 只 |
birdSize |
0.8 |
鸟的尺寸 |
wingSpan |
25 |
翼展 |
speedLimit |
4 |
速度上限 |
separation / alignment / cohesion |
46 / 11 / 20 |
boids 三力的作用半径(原版语义) |
colorMode 四档(与 Vanta 官网面板同款):
| 值 | 效果 |
|---|---|
varianceGradient(默认) |
三通道各取独立随机数 c1 + rand×c2 再 clamp,每个顶点都重新取色 → 鸟身带渐变,整体色阶跳动最大 |
variance |
同上,但每只鸟一个颜色 |
lerpGradient |
沿 c1→c2 直线插值,每顶点随机 → 颜色永远落在这两色之间,最柔和 |
lerp |
同上,但按鸟的序号在渐变上排开 |
原版是 three.js + GPGPU:群集规则写在 fragment shader 里,位置/速度存在两张浮点纹理上 ping-pong,翅膀摆动在顶点着色器里。这里的做法:
- 群集规则:把
fragmentShaderVelocity逐条翻译成 CPU 版 —— 分离 / 对齐 / 聚合三段的分段函数、zoneRadius阈值、向心吸引(含dir.y *= 2.5那个细节)、鼠标"天敌"半径 150、speedLimit截断,全部照抄 - 渲染:位置/速度仍按原版上传成两张浮点纹理,顶点/片元着色器逐行照搬 → 一次
drawArrays画完 N×9 个顶点,颜色在三角形内插值出渐变 - 几何:每只鸟 3 个三角形(身体 / 左翼 / 右翼),翼尖顶点靠
sin(phase)摆动;reference属性按原版规则指向 boid - 帧率无关:原版 GPU 版用
delta秒推进,所以这套也是——同样参数在任何刷新率上速度一致
性能:256 只鸟每帧 65536 次邻居配对 + 一次 draw call。CPU 侧约 2~3ms/帧。 WebGL 不可用时自动退回 Canvas2D(每只鸟一条线性渐变近似顶点插值),左下角会显示当前用的是哪个渲染器。
BirdsField.tsx 是现成组件("use client",fixed 全屏 canvas,自带 resize、鼠标交互与卸载清理),顶部常量就是上面那张参数表:
import BirdsField from "./BirdsField";
<div style={{ position: "relative", height: "100vh" }}>
<BirdsField zIndex={0} />
</div>复制 index.html 里画布部分的代码即可,没有任何依赖。核心就是三块:stepVelocity()(群集)、两张浮点纹理、一次 drawArrays。
把原版(three.js + GPGPU)和这套实现用同样的参数、同样的画布尺寸各自渲染后对比:
| 指标 | 原版 Vanta | 本实现 |
|---|---|---|
| 画布 | 1280×713 | 1280×713 |
| 亮部像素 | 3747 | 4870 |
| 调色板均值 | rgb(178,162,123) | rgb(182,167,121) |
| 每通道标准差 | 75 / 72 / 57 | 75 / 69 / 51 |
| 与紧邻像素同色的比例(越低越说明有渐变) | 1.4% | 1.8% |
最后一行是关键:平铺填充会到 75%,1% 量级说明顶点颜色插值出来的渐变确实在。
这是一个复刻,不是原创效果的诞生地:
- 原效果:three.js 示例
canvas_geometry_birds(@mrdoob 及 three.js contributors) - 本仓库复刻的是 Vanta 收录的
BIRDS版本 —— MIT, © 2020 Teng Bao
本仓库代码以 MIT 发布,见 LICENSE。
