CC2の楽屋裏

ゲーム制作会社サイバーコネクトツー公式ブログ

*

第007回UE4のアセットの参照方法について、そのロードの違い

   

皆さんボンジュール(フランスのあいさつ)!
ランダムのスペルが覚えられないプログラマ親泊です。

今回のTechBlogは、UE4のアセット参照方法についてと、そのロードがどうなっているか、になります。
まず、ゲームに必須なアセットですが、アセットは作ったら終わりではなく、そのアセットをゲーム内に読み込み、使用できる状態にしなければなりません。これはUE4でも同じです。
アセットは階層的に他のアセットを参照しています。例えば、StaticMeshからはMaterialを参照し、MaterialからはTextureが参照されています。この参照関係をもとにUE4ではエンジン側でいいかんじにロードしてくれます。こちらが意識せずともStaticMeshを読み込むと同時にMaterialとTextureも読み込みます。

スクリーンショット (19)

しかし、いいかんじにしてくれるからといってなんとなく作ると痛い目を見ます(痛い目を見た)。

アセットの参照方法について

リファレンスビューワー

UE4ではリファレンスビューワーで参照関係を見る事ができます。

スクリーンショット (20)

スクリーンショット (21)

白いワイヤーでつながっているのがハードリファレンス、マゼンタのワイヤーでつながっているのがソフトリファレンスです。

ハードリファレンス

アセットへの直接参照をハードリファレンスといいます。
ハードリファレンスを持っているアセットは、そのアセットがロードされたときに、参照先のアセットも自動的にロードされます。

メリット

自動的にロードされるので、ロードし忘れが発生しない。

デメリット

自動的にロードされているので、数が多くなるとメモリをたくさん消費し、ロード時間も長くなる。

シンタックス

1) UPROPERTY(Edit~)でプロパティから直接参照を持たせると、とりあえずハードリファレンスになります。
スクリーンショット (22)

2) コンストラクタでConstructorHelpers::~Finderでアセットを登録すると、ハードリファレンスになります。
スクリーンショット (23)

それぞれの特徴としてプロパティへ参照を持たせた場合は非同期ロード、コンストラクタで参照を登録している場合は静的ロードになります。

ソフトリファレンス

アセットへの間接参照をソフトリファレンスといいます。
ソフトリファレンスで指定されたアセットは、参照元のアセットがロードされても自動的にロードされません。ユーザー側で手動でロードをする必要があります。

メリット

ロードをユーザー側で決定できるので、細かい制御ができる。

デメリット

ロードをし忘れたり、ロードのタイミングが悪かったり、人為的なエラーが発生する。

シンタックス

ソフトリファレンス用のテンプレートTSoftObjectPtrとTSoftClassPtrを使うとソフトリファレンスになります。
スクリーンショット (26)

ソフトリファレンスは、アセットへのパス情報しかもっていません。非同期ロード、静的ロードは任意になります。

痛い目を見た話

私がソフトリファレンスを意識していなかった為に、実装後に修正しなければならないことがありました。

それはHitした物体にデカールを張り付けるという処理の中で、Hitしたオブジェクトの物理マテリアル種類(SurfaceType)と攻撃の属性を見てデカールのマテリアルを切り替えるという実装を行った際に起きました。切り替える種類は「SurfaceType × 攻撃側の属性」分あり、管理の利便性を考え2次元配列のマテリアルの参照テーブルをConstructorHelpers::ObjectFinder()関数にてコンストラクタで自動生成していました。

しかし、生成した参照がハードリファレンスだった為に、テーブルにあるマテリアルが自動的にロードされる仕組みになっていました。開発が進むにつれてSurfaceTypeと攻撃側の属性の数がだんだん増えていった結果、データテーブルには約750個のマテリアル参照が存在し、データテーブルをロードしただけで200MBのメモリを消費するようになっていました。

