2019年12月11日
プログラミング
Web Audio API + three.js で音に連動する3Dオブジェクトを作ってみた!


はじめに
新しい技術にチャレンジし続けるpalanのアドベントカレンダー Day11です!
昨日は「React360でのレイアウトについて【これからはじめるReact360】」という記事でした。
本日は「Web Audio API + three.js で音に連動する3Dオブジェクトを作ってみた!」という記事を書いてきます!
完成形はこのようになります!
実装内容
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 再生中の音から波形データを取得して描画する~
プログラミングのお仕事に関するご相談
Bageleeの運営会社、palanではプログラミングに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
2
0
関連記事
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへ
palanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー

Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。

やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。

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

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

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

Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。

ゲスト bagelee

かっきー

まりな

suzuki
miyagi

ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。

いわもと
デザイナーをしています。 好きな食べ物はラーメンです。

taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。

kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya

aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。

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

sugimoto
asama
ando
iwasawa ayane

oshimo
異業界からやってきたデザイナー。 palanARのUIをメインに担当してます。 これからたくさん吸収していきます!