|
執筆バージョン: Unreal Engine 5.6
|
UEがヒッチする理由は二つある。GCとSpawnActorだ!(諸説あります)
ゲームを作っているとどうしても避けられないSpawnActorですが、こちら中々に重たい処理です。
複数のアクタを一度にスポーンさせずに複数フレームに分散したり、オブジェクトプールを作成して使いまわしたりと、プロジェクト毎にそれぞれ工夫されている事と思います。
今回、SpawnActorを高速化(出来るかもしれない)フラグのご紹介と、その効果のほどを検証していきたいと思います。
はじめに
SpawnActorを高速化する夢のフラグ、それがAActor::bOptimizeBPComponentDataです。
エディタなら、Cooking – Advanced – Generate Optimized Blueprint Component Dataがそれです。

マウスカーソルをあわせてTooltipを表示してみると
「Whether to cook additional data to speed up spawn events at runtime for any Blueprint classes based on this Actor. This option may slightly increase memory usage in a cooked build.」
とあります。
皆さん英語は得意ですか?僕は苦手なのでエディタの言語を日本語にしてもう一度、Tooltipを見てみましょう。
「このアクタに基づくすべてのブループリントクラスで、実行時にスポーンイベントを高速化するために追加データをクックするかどうか。このオプションを使用すると、クックされたビルドでのメモリ使用量がわずかに増加する可能性があります。」との事です。
それでは、こちらのフラグの効果のほどを検証してみたいと思います。
計測準備
まずは計測用のブループリントを用意しましょう。
Actorを親に、StaticMeshComponentを追加してキューブを設定しただけのシンプルなブループリントクラスを作ります。

コンポーネント構成
これをGenerate Optimized Blueprint Component Dataにチェック入れた版と、入れない版で別クラスとして保存して、それぞれスポーンさせて処理時間を計測したいと思います。
Generate Optimized Blueprint Component Data チェックなしを、TestActor_BP_NoOpt。
Generate Optimized Blueprint Component Data チェックありを、TestActor_BP_Optとしました。
以上でブループリントクラスの準備は完了です。
次にアクタをグリッド状にスポーンする関数「SpawnActor on Grid」を作成します。
1つだけスポーンしたのでは、処理時間が短すぎて誤差が出てしまいそうなので、たくさんスポーンさせる作戦です。
検証の本質ではないので詳しくは解説しませんが、こんな感じの関数をレベルブループリントに作成しました。

SpawnActor on Grid関数
Generate Optimized Blueprint Component Dataはエディタ上で実行したのでは効果がありませんので、パッケージをビルドしてから計測します。
これで準備が整いました!
計測
それではUnrealInsightsを用いて計測していきましょう!
計測環境は以下の通りです。
CPU: Ryzen 7 5700X
メモリ: DDR4 3200MT/s
SpawnActor on Gridを使って、1万個ずつアクタをスポーンさせていきます。

ドカンとスポーンされた TestActor_BP_NoOpt 1万個と、TestActor_BP_Opt 1万個。合計2万アクタ
そしてUnrealInsightsの計測結果がこちら!

TestActor_BP_NoOpt 1万個のスポーンが1.6秒。
TestActor_BP_Opt 1万個のスポーンが1.4秒。
大体12%ほどの高速化となりました!
計測準備 その2
思ったんですけど、実際のゲームではコンポーネントが1つだけのアクタというのは現実的ではないですよね。
もっとたくさんのコンポーネントを追加して、もう一度計測してみます。
TestActor_BPに更にSceneComponentを10個追加したクラスを作成します。

コンポーネント構成
Generate Optimized Blueprint Component Data チェックなしを、TestActor_BP_10_NoOpt。
Generate Optimized Blueprint Component Data チェックありを、TestActor_BP_10_Optとしました。
これで再度計測をしてみましょう。
計測 その2
早速ですが計測結果がこちら。

