ゲームを作ったり作らなかったり

ゲームを作ったり作らなかったり。作ってる時はUE4/モデリング/レベル・サウンドデザイン等、作ってない時はインディゲーム・SteamやModの話題等。

真砂楼の開発手法について ライティング&GPU最適化編

今回は真砂楼のライティングとGPU最適化について紹介します。
真砂楼ではどのようなライティング手法を用いたのかと、その上でどのようにGPU最適化を行ったか解説します。

真砂楼のライティングコンセプト

スクリーンショットスクリーンショット

真砂楼のグラフィックの方向性はフォトリアリスティックで、すべてUE4の標準機能を用いました。
ポストプロセスは一部の演出で用いるのみで、グラフィックの個性を出す為にはほぼ使用していません。(トーンマッパーでのコントラスト・彩度の調整のみ)

ゲーム内容が屋内探索のみになるので、プレイヤーが持っているという設定の懐中電灯の光が主なライティング要素となります。但し建物の一部は月明かりが入る設定です。

プレイヤー用のスポットライト

真砂楼のライティングではプレイヤーが持つ懐中電灯の光が大きな部分を占めています。

この懐中電灯の光を再現するにあたっては、実際にプレイヤーの頭に近い位置にスポットライトを配置しています。

なお、カメラと全く同座標と言うわけではなく、あえて若干ずらしています。
これは同座標だと光で照らした先に浮かぶ影が視認出来ない為、あえて座標をずらして角度をつけて照らす事で影を映すようにしています。

f:id:tekktekk:20210424195407p:plain

IESプロファイルとライト関数

真砂楼の開発初期では、懐中電灯の明るさのムラを表現するのにIESプロファイルを使用していましたが、途中からライト関数へ切り替えました。

ライト関数ではライトの微調整が出来ること、及びテクスチャの調整がしやすいことから最終的にそのまま使用しています。

IESプロファイルよりライト関数の方が負荷は高い為、可能ならばIESプロファイルを使用するのが望ましいですが、その分を考慮しても細かい調整がしたかったので今回はライト関数を使用することにしました。

f:id:tekktekk:20210424200540p:plain

懐中電灯っぽさを出す為に、単に円形のライトにするだけでなく環状の暗い部分を設けたり、範囲外は完全に暗くしています。

SSGI

真砂楼では、SSGI(Screen Space Global Illumination)を使用しています。
名前の通りスクリーンスペースのGIなので、画面内の映り方によって効果が大きく変わるものですが、真砂楼では画面内をほぼ同じようにスポットライトで照らす為、一定した効果が得られると期待してSSGIを導入しました。

真砂楼では4段階のグラフィック品質を設定できるようになっていますが、色味が変化しないようにどの設定でもSSGIを使用するようにしています。
また、SSGIの品質はどの設定でも最低品質を使用し、r.SSGI.HalfRes=1で解像度を半分に下げています。
これはSSGIに高い品質を求めていないのでなるべく負荷を下げる為の処置です。
品質を下げる事で副作用としてAOのノイズが大きくなりますが、これも画面内が常にスポットライトで照らされている事でほとんど目立たなくなっています。

f:id:tekktekk:20210424201116p:plain

SSGI有り。自販機の赤色が隣接する壁に反映

f:id:tekktekk:20210424201138p:plain

SSGI無し

指向性ライトとスポットライト

真砂楼ではプレイヤー用のスポットライト以外にも月明かりを表現するためにスポットライトをレベル上に配置しています。
開発当初は指向性ライトにしていましたが、最適化の為にプロジェクト後半からスポットライトに変更しています。 

GPU最適化

GPU最低環境と推奨環境

Steamに記載している真砂楼のハードウェア情報は、

GPU最低環境
GTX950相当
グラフィック設定最高(Epic相当)・1080p・30FPS動作を前提

GPU推奨環境
GTX1650相当
グラフィック設定最高(Epic相当)・1080p・60FPS動作を前提

となります。
最低環境に関しては、テスト出来る中で最もパフォーマンスが低いGPUがGTX950だったのでこの設定になっています。
実際にはグラフィック設定を落とすことでビデオカード非搭載のPCでも一応プレイ出来ます。

推奨環境は当初GTX1050とする予定でしたが、一時的に60FPSを切ってしまうのをクリアするのが難しかったのでGTX1650に引き上げました。
GTX1650なら推奨環境の定義をすぐにクリア出来たので、それ以降は最低環境の為の最適化に注力しました。

パフォーマンス確認方法

基本的にはコンソールコマンドのstat GPUを使用してDevelopmentビルドで確認しました。

