はじめに
Jater (Ruohao) Xuによる『逆コーラップス:パン屋作戦』の開発経験についての3部構成のブログで、今回は第2回目となります。最初の記事はこちらで読むことができ、Wwiseを使用したゲーム中のシネマティックスをWwiseで駆動する方法について解説します。パート3も近日掲載予定です。
傾いた2Dビュー用にカスタマイズされた、Wwiseリスナー位置投影システム
Techブログ|パート2
『逆コーラップス』のアートスタイルは独特であり、傾かせた2Dレベルマップの採用は、ゲームを際立たせるための芸術的な選択の1つでした。本ゲームのカメラビューは一見、上から下を見下ろした2Dビューのようです。ところが舞台裏では、レベルのマップがカメラの正面からわずかに傾いた面に詳細に仕込まれています。
上から下を見下ろす典型的な視線に3Dオーディオを合わせることは、比較的簡単です。一方、『逆コーラップス』のような傾いた2D面に対するトップダウンビューにおいては、デフォルトの3Dオーディオシステムで正確な結果を提供できない可能性があります。当初はこのアプローチを試しましたが、減衰のバグが発生してしまい、特にカメラを左から右へ、または上から下へ動かす時の問題が顕著でした。
これを解消し、傾いた2D面を見るトップダウンビューにシームレスに繋げるため、3Dオーディオのデフォルトシステムを調整したカスタムシステムをつくる必要がありました。
問題の状況を上図に示します。カメラの視錐台の観点から見ると、マップが傾斜しているように見え、デフォルトのオーディオ減衰では不正確となります。
解決策としてUnityゲームオブジェクト、スクリプト、Wwise RTPCなどを使った単純な投影システムを用い、オーディオ専用のXYZ投影座標システムを構築します。オーディオリスナーの位置をデフォルトのメインカメラ上からマップ回転後の変換後の位置に移すことにより、私たちの目的を達成することができます。本方式はWwiseのデフォルトオーディオ減衰とシームレスに統合できます。さらに手作業で減衰範囲を調整する必要のある特殊ケースにおいても、Wwise RTPCを通し、カスタム作成した座標システムを転用することができます。
これを達成するためにはまず、以下の動画においてマゼンタ色の立方体として表現される投影位置を、プレハブゲームオブジェクトとして設定する必要があります。このゲームオブジェクトを、メインカメラに対して一定のオフセット距離にある任意のカメラにアタッチします。本ゲームでは複数のカメラセットアップがあるため、今回のプロジェクトではこれをプレハブゲームオブジェクトとすることが重要です。実行時にどのカメラセットアップにおいても、そのゲームオブジェクトの子として投影システムを実装またはスイッチできなければなりません。ただしこのセットアップがすべてのプロジェクトにおいて同じとは限らないため、注意することが大切です。
プロジェクト位置のプレハブゲームオブジェクトを設定した後、次の手順として今回のWwise UnityインテグレーションにあるAkAudioListener.csスクリプトを親のプレハブゲームオブジェクトに追加します。この行為により、これがゲームのオーディオリスナーに指定されます。続いてMainCameraゲームオブジェクトから、デフォルトのオーディオリスナーを削除します。
上図はこのサウンド投影システムで使用する、今回の特別なオーディオリスナーとなるゲームオブジェクトのプレハブのセットアップです。その名はSoundProjectSamplerです。
上の動画がカメラビューから見た今回のマップの課題点や、エンジン側の最終的な稼働システムを披露しています。
座標データをUnityからWwiseへ転送するRTPCをWwiseで設定します。こうすることで、私たちが望むサウンド修正の結果を適用することができます。RTPCの具体的な範囲は、そのゲームのマップ単位によって異なります。今回のケースでは範囲を0~100に設定しました。
上記ソリューションと同様に、カメラオブジェクトにもスクリプトをアタッチし、LateUpdate()関数内に以下のRTPCコールを含めます。Update()関数においても機能しますが、LateUpdate()を使うことで、オーディオ座標をアップデートする前にすべてのレンダリング操作が完了することを保障できます。この順序がオーディオとビジュアルの同期を維持するために役に立ちます。
AkSoundEngine.SetRTPCValue(CameraDistance_X, Normalization(soundProjectionSampler.transform.position.x, 0.0f, 100.0f));
AkSoundEngine.SetRTPCValue(CameraDistance_Y, Normalization(soundProjectionSampler.transform.position.y, 0.0f, 100.0f));
AkSoundEngine.SetRTPCValue(CameraDistance_Z, Normalization(soundProjectionSampler.transform.position.z, 0.0f, 100.0f));
気づいたかもしれませんが、上記ソリューション内にある Normalization() というヘルパー関数が、最小値・最大値の範囲に基づいて、任意のfloat値を最終的に0~1の範囲に変換します。使用するRTPCの範囲を統一しやすくするために、このようなしくみを用意することを強くおすすめします。以下ノーマライゼーションの数式に従い、簡単に関数を記述することができます:
ノーマライズされた値 = (ノーマライズする値 - 下限値) / (上限値 - 下限値)
さまざまなプログラミング言語のノーマライゼーション式の実装例が、C#やC++のインスタンスなど豊富にあります。簡単なオンライン検索で複数の結果が出てくると思いますので、ここでは割愛します。
このRTPCを繋げることにより、Wwiseのデフォルト減衰システムを使い正確なオーディオ結果を達成することができます。加えてXYZ座標RTPCをオーディオソース自体に直接適用することにより、各サウンドを自由に微調整することも可能です。これによりサウンドデザイナーは自分の減衰システムを設定したり、デフォルトの減衰システムに重ねて拡張させたりすることができます。
この例ではゲームプレイレベル3009においてFungus(菌類)を手榴弾で着火した際、音の減衰がどのように修正されるのかが分かります。最初にFungus音を3DサウンドとしてWwiseの減衰を使い設定し、デフォルトの減衰設定を適用します。さらに私たちが作成した投影座標を使い減衰を駆動させ、正確なゲームマップ単位に基づいて音の減衰をさらにカスタマイズし、微調整してゆきます。
既存の減衰プロファイルと連動させるだけでなく、XYZ座標RTPCはゲームオブジェクトのスコープのサウンドに対しても、減衰エフェクトを個別に作成することができます。サウンドデザイナーはマップの各軸で音を微調整することができ、『逆コーラップス』のように独特なアングルをもつマップにおいても、正確な音響結果を生成する精密な調整が可能となります。
この柔軟性がサウンドデザイナーの技を深め、没入感あるオーディオ体験に繋がり、ゲームのビジュアルを補強してゲームプレイの雰囲気全体を高めます。
注:今回引用したコードスニペットは、この記事で紹介するために改めて再構築した汎用バージョンです。基礎にあるロジックが正しく機能することを確認済みであり、プロジェクト固有のAPIコールや関数は、著作権に抵触する可能性があるため省略しました。
コメント