3. Звук в Three.js


Three.js предоставляет удобные инструменты для работы с аудио на основе Web Audio API. Звук может быть:

  • статическим (Audio) – просто воспроизводится в сцене;
  • позиционным (PositionalAudio) – его громкость и панорама зависят от положения источника относительно камеры.

Для работы со звуком необходимо:

  • Добавить в сцену AudioListener и привязать его к камере.
  • Загрузить звуковой файл с помощью AudioLoader.
  • Создать объект звука (Audio или PositionalAudio) и связать с ним загруженный буфер.
  • Добавить звук в сцену и управлять воспроизведением.

Пример позиционного звука, который движется вместе с объектом:

import * as THREE from 'three';
import { OrbitControls } from 'https://unpkg.com/three@0.128.0/examples/jsm/controls/OrbitControls.js';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(2, 2, 5);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 1. Создаём слушатель и прикрепляем к камере
const listener = new THREE.AudioListener();
camera.add(listener);

// 2. Загружаем звук
const audioLoader = new THREE.AudioLoader();
const sound = new THREE.PositionalAudio(listener); // позиционный звук

audioLoader.load('sound.mp3', (buffer) => {
    sound.setBuffer(buffer);
    sound.setRefDistance(2);   // расстояние, на котором громкость нормальная
    sound.setVolume(0.8);
    sound.setLoop(true);       // зацикливание
    // sound.play();            // воспроизведение – обычно по взаимодействию
});

// 3. Создаём объект, к которому привяжем звук
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x44aa88 });
const cube = new THREE.Mesh(geometry, material);
cube.add(sound);               // звук будет следовать за кубом
scene.add(cube);

// Свет и управление
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 2, 1);
scene.add(light);
const controls = new OrbitControls(camera, renderer.domElement);

// Анимация
function animate() {
    requestAnimationFrame(animate);
    cube.rotation.y += 0.01;
    controls.update();
    renderer.render(scene, camera);
}
animate();

// Включаем звук только после взаимодействия пользователя (политика браузера)
window.addEventListener('click', () => {
    if (!sound.isPlaying) sound.play();
});

Ключевые моменты:

  • AudioListener должен быть прикреплён к камере – это «уши» слушателя.
  • Для позиционного звука важен параметр setRefDistance – чем он меньше, тем быстрее затухает звук с расстоянием.
  • Современные браузеры запрещают автоматическое воспроизведение звука без жеста пользователя. Поэтому play() обычно вызывается по клику или нажатию клавиши.
  • Можно использовать Audio вместо PositionalAudio, если источник не должен зависеть от положения.