[UE4] テクスチャのメモリについて

MipmapとTextureStream周りの挙動によるテクスチャのメモリ周りについて纏めました。
間違ってたらごめんなさい、指摘ください。
**検証UE4**: 4.24.0
**検証環境**: windows - Developmentパッケージ

ここで取り扱う「Mip」はテクスチャのMipmapになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/77bbf418-0fc4-714f-94a6-05759f0420f2.png)


# 結論
（いつも記事とか資料が長いと言われるので先に結論……）

- <font color="OrangeRed">テクスチャのサイズがフルでロードされる訳ではない。レンダリングに必要なMip分しかロードされずメモリに乗らない。</font>（Mipなし、NeverStream除く）
    - →テクスチャの最大サイズを減らしてもメモリ的には減らない可能性がある
        - ただし、カメラに映った際に低解像度でボケてもいい、位まで落とすと効果はある
- <font color="OrangeRed">画面に表示されない限り、テクスチャアセットをロードしていてもメモリ的にほぼ問題にならない</font>（Mipなし、NeverStream除く）
    - →最小解像度Mip分のメモリや、ロード時間に関しては掛かる
- <font color="OrangeRed">3Dで出すテクスチャは極力Mip有り、NeverStream無しにしておく。メモリ節約になる</font>
    - PostProcessとかで使う等、カメラとの位置が固定されているテクスチャは逆にMip無しにすると低解像度Mip分空くかも

# はじめに
UE4では、必要になった時に、必要なMipを読み込むTextureStreamという機能があります。
必要ない時は高解像度Mipをロードせずメモリを節約する形です。
こちらのスライドに分かりやすく書いてあります（10ページ位から）
　→[そう、UE4ならね。あなたのモバイルゲームをより快適にする沢山の冴えたやり方について Part 2 <Texture Streaming, メモリプロファイル, Auto Instancing編> - SlideShare EpicGameJapan 岡田和也](https://www.slideshare.net/EpicGamesJapan/ue4-festeast2019-ue4mobilepart2-179705328/10)


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">よくある誤解で、アセット見て「テクスチャ大きすぎ！」って指摘するのがある。例えば4Kテクスチャだらけのキャラでも、720pで画像くらいの大きさで描画する際に使われるテクスチャは256が殆ど。なのでオリジナルのテクスチャのサイズが4Kでもそれは描画にもメモリにも負荷にならないんよね。<a href="https://twitter.com/hashtag/UE4?src=hash&amp;ref_src=twsrc%5Etfw">#UE4</a> <a href="https://t.co/bGLOBcSQSX">pic.twitter.com/bGLOBcSQSX</a></p>&mdash; スミオ（SUMIO） (@tempkinder) <a href="https://twitter.com/tempkinder/status/1091971203923759104?ref_src=twsrc%5Etfw">February 3, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

TextureStreamingは、画面にレンダリングする際に必要なMipサイズが足りないと、そのMipをロードします。
（詳細な条件は省きます。時間ができたら追記するかも）
→カメラがオブジェクトに近づく
→低解像度のMipだとボケるので高解像度のMipが必要になる
→高解像度のMipをロードする

この辺りの挙動をテストしました

# Mipロードの検証
各パターンのテクスチャを10枚分用意し、貼り付けました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/ac6f82f3-26b0-9818-798a-358bab00a780.png)

そして、

- カメラが遠い時→低解像度Mipが出る時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/cbd4404f-76e3-f50e-310b-c7abae756e3f.png)
- カメラが近い時→高解像度Mipが出る時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/07c03b4b-d585-ffcc-4115-16b8985b3103.png)



のstat memory, stat streaming, タスクマネージャでのメモリの数値を計測しました

## 2x2のテクスチャ
- カメラが遠い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/348e3824-8190-8f35-c6ed-78353551db39.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/2f44431f-9ff4-1b67-6534-012a659e67a6.png)
- カメラが近い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/74b0202f-2345-e820-b719-3e9b375e852a.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/52300dfa-3e46-10b7-b95e-ba04b3a4946b.png)

