コードをメモ帳などのテキストエディタに貼り付け、ファイル名を「index.html」として保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
音源が大きな3次元の楕円軌道上を動き、その時の音の変化をシミュレーションしてます。
Web Audio APIを使って、移動する音源をシミュレート
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3次元のランダムな楕円軌道で動く音源とカラフルなキューブ</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
<!-- three.jsのスクリプトをCDNから読み込む -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
</head>
<body>
<h2>3次元のランダムな楕円軌道で動く音源とカラフルなキューブのシミュレーション</h2>
<script>
// Web Audio APIの初期化
let audioContext = null;
let oscillator = null;
let panner = null;
let gainNode = null;
// シーン、カメラ、レンダラーの初期化
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 楕円の半径をランダムに設定
const radiusX = Math.random() * 300 + 200; // 楕円の長半径 (200〜500)
const radiusY = Math.random() * 200 + 100; // 楕円の短半径 (100〜300)
const radiusZ = Math.random() * 150 + 50; // 楕円の高さ (50〜200)
let angle = 0;
// 音源の球体を作成
const geometry = new THREE.SphereGeometry(10, 32, 32);
const material = new THREE.MeshBasicMaterial({ color: 0x0000ff });
const soundSource = new THREE.Mesh(geometry, material);
scene.add(soundSource);
// カラフルなキューブをランダムで10個作成
function createColorfulCubes() {
for (let i = 0; i < 10; i++) {
const cubeSize = Math.random() * 20 + 10; // ランダムなサイズ
const cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff }); // ランダムな色
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
// ランダムな位置を設定
cube.position.set(
Math.random() * 600 - 300, // X座標
Math.random() * 400 - 200, // Y座標
Math.random() * 600 - 300 // Z座標
);
scene.add(cube);
}
}
// カメラの位置を設定
camera.position.z = 500;
// 音源の位置更新と描画のループ
function updatePosition() {
const x = radiusX * Math.cos(angle);
const y = radiusY * Math.sin(angle);
const z = radiusZ * Math.sin(angle * 0.5); // Z軸の動きを追加
// 音源の位置を更新
soundSource.position.set(x, y, z);
// 音源の位置に基づくステレオ効果
if (panner && gainNode) {
const panningX = x / radiusX; // 左右のパン
const distance = Math.sqrt(x * x + y * y + z * z) / radiusX; // 音量調整のための距離
panner.setPosition(panningX, 0, -0.5); // 前後方向は固定
gainNode.gain.setValueAtTime(1 - distance, audioContext.currentTime); // 距離に基づいて音量を調整
}
angle += 0.02;
if (angle > 2 * Math.PI) {
angle = 0;
}
requestAnimationFrame(updatePosition);
renderer.render(scene, camera);
}
// ユーザーのクリックで音を開始
document.body.addEventListener('click', () => {
if (!audioContext) {
// 初回クリック時にAudioContextと音源の初期化
audioContext = new (window.AudioContext || window.webkitAudioContext)();
panner = audioContext.createPanner(); // 音の位置を制御する
gainNode = audioContext.createGain(); // 音量を制御する
oscillator = audioContext.createOscillator();
oscillator.type = 'sine'; // 正弦波
oscillator.frequency.setValueAtTime(440, audioContext.currentTime); // 440Hz (A4の音)
oscillator.connect(panner).connect(gainNode).connect(audioContext.destination);
oscillator.start();
}
audioContext.resume(); // AudioContextの再開
});
createColorfulCubes(); // カラフルなキューブを作成
updatePosition(); // 位置更新のループ開始
</script>
</body>
</html>
参考。
空間オーディオで移動する音源のサンプル
// オーディオコンテキストを作成
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
// 音源(オシレーター)を作成
const oscillator = audioContext.createOscillator();
// ゲインノードを作成(音量調整)
const gainNode = audioContext.createGain();
// PannerNode(パンニングノード)を作成
const panner = audioContext.createPanner();
panner.panningModel = 'HRTF'; // 空間オーディオモデルの設定
panner.distanceModel = 'linear'; // 距離による音量の減衰モデル
panner.positionX.setValueAtTime(0, audioContext.currentTime); // X座標の初期位置
panner.positionY.setValueAtTime(0, audioContext.currentTime); // Y座標の初期位置
panner.positionZ.setValueAtTime(-1, audioContext.currentTime); // Z座標の初期位置(リスナーの前)
// ノードを接続
oscillator.connect(gainNode);
gainNode.connect(panner);
panner.connect(audioContext.destination);
// オシレーターの設定
oscillator.frequency.value = 440; // 440Hz(A4の音)
oscillator.type = 'sine'; // サイン波
// 音声を開始
oscillator.start();
// 音源の移動をシミュレートする関数
function moveSource() {
let startTime = audioContext.currentTime;
let duration = 5; // 音源が移動する時間(秒)
let endTime = startTime + duration;
// X軸の位置を時間に応じて変化させる
panner.positionX.linearRampToValueAtTime(5, endTime); // 右に移動
// 移動が終了したら音声を停止
oscillator.stop(endTime);
}
// 音源の移動を開始
moveSource();
説明
PannerNode: PannerNodeは、音を3D空間に配置するために使用します。このノードのpositionX, positionY, positionZプロパティを使って、音源の位置をリアルタイムで変更できます。
HRTF: パンニングモデルとしてHRTF(Head Related Transfer Function)を使用しています。これは、人間の耳で音を聞くときの立体感をシミュレートするモデルで、よりリアルな3D音響を体験できます。
音源の移動: panner.positionX.linearRampToValueAtTime()を使用して、音源が一定の時間内に徐々に右側に移動するようにしています。
このコードでは、音源が5秒かけてリスナーの前から右側に移動します。これにより、音源が動いているような効果をシミュレートできます。また、positionYやpositionZも変更すれば、上下や前後方向の移動も可能です。