UE5 + ADXでつくる、オブジェクトの速度に応じて変わるサウンド

# はじめに
ADXアンバサダーとして記事を書いておりますSigと申します。
この記事ではアンリアルエンジン5（以下UE5）とサウンドミドルウェア「ADX for UE」を連携させ、現在の速度に応じて音の大きさ・高さが変わるオブジェクトを実装してみます。

https://twitter.com/sleepyslowsheep/status/1392751466490695680?s=20

ゲーム内のシチュエーションにおいては、乗り物のエンジンや飛行するモンスターの風切り音などが考えられます。
オブジェクトが動く速度に応じて、駆動音や疾走感のある音に変化していくことで実在感やケレン味のある演出なども実現できるでしょう。

当記事ではUE5.3+「ADX LE UE SDK(2.01.00)」を使用します。
また、基本的にブループリントのみでの実装を行います。
ADX for UEはインディー向けの「LE版」であれば、無料で使用できます。
https://game.criware.jp/products/adx-le/

# 前提
「ADX for UE LE」を使用します。導入や簡単な使い方は以下の記事にあります。
ADX for UEの導入で、一歩上のサウンド表現を（導入編）
https://qiita.com/SigRem/items/4250925f6d66a4fd287a
ADX for UEの導入で、一歩上のサウンド表現を（実践編）
https://qiita.com/SigRem/items/c089b71c42e898980a46

# 実装

### AtomCraftでマテリアルを準備
マテリアルツリーに音源を用意します。
今回はオブジェクトが移動中に再生されるサウンドひとつをインポートしました。
力が加わっているあいだ再生され続けるので、ループする素材が望ましいです。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/2f5977ff-4775-ea50-43a6-46562f22011b.png)
マテリアルを選択し、インスペクターの「ループ情報の上書き」を「True」にし、「ループタイプ」が「ループ」であることを確認します。
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/9a66940a-86a7-fe44-2ddc-929938420500.png)


### キューの作成
新規にキューを作成します。
キューシートを右クリックし、「新規オブジェクト」→「キュー『ポリフォニック』の作成」を選択します。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3a8cbbf1-10d4-e597-0648-faf7b9760a19.png)
キューが作られるので適当に名前をつけます。

マテリアルツリーから音源をドラッグアンドドロップし、トラック上に配置します。
![A04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f666da3f-48ba-d91f-d8d8-04f7f9ba93bf.png)

### AISACコントロールの設定
音の高さ（ピッチ）を変化させるため、AISACコントロールを作成します。
トラックリストの空欄で右クリックし、「新規オブジェクト」→「AISACの作成」を選びます。
![A05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6e0c3b58-1275-8068-3707-ac6a30eedf96.png)

「AISACの追加」ウィンドウでは、「AISACグラフタイプ」を「ピッチ」に設定しておきます。
![A06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ba913ebf-88ab-9586-4e88-d77a06aea304.png)

「ワークユニットツリー」の「Aisac_0」をダブルクリックしてAISACコントロールの編集画面を開きます。
![A07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f5a1906b-9564-28dc-b896-4cb21c8a2df3.png)
![A08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e3ff17f2-3e01-6227-fe37-1dcfce55ca89.png)

青いグラフを操作し、右端と左端を任意の高さにします。
![A09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3788ac49-54f6-d636-5b8e-692eca7bfe0b.png)
再生しながら上部のスライダーを動かし、AISACコントロールの動きを確認してみましょう。
![A10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6c206548-45a1-d76c-310c-1fc26714a147.png)


### キューシートのビルド
ここまで設定できたらキューシートをビルドします。
![A11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/a22b7e19-273a-7b91-a3a9-c93f11b76139.png)
![A12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/45a9427c-b1f9-d5ce-d5a9-ab2390797f73.png)


## UE5で変化するサウンドを実装する

### UE5にキューシートをインポート

ビルドしたacf、acbファイルをUE5のコンテンツブラウザ（コンテンツドロワー）にドラッグ&ドロップしインポートします。

acfファイルインポートの際に出てくるダイアログでは「Yes」を選択します。
これにより、プロジェクトの設定が自動的に完了します。
![A01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/98260371-7771-3652-be81-861341cfa301.png)

コンテンツブラザにアセットが追加されます。
![A02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4772a3e7-c250-2f33-74dd-bd0ff08975f7.png)

キューシートをダブルクリックして開き、キューが再生できることを確認します。
![A03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/658b394f-a4dd-0be3-ede2-2dcc9fd705f5.png)


### アクターの作成
オブジェクト本体となるアクターを作成します。
コンテンツブラウザの任意の場所で右クリックし、「Blueprint Class」を選択します。
![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/362b1eea-425a-8164-8616-b2d80353a811.png)

親クラスは「Actor」を選びます。
![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/8eb0582e-3e72-e7ac-58e2-68de670beb33.png)

アクターが作られるので、適当に名前をつけます。
![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/e65643e4-c94c-5db1-6fa0-146464f47a90.png)

アクターをダブルクリックして開き、「+Add Component」ボタンからStatic Meshコンポーネントを追加します。
![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0bd838d5-1f29-1251-2d47-5ddb045674d2.png)

StaticMeshコンポーネントをドラッグし、「DefaultSceneRoot」上でドロップします。
![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/639791c7-13c7-11e5-5ebe-fd2801d2ac08.png)

アクターのルートコンポーネントが「StaticMesh」になります。これにより、物理演算などでメッシュの位置が変わった場合に、StaticMeshコンポーネントの座標を基準としてアクターの座標に反映されるようになります。
![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/863b5a02-1f6a-3729-e987-9ada35b93e5d.png)

