真砂楼の開発手法について Steam Audio編
今回は真砂楼で採用したSteam Audioについて紹介します。
真砂楼の開発手法について サウンド編 - ゲームを作ったり作らなかったり
の続きになります。
UE4+Steam Audioで出来る事と、実際に対処したアンチパターンを解説します。
前置き
本記事で解説する内容は、真砂楼の開発においてSteam Audioを使用した際に得た知見に基づきます。
UE4はランチャーからダウンロードした4.25.4を使用し、Steam Audioはそれに付属するプラグインをそのまま使用しました。
また、開発中はC++でのプラグイン拡張は行わず、コードを見てプラグインの内容を検証したりまではしていません。
その為、技術的な詳細に関しては誤った内容が含まれている可能性があります。(特にメモリ・ロード周り)
Steam Audioとは
https://valvesoftware.github.io/steam-audio/
Valveが提供している空間音響(Spatial Audio)ソリューションです。
UE4では標準搭載のプラグインとなっているので、プラグイン一覧で有効化する事で使用可能です。
UE4プラグインのドキュメントは以下のURLにあります。
https://valvesoftware.github.io/steam-audio/doc/phonon_unreal.html
対応プラットフォームはPCとAndroidになるので、コンソールは対象外になります。
その為、コンソール移植を考えているタイトルで採用する場合は注意が必要です。
UE4用プラグインではゲーム・VR用に3Dサウンドを提供するものとなっています。
ちなみに、UE4に標準搭載されている空間音響用プラグインでは他にOculus Audio・Resonance Audio・MicrosoftSpatialSoundがあります。
Steam Audioで出来る事
コード編集無しで空間音響をセットアップ
基本的には、
・プロジェクト設定
・Sound Attenuationアセットから指定するSteam Audio用のアセット設定
・レベル上の各アクタにPhonon GeometryやPhonon Materialを追加して設定
上記の設定で完結する為、プラグインのソースコードを編集したり、プロジェクト内でBPやC++を使って操作する必要もありません。(機能拡張を行う場合は当然必要です)
HRTFの補間方法の選択
UE4標準の機能でも空間化の方法としてPanningとBinauralを選択できます。
おそらくBinauralを選択した際にHRTFが使用されるものと思われるので、Steam AudioでHRTFを利用可能なのは特段のメリットではなさそうです。
但し、Steam AudioではHRTFの補間方法としてNearestとBilinearを選択出来ます。(サウンド単位で設定可能)
Nearestを選択した場合はBilinearよりCPU負荷が下がる為、パフォーマンス最適化向けのオプションと思われます。
ゲーム内の環境(シーンのジオメトリ)に応じた音響効果
Steam Audioでは、オクルージョンだけでなくリバーブもシーン上のジオメトリから計算します。
計算方法にはリアルタイム処理とベイクデータを用いた処理の2種類が用意されており、リアルタイムの場合はPhonon・Intel Embree・AMD Radeon Raysの3種類からレイトレーサを選択出来ます。
ハードウェア依存性を考慮する場合はデフォルトのPhononを選択するのが良いかと思います。
真砂楼ではPhononを使用しました。
また、AMD TrueAudio Nextがサポートされており、パフォーマンスを考慮して選択できるようになっています。
リスナー中心のリバーブとソース中心のリバーブ
ベイクにおいては、リスナー中心のリバーブとソース中心のリバーブをそれぞれベイクする事が出来ます。
リスナー中心のリバーブはシーン全体のベイク、ソース中心のリバーブは各Audio Component単位のベイクとなります。
両者は、併用するかどちらか片方を使用するかの選択が可能です。
真砂楼では作業量を減らすためにリスナー中心のみを使用しています。
材質の設定
Steam Audioでは、各アクタにPhonon Materialコンポーネントを追加する事でアクタ単位の材質設定が可能です。
材質設定はオクルージョンとリバーブの計算に使用され、遮音・吸音・伝搬等のパラメータが反映されます。
材質は用意されているプリセットから選択できる他、自分でカスタムした設定値を使用することも可能です。
ただし、カスタムしたものをプリセットに追加する事は出来ない為、様々なアクタに個別に値をもたせたい場合は手入力する事になります。
なお、プロジェクト設定からデフォルトの材質を設定出来るようになっており、これを利用して全体に適用し、一部のアクタのみ材質を変更するのが実用的な運用になります。
真砂楼では、プロジェクト設定ではカスタムした値を適用し、一部の岩や石膏のみプリセットを個別適用しています。
リアルタイムとベイクの違い
リアルタイムのリバーブにした場合はベイクと比べてCPU負荷が増加します。
CPU負荷はプロジェクト設定からCPU使用率を指定する事でスケーリング出来ます。
ベイクのリバーブではリアルタイムと比べてCPU負荷の増加が少なくなります。
ただし、ベイクデータの読み込み・構築が必要になる為、ロード時間とメモリ使用量が増加します。
どちらを選択するかはプロジェクトの傾向を見て判断するのが良いかと思います。
具体例として、真砂楼では全てのレベルを可視状態にした場合の全体ポリゴン数は300万程度です。これをそのままベイクした場合、一番高い品質でベイクするのに4~5時間以上かかり、ベイクしたデータの容量は150MBを超えます。
この条件ではリアルタイムにした方が良さそうですが、以下の点から今回はベイクを選択しています。
・真砂楼の開発においてはCPU最適化よりもGPU最適化に作業コストを割くべきと判断
→最初からベイクを選択してなるべくCPU負荷が低い状態にしておく
・開発終盤にサウンド以外の部分でCPU負荷が増加して目標値を超えた場合、最悪はサウンドで負荷を下げる必要がある
→その時はリアルタイムからベイクに切り替える事になるので、それなら最初からベイクを選択
結果として、真砂楼のCPU負荷は非常に低く、開発終盤にCPU最適化コストはほぼかかりませんでした。60FPSが推奨環境での基準ラインだった為、Game Threadが16msを超えないのが絶対でしたが、DevelopmentパッケージではCore i7 9750Hで5ms以下となっています。
この数値で見るとリアルタイムに切り替えても問題は無さそうな範囲ですが、プロジェクト後半にリアルタイムでの負荷とリバーブ品質を検証する時間が無かった為、今回はそのままベイクを選択しました。
なお、リアルタイム時のCPU使用率の設定はBPに公開されていない為、環境に合わせたスケーリングが出来ないことを考えると、実際にリアルタイムに切り替えた場合は最小環境のCPU指定を考慮する必要があったと思われます。
アンチパターンとその対処
直接遮蔽の音の減衰率が高すぎる
真砂楼では襖の隙間から電源のついたテレビを見る、というシーンがあります。この際に襖で視線が塞がれてテレビが見えなくなると、サウンドが襖で遮蔽される事になり、音量が減少します。
ここまでは問題無いのですが、Steam Audioに用意されている材質のプリセットには襖に近いものがなく、更に全体的に減衰率が高いので、ほとんど音が聞こえなくなってしまいます。
そこで、真砂楼では減衰率の低いカスタム値を用意し、それをプロジェクト設定で一括して適用しました。これは襖以外にも減衰率が低いオブジェクトが全体的に多い為、一括適用した上で一部の減衰率が高いものには個別適用する方が効率が良いと考えた為です。
ベイクデータが大きいとロードに時間がかかる
真砂楼ではベイクデータを使用したリバーブを選択しています。
ベイクするのはリスナー中心のリバーブのみですが、開発終盤にはその単体のベークデータだけで100MBを超えるようになりました。
これはほぼそのままメモリに乗るだけでなく、ロード・構築の為に時間がかかるようになります。
真砂楼で問題となったのは、タイトル画面とプレイアブルなシーンを同一のパーシスタントレベル(PL)にしている為、ベイクデータがタイトル画面へ遷移した時点でロードされる点です。
ゲーム起動→タイトル画面用PL→プレイアブル用PL
という流れであれば、ベイクデータをプレイアブル用PLに格納しておけばタイトルからプレイアブルへ遷移する際にロードされます。
しかし、
ゲーム起動→タイトル画面用PL→(そのままPLの切り替え無しでプレイアブルへ)
となる場合は、ゲーム起動後のタイトル画面用PLを開く時にベイクデータがロードされます。
ゲーム起動直後はロゴムービーが表示され、その間にベイクデータが処理されれば問題無さそうに思えますが、Steam Audioのベイクデータは紐付いているパーシスタントレベルを開く際に処理されるようです。
そのため、実際にはロゴムービーが終了しタイトル画面用PLを開いた直後に処理が始まることになります。
その結果、真砂楼ではムービー終了後にタイトル画面に遷移するまでに数秒の間が空くようになっています。
ムービー終了→タイトル画面用PLへ遷移→ベイクデータ処理→タイトル画面表示
という流れになり、ベイクデータの処理にかかる5秒程が待ち時間に直結してしまいました。
ちなみに、真砂楼では時間を最終的に5秒程に抑えられましたが、長い時は10秒を超えていました。
この長い待ち時間はベイクデータを小さくすれば解決する、と思いきやそうではありませんでした。
結論から言うと、ベイク前のプローブ配置で不要な箇所にプローブが置かれており、それが原因でした。
真砂楼では窓から外の景色が見えないように黒い板で窓の周辺を覆っているのですが、この板が斜めに角度をつけて配置されている箇所に対してプローブが配置されていました。
これがそのままベイク時に反映された結果、ベイクデータが複雑になっていたものと思われます。
これについて対策しつつ、ベイクデータ自体も小さくなるように背景を削減した結果、最終的には待ち時間が5秒程まで縮小されました。
ベイクデータが大きくなりすぎる
Steam Audioのベイクデータの容量は基本的にベイク対象となるシーンの総ポリゴン数が影響します。(300万ポリゴンで100MB~)
ベイク対象となるのは可視状態になっているレベルのみなので、ベイク対象から外したいプロップ等は別のサブレベルへ移動し、サブレベルを不可視状態にすることでベイク対象から外すことが出来ます。
狭い場所でリバーブが効かない
ベイクは配置されたプローブを基に行われる為、プローブが1つも配置されていない箇所があるとリバーブが効かなくなります。
PhononProbeVolumeのHorizontal Spacingの値が水平方向の配置間隔になるので、このデフォルト値400から更に低い値にする事で配置間隔を狭める事が出来ます。
真砂楼では120に設定する事で幅2m以下の狭い通路にも確実にプローブが配置されるようにしています。
シーンをエクスポートする時やベイクする時にエディタがクラッシュする
エクスポートやベイク対象に含まれるアクタの条件によってはエディタがクラッシュします。
コンポーネントの可動性(Mobility)がMovableのものが対象に含まれているとクラッシュするようで、真砂楼ではMovableが含まれるBPが配置されているサブレベルを不可視状態にして回避しました。
最後に
真砂楼の開発を通じてSteam Audioのメリットを感じたのは、
・環境に合わせたリバーブをプロシージャルで実現出来る
・材質設定に沿った遮蔽が出来る
の2点でした。
真砂楼としては前者の恩恵を大きく受けていると思います。
後者に関しては、デフォルトのプリセット値を変更出来ないのと、プリセットを各アクタで指定する作業を自動化出来なかったので、とりあえずの適用をしたのみとなりました。
Steam Audioの使用は初めてだったので、検証をしながらの作業となりそれなりの時間を割きましたが、その分の空間音響は得られたと思います。
ベイク時のメモリ・ロード周りの問題と、コンソールに対応していないという点がネックではありますが、PCのみに絞った開発であれば十分使用出来るプラグインだと感じました。