Unreal Engine (UE) Advent Calendar 2025 シリーズ4 11日目の記事です。
概要
消費メモリを削減をする際に、まず行うのがテクスチャの削減です。なので、本来であれば
上記の前回の記事より、こっちの記事を先に出すべきだったかもしれません。
それはさておき、テクスチャは他のアセットに比べて比較的サイズが大きいため、特にUnified Memory Architectureを採用しているプラットフォームでは、残メモリ量の回復に効果が高いです。
この記事では、テクスチャのメモリ削減を行う際によく使う手段を紹介します。
前回の記事と同じく、UE5.4 の内容をベースに書かれています。ただ、エンジンのバージョンに依存している内容は少なく、昔から変わっていない部分が多いので、他のバージョンを採用している人にも参考になると思います。
ListTexturesでリストアップ
まず、問題になっているシーンで読み込まれているテクスチャを精査します。それには、ListTexturesというコンソールコマンドを使用するのが便利です。
ListTexturesのコンソールコマンドを実行すると、ログに現在読み込まれているテクスチャがずらっと出てきます。
オプションとしてよく使うのは以下の3つ
-
Streaming
- ストリーミング対象のテクスチャだけリストアップします
- 大半のテクスチャはこちら。
-
NonStreaming
- 非ストリーミングテクスチャだけリストアップします。
- 主にUIのテクスチャが多いですが、アセット単位でNeverStreamを付けたテクスチャや、Postprocessで使うようなRenderTextureなども含まれる場合があります。
-
-csv
- ログ内にcsv形式で出力してくれます
- エクセルなどに読み込ませて、ソートしたり統計を取ったりするときに便利
- 他のオプションと違って、-(ハイフン)必須
出力結果の見方
Cmd: ListTextures
Listing all textures.
MaxAllowedSize: Width x Height (Size in KB, Authored Bias), Current/InMem: Width x Height (Size in KB), Format, LODGroup, Name, Streaming, UnknownRef, VT, Usage Count, NumMips, Uncompressed
3813x1192 (36288 KB, 0), 3813x1192 (36288 KB), PF_FloatRGBA, TEXTUREGROUP_ColorLookupTable, /Interchange/Utilities/New_LUT.New_LUT, NO, NO, NO, 0, 1, NO
2048x2048 (32768 KB, 0), 2048x2048 (32768 KB), PF_FloatRGBA, TEXTUREGROUP_World, /Engine/EngineMaterials/DefaultBloomKernel.DefaultBloomKernel, NO, NO, NO, 0, 1, YES
2048x2048 (2752 KB, 0), 2048x2048 (2752 KB), PF_DXT1, TEXTUREGROUP_Skybox, /Engine/EngineSky/T_Sky_Blue.T_Sky_Blue, YES, NO, NO, 1, 12, NO
1024x1024 (704 KB, 0), 1024x1024 (704 KB), PF_DXT1, TEXTUREGROUP_World, /Engine/EngineMaterials/DefaultDiffuse.DefaultDiffuse, YES, YES, NO, 0, 11, NO
512x256 (704 KB, 2), 512x256 (704 KB), PF_B8G8R8A8, TEXTUREGROUP_Skybox, /Engine/EngineSky/T_Sky_Clouds_M.T_Sky_Clouds_M, YES, NO, NO, 1, 12, YES
512x512 (384 KB, 0), 512x512 (384 KB), PF_DXT5, TEXTUREGROUP_World, /Engine/EngineMaterials/T_Default_Material_Grid_M.T_Default_Material_Grid_M, YES, NO, NO, 234, 10, NO
256x256 (48 KB, 0), 64x64 (8 KB), PF_DXT1, TEXTUREGROUP_World, /Engine/EditorMaterials/ParticleSystems/PSysThumbnail_NoImage.PSysThumbnail_NoImage, YES, NO, NO, 0, 9, NO
128x128 (24 KB, 0), 64x64 (8 KB), PF_DXT5, TEXTUREGROUP_World, /Engine/EditorMaterials/ParticleSystems/PSysThumbnail_OOD.PSysThumbnail_OOD, YES, NO, NO, 0, 8, NO
256x256 (48 KB, 0), 64x64 (8 KB), PF_DXT1, TEXTUREGROUP_World, /Engine/EditorMaterials/WidgetGridVertexColorMaterial.WidgetGridVertexColorMaterial, YES, NO, NO, 0, 9, NO
256x256 (88 KB, 0), 64x64 (8 KB), PF_DXT5, TEXTUREGROUP_World, /Engine/EditorResources/S_PortalActorIcon2.S_PortalActorIcon2, YES, NO, NO, 0, 9, NO
通常の出力はこんな感じにサイズ順に出てきます。容量削減に向けた調査でよく使いますが、見るべきポイントをいくつか紹介しておきます
テクスチャの最低サイズについて
Current/InMemのサイズの最低値は64x64です。そのため、メモリ上にロードした時点で最低64x64のテクスチャは必ず読み込まれることになります。(当然、1x1などテクスチャサイズの方が小さければ、そこまで)
おそらく、ロード処理の頻度を抑えるのと、消費メモリ量のトレードオフで、最低値をこのサイズにしているのではないかと思います。例えば、64x64が32x32になった場合、DXT5で3KB程度、無圧縮のRGBA8でも12KB程度しか減りません。
その分、メモリを節約するよりは読み込みの頻度を下げることを選択したのだと思います。
意図していないテクスチャが無いか
まずは、意図しないテクスチャが列挙されていないかを確認してください。
例えば、
- あるモード専用のUIテクスチャが、通常時でも読み込まれている
- その場にいないキャラクターのテクスチャが読み込まれている
- テストデータが読み込まれている
- (パッケージの場合)エディタコンテンツが読み込まれている
など、不要なテクスチャは真っ先に削除できるはずなので、容量の大小関係なく確認します。意外とテクスチャから、無駄なマテリアルやスタティックメッシュなどが芋づる式に判明することもあります。
不要なテクスチャの参照元は?(その1)
不要なテクスチャがある場合、どこで読み込まれているかの確認をして、問題を解消していきます。通常のテクスチャアセットであれば、ReferenceViewerを使って参照元をたどっていくのが、一番簡単な方法です。
適当に選んだMegaScansのテクスチャを例に説明します。