StaticMeshコンポーネントを選択し、Detailsパネルにてメッシュを選択します。予め、メッシュにコリジョンがついていることを確認しておくといいでしょう。
画像ではメッシュのマテリアルを上書きしています。
![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/ccd1b764-1ac4-ddf0-cdd0-3b4e79691bbb.png)

「Simulate Physics」のチェックをつけます。メッシュの物理演算が有効になります。
![B08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/fdd573bd-42c4-9df5-4e40-7dd05a2fccf9.png)

「+Add Component」から、Atom Componentを追加します。これがサウンドの音源になります。
![B09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c7fcd9f5-d96e-eb1a-c1f6-5943f3e32f24.png)

コンポーネントの構成としては、StaticMeshコンポーネントの子としてAtomコンポーネントがぶら下がっているようになっていればOKです。もしなっていない場合、Atomコンポーネントをドラッグ&ドロップして次の画像のようにしてください。
![B10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/0f222bd5-0808-192c-7f20-e23f457a51e5.png)

Detailsパネルで、まず再生したいキューシートを選択し、再生したいキューを指定します。
![B11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/94110c75-f659-48bf-85ce-9907c2f7b551.png)


レベル上に配置し、再生してみましょう。再生モードを「Simulate」にすると分かりやすいです。
![B12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/c8b6d055-dd5f-9675-8abc-51966687a430.png)

サウンドが再生され続けるほか、物理演算によりメッシュが地面に落ちるのが確認できます。
![B13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/57d16034-f813-8df7-7efb-ecb53188ece0.png)



### ブループリントで速度に応じた音量を再生する

ブループリントのイベントグラフに移動し、処理を編集していきます。
例として、落下したりプレイヤーが押したりして動いている間、速度に応じて駆動音が大きくなり、ピッチが変化するオモチャを作ってみましょう。

![C01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/57f73d36-dbfa-d887-cc56-64927285a719.png)

オブジェクトの速度を取得するには**Get Velocity**ノード、そこから速度をfloat変数として取得（速度の長さを取得）するには**Vector Length**ノードを使います。
![C02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/d0ca9745-0185-1ea7-f702-b07768d6e1be.png)

これらのノードはセットで使うと汎用性が高く、様々な場面に使えます。

この速度をAtomコンポーネントの音量に反映させていきます。
……が、そのままの値では音量への影響が大きすぎるので、速度に倍率をかけて小さくします。
また、音量を0～1の間で変動させたいので**Clamp(float)**ノードを噛ませます。
**Clampノードを使わない場合、音量が異常に大きくなってしまうので注意！**
![C03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6e20a066-3f64-6245-95e0-020bd43c86b3.png)



ComponentsパネルからAtomコンポーネントをグラフ上にドラッグ&ドロップし、コンポーネントを取得するノードを作ります。
![C04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/210e59b2-caba-9d76-3072-bf18b9d73971.png)

**Get Atom Component**から**Set Volume**ノードを配置し、Atomコンポーネントの音量を変動させます。
![C05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/11549549-41d3-5bb2-f978-75b4a29be7f7.png)


**Event Tick**から線をつなげれば、毎フレーム処理が走り速度に応じた音量が変化するようになります。
![C06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/3ca22d41-c50c-187b-2aa0-adfa5e16b403.png)


ゲームを再生してみましょう。「Simulate」モードならゲーム再生中にもオブジェクトを選択して操作することができます。
また、通常のPlay in Editorモードでも、「F8」キーを押すことでエディタ上での操作が可能になります（猛威一度キーを押すと元に戻ります）。
再生中にオブジェクトを選択し、マニピュレータをドラッグして動かすと、速度が速くなったときにだけサウンドが聞こえてくるはずです。
![C07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6c584be2-5679-afa2-7a94-4bbaef7e8981.png)
![C08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/4419cfbd-0950-ba81-e098-36a0630283d4.png)



### 速度に応じてピッチを変動させる

AtomCraftでピッチの変動を設定していますので、ブループリントからそちらも制御してみましょう。
AISACコントロールの値を変動させるには**Set Aisac by Name**ノードを使用します。
![D01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/2388f185-093f-9558-be97-b9cb53983301.png)

**Clamp(float)ノード**の値を「Value」ピンにつなげて、「AisacControl」のコントロール名を指定すれば処理が完成します。
![D02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/6e478262-4b20-bd05-6cfa-d3957469b664.png)


グラフの全体図はこんな感じです。
![D03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/bcbd3f94-4986-79ae-391d-e4aa0b26a28a.png)


音量やピッチ、さらに他のパラメータも設定次第で変化させることができる処理を紹介しました。
速度というパラメータはゲームメカニクス的にも演出的にも活用できる要素です。様々なアプローチを試してみてください。


## 補足

AtomCraft側で「ドップラー係数」を使用し、現実のドップラー効果のように速く動く物体に対してサウンドを変化させることもできます。

ドップラー係数を設定するには、まずキューを選択して、インスペクターの「3Dポジショニング」のボタンを押して項目へ移動します。
![E01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/5bf32238-f98f-05e3-6e69-8a3ba9fb54da.png)
「ドップラー係数」を設定できます。まず低めに設定し、セッションウィンドウで試してみましょう。
![E02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/01a7fe2a-3cc5-0126-4111-e91c5a9e4e85.png)
![E03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/7fa24890-4f5b-5b5e-382a-3292c938d293.png)
セッションウィンドウの「3Dポジショニング」の場所で音源を動かし、聞こえ方を確認してみましょう。
![E04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/f9981ebc-0f49-374b-209a-84d760cfa33e.png)
聞こえ方が変わらない場合、「プレーヤーに3Dオブジェクトをアタッチ」にチェックを入れてあることを確認してください。
![E05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154452/06800b01-8c53-93a7-c4a0-14a3c91bec56.png)