結局この問題は
1. 各レベルで使用されるマテリアルを特定し、リスト化する
2. リストを元に常駐アセット、管理アセットで分ける
3. 常駐アセットを起動時にロードし、管理アセットはレベル遷移時にロード/アンロードを適宜行う
という対応を取ることで解決しました。

参照を意識した設計

上記のハードリファレンスとソフトリファレンスの特徴を踏まえると、ファクトリーやマネージャーへソフトリファレンスで選択の余地のあるアセットを登録します。(便宜上この選択の余地のあるアセットをキーアセットと呼びます。)キーアセットへハードリファレンスで必須パーツを登録すると、キーアセットのロードから自動的に必要なアセットをすべてロードできる流れができます。
ここで、必須パーツとは、選択の余地がないアセットを指します

ここで重要なのは、キーアセットによってロードが必要なアセット単位を切り分けられるということです。

スクリーンショット (41)

この設計を意識して、キャラクターを作るファクトリーを作ってみます。

ディレクターから来た要件:同じメッシュを利用して、マテリアルだけ変えたキャラクターでキャラクター数を水増ししたい。

上記の要件であれば、メッシュは同じものを利用するので選択の余地がありません。マテリアルは変更するので、キーアセットとして利用します。したがって、ファクトリからのアセットリファレンスは、以下のようになります。

キャラクターブループリント:ハードリファレンス
キャラクターメッシュ:ハードリファレンス
キャラクターメッシュのマテリアル:ソフトリファレンス
スクリーンショット (46)

レベル起動時にファクトリーから指定したキャラクターを作ります。キャラクターをワールドにスポーンした後、特定のマテリアルをロードし、メッシュへ登録します。
スクリーンショット (31)

すると、生成されるキャラクターによってマテリアルが変わっているのが確認できます。
スクリーンショット (47)

ここで比較のために、ファクトリーにハードリファレンスでマテリアルを登録したバージョンを用意します。
スクリーンショット (45)

青いグレイマンのみのレベルを用意して「ソフトリファレンスあり」と「ハードリファレンスのみ」でMemReportを取ります。
スクリーンショット (37)

MemReportの比較から、不必要なマテリアルがロードされていないことが確認できます。
スクリーンショット (34)

まとめ

どんなゲームでも、ローディング時間やメモリ効率は常にプログラマの敵として存在します。快適なプレイ環境を提供するために、必須アセットと状況によって読み込むアセットをきちんと整理して管理するという点を意識していきたいですね。

参考

アセットの参照

アンリアル エンジン 4 のメモリリーク対策

おわりに

さて、今回のTechBlogいかがだったでしょうか?
アセットの参照は初期段階で整理しないと、見えない工数と化して開発スケジュールを圧迫します。さらにただただ面倒なので、モチベーションも下がってしまいます。
常に最善の策を模索して、効率的な開発を!

皆さんのご意見、ご要望をお待ちしています。下記 CC2技術ブログのメッセージフォームにて、お気軽にお問い合わせください。

「CC2技術ブログ」へのご意見・ご要望はこちらから

 - CC2技術ブログ

  関連記事

CC2技術ブログ
第006回 コマンドラインからConfig設定を上書きする時の注意点

皆さん、こんにちは。サイバーコネクトツーでテクニカルサポートのマネージャーをして …

tb004_15
第005回 Tick関数がどう処理されているかUnrealC++を追ってみよう!

皆さんグーテンターク(ドイツのあいさつ)! CC2TechBlog今回の担当は新 …

tb004_09
第004回 UE4のアセットを一括修正する

ツール系テクニカルアーティストのしばはらです。 プロジェクトが進んで、ある程度ア …

tb002_04
第002回 アクタのトランスフォームの実態

皆さんストラーズドヴィーチェ(ロシアのあいさつ)! 今回の担当は、新人プログラマ …

第001回 UE4のコンテンツブラウザフィルターを自作する

はじめまして サイバーコネクトツーでツール系テクニカルアーティストをしております …

第003回 UE4のショートカットキーの仕組み

今回は ツール系テクニカルアーティスト しばはらがお送りします。 突然ですが、P …