元々低解像度しか用意されていないので変わらないです

## 4096x4096 Mip有りテクスチャ
- カメラが遠い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/a443f19f-5880-5a63-f052-8696c37c0ce9.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/40190b3e-9e47-8486-30ed-a6112d159d94.png)
- カメラが近い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/20af3dc1-faa0-49f1-9244-3d931de57c01.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/d11286d4-ca75-e39e-327b-5f3cb2e1c83c.png)

遠い時は2x2と変わりは有りません。
近い時はおおよそstatで70MB増えています。
しかし、もしフルでテクスチャがロードされていると、4096 x 4096 x RGBA8 (x mip) x 10枚 = 700MB超のメモリが確保されるハズです。
それが70MB程度で済んでいます。

## 4096x4096 Never Streamテクスチャ
テクスチャの設定でNever Streamにしていますと、TextureStreamingの効果が無効化され、常にフルのテクスチャがロードされます。
距離に応じたMipが必要ないUI/HUD/2Dに使用することは有るかと思います。

- テクスチャアセットのエディタで設定できます
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/30549f80-539f-3913-9e53-e9d223692449.png)


- カメラが遠い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/716d542b-0b77-d896-0907-efabb1bd3c50.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/e0f7f49a-a64e-495d-6787-ff0e696f140f.png)
- カメラが近い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/2bf60747-6813-cde9-e168-8988a24355e9.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/a6410a2d-3077-4792-9fae-6080466ddc61.png)

カメラが遠かろうがフルでロードされています。
遠景とかですと、画面に数pxしか出ないのにMipが全部ロードされる、といった大変な事になります。
「4096x4096 Mip有りテクスチャ」版と比べてみても、かなり余分なテクスチャがロードされていることが分かります。

→<font color="OrangeRed">**逆にNeverStreamが無効で、Mipが存在していると使用テクスチャメモリはかなり削減されています。**</font>

## 2x2のシーンで「4096x4096 Mip有り」のテクスチャアセットをロードしている
画面に表示されてはいないけど、「4096x4096 Mip有り」を内部的にロードしている状態です。

- こんな感じでレベルBPにテクスチャアセットの参照をつけてロードされてしまうように
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/53db6d7d-b237-7a13-16fe-c65c5706e8e1.png)
- 実行後も4096x4096テクスチャのアセットがロードされているのを確認
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/8b10f938-37b3-9d99-a06a-a9cccd0a706d.png)
    - でも画面には一切表示されません


- カメラが遠い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/5bb01549-e8af-b249-0bb2-94dd6c85fb2d.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/a3cd7cb7-e51a-9e65-5054-5ce1fe6bdf46.png)
- カメラが近い時
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/a330f941-04f6-74ae-70ee-0c0d3c5b59ee.png)
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/5feea8e7-e524-d45f-eba6-fb5e3ac9f9b6.png)

サイズ的には、2x2のテクスチャ＋4096x4096 Mip有りテクスチャの最小値（一番遠い時のMip)がロードされているのが分かります。
ロードはされているので、最小解像度Mipが必要。
だけどカメラにアップで映される事がないので、高解像度Mipがロードされる事がない。です。

→<font color="OrangeRed">**テクスチャアセットがロードされていても、画面に表示されない限りはそこまで問題にならない、という事になるかと思います。**</font>
（NeverStreamはダメ）

# Poolサイズ
このTextureStreamingには使用できるメモリ制限があります。
r.Streaming.PoolSize で定義されます。（Windowsデフォルトだと1000MBほど）

