【Unreal Engine】UE5のソフト参照と非同期ロード:使わないメッシュまで読み込まれる問題を直す

作成: 2026-07-20

アセットを参照しただけで実体までメモリに載る仕組みを図解。ハード参照とソフト参照の違い、Soft Object / Soft Class Referenceの作り方、Async Load Assetで必要になってから読み込む手順、Load Asset Blockingを避ける理由、そして仮メッシュを見せてから差し替える実践まで。

敵を1種類しか出さないマップなのに、レベルを開くと全種類の敵のメッシュがメモリに載っている。序盤の草原にいるだけなのに、ラスボスの巨大なメッシュまで読み込まれている。Blueprintを1つ開くだけで、関係するアセットが芋づる式に引きずられて、起動に何十秒もかかる。

これらは、 アセットを参照した瞬間に、その実体まで一緒に読み込まれる ことから起きています。UEでこれを制御するのが ソフト参照非同期ロード です。参照を「場所だけ覚える」形に変え、実体は必要になってから読み込みます。この記事では、ハード参照とソフト参照の違いから、ソフト参照の作り方、 Async Load Asset で読み込む手順、避けるべき同期ロード、そして仮メッシュを見せてから本物へ差し替える実践までを解説します。

使うメッシュだけが載ったメモリの箱と、使わないメッシュまで載って膨らんだ箱を見比べるソフトブルーの人形

この記事でわかること

  • ハード参照は 一緒に読み込まれる 、ソフト参照は 場所だけ覚える
  • Soft Object Reference / Soft Class Reference の作り方
  • Async Load Asset必要になってから 読み込む
  • Load Asset Blocking使わない理由
  • どこで効くか( 大きなメッシュ・カットシーン・ボス・DLC
  • 実践: 敵のメッシュを、必要になってから読み込む

Sponsored

ハード参照とソフト参照の違い

まず、UEで「参照する」とは何かを整理します。変数の型を Static Mesh(オブジェクト参照)にして、そこにアセットを入れる。これが ハード参照 です。このとき、参照した側を読み込むと、参照された相手も 必ず一緒に メモリへ載ります。

ハード参照は1つ読むと連鎖して全部読み込まれ、ソフト参照は場所だけ覚えて実体は読み込まないことを示した対比図

問題は、これが 連鎖する ことです。敵のBlueprintがメッシュをハード参照し、そのメッシュがマテリアルを、マテリアルがテクスチャを参照している。すると、敵のBlueprintを読み込んだだけで、その先のマテリアルもテクスチャも芋づる式に読み込まれます。敵を20種類 Data Table に並べていれば、1体出すつもりでも20体分が引きずられます。

ソフト参照 は、この連鎖を断ち切ります。ソフト参照が持っているのは実体ではなく、 アセットの場所(パス)を書いた文字列 です。「/Game/Enemies/SM_Dragon にドラゴンのメッシュがある」と覚えているだけで、ドラゴンの実体はメモリに載りません。

ハード参照ソフト参照
持っているものアセットの 実体アセットの 場所(パス)
読み込むと相手も 一緒に 載る相手は 載らない
使うときそのまま使える自分で 読み込んでから 使う
向いているもの常に必ず使う軽いもの大きい、使うとは限らないもの

ここが要点です。 ソフト参照は「読み込まない」仕組みではなく、「読み込むタイミングを自分で決める」仕組み です。実体が要るときは、次の節以降で自分で読み込みます。

Sponsored

ソフト参照の作り方

作り方は、変数の型を選ぶときの 参照の種類 を変えるだけです。

変数の型ドロップダウンで、オブジェクト参照からSoft Object Referenceへ切り替える様子を示した図

変数を作り、型のドロップダウンで目的のアセット型(Skeletal Mesh など)を選ぶと、右側にもう一段の選択肢が出ます。ここで参照の種類を選びます。

参照の種類意味
Object Referenceハード参照(実体)いつものメッシュ変数
Soft Object Referenceソフト参照(アセットの場所)メッシュ・テクスチャ・サウンドなど アセット
Class Referenceハード参照(クラス)Spawnするクラス変数
Soft Class Referenceソフト参照(クラスの場所)Blueprintクラスを 後で 読み込む

アセットそのもの(メッシュ、テクスチャ、サウンド、Niagara)を後で読み込むなら Soft Object ReferenceBlueprintクラス(Spawnする敵やUIの種類)を後で読み込むなら Soft Class Reference です。詳細パネルでの見た目もほとんど同じで、アセットを選ぶスロットが並びます。違うのは、そこに入れても実体が読み込まれない点だけです。

補足: ソフト参照の変数に一度アセットを設定してしまえば、あとはハード参照と同じ感覚で扱えます。差が出るのは「使う瞬間」だけです。ソフト参照はそのまま Set Skeletal Mesh Asset などへ繋げません。 必ず一度、実体へ読み込む手順を挟みます。


Async Load Assetで読み込む

ソフト参照から実体を取り出す、標準の方法が Async Load Asset ノードです。「非同期(Async)」とあるとおり、 ゲームを止めずに、裏で読み込む のが特徴です。

Async Load AssetのAsset入力にソフト参照を繋ぎ、Completedから出るObjectをキャストして使うノードへ渡す流れ図

ノードのピンは次のとおりです。

ピン種類内容
Asset入力読み込みたい Soft Object Reference
Completed出力(実行)読み込みが終わった瞬間に発火する
Object出力(データ)読み込まれたアセットの実体(Object型)

流れはこうです。 Async Load AssetAsset にソフト参照を繋ぐと、その場では処理が先へ進みます。裏で読み込みが終わると Completed が発火し、そのとき Object に実体が入っています。 Object は汎用のObject型なので、 使いたい型へキャスト してから、Set Skeletal Mesh Asset などへ渡します。

クラスのほうを読み込むときは、双子の Async Load Class Asset を使います。入力に Soft Class Reference を取り、Completed から読み込まれたクラスが得られます。Spawnするクラスを後から読み込みたいときはこちらです。

Completed が発火するまでには 数フレームから、大きなアセットでは数百ミリ秒 かかることがあります。その間ゲームは動き続けるので、 読み込み中に何を見せるか を決めておきます(仮のメッシュ、ローディング表示、半透明のプレースホルダーなど)。実践の節で、仮メッシュを見せてから差し替える形を組みます。

補足: Async Load Asset は、すでに読み込み済みのアセットに対して呼んでも安全です。その場合は読み込みをやり直さず、キャッシュ済みの実体をすぐ Completed で返します。「もう読み込んだかどうか」を毎回自分で確認しなくても、まず呼んでしまって構いません。読み込み結果が有効かどうかは、返ってきた ObjectIs Valid に通せば確認できます。

Sponsored

Load Asset Blockingを使わない理由

ソフト参照を実体に変える方法には、もう1つ Load Asset Blocking があります。名前のとおり その場で即座に読み込む ノードで、一見こちらのほうが簡単です。ただ、実務ではほとんどの場面で避けます。

Load Asset Blockingは1フレームが長く伸びてカクつき、Asyncは複数フレームに分散して滑らかなことを示したタイムライン比較図

Load Asset Blockingゲームスレッドを止めて 読み込みます。読み込みが終わるまで、次のフレームへ進めません。小さなアセットなら一瞬ですが、大きなメッシュやテクスチャだと、その1フレームだけ処理時間が跳ね上がり、 目に見えるカクつき(ヒッチ) になります。公式ドキュメントも、可能なら Async Load Asset を使うよう案内しています。

Async Load AssetLoad Asset Blocking
読み込み中ゲームは 動き続けるゲームが 止まる
大きいアセット複数フレームに分散1フレームが伸びて カクつく
結果の受け取りCompleted で後からその場で即
向いている場面ほぼすべて本当に一瞬で終わる小物、ローディング画面の裏

そして、 意図せず同期ロードが走ってしまう 罠にも注意します。ソフト参照から実体を取り出すとき、Load Asset Blocking を使わなくても、 ソフト参照をハード参照へ変換する操作 をすると、その瞬間に同期ロードが走ります。「ソフト参照にしたのに、なぜかロード待ちで固まる」ときは、この変換がどこかに紛れていないかを疑ってください。読み込みは Async Load Asset に一本化するのが安全です。


どこで効くのか

ソフト参照は便利ですが、 すべてをソフト参照にするのは逆効果 です。読み込み自体はなくならないので、常に必ず使うアセットまでソフト参照にすると、使う直前に毎回ロード待ちが挟まります。

効くのは、次の条件が重なるアセットです。

条件
大きい高解像度のスケルタルメッシュ、4Kテクスチャ、長い音声
いつも使うとは限らないボス、特定マップの敵、実績解除で出る要素
使う瞬間が予測できるエリアに入る、会話が始まる、ボス戦に移行する
ハード参照は起動時からボスのメッシュ・ムービー・図鑑の画像がすべてメモリに載り続けるのに対し、ソフト参照はボス戦に入った時点で必要な分だけ載ることを2本の帯で比較した図

具体的には、次のような場面で差が出ます。

  • ボスや大型の敵 : 戦闘エリアに入るまで読み込まない。序盤マップのメモリからボスのメッシュが消える
  • カットシーン専用アセット : イベントが始まる直前に読み込み、終わったら手放す
  • 図鑑・コレクション画面 : 全アイテムのアイコンを一度に抱えず、表示中のものだけ読み込む
  • DLC・追加コンテンツ : 本編のメモリに常駐させず、その機能に入ったときだけ読み込む

逆に、プレイヤーキャラクターの標準メッシュや、常時出る雑魚敵、UIの基本パーツのように 常に画面にあるもの は、素直にハード参照にしておくほうが、ロード待ちがなくて快適です。判断の軸は 「大きくて、使うとは限らないか」 です。

読み込む量そのものを、レベル側から丸ごと制御する方法もあります。エリア単位で読み書きするレベルストリーミングとWorld Partitionと組み合わせると、より大きな単位で効きます。

Sponsored

Asset Managerの入口

ソフト参照を、もう一段しっかり管理する仕組みが Asset Manager です。これは「どのアセットが、どこに、どれだけあるか」をエンジンに把握させ、読み込み・解放をまとめて制御する土台です。

本格的に使うのは、アセットの種類が増え、読み込みの状態を一元管理したくなってからです。入口としては、 Primary Data Asset を作って Project Settings > Asset Manager に型を登録するところから始めます。この具体的な手順と、Data Assetの中でソフト参照を使う組み方は、Data Assetでデータ駆動設計する記事にまとめてあります。 この記事は「ソフト参照そのものの仕組みと、Async Load Assetで読み込む手順」に集中 し、Asset Manager側の設定はそちらへ譲ります。

まずは、変数1つをソフト参照にして Async Load Asset で読み込む、という最小の形を手に馴染ませるのが先です。Asset Managerは、それが物足りなくなってからで間に合います。


実践:敵のメッシュを必要になってから読み込む

RPGのフィールドボス、メトロイドヴァニアのエリアボス、ローグライクの階層ボス。 戦うまで出番のない大きな敵 は、ソフト参照がいちばん効く題材です。ここでは、ボスの高解像度メッシュを、プレイヤーが戦闘エリアに入るまで読み込まない形を組みます。

完成形

戦闘エリアに入る前、ボスの居る場所には 簡素な仮メッシュ だけが立っています。プレイヤーがトリガーに触れると、裏でボスの本メッシュが読み込まれ、 数フレーム後に本物へ差し替わり ます。エリアに入るまで、ボスの巨大なメッシュはメモリに載りません。

トリガーに入る前は仮メッシュ、入った後にAsync Loadが完了して本メッシュへ差し替わる様子と、Size Mapの前後比較

再現条件

Third Person テンプレート (Blueprint)で新規プロジェクトを作り、次を用意します。

1. ボス(BP_Boss

Character(またはActor)を親クラスに作り、Skeletal Mesh Component軽い仮メッシュ(Starter Contentの Mannequin や低ポリのもの)をあらかじめ割り当てておきます。これが読み込み中に見せるプレースホルダーです。

変数名初期値設定
BossMeshSkeletal Mesh( Soft Object Reference本ボスの高解像度メッシュInstance Editable をオン
HasLoadedBooleanfalse二重読み込み防止

要点は BossMesh の参照の種類 です。型のドロップダウンで Skeletal Mesh を選んだあと、参照の種類を Soft Object Reference にします。ここをハード参照にすると、BP_Boss を読み込んだ時点で本メッシュも載ってしまい、この記事の目的が消えます。

2. トリガー(BP_BossTrigger

Actorを親クラスに作り、Box Collision を1つ置きます。プレイヤーが重なったら、ボスに「読み込め」と伝える役です。伝え方はイベントディスパッチャーでも、トリガーがボスへの参照を持って直接呼んでも構いません。ここでは分かりやすさを優先し、トリガーがレベル上の BP_Boss を参照して直接関数を呼びます。

ボス側のグラフ

BP_Boss に、読み込みと差し替えの関数を組みます。

On Component Beginでトリガーが呼ぶLoadBossMesh。Async Load AssetのCompletedからObjectをキャストしてSet Skeletal Mesh Assetへ渡すノードグラフ
BP_Boss

関数 LoadBossMesh
  → Branch(Condition: HasLoaded)
      True  → (何もしない。二重読み込みを防ぐ)
      False →
        Set(HasLoaded = true)
        → Async Load Asset(Asset: BossMesh)
            Completed →
              Cast to Skeletal Mesh(Object: Async Load Asset の Object 出力)
                → Is Valid(As Skeletal Mesh)
                    Is Valid → Set Skeletal Mesh Asset
                                  Target : Mesh
                                  New Mesh : As Skeletal Mesh
                    Is Not Valid → Print String("BossMesh の読み込みに失敗")

トリガー側は、プレイヤーが重なったら LoadBossMesh を呼ぶだけです。

BP_BossTrigger
On Component Begin Overlap(Box)
  → Cast to(プレイヤーのキャラクター)  ※プレイヤーだけに反応させる
      → 対象の BP_Boss(参照)→ LoadBossMesh

Async Load Asset を挟むことで、LoadBossMesh を呼んだフレームではゲームが止まりません。読み込みが終わったフレームで Completed が発火し、そこで初めてメッシュが差し替わります。 Is Valid を通すのは、アセットが削除・移動されていた場合に Object が空で返ることがあり、そのまま Set Skeletal Mesh Asset へ渡すと Accessed None になるためです(→ デバッグの記事)。

確認する

まず、 メモリに載っていないこと を確かめます。BP_Boss を右クリックし、 Size Map を開きます。

  • BossMesh をハード参照(Object Reference)にしていると、Size Mapに ボスの高解像度メッシュとそのマテリアル・テクスチャがまるごと 含まれ、合計サイズが大きくなります(たとえば 80MB)
  • Soft Object Referenceに変える と、そのメッシュがSize Mapから 消えBP_Boss 自体は数百KBまで下がります

これが「参照しても実体が載らない」ことの、目に見える証拠です。

次に、 必要になってから読み込まれること を確かめます。Standalone Game で起動し、ボスへ近づいてトリガーに入ってください。

トリガーに触れる前は簡素な仮メッシュ、触れた数フレーム後に本ボスのメッシュへ差し替われば成功 です。差し替えに一瞬の間があること自体が、その瞬間まで本メッシュが読み込まれていなかった証拠になります。

うまくいかないときの切り分けです。

  • 最初から本メッシュが立っているBossMesh の参照の種類が Soft Object Reference になっていない。ハード参照のままだと配置時に読み込まれる
  • トリガーに入っても差し替わらない → トリガーの On Component Begin Overlap が発火していない。Box Collisionの Generate Overlap Events と、プレイヤー側のコリジョン設定を確認する
  • 差し替わるが、ゲームが一瞬固まるLoad Asset Blocking を使っているか、どこかで同期ロードが走っている。Async Load Asset に統一する
  • Accessed None が出るObjectIs Valid に通さずに Set Skeletal Mesh Asset へ繋いでいる。または BossMesh にアセットを設定し忘れている
  • 2回目のトリガーで重いHasLoaded の分岐が効いていない。読み込み済みなら Async Load Asset を呼ばないようにする

ポイントは2つです。

  • 参照の種類が、読み込むタイミングを決める: ハード参照は配置・生成の瞬間に、ソフト参照は Async Load Asset を呼んだ瞬間に読み込まれます。「いつ読み込むか」を自分の手に取り戻すのが、ソフト参照の目的です
  • 読み込み中の見た目を必ず用意する: Async Load Asset は数フレームかかります。その間を仮メッシュやローディング表示で埋めておかないと、一瞬何もない場所ができます。非同期にする以上、「まだ来ていない状態」の絵を先に決めておきます

同じ発想は、カットシーン専用アセット、図鑑のアイコン、DLCの要素にもそのまま効きます。「大きくて、使うとは限らないもの」を見つけたら、参照の種類を疑ってみてください。

Sponsored

おまけ:先に知っておくと良いこと

  • Reference Viewerで連鎖を見る: アセットを右クリックし Reference Viewer を開くと、そのアセットが何を参照し、何から参照されているかが図で見えます。「なぜこのメッシュが読み込まれるのか」を追うとき、Size Mapとセットで使うと原因を特定できます
  • 読み込んだら、いらなくなったら手放す: Async Load Asset で読み込んだアセットは、どこかがハード参照している間はメモリに残ります。ボス戦が終わってメッシュが不要になったら、参照を切ってGCに回収させます。読み込みっぱなしだと、ソフト参照にした意味が薄れます
  • 配列をまとめて読み込むなら Async Load Assets: 複数のソフト参照を一度に読み込みたいときは、複数形の Async Load Assets があります。図鑑のように「表示するぶんだけまとめて」読み込む用途に向きます。1つずつループで Async Load Asset を呼ぶより、まとめて渡すほうが扱いやすいです
  • メモリの実測は Memreport: いま何がどれだけメモリに載っているかは、コンソールの Memreport -full で書き出せます。ソフト参照化の前後で比べると、狙ったアセットが本当に減っているかを数字で確認できます(測り方の考え方は → 計測の記事
  • 起動が遅い犯人もハード参照: 「Blueprintを開くだけで数十秒」の多くは、そのBlueprintが重いアセットをハード参照で抱えているためです。Reference Viewerでたどって、後で読み込めるものをソフト参照へ移すと、エディタの操作自体が軽くなります

まとめ

  • ハード参照は 参照した瞬間に実体も載る 。しかも連鎖して芋づる式に広がる
  • ソフト参照は アセットの場所だけを覚える 。実体は載らない。 Soft Object Reference はアセット、 Soft Class Reference はクラス
  • 実体が要るときは Async Load Asset で読み込む。CompletedObjectキャストして 使う
  • Load Asset Blocking と同期ロードは避ける 。ゲームが止まってカクつく
  • 効くのは 大きくて、使うとは限らない アセット。全部ソフト参照にすると逆効果
  • 非同期にする以上、 読み込み中の見た目(仮メッシュ)を先に決めておく

いま作っているプロジェクトで、いちばん大きいアセットは何でしょうか。それは常に画面にありますか。「大きくて、たまにしか使わない」ものが見つかったら、その参照の種類を Soft Object Reference に変えるところから始めてください。出し消しの多い軽いアクターが重さの原因なら、オブジェクトプーリングのほうが効きます。