TestActor_BP_10_NoOpt 1万個のスポーンが2秒。
TestActor_BP_10_Opt 1万個のスポーンが1.7秒。
約15%ほどの高速化となりました。
計測準備 その3
今までの検証ではエディタ上で作成したブループリントクラスで計測を行いましたが、同じコンポーネント構成を再現したC++クラスを作成して、そちらでも計測を行いたいと思います。
こんな感じでC++でコンポーネントを作成していきます。
|
|
//疑似コードです ATestActor10::ATestActor10() { Cube = CreateDefaultSubobject(TEXT("Cube")); SetRootComponent(Cube); const int SceneNum = 10; for (int i = 0; i < SceneNum; ++i) { FName ComponentName(FString::Printf(TEXT("Scene%d"), i)); TObjectPtr temp = CreateDefaultSubobject(ComponentName); temp->SetupAttachment(Cube); Scenes.Add(temp); } } |
そしてエディタ上で、このC++クラスを継承したブループリントクラスを作成して、SkeltalMeshコンポーネントにキューブのメッシュを設定しておきましょう。
コンポーネントはエディタ上では追加しません!

コンポーネント構成 (Sceneの綴りをタイポしています…恥ずかしい……)
こちらもフラグありなしで、2種類のクラスを用意します。
Generate Optimized Blueprint Component Data チェックなしを、TestActor_C_10_NoOpt。
Generate Optimized Blueprint Component Data チェックありを、TestActor_C_10_Optとしました。
計測 その3

TestActor_BP_10_NoOpt 1万個のスポーンが1.9秒。
TestActor_BP_10_Opt 1万個のスポーンが1.7秒。
TestActor_C_10_NoOpt 1万個のスポーンが1.4秒。
TestActor_C_10_Opt 1万個のスポーンが1.4秒。となりました!
エディタでコンポーネントを追加していないクラスは、Generate Optimized Blueprint Component Dataをチェックしても高速化の恩恵はありませんでした。
TestActor_BP_10_Optと比べるとC++クラスの方が17%(1.7sec -> 1.4sec)程高速になっていますね。
TestActor_BP_10_NoOptと比べると25%(1.9sec -> 1.4sec)以上の高速化となっています。
どうしても速度を稼ぎたい場合は、C++でコンポーネントを作成する方が良さそうです。
メモリ使用量について
Tooltipに気になる事が書いてあったのを覚えていますでしょうか?
「このオプションを使用すると、クックされたビルドでのメモリ使用量がわずかに増加する可能性があります。」
こちらのメモリ使用量についても検証しておきましょう。
コンソールコマンドの「memreport -full」を使ってメモリ使用量を確認した結果がこちら!
| Class |
Count |
NumKB |
MaxKB |
| TestActor_BP_10_NoOpt |
10000 |
8515.62 |
9375.00 |
| TestActor_BP_10_Opt |
10000 |
8515.62 |
9375.00 |
| TestActor_C_10_NoOpt |
10000 |
7812.50 |
8750.00 |
| TestActor_C_10_Opt |
10000 |
7812.50 |
8750.00 |
Generate Optimized Blueprint Component Dataのあり・なしでメモリの使用量に変化は見られませんでした。
Tooltipsでも「可能性がある」と記載されていましたので、確定でメモリ使用量が増えるわけではないのかもしれません。
C++クラスよりブループリントクラスのほうがメモリ使用量が増えている点に注目ですね。
まとめ
- エディタでコンポーネントを追加したブループリントクラスは、C++で作ったコンポーネントに比べ、スポーン処理が重くなる
- それを緩和してくれるのがGenerate Optimized Blueprint Component Data
- メモリ使用量はわずかに増加する…らしい
(今回の検証ではメモリ使用量の変化は観測できませんでしたが、ご自身のプロジェクトでテストしていただきメモリ使用量をご確認の上、ご利用ください)
- C++で実装されたコンポーネントは、この高速化の恩恵はない
さいごに
フラグ1つにチェックいれるだけで簡単に試せますので、ご自身のプロジェクトでも是非お試しいただきたいです。
今回、計測にUE5.6を使用しましたが、UE4でもフラグは用意されていますので利用できると思います。
あなたの作っているゲームが少しでも速く動くようになれば幸いです。
それではみなさん、よいゲーム開発ライフを!