- →[[UE4] Texture Streaming Pool Sizeの決め方を考えてみる Qiita @EGJ-Nori_Shinoyama ](https://qiita.com/EGJ-Nori_Shinoyama/items/cc959d201ff011df872f)

Poolサイズをオーバーすると、Mipがロードされなくなります

- Poolサイズが足りている時
    - ![2020-03-31_02h39_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/e760b473-f7f2-03a3-0ca1-6dc4b15e6155.png)
- Poolサイズが足りない時
    - ![2020-03-31_02h38_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58518/81c32f12-c6de-62da-e139-2b3a4dd3f094.png)
        - 左上に「TEXTURE STREAMING POOL OVER」エラーが出ます

- コチラが詳しいです
    - →[[UE4] Texture Streaming Pool Over Budgetの意味 - Qiita @EGJ-Nori_Shinoyama](https://qiita.com/EGJ-Nori_Shinoyama/items/ab81692f973ca635596f)
- （Poolメモリは起動時にｶﾞﾂｯと取られるのではなくて、必要になった段階で随時確保されていく感じ……？）





# 補足事項

- このロードしたMipは内部的にキャッシュしており、そのまま離れても破棄されない事があります。
    - 下記コマンドでそのキャッシュをしないようにでき、カメラが離れてMipが不必要になるとすぐに破棄されます。
    - r.Streaming.dropmips 1
        - →[[UE4] Texture Streaming Pool Sizeの決め方を考えてみる Qiita @EGJ-Nori_Shinoyama ](https://qiita.com/EGJ-Nori_Shinoyama/items/cc959d201ff011df872f)
- ロードされるMipは低解像度のMipから順番にロードされていきます
    - [低解像度のmipから順次読み込まれます。大きい方から削られたり追加されたりしていきます。- Twitter @tempkinder](https://twitter.com/tempkinder/status/1091980127997587463)
- [２のべき乗じゃないテクスチャはMipMapが作られず、常に再高解像度のテクスチャがメモリに乗ることになります。- Twitter @tempkinder](https://twitter.com/tempkinder/status/1092286651345231872)



# 参考資料
- <font color="OrangeRed">**重要**</font>[UE4] Texture Streaming Pool Sizeの決め方を考えてみる  - Qiita @EGJ-Nori_Shinoyama 
    - https://qiita.com/EGJ-Nori_Shinoyama/items/cc959d201ff011df872f
- [UE4] StreamingされないTextureはStreaming Texture Poolに入るのか？？  - Qiita @EGJ-Nori_Shinoyama 
    - https://qiita.com/EGJ-Nori_Shinoyama/items/be87422c7859eb7e2027
- [UE4] Texture Streaming Pool Over Budgetの意味 - Qiita @EGJ-Nori_Shinoyama 
    - https://qiita.com/EGJ-Nori_Shinoyama/items/ab81692f973ca635596f
- [UE4] Texture GroupがTexture Streamingに与える影響 - Qiita @EGJ-Nori_Shinoyama 
    - https://qiita.com/EGJ-Nori_Shinoyama/items/8b3c2e4e372f05e33476
- [UE4] TextureのNever Streamの動的変更について - Qiita @EGJ-Nori_Shinoyama
    - https://qiita.com/EGJ-Nori_Shinoyama/items/9442d7900fe1b49f24ec
- そう、UE4ならね。あなたのモバイルゲームをより快適にする沢山の冴えたやり方について Part 2 <Texture Streaming, メモリプロファイル, Auto Instancing編> - SlideShare EpicGameJapan 岡田和也
    - https://www.slideshare.net/EpicGamesJapan/ue4-festeast2019-ue4mobilepart2-179705328
- よくある誤解で、アセット見て「テクスチャ大きすぎ！」って指摘するのがある。例えば4Kテクスチャだらけのキャラでも、720pで画像くらいの大きさで描画する際に使われるテクスチャは256が殆ど。なのでオリジナルのテクスチャのサイズが4Kでもそれは描画にもメモリにも負荷にならないんよね。#UE4 - Twitter [@tempkinder](https://twitter.com/tempkinder)
    - https://twitter.com/tempkinder/status/1091971203923759104