关于 threejs-impl-audio
面向 Three.js 开发者的场景音频实现参考技能,介绍普通播放、空间音频、文件加载及频率分析。也说明浏览器对用户交互和音频上下文的要求。
主要功能
- 01音频监听器与播放设置
- 02全局音频和 3D 空间音频
- 03音频文件加载与播放控制
- 04浏览器音频交互要求
- 05用于可视化的频率分析
适用场景
- 01添加背景音乐或 UI 音效
- 02在场景中放置随距离变化的声音
- 03可视化音频频率数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-impl-audio安装后在 Claude Code 中输入/threejs-impl-audio确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-impl-audio
快速参考
类层次结构
EventDispatcher
└── Object3D
├── AudioListener (receiver — attach to camera)
├── Audio (non-positional — background music, UI sounds)
└── PositionalAudio (3D spatial — attached to scene objects)
辅助类:
AudioLoader— 将音频文件加载到AudioBufferAudioAnalyser— 用于可视化的实时频率分析
架构概览
| 组件 | 作用 | 附加到 |
|---|---|---|
AudioListener | 虚拟耳朵(Web Audio API 输出端) | 摄像机(始终) |
Audio | 非位置音效(任何位置的音量都相同) | 任意 Object3D 或场景 |
PositionalAudio | 3D 空间音效(音量取决于距离) | 场景中的网格或 Object3D |
AudioLoader | 异步音频文件加载器 | 不适用(工具) |
AudioAnalyser | FFT 频率数据提取器 | 包装一个 Audio 实例 |
重要警告
绝不要在未先确保用户交互后已恢复 AudioContext 的情况下调用 sound.play()。现代浏览器始终会挂起 AudioContext,直到发生用户手势(点击、轻触或按键)。
绝不要在同一场景中创建多个 AudioListener。多个监听器会导致未定义的空间化行为。
绝不要设置 autoplay = true 并期待无需用户交互即可播放。浏览器会静默阻止播放。
始终将 AudioListener 附加到摄像机。如果附加到其他对象,空间音频计算会使用错误的参考位置。
始终在用户交互处理程序中调用 listener.context.resume(),然后再播放任何音频。
绝不要忘记处理 AudioLoader.load() 中的 onError 回调。音频文件缺失时,如果没有错误处理,加载会静默失败。
AudioListener 设置
AudioListener 是场景的虚拟麦克风。它封装了 Web Audio API 的 AudioContext 和 AudioDestinationNode。
import * as THREE from 'three';
const listener = new THREE.AudioListener();
camera.add( listener ); // ALWAYS add to camera
主音量控制
listener.setMasterVolume( 0.8 ); // range [0, 1]
const vol = listener.getMasterVolume(); // returns 0.8
全局音频滤波器
const filter = listener.context.createBiquadFilter();
filter.type = 'lowpass';
filter.frequency.value = 1000;
listener.setFilter( filter );
// Later: listener.removeFilter();
Audio(非位置音效)
使用 Audio 播放背景音乐、环境音景和 UI 反馈音效。无论监听器的位置如何,音量都相同。
加载和播放
const sound = new THREE.Audio( listener );
const audioLoader = new THREE.AudioLoader();
audioLoader.load( 'music.mp3', ( buffer ) => {
sound.setBuffer( buffer );
sound.setLoop( true );
sound.setVolume( 0.5 );
// Do NOT call sound.play() here — wait for user interaction
});
遵守自动播放策略(必须)
document.addEventListener( 'click', () => {
if ( listener.context.state === 'suspended' ) {
listener.context.resume();
}
if ( !sound.isPlaying ) {
sound.play();
}
}, { once: true } );
播放控制
sound.play(); // start playback
sound.pause(); // pause (resume with play())
sound.stop(); // stop and reset to beginning
sound.setPlaybackRate( 1.5 ); // 1.5x speed
sound.setDetune( -100 ); // pitch down 1 semitone (100 cents)
其他音源
// HTML5 media element (for streaming large files)
const audioEl = new Audio( 'long-track.mp3' );
sound.setMediaElementSource( audioEl );
// Microphone input
navigator.mediaDevices.getUserMedia( { audio: true } ).then( ( stream ) => {
sound.setMediaStreamSource( stream );
});
PositionalAudio(3D 空间音效)
使用 PositionalAudio 播放场景中某个位置发出的声音。音量和立体声声像会随监听器的距离和朝向变化。
基本设置
const positionalSound = new THREE.PositionalAudio( listener );
audioLoader.load( 'engine.ogg', ( buffer ) => {
positionalSound.setBuffer( buffer );
positionalSound.setRefDistance( 20 );
positionalSound.setRolloffFactor( 1 );
positionalSound.setDistanceModel( 'inverse' );
positionalSound.setLoop( true );
positionalSound.setVolume( 0.5 );
});
mesh.add( positionalSound ); // sound position follows the mesh
距离模型决策树
| 模型 | 适用场景 | 行为 |
|---|---|---|
'inverse'(默认) | 真实环境 | 渐进衰减;永远不会降至零 |
'linear' | 可控范围(例如基于房间的场景) | 音量在 maxDistance 处降至零 |
'exponential' | 强烈的近远对比 | 快速衰减曲线 |
参数选择:
refDistance— 音量为 100% 时的距离。将其设为场景单位中的“舒适聆听范围”。典型值:1到20。maxDistance— 仅对'linear'模型有效。'inverse'和'exponential'会忽略此参数。rolloffFactor— 音量降低的速度。对于'inverse':1= 真实衰减。对于'linear':1= 完整范围。值越高,衰减越快。
定向音频锥体
positionalSound.setDirectionalCone( 180, 360, 0.1 );
// coneInnerAngle: 180° — full volume zone
// coneOuterAngle: 360° — transition zone
// coneOuterGain: 0.1 — volume outside outer cone (10%)
AudioLoader
始终使用 AudioLoader 加载音频文件。它会通过回调返回一个 AudioBuffer。
const loader = new THREE.AudioLoader();
loader.load(
'sound.ogg',
( buffer ) => { sound.setBuffer( buffer ); }, // onLoad
( xhr ) => { console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); }, // onProgress
( err ) => { console.error( 'Audio load failed:', err ); } // onError — ALWAYS handle
);
支持的格式: MP3、OGG、WAV、AAC。OGG 的压缩率和音质表现最佳,但 Safari 不支持。为确保跨浏览器兼容性,始终提供 MP3 作为备用格式。
AudioAnalyser
封装 Web Audio API 的 AnalyserNode,用于实时频率可视化。
const analyser = new THREE.AudioAnalyser( sound, 256 );
// fftSize MUST be a power of 2: 32, 64, 128, 256, 512, 1024, 2048
function animate() {
requestAnimationFrame( animate );
const data = analyser.getFrequencyData(); // Uint8Array, length = fftSize / 2
const avg = analyser.getAverageFrequency(); // number (0-255)
// Drive visuals from audio data
mesh.scale.y = 1 + avg / 128;
renderer.render( scene, camera );
}
频率数据详情
getFrequencyData()返回一个包含fftSize / 2个元素的Uint8Array- 每个元素的范围为
0到255(分贝幅度) - 索引
0对应最低频率,最后一个索引对应最高频率 getAverageFrequency()返回所有频段的算术平均值
集成清单
- 创建一个
AudioListener并将其添加到摄像机 - 使用该监听器创建
Audio或PositionalAudio - 使用
AudioLoader加载音频 - 设置缓冲区、音量、循环和距离属性
- 添加用户交互处理器以恢复
AudioContext - 仅在用户交互后调用
play() - 对于空间音频:将
PositionalAudio添加为目标网格的子级
参考链接
- references/methods.md -- AudioListener、Audio、PositionalAudio、AudioLoader、AudioAnalyser 的完整 API 签名
- references/examples.md -- 常见音频场景的可运行代码示例
- references/anti-patterns.md -- 使用 Three.js 音频时不该做的事