2019年12月11日

プログラミング

Web Audio API + three.js で音に連動する3Dオブジェクトを作ってみた!

目次

  1. はじめに
  2. 実装内容
  3.  3Dオブジェクトの配置
  4.  音声データの読み込み
  5.  音声データと各種機能の設定
  6.  音声データと3Dオブジェクトとの連動
  7. まとめ
  8. 参考・リンク

はじめに

新しい技術にチャレンジし続けるpalanのアドベントカレンダー Day11です!

昨日は「React360でのレイアウトについて【これからはじめるReact360】」という記事でした。

React360でのレイアウトについて【これからはじめるReact360】

本日は「Web Audio API + three.js で音に連動する3Dオブジェクトを作ってみた!」という記事を書いてきます!

ogp.png (474.1 kB)

完成形はこのようになります!

実装内容

1. 3Dオブジェクトの配置 – initThree関数

まずは、3Dオブジェクトを配置していきます。

three.js では面のある3Dオブジェクトの場合は Mesh で作成できますが、
点のみの3Dオブジェクトの場合は BufferGeometry を用いて新しく geometry を作成することになります。

BufferGeometry には、最低でも頂点の情報が必要となります。

頑張れば球体の頂点定義はできなくはないのですが、
three.js には SphereGeometry があるので、そこから頂点情報を抽出します!

そして、SphereGeometry の頂点情報を格納した配列 sphereVertices は、
下記のようなデータ構造になっています。
[{ x: ???, y: ???, z: ??? }, ...]

BufferGeometry に使用する頂点のデータ構造は下記のようになるため、
このデータ構造にならった配列になるようfor文を書いています。
[x1, y1, z1, x2, y2, z2, ...]

ポイント 76〜98行目
// 球体の頂点情報を取得
sphereVertices = new THREE.SphereGeometry(10, 24, 24).vertices;

// 球体の頂点を格納する配列の用意
pointPositions = new Float32Array(sphereVertices.length * 3);

// vertexPosition = { x: ???, y: ???, z: ??? } なので...
// x, y, z の値を順番に pointPositions に格納する
let a = 0;
for (let i = 0; i < sphereVertices.length; i++) {
let vertexPosition = sphereVertices[i];
pointPositions[a] = vertexPosition.x;
pointPositions[a + 1] = vertexPosition.y;
pointPositions[a + 2] = vertexPosition.z;
a += 3;
}

// geometry の用意
pointsGeometry = new THREE.BufferGeometry();
pointsGeometry.setAttribute(
"position",
new THREE.BufferAttribute(pointPositions, 3)
);

2. 音声データの読み込み – initAudio関数

次に、音声データを読み込みます。

XMLHttpRequestを利用して、音声データ(バッファ)を取得します。

取得できたらデコードをして、その音声データを次に実行される処理へ渡します。

ポイント 122〜135行目
let request = new XMLHttpRequest();
request.open("GET", audioSource, true);
request.responseType = "arraybuffer";
// 取得した音声データ(バッファ)をデコードし、
// デコードされた音声データをこの後の処理に渡す
request.onload = () => {
audioContext.decodeAudioData(request.response, buffer => resolve(buffer));
};
request.send();

3. 音声データと各種機能の設定 – setAudio関数

つづいて、音声データと各種機能の設定を行います。

特に波形取得機能の接続が大事になります!

波形取得機能を定義するだけで勝手に音源の波形データを取得できるわけではないので、音源と波形取得機能を接続。

そして、波形取得機能と出力機能を接続することでやっと再生の準備が整います!

音源の再生は audioBufferSource.start(0);で開始されます。

ポイント 154〜161行目
// 音源を波形取得機能に接続
audioBufferSource.connect(audioAnalyser);

// 波形取得機能を出力機能に接続
audioAnalyser.connect(audioContext.destination);

// 音源の再生を開始する
audioBufferSource.start(0);

4. 音声データと3Dオブジェクトとの連動 – playAudio関数

最後に、音声データと3Dオブジェクトを連動させていきます。

配列 audioCount にはこの関数実行時の波形データが入ります。

波形データの最大値を number で取得し、 0 〜 1 の範囲になるよう調整しします。

そして、3Dオブジェクトのscaleに代入するのですが…
scaleのデフォルト値は 1 であるため 0 になると3Dオブジェクトが見えなくなってしまいます。
そのため Math.pow(number,) + 0.5;という処理で 0.5 以上になるよう調整しています。

これで音に連動する3Dオブジェクトの完成です!

ポイント 165〜178行目
// 時間領域の波形データを格納する
audioAnalyser.getByteTimeDomainData(audioCount);

// この関数実行タイミングでの波形データの最大値を取得
let number = audioCount.reduce((a, b) => Math.max(a, b));

// 0 〜 255 の値が入るので、 0 〜 1 になるように調整
number = number / 255;

// 取得した値を2乗(大きい値はより大きく、小さい値はより小さく)して
// 0.5 以上になるよう調整する
points.scale.x = Math.pow(number, 2) + 0.5;
points.scale.y = Math.pow(number, 2) + 0.5;
points.scale.z = Math.pow(number, 2) + 0.5;

まとめ

今回は音声ファイルを使用して波形データを取得しましたが、
マイクを使用してリアルタイムに波形データを取得できれば、
インタラクティブ性が加わり、もっと面白くなりそうですね!

参考・リンク

interactive / points – three.js examples
three.js/webgl_interactive_points.html at master · mrdoob/three.js

Web Audio APIを利用してオーディオビジュアライザを作成する ~その1 音声データを読み込んで音を出す~
Web Audio APIを利用してオーディオビジュアライザを作成する ~その2 再生中の音から波形データを取得して描画する~

BGM・ジングル・効果音のフリー素材|OtoLogic
フリーBGM:ソウル|OtoLogic

0

0

AUTHOR

sasai

ささい エンジニア

フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。

アプリでもっと便利に!気になる記事をチェック!

記事のお気に入り登録やランキングが表示される昨日に対応!毎日の情報収集や調べ物にもっと身近なメディアになりました。

palanでは一緒に働く仲間を募集しています

正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。

話を聞いてみたい

運営メンバー

eishis

Eishi Saito 総務

SIerやスタートアップ、フリーランスを経て2016年11月にeishis, Inc.を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。

sasakki デザイナー

アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。

しまだ

しまだ デザイナー

WebAR/VRのデザインと3DCG制作がメインです。 肩書きは「アニメ案件に関わりたいデザイナー」。

Miu マーケター

ドイツでWEBマーケティングしています。

しんのき エンジニア

主に React Native を使ったアプリ開発と AWS や Firebase を使ったサーバーレスアーキテクチャを担当しています。元々はインフラとかPHPをやっていました。

yamakawa

やまかわたかし デザイナー

フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReact NativeやReact360をよく触っています。

furuya エンジニア

サーバーサイド、フロントエンド、Unityと色々手を出してる雑食系エンジニア。ReactNativeが最近のマイブーム。

Sayaka Osanai デザイナー

Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。

はらた

はらた エンジニア

サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています

うえまつゆい エンジニア

サーバーサイドエンジニアからフロントエンドエンジニアになりました。主にReact Nativeでのアプリ開発をしています。

kobori

こぼり ともろう エンジニア

サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。

sasai

ささい エンジニア

フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。

damien

Damien

WebAR/VRを中心に企画やディレクションやエンジニアもちょっとやっています。森に住んでいます。

デザイナーゲスト

ゲスト デザイナー

CONTACT PAGE TOP