ADX for Unityで、物理演算に材質を加味したサウンド演出をする

# はじめに

本記事は、以下の「ADX for Unityで、物理挙動にランダム性のある効果音をつける」の続きとなります。

https://qiita.com/nimushiki/items/5bf7a4b3b7a4e661eea4

Unityには標準で物理演算エンジンが備わっているので、簡単に物理挙動を実装することが出来ます。その衝突に適切な音を発生させるのは大変ですが、同一素材での実装については上記記事内で紹介しました。

今度は、銃弾や斬撃が当たったときの音を素材ごとに変えたい、同じ素材であっても物理特性が複数存在する、といった場合はどうしたらよいでしょうか。

本記事ではUnityとサウンドミドルウェア「ADX for Unity」を用い、材質毎に音源を変えたり、材質の特性に合わせたエフェクトを掛け、表現力を高める実装例を紹介します。

この記事は「ADX2+UE4を使って、物理演算に材質を加味したサウンド演出」のUnity版です。元記事作者のSigさん ( https://qiita.com/SigRem )の許可を得て作成しています。

https://qiita.com/SigRem/items/ab19045645192641aa5c

# 前提

### 動作確認環境

Windows 10 Home 20H2
Unity 2020.3.27f1  + ADX LE Unity SDK 3.06.03
CRI ADX LE Tools for Windows 3.46.09

### 前提記事

CRI ADXの導入方法や基本的な操作については、以下の記事を参照して下さい。

https://qiita.com/Takaaki_Ichijo/items/16e6501fc07f5b3b3377

# やること

- AtomCraftでキューを作成
- パラメータを調整し、音に性質を追加する
- Unityにインポート、テストシーンを作成する
- 材質毎にサウンドを鳴らし分ける処理を実装する
- サウンドに対し材質に応じたエフェクトを掛ける処理を実装する

# 実装

## AtomCraft側

まずは、再生する音データの作成を行います。ADXにおいては、再生用のデータはUnityとは別のツール「AtomCraft」を使います。その手順については、元の記事（UE4向け記事）の同名の項と同じになりますので省略しています。

本記事の手順を試す場合は、まず元の記事の[該当項目](https://qiita.com/SigRem/items/ab19045645192641aa5c#atomcraft%E5%81%B4)を進めてから本記事を進めてください。UE4版との違いとして1点、「Atomキューシートバイナリのビルド」画面で、一番左下のオプション「UnityAssets出力」にチェックを入れるのを忘れないようにして下さい。

## Unity側の実装

### キューシートのインポート

AtomCraftからエクスポートしたファイルをインポートします。

### 材質毎のサウンド鳴らし分けの実装

### スクリプトの作成

以下のようなRandomHitMaterial.csを作成します。

```RandomHitMaterial.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RandomHitMaterial : MonoBehaviour
{
    public CriAtomSource criAtomSource;
    public string materialName;
    private CriAtomExPlayer ex;

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.impulse.magnitude < 1) return;

        criAtomSource.volume = Mathf.Clamp( collision.impulse.magnitude, 0, 3);
        
        ex = criAtomSource.player;
        ex.SetSelectorLabel("Selector_Physics", materialName);

        criAtomSource.Play();
    }
}
```

動作は単純で、オブジェクトが何かにぶつかったら音を再生します。
前回と違うのは、素材ごとに効果音を鳴らし分けるためのセレクターが設定されているので、SetSelectorLabelでセレクター名・レーベル名を指定している部分です。

### テストシーンの作成

以下のようなシーンを作成します。

![2022-04-18 17.42.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/d9445328-5bc0-fb75-bc4d-b87ac869cd34.png)

![2022-04-18 17.58.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/d7b56321-5058-597e-6f9b-6ac52ce0566d.png)

- CriWareLibraryInitializer、CriWareErrorHandler
- CRIWARE
- Plane
    - ここまで同じ
- Cue_Impact(CriAtomSource)
    - 前項でインポートした音源
- Cube
    - Rigidbodyをアタッチ
    - 先程作成したRandomHitMaterial.csをアタッチ
    - CriAtomSourceにCue_Impact(CriAtomSource)を設定
    - 同じものを素材の数＋デフォルト分用意
    - MaterialNameにAtomCraftで設定した素材名を入れる
    - ゲームオブジェクトの名前も素材がわかるように変えるとよい

### テストシーンの実行

実装出来たら忘れずに保存し、実行しましょう。
Cubeを動かしたり増やしてぶつけたりすると、MaterialNameで指定した名前にあった音が鳴るはずです。

### サウンドエフェクトを材質の特性に合わせる実装

### PhysicMaterialの作成

UnityにはPhysicMaterialという物体の特性を設定するためのマテリアルがあります。
AtomCraftで用意した音声データに合わせ、以下のようなマテリアルを作っていきます。例では各１種ずつですが、同じ素材に特性違いのマテリアルを用意し音の変化を確認するのもよいでしょう。

![2022-04-18 17.47.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/8910f2ad-3b66-44e2-fc77-c4b2bb9f0779.png)

Frictionは摩擦係数、Bouncinessは反発係数です。各設定項目の詳しい内容については公式マニュアルを御覧ください。

https://docs.unity3d.com/ja/2020.3/Manual/class-PhysicMaterial.html

### テストシーンの修正

以下のようにシーンを修正します。

![2022-04-18 17.57.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2576800/c866e87c-b6af-fe73-9f28-a18164730f6c.png)

- 各CubeのBoxColliderのMaterialに、対応するPhysicsMaterialを設定する

### スクリプトの作成

以下のようにRandomHitMaterial.csを修正します。

``` RandomHitMaterial.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RandomHitMaterial : MonoBehaviour
{
    public CriAtomSource criAtomSource;
    public string materialName;
    private PhysicMaterial PhysicMaterial;
    private CriAtomExPlayer ex;

    private void Start()
    {
        PhysicMaterial = GetComponent<BoxCollider>().material;
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.impulse.magnitude < 1) return;

        criAtomSource.volume = Mathf.Clamp( collision.impulse.magnitude, 0, 3);
        
        ex = criAtomSource.player;
        ex.SetSelectorLabel("Selector_Physics", materialName);

        // バンドパス　Cof高域
        criAtomSource.SetAisacControl("AisacControl_00", PhysicMaterial.dynamicFriction);

        // エンベロープ　アタック時間
        criAtomSource.SetAisacControl("AisacControl_01", 1 - PhysicMaterial.bounciness);

        criAtomSource.Play();
    }
}
```

PhysicMaterialの設定値に応じ、AtomCraftで設定したAISACをSetAisacControlで変更していきます。
DynamicFrictionの値をハイパスフィルターに対応させているため、動摩擦係数が大きいほど音がくぐもり鈍い音が出るようになります。
Bouncinessの値はアタック時間に対応させますが、反発力が高いほどハッキリとした音にしたいため、1 - PhysicMaterial.bouncinessという式になっています。

### テストシーンの実行

実装出来たら忘れずに保存し、実行しましょう。
先程の実装に加え、PhysicMaterialに応じたエフェクトがかかった音が鳴ると思います。PhysicMaterialの値はゲームプレイの都合を大きく受けるので、AtomCraft側でも都度調整する必要がでてきそうです。