THREE.AudioLoader
是 three.js
库中的一个类,用于异步加载音频文件。three.js
是一个流行的 JavaScript 库,用于在网页上创建和显示 3D 图形。以下是关于 THREE.AudioLoader
的一些基本用法和属性:
入参 (Input Parameters):
manager
(可选): 一个THREE.LoadingManager
实例,用于管理加载状态和资源。
出参 (Output):
THREE.AudioLoader
本身并不直接返回加载的音频数据。相反,它通常与 load
方法的回调函数一起使用,该回调函数会在音频加载完成后被调用。
方法 (Methods):
load(url, onLoad, onProgress, onError)
: 加载音频文件。url
: 音频文件的 URL 或路径。onLoad
: 音频加载完成时的回调函数,通常接收一个Audio
实例作为参数。onProgress
: (可选) 加载进度更新时的回调函数,通常接收加载进度(0 到 1 之间)作为参数。onError
: (可选) 加载错误时的回调函数,通常接收错误对象作为参数。
属性 (Properties):
THREE.AudioLoader
本身并没有很多直接暴露给用户的属性。它主要通过方法和回调函数来与用户交互。但是,你可以通过 load
方法的 onLoad
回调函数来访问加载后的 Audio
实例,该实例具有音频文件的相关属性和方法。
例如:
var audioLoader = new THREE.AudioLoader();
audioLoader.load(
'path/to/audio.mp3',
function(audio) {
// 音频加载完成,可以在这里操作 audio 实例
audio.play(); // 播放音频
},
function(xhr) {
// 加载进度更新,可以在这里获取进度信息
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function(error) {
// 加载出错,可以在这里处理错误
console.error('An error happened', error);
}
);
在上面的例子中,audio
是一个 Audio
实例,你可以调用它的方法(如 play
、pause
、setVolume
等)来控制音频的播放。
demo 源码
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webaudio - timing</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="overlay">
<button id="startButton">Play</button>
</div>
<div id="container"></div>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener noreferrer">three.js</a> webaudio - timing<br/>
sound effect by <a href="https://freesound.org/people/michorvath/sounds/269718/" target="_blank" rel="noopener noreferrer">michorvath</a>
</div>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
// 导入所需的模块
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 定义全局变量
let scene, camera, renderer, clock;
const objects = [];
const speed = 2.5;
const height = 3;
const offset = 0.5;
// 获取开始按钮并添加点击事件监听器
const startButton = document.getElementById('startButton');
startButton.addEventListener('click', init);
// 初始化函数
function init() {
const overlay = document.getElementById('overlay');
overlay.remove();
const container = document.getElementById('container');
// 创建场景和时钟
scene = new THREE.Scene();
clock = new THREE.Clock();
// 创建相机
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(7, 3, 7);
// 添加灯光
const ambientLight = new THREE.AmbientLight(0xcccccc);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5);
directionalLight.position.set(0, 5, 5);
scene.add(directionalLight);
directionalLight.castShadow = true;
directionalLight.shadow.camera.left = -5;
directionalLight.shadow.camera.right = 5;
directionalLight.shadow.camera.top = 5;
directionalLight.shadow.camera.bottom = -5;
directionalLight.shadow.camera.near = 1;
directionalLight.shadow.camera.far = 20;
directionalLight.shadow.mapSize.x = 1024;
directionalLight.shadow.mapSize.y = 1024;
// 加载音频文件并创建球体
const audioLoader = new THREE.AudioLoader();
const listener = new THREE.AudioListener();
camera.add(listener);
const floorGeometry = new THREE.PlaneGeometry(10, 10);
const floorMaterial = new THREE.MeshLambertMaterial({ color: 0x4676b6 });
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = Math.PI * -0.5;
floor.receiveShadow = true;
scene.add(floor);
const ballGeometry = new THREE.SphereGeometry(0.3, 32, 16);
ballGeometry.translate(0, 0.3, 0);
const ballMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccc });
audioLoader.load('sounds/ping_pong.mp3', function (buffer) {
for (let i = 0; i < 5; i++) {
const s = i / 5 * Math.PI * 2;
const ball = new THREE.Mesh(ballGeometry, ballMaterial);
ball.castShadow = true;
ball.userData.down = false;
ball.position.x = 3 * Math.cos(s);
ball.position.z = 3 * Math.sin(s);
const audio = new THREE.PositionalAudio(listener);
audio.setBuffer(buffer);
ball.add(audio);
scene.add(ball);
objects.push(ball);
}
animate();
});
// 创建渲染器和控制器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 1;
controls.maxDistance = 25;
// 监听窗口大小变化
window.addEventListener('resize', onWindowResize);
}
// 窗口大小变化时更新相机和渲染器尺寸
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// 动画循环
function animate() {
requestAnimationFrame(animate);
render();
}
// 渲染函数
function render() {
const time = clock.getElapsedTime();
for (let i = 0; i < objects.length; i++) {
const ball = objects[i];
const previousHeight = ball.position.y;
ball.position.y = Math.abs(Math.sin(i * offset + (time * speed)) * height);
if (ball.position.y < previousHeight) {
ball.userData.down = true;
} else {
if (ball.userData.down === true) {
const audio = ball.children[0];
audio.play();
ball.userData.down = false;
}
}
}
renderer.render(scene, camera);
}
</script>
</body>
</html>