GPU最低環境は自分の環境では無かったので、StartFPSChartとStopFPSChartのコマンドでFPSチャートを作るようにし、その結果を共有してもらいました
流れとしては、まず自分の環境で最適化による効果の有無を確認し、その後FPSチャートで最低環境での効果の程度を観察しました。

今回は基準ラインである30FPS(33ms)だけを見ていたのでFPSチャートを使用しましたが、内訳を細かく見たい場合はProfileGPUコマンドやUnreal Insightsを使うのが良いかと思います。

最適化内

各ライトのShadow Resolution Scaleを削減

真砂楼では基本的にどのライトもShadow Resolution Scaleをある程度減らしています。
ただ、指向性ライトを使わないことでシャドウマップの描画自体がかなり抑えられている(影が落ちる場所が少ない)ので、そこまで大きな効果はありませんでした。
なるべく見た目に影響の無い範囲でShadow Resolution Scaleを下げ、その後Shadow Filter Sharpenを上げる事で元と近い見た目になるよう調整しています。

スポットライトのMobilityをMovableからStationaryに変更

背景用のスポットライトは全てMobilityをMovableからStationaryに変更しました。
スポットライト同士が近く、範囲が重なっている箇所ではあまり効果がありませんが、元々スポットライトの配置数が少ない箇所では効果がありました。

スポットライトのカリング距離を設定

ToggleDebugCameraコマンドとFreezeRenderingコマンドを使用してプレイヤーの視界外を観察してみると、メッシュはカリングされていてもライト自体はカリングされていないようでした。

これにより不要な場所でボリューメトリックフォグが描画されていたので、Max Draw DistanceとMax Distance Fade Rangeに値を入力して距離の制限を加えました。

Precomputed Visibilityを使用

真砂楼で最も負荷が高いのがVisibility Commandsだったので、これを削減するためにまずはCull Distance Volumeの調整を行ったのですが、劇的な効果はありませんでした。
(映ってほしいものが映ってなかった、というのを避ける為にあまり積極的な数値を入れなかったのもあります)

動的オクルージョンの調整でも削減が難しく、stat GPUのVisibility Commandsで5msを超えてしまう程でした。
そこで本来行う予定はなかったのですがPrecomputed Visibility(事前計算された可視性)を使用する事にしました。
Precomputed Visibilityはビルドする必要がある為、サブレベルのロード・アンロードで表示・非表示が切り替わるアクタがあると影響を受けてしまうのでその点に注意が必要なのですが、Visibility Commandsの削減には非常に効果がありました。
結果的にVisibility Commandsを3ms程度に抑えられたので、最も効果があった最適化になりました。

ボリューメトリックフォグ

真砂楼ではExponential Height Fogは効果的に使わず、エフェクトの為だけにボリューメトリックフォグを使っているので、ボリューメトリックフォグにかかるコストはなるべく削減しました。

r.VolumetricFog.GridPixelSize
r.VolumetricFog.GridSizeZ

のコマンドをそれぞれデフォルト値の半分以下に変更しています。

最後に

あまり具体的な数字が出てこない事からも分かる通り、あまり厳密な最適化は行っていませんが、ひとまず最低環境の要件は押さえられました。

2~3世代前のエントリークラスGPUでEpic設定・フルHDで30FPS、という条件なので、ゲーミングPCを持っている人ならとりあえず負荷も画質も気にせず遊べる程度にはなっていると思います。

今回最適化にかけたコストは低く、推奨環境はGTX1650に設定した時点で要件をほぼクリアしていたので、最低環境で要件をオーバーしそうな所に的を絞りました。

最適化の作業期間はおよそ1~2ヶ月程で、プロジェクト中盤から定期的にパフォーマンスを見ておき、プロジェクト後半で気になる所を重点的に行う、という流れでした。



今回で真砂楼の開発手法に関する記事は最後となります。

一年ぶりに記事にしただけあって、このブログ始まって以来で最も内容のある記事になった気がします。
とは言えもう少し具体的な内容のものを書いていきたいですね。(最適化に関しては開発中にちゃんと資料を残しておけばよかったと後悔)

UE4を使って自分自身の手でゲームを開発してリリースする、という目標に関しては今回の経験でだいぶ近づくことが出来ました。
ゲームを作るために何が必要で、何をすればリリース出来るか、そしてそのスケジュール・ワークフローをどう考えるか、は一通りわかるようになってきました。

今後はこの経験を生かして、自分が作りたいゲームのリリースに向けて頑張っていきたいです。