点一下「开始音频可视化」,画面就变成一条穿行在数字地形里的飞行镜头:下方是一整片绿色的三角网格地面,上方是一片蓝色的镜像「天空」,两层网格都随着音乐起伏——低频让近处的山脊猛地拱起,高频在远处抖出细碎的尖峰。鼠标在画面上移动可以改变视角,按住左键会加速前进。技术上是 Web Audio 的频谱分析配原生 Canvas,而且没有用 Canvas 的画线 API,整幅画面是逐像素写进去的。
这份源码的三个特别之处
线是自己画的。脚本没调用 moveTo/lineTo,而是拿到一整块像素数据后,用布雷森汉姆算法逐点写像素再一次性贴回画布,几万条线段只产生一次绘制调用。
三维投影只有两行。没有引入任何 3D 库,透视靠的是「焦距除以焦距加深度」得到缩放系数,再乘以原始坐标,就是最基本的针孔相机模型。
地形是循环复用的。网格按固定步长向镜头推进,越过镜头的那一排不会销毁,而是回到最远处重新取一次音频强度,所以地形可以无限延伸而内存不涨。
频谱是怎么变成山脉的
关键在于给每个网格点分配一个固定的频段序号。建网格时序号从 8 开始逐点递增,超过上限就绕回去:
var scale = fov / (fov + particle.z);
每帧读出整条频谱后,网格点按自己的序号取对应频段的强度当作高度。序号是连续分配的,所以相邻的点拿到的是相邻频段,地形起伏才是连贯的波形,而不是一片随机噪点。起始序号跳过了最低的 8 个频段,因为那几档是直流与极低频,数值长期偏高,会让近处的地面整体被顶起来。
能改的地方
推进速度、加速上限、焦距(也就是透视强度)都是脚本开头的变量,焦距同时决定了网格的覆盖范围,改动后建议一起调网格步长。地面与天空的配色在绘制循环里按高度插值,换成暖色系就是另一种氛围。换音乐只需替换音频文件路径;频谱精度由分析器的 fftSize 控制,调小会让山脊更平滑、性能更好。
常见问题
点了按钮没有声音也不动?
浏览器要求音频必须由用户手势启动,所以页面用了一个起始按钮;如果仍然无声,多半是音频上下文处于挂起状态,需要在点击回调里显式恢复它。另外页面要通过本地服务器打开,直接双击 HTML 会因跨域限制而拿不到频谱数据。
画面卡顿怎么办?
逐像素写入的开销和画布面积成正比,全屏高分屏下压力较大。把网格步长调大、或者给画布设一个固定的较小尺寸再用 CSS 拉伸,都能明显改善。
可以接麦克风输入吗?
可以。把音频源从 Audio 元素换成麦克风的媒体流,接到同一个分析器上即可,后面的地形逻辑完全不用改。
适合用在哪
音乐现场与电子音乐活动的主视觉、播客站点的播放页背景、科技感开场动画,也是一份很好的「不用 3D 库做透视投影」的教学范例。像素级画线、透视换算与频谱映射的完整实现都在脚本里,下载后可查看。