はじめに
Impacterはインパクト(衝突)をモデル化したWwise向けの新しいプラグインのプロトタイプで、紹介は こちら にあります。今回の記事は、 Unreal Engineで作成したデモゲーム環境に、Impacterを使ってサウンドを実装して統合する過程についてです。まずImpacterの主な機能を簡単に紹介してから、Unrealという環境でどう活用するのかを詳しく説明します。主に、Impacterの質量や速度のパラメータを、物理システムを使って動かす方法に焦点をあてます。ゲームエンジンはほかにもありますが、今回の内容は、あなたが使っているメインのツールが何であれ、応用できます。
Impacter
Impacterはソースプラグインとして、異なるサウンドのコンポーネントでクロスシンセシスを行い、サウンドを、物理情報を活用して変換します。Impacterの詳細を知りたければ、ライアン・ダンの ブログ や、 ドキュメンテーション が参考になりますが、ここで主な機能を簡単に説明します:
クロスシンセシス
- Impacterに、複数のサウンドを読み込めます。これらは内部で分析され、「インパクト(Impact)」と「ボディ(Body)」の2つのコンポーネントに分けられます。インパクトは、オブジェクトが打たれたときの最初の衝撃のことです。ボディは、最初の打撃のあとのオブジェクトのレゾナンスのことです。
- インパクトとボディのコンポーネントを、自由に組み合わせることができます。Impacterが再生するたびにインパクトとボディのコンポーネントをランダムに選択します。
物理情報を取り込めるパラメータ
- Mass(質量)は、衝撃を受けるオブジェクトのサイズを表します。
- Velocity(速度)は、オブジェクトが受ける衝撃の力を表します。
- Position(位置)は、オブジェクトが打たれた場所を表します。このパラメータは音響モードの現象をヒントにしています。位置を変えていくと、音のレゾナンスが微妙に変化します。
- Roughness(ラフネス)は音の粗さのことで、音のレゾナンスに周波数変調(FM)を追加することで実現します。
Impacter Unrealデモ
Impacterを(簡単な)ゲーム環境で、テストし、いくつかの使い方をデモする手段として、Impacter Unrealデモが開発されました。これから、そのユースケースの一部をおおまかに説明しながら、ゲームの物理によってどのようにImpacterを効果的に動かせるかを検討します。
駆け足で出発(フットステップ)
このデモのフットステップの仕組みは、ごく標準的です。Wwiseに、いくつかの地面素材の足音が入ったスイッチコンテナと、このスイッチコンテナを制御するState Group(名前はFootstepMaterial)があります。ゲームの地面によって、WwiseのFootstepMaterialのステートが設定されます。
1つのフットステップSFXに、1つのImpacterインスタンスが入っているので、クロスシンセシスを使用することで、コスト以上の効果があると言え、オーディオサンプルからバリエーションを増やせます。とはいえ、ここまではフットステップの典型的なシナリオです。
質量(Mass)と速度(Velocity)のパラメータの活用を考え出すと、もっと面白いことになります。これを利用して、様々なキャラクターの大きさに、足音を対応させることができます。フットステップのサウンド1つ1つの、速度と質量の両方を変えるための、CharacterSizeという別のRTPCがあるのです。Unrealで、キャラクターオブジェクトの大きさを使って、CharacterSize RTPCが設定されます。キャラクターのスピード(そして走るアニメーション)は、キャラクターオブジェクトのサイズに反比例します。これは巨大な動きの重いキャラクターから、小さく身軽なキャラクターに移るときの効果をシミュレーションしています。その様子は、CharacterSize RTPCをImpacterのVelocityとMassにマッピングすることで、簡単にフットステップサウンドに反映できます。
ワールドのオブジェクトが衝突すると
環境内のオブジェクトやサーフェスには、それぞれに対応するWwiseイベントがあり、このイベントが、Impacterのインスタンスを1つまたは複数トリガーさせます。Impacterのインスタンスでは、VelocityとMassがRTPC(ImpactVelocityとImpactMass)にフックアップされていて、コリジョンが発生したときに、ゲームがRTPCを駆動させます。
UnrealデモをつくってImpacterを統合する際に、最も重要なタスクの1つが、Impacterサウンドが自然な反応を出せるよう、コリジョンの最中にUnreal物理システムにクエリをかけてMassやVelocityパラメータのための無理のない数値を提供することでした。これを実装する場所がImpacterComponentというカスタムSceneComponent Blueprintです。ゲームの各Actor Blueprintクラスに、ImpacterComponentがあります(複数の場合も)。2つのオブジェクトでコリジョンが発生すると、それらのImpacterComponentが、ImpactComponentCollisionをコールします。ここで、各オブジェクトのImpacterイベントがトリガーされる前に、Wwiseに送られるImpactVelocityとImpactMassのRTPC値を計算します。
ここで、いくつかの用語を定義すると分かりやすくなります。 静的オブジェクト とは全く動かないオブジェクトのことで、逆に 動的オブジェクト はワールド内を動き回ることができます。2つのオブジェクトが衝突すると、Unrealで、コリジョンイベントが2つ、すまり各オブジェクトのImpacterComponentに対して1つずつ、トリガーされます。
どのオブジェクトもこのようにコリジョンを処理します。On Component Hitイベントが、ImpactComponentのCheckImpactComponentCollisionをコールします。CheckImpactComponentCollisionは、Other Actorに、ImpactComponentがあるかを確認します。もしImpactComponentがみつかれば、ImpactComponentCollisionをコールします。
これを分かりやすくするために、発射物が壁に衝突するという具体例を考えてみます。壁の観点から言えば、衝突してくるオブジェクト(Other、つまりもう一つのオブジェクト)は、発射物です。発射物の観点から言えば、衝突してくるオブジェクト(Other、つまりもう一つのオブジェクト)は、壁です。壁が発射物に衝撃を与えるというのも、発射物が壁に衝撃を与えるというのも、直観的におかしいと感じるかもしれませんが、本節を読み進むうえで、頭に入れておくと便利な2つの条件です。肝心なのは、各オブジェクトが、自分に対応するWwiseイベントをトリガーさせ、 自分自身の 物理特性と、 もう一つ のオブジェクトの特性の両方を使い、ImpactVelocity と ImpactMassのRTPCを計算するという考え方です。
ImpacterComponentはゲームのどのオブジェクトでも使われるので、コリジョンの物理から、RTPC値に、 物理的に現実みのある 、 標準化できるような マッピングを実装することが、ここでの目標です。そうすれば、オブジェクトの物理特性だけでサウンドを駆動することができ、サウンドデザイナー側でさらに手作業で微調整する必要がありません。サウンドデザイナーがVelocityやMassのカーブを適切に調節さえしていれば、レベルデザイナーは、音がきちんと反応すると確信をもって、オブジェクトをデザインし、配置し、変形させることができます。
それでは、以上を念頭に、ImpactComponentがImpactComponentCollision関数を使い、コリジョンイベントの最中にRTPC値を計算する様子を見ていきます。
MassとVelocity
RTPCのImpactMassとImpactVelocityの値は、それぞれGetImpactMassとGetImpactForceで計算されます。どちらも、ImpactComponentCollisionにコールされます。
Mass(GetImpactMass)
質量(Mass)は、動的オブジェクトの場合はUnrealの物理システムから直接、取得します。(注:オブジェクトのPhysical Materialsを設定するときに、オブジェクトに適切な質量が備わるように、 密度 の値を適切なものにする必要があります。) 静的なオブジェクトは、物理のシミュレーションをしないので質量値がありません。代わりに、明示的な質量値を与えます。MassのRTPC値を設定するときに、コリジョン中にぶつかってくるオブジェクトの質量に基づいて、壁や床の質量値は重み付けします。
Velocity(GetImpactForce)
オブジェクトの速度(velocity)を、ImpacterのVelocityパラメータに直接、マッピングすることができます。ただ、そうしてしまうと、小さくて軽いオブジェクトに、不自然に大きなインパクトが発生してしまいます。例えば、小さなやわらかいボールが、それなりのスピードで金属面に衝突すると、金属面側で大きなインパクト音がトリガーされることがあります。このような理由から、衝突の 力 をImpacterのVelocityパラメータにマッピングした方がいいのです。したがって、速度だけでなく 運動量 (速度×質量)を採用すべきです。そうすれば軽いオブジェクトは、ImpactVelocity RTPC値が小さくなり、インパクト音がもっとソフトになります。さらに、2つのオブジェクトのImpactVelocity RTPC値の計算では、 両方の オブジェクトの運動量に配慮する必要があります。最後に、やわらかいオブジェクトの方がやわらかいインパクト音を出すように、マッピングに密度を直接、導入することができます。
質量の場合と同様に、速度の計算も、衝突するオブジェクトが動的か静的かによって、多少異なります。衝突するオブジェクトが静止している場合は、力を計算するのにImpactedByStaticObject関数を使います。衝突するオブジェクトが動的な場合は、ImpactedByDynamicObjectを使います。
ImpactedByStaticObject(静的オブジェクトからのインパクト)
ここでは、衝突を受けるオブジェクトの運動量(Momentum)と、衝突してきたオブジェクトの密度(Density)をかけて、ImpactVelocity RTPC値を計算します。衝突してきたオブジェクトとは、壁や床なので、忘れないでください。
ImpactedByDynamicObject(動的オブジェクトからのインパクト)
ここでは、各オブジェクトの運動量の合計(Momentum Sum)を使い、それをオブジェクトの密度(Density)の中で一番小さいもので重み付けします。なお、この状況では、衝撃を受けたオブジェクトが静的なこともあり、その場合の運動量は0なので、運動量の合計は、衝突してきたオブジェクトの運動量に等しくなります。
ここで、可能性のある条件を整理してコリジョン表にすると分かりやすくなります。図1は、VelocityやMassのRTPCが、コリジョンのシナリオによってどう計算されるかを示しています。なお、2つの静的(Static)オブジェクト同士では衝突が起きません。
図1: RTPC計算マトリックス
テストと微調整
マッピングが完成したので、発射物をサーフェスめがけて発射し、どのような音になるのかをテストします。
なんともひどい音です!というのも、ボールが床を転がると、Unrealの物理システムがコリジョンイベントを立て続けに発射するからです。転がるボールに、複数の個別のインパクトイベントが入っているわけではないので、地面サーフェスでのインパクトを無効にして、それで終わりにすることもできます(あるいは別のプラグイン、例えばSoundSeed Grainなどを使い、転がるサウンドを実装できます)。ただ、実は逆に、継続的なコリジョンを利用して、何かが転がるのを細かい沢山のインパクトとしてシミュレーションすれば、「転がりながら前進」できます。はじめにImpacterComponentがどれだけ頻繁にWwiseイベントをトリガーするのかを制限します。
それほど悪くないですが、かなりメトロノーム的なので、不自然に聞こえるかもしれません。緩和するために、Wwiseイベントの間隔を少しランダムにしてみます。タイマーがリセットされるたびに、間隔の長さが、ランダムにオフセットされる設定を追加します。
少し良くなってきましたが、ボールが転がるときに繰り返されるインパクトが、回転の動きにしては強すぎます。誰かが何回も床を叩きつけているように聞こえます。これを回避するために、動きの方向性も検討してみます。具体的には、オブジェクトの速度ベクトル(Velocity vector)と、オブジェクトの中心からサーフェス上のインパクトポイント(Object centre to impact point)へのベクトルの、ドット積を使います。ややこしい文章になってしまったので、図で解説します。
d = v.i ただし v = 速度ベクトル 、i = サーフェス上ヒットポイント - オブジェクトの中心。
d を使ってImpactVelocity RTPC値に重み付けしました。
オブジェクトがインパクトを受けるポイントにまっすぐ向かっていれば、 d = 1 。ボールが床を転がっているときはdが小さいので、 RTPC値は減少します。
これでサウンドの統合がさらに改善されました。ボールが床で最初に跳ね上がったときと、そのあとに床を転がるときで、音が明らかに違います。
ところで、 d 係数を追加したことで、床を転がるとき以外の状況でもRTPCの計算が改善されます。例えば、高速で動くオブジェクトがほかのオブジェクトの側面をかすめただけの場合と、正面衝突した場合とでは違うことを、うまく表現してくれます。動的なインパクト(どちらのオブジェクトも動いているとき)では、双方のオブジェクトに d 値があります。そこで、これらの値のうちの最大値を、両方のVelocityのRTPC値の重み付けに使います。静的オブジェクト(床や壁)は d = 1(最大値)なので、衝突するオブジェクトが静的で衝突されるオブジェクトが動的な場合は、必ず動的オブジェクトの d を使います。
ものを壊す
Impacterは特定の種類のサウンド用にデザインされています。そのアルゴリズムは、振幅エンベロープが指数関数的に減衰し、主なトランジェント領域が1つだと仮定しています。言ってみれば、サウンドの「見た目」は次のようになります。
とはいえ、ほかの種類のサウンドではどうなるかを探ることも可能です。Impacter Unrealデモでは、トランジェント領域が複数あるという点でこのアルゴリズムの仮定に反するような、壊れたり砕けたりするサウンドをいくつか用いています。
ここでの問題は、振幅エンベロープが音によって明らかに違うということで、ボディコンポーネント(共鳴する部分)で不自然な、まるでringing(鳴り響く)るような音が発生する可能性を生み出します。 オシレータとフィルターバンクの振幅は、元の音の振幅エンベロープに従います。 それを、全く違う振幅エンベロープのサウンドのインパクトコンポーネントと組み合わせると、人工的に聞こえます。
ImpacterのUIにあるチェックボックスは、このような状況を想定して、含めるか含めないかを設定できるようにしています。複数サウンドのセットに対してクロスシンセシスを試してみて、問題のあるインパクトやモデルの組み合わせがあれば、それを除外できます。
Unrealで、Destructible Meshesを利用して、十分な力で衝撃を与えると壊れるようなブロックを作りました。破壊(Break)サウンド用のImpacterインスタンスがありますが、インパクトと同様に、この破壊サウンドにもRTPCに接続されたMassやVelocityがあります。
また、このような破壊音を実装するときの別のアプローチとして、破壊して砕けて環境(そしてお互い)と衝突したときに、個々の破片がWwise Impacterサウンドをトリガーさせる、というやり方もできます。こうすれば、複数の個別のインパクトサウンドが組み合わされ、「破壊と散乱」のサウンドが、ゲーム内で起きる物理的な接触の直接の結果として出現します。Unrealデモの破壊可能なボックスがその一例です。最初は、ボックスが壊れるときにトリガーされる破壊(Break)サウンドを使ってみました。
この破壊サウンドは非常に特徴のある振幅エンベロープと、複数のトランジェントがあり、問題でした。動画で分かるように、大きなボックスの破壊と複数のトランジェントは聞こえますが、それに対応する物理的なやりとりがありません。そこで、ボックスの各パーツにImpacterComponentを付けることにしました。これらのImpacterComponentは、最初はアクティブでありません。ボックスが壊れると、個々のパーツのImpacterComponentがアクティブになり、コリジョンに反応し始め、Wwiseイベントがトリガーされます。そうするとボックスが破壊されたときに、パーツのそれぞれのインパクトで、破壊と散乱のサウンドが自然につくり出されます。
Positionのマッピング
PositionパラメータはUnrealデモの大部分でランダムに設定され、サウンドの多様性を広げてくれます。Positionパラメータは、一部のフィルタやオシレータのゲインを下げることで、レゾナンスを変化させます。非線形の周波数に依存するゲインランプが、サウンドのBodyコンポーネントに適用されます。Positionパラメータは、この内部のゲインランプの位置を制御します。言い方を変えると、Positionを変えて音のレゾナンスを微妙に変化させることができるのです。Positionを0に設定すると、音がめいっぱい響きます。つまり、ゲインリダクションは適用されません。Positionが0から1になるときに、内部のゲインランプが、ピーク周波数のゲインをゆっくりと下げたり上げたりします。
Impacterデモでは、大きなガラス壁で、インパクトの位置から壁の中心までの距離を、ImpactPosition RTPCにマッピングします。マッピングは逆方向で行われ、コーナーやエッジのレゾナンスを最も大きくして、インパクトが中央に向かっていくほど、様々なピーク周波数を減衰させます。
学んだこと
ゲームの物理からRTPCに対するマッピングを充分に考慮できれば、インパクト音を統合するツールとして、Impacterは非常に役に立ちます。Impacterでサウンドを統合する際に注意してほしい一般的な原則を、ここで紹介します。
範囲全体を考慮した設計に
- ゲーム物理と統合したときに完全に表現できるように、MassやVelocityのパラメータの両端のサウンドをテストしてください。
威力を活用
- ImpacterのVelocityパラメータは、コリジョンの勢いで動かすようにしてください。このとき、2つのオブジェクトの密度や運動量など、様々な要因が影響します。
ポジションを変え続ける
- 最大限のバリエーションが欲しい場合は、Positionパラメータをランダム設定にしたほうが一般的に良いです。音の響きに微妙な変化が生じ、銃弾の衝撃や足音などの場面には特に便利です。
ルールは破って良し、でも短く
- 衝突のサウンド用につくられていますが、ほかにも色々とインプットして結果を見るのも、やはり面白いものです。ただし、特に長いサンプルを追加するときは注意が必要です。シンプルなインパクトは分析の段階がわりと速いですが、長い音を分析する場合は、時間がかかるかもしれません。
次回3回目のブログは、クロスシンセシスでつくり出すバリエーションについてです!
コメント