アセットの右クリックメニューからReferenceViewerを選択すると、上図のような結果が確認できます。
ここでは、T_Qua_Sla_Cluster_Ledge_Rock_M_01_N のテクスチャは Qua_Sla_Cluster_Ledge_Rock_M_01 のマテリアルインスタンスから参照され、そのマテリアルインスタンスは SM_Qua_Sla_Cluster_Ledge_Rock_M_01 のスタティックメッシュから参照されていることが分かります。
Qua_Sla_Cluster_Ledge_Rock_M_01で、T_Qua_Sla_Cluster_Ledge_Rock_M_01_Nのテクスチャを使っていないはず。とかがあれば、TextureParameterなどの設定に不備が無いか確認をして、参照を外す対応を行います。
不要なテクスチャの参照元は?(その2)
アセット以外で動的に設定している場合など、ReferenceViewerで意図しない参照が見つからない時は、以下のobj refs コマンドで読み込まれている状態の参照情報を取得します。
obj refs name=テクスチャ名のコマンドを実行すると、以下のような出力が出ます。
Cmd: obj refs name=T_Qua_Sla_Cluster_Ledge_Rock_M_01_N
LogReferenceChain: Display: InitialGather memory usage: 7.93
(standalone) MaterialInstanceConstant /Game/Scene_QuarrySlate/Assets/MS/3D/Qua_Sla_Cluster_Ledge_Rock_M_01/MI_Qua_Sla_Cluster_Ledge_Rock_M_01.MI_Qua_Sla_Cluster_Ledge_Rock_M_01
-> TArray UMaterialInstance::TextureParameterValues = (standalone) Texture2D /Game/Scene_QuarrySlate/Assets/MS/3D/Qua_Sla_Cluster_Ledge_Rock_M_01/T_Qua_Sla_Cluster_Ledge_Rock_M_01_N.T_Qua_Sla_Cluster_Ledge_Rock_M_01_N
ここで確認した、T_Qua_Sla_Cluster_Ledge_Rock_M_01_Nのテクスチャの場合、Qua_Sla_Cluster_Ledge_Rock_M_01というマテリアルインスタンスから参照されていることが分かります。
あちこちから参照されているテクスチャなど、参照関係によっては百行以上の長い出力になる場合があります。たいてい一番上に書かれているものが直接参照されている物であることが多いので、上から順に参照関係を確認することをお勧めします。
予想外に大きなテクスチャが無いか
次に、MaxAllowedSizeを見て例えば8Kや16Kのテクスチャが読み込まれていたら、詳細を確認したほうが良いです。(プラットフォームによっては、4Kも怪しい)
意図的にそのサイズを扱っている場合もありますが、LODBiasなどで制限する予定が設定をし忘れている。などを疑います。
また、Size in KBが大きいのも同様にチェックします。圧縮しているつもりが未圧縮だったり、ファイルフォーマットが意図しない設定になっていて、容量を食っていた事例がありました。
そのテクスチャは本当にNonStreaming?
Streamingの項目がNOの中に、通常の背景テクスチャなどが混じってないでしょうか?
たいていの場合、アセットの設定にNeverStreamが付いていると思いますが、NeverStreamを付けると常に最大解像度まで読み込みます。メモリを圧迫する原因となるため、よほど特別な事情が無い限りNeverStreamは有効にしない方が良いです。
例えば、テクスチャストリーミングが間に合わないのを回避したい場合は、先読みをして回避することをお勧めします。(NeverStreamは最後の手段)
先読み方法の参考資料
- マップ切り替えなどの場合
- シーケンサーのカット切り替えの場合
- VirtualTextureの場合
設定の検証について
ListTexturesで出てくるTEXTUREGROUPの設定やファイルフォーマットの設定について、正しいのか検証したい場面があります。もし、アセットを網羅的に確認したい場合は、コンテンツブラウザで行うことをお勧めします。

Columns表示で各種設定値の確認やソートができます。また、検索ボックスを使って各設定値を使ったフィルタリングも可能です。(参考:Unreal Engine の高度な詳細検索 | Unreal Engine 5.7 ドキュメンテーション | Epic Developer Community )
ListTexturesの結果から確認していく事は可能ですが、ListTexturesはあくまで 「その時に読み込まれているテクスチャ」 しか列挙されません。そのため、漏れが出る可能性がありますので、設定値の確認はコンテンツブラウザを使うことをお勧めします。
あとがき
テクスチャは、PCではVRAMという独立したメモリに格納されるので、メモリという観点からはテクスチャ削減の優先度は高くないかもしれません。とはいえ、無駄なテクスチャを読み込んでいるということは、その分ロード時間も無駄にしているので、ぜひ対応することをお勧めします。
参考資料
ListTexturesの使い方
obj refsの使い方
今回使った参照関係の確認以外にも、メモリ削減の調査をするときには重宝しています。
VirutalTexturePrefetchMips (UE5.6~)
いままでVirtualTextureの先読みはしづらかったですが、これでだいぶ楽になるかも?