[UE4] Texture GroupがTexture Streamingに与える影響


# Texture Groupってなに？
UE4では、各種TextureにTexture Groupという設定項目があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363464/6d0dcec0-4930-a68f-09c6-4e5bd201a197.png)

この設定は、そのGroupに属するテクスチャらの最大解像度であったり、MipMapの作成方法だったり、デフォルトでのそのテクスチャのサンプリング方式(リニアだとかポイントだとか)を一括で設定できる便利なものです。上記の設定項目を見てみると、World, Character, Effect, UIなどなど、そのテクスチャがシーン内でどのような用途で使われるかによって区分されています。では、各グループはテクスチャに具体的にどのような設定を行うのでしょうか？　デフォルトの設定は、EngineのEngine\Config\BaseDeviceProfiles.iniに以下のように書かれています。

```
[/Script/Engine.TextureLODSettings]
@TextureLODGroups=Group
TextureLODGroups=(Group=TEXTUREGROUP_World,MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)
+TextureLODGroups=(Group=TEXTUREGROUP_WorldNormalMap,MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)
+TextureLODGroups=(Group=TEXTUREGROUP_WorldSpecular,MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)
+TextureLODGroups=(Group=TEXTUREGROUP_Character,MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)
+TextureLODGroups=(Group=TEXTUREGROUP_CharacterNormalMap,MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)
+TextureLODGroups=(Group=TEXTUREGROUP_CharacterSpecular,MinLODSize=1,MaxLODSize=4096,LODBias=0,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)
```
このようにMinLOD, MipFilter, MipGenSettingsなどなど、沢山設定されているのがわかるかと思います。そしてこれらはあくまでDefault値ですので、ユーザがプロジェクト毎に適切に設定することにより、Characterはこの設定で～、Weaponはこの設定で～、と独自で変更することができます。


まとめると以下の様な感じでしょうか。。
##### TextureGroupとは

* __Texture GroupはそのGroupに属するテクスチャの様々なパラメータを一括で設定する便利な機能__
* __各Groupの設定のデフォルト値は.iniファイルに記載されている__
* __各プロジェクトが、自身のプロジェクトのiniファイル内で設定することで上書きされ、ゲーム固有の設定が可能となる__

(より詳細は、[公式ドキュメント](http://api.unrealengine.com/JPN/Engine/Content/Types/Textures/SupportAndSettings/)に記載されておりますのでそちらも合わせて参照してください。)
そして、今回はそこからちょっとだけ突っ込んで、このTextureGroupの設定とテクスチャストリーミングの挙動について簡単に見ていきます。

# Texture Streaming時に優遇されるTexture Group
実は、いくつかのTextureGroupは、テクスチャストリーミング時になるべくメモリに残ろうとしたり、読み込みを優先的に行ったりと優遇されます。これは[テクスチャストリーミングの公式ドキュメント]()に実は以下の様にさらっと書かれております。。。。。

>ミップを減らすときに、テクスチャを処理する順序は保持の優先度によって決まり、以下のルールの順に従います。
>
> - ランドスケープ テクスチャ、強制ロード テクスチャ、および既に解像度が足りないテクスチャを保持します。
> - 画面上で可視のミップを保持します。
> - __キャラクターのテクスチャ__、およびメモリを多く使わないテクスチャを保持します。
> - 直近に見えたもののミップを落としてから、不可視のミップを落とします。

や、
> 優先度は、評価されたいくつかの基準によって以下の順序で決まります。
> 
> 1. 最初に可視のミップからロードします。
> 2. 最初に強制ロードテクスチャ、__ランドスケープ テクスチャ__、および__キャラクターのテクスチャ__からロードします。
> 3. 最初にターゲット解像度からかけ離れているテクスチャからロードします。
> 4. 不可視のものについては、直近に見えたものからロードします。

です。

結局やってくれることは、キャラクターのテクスチャをなるべく早く読み込んで、一度メモリ上に置かれたらなるべく捨てないようにしてくれるのですが、
この様に、テクスチャストリーマは各テクスチャーがどんなものに使われるかを判断します。その判断基準がTextureGroupです。ちょっとコードを覗いてみると、Streamingコード内部に以下の様にTextureGroupが直書きされています。


```StreamingTexture.cpp
//FstreamingTexture::UpdateStaticData()内部
...
bIsCharacterTexture = (LODGroup == TEXTUREGROUP_Character || LODGroup == TEXTUREGROUP_CharacterSpecular || LODGroup == TEXTUREGROUP_CharacterNormalMap);
bIsTerrainTexture  = (LODGroup == TEXTUREGROUP_Terrain_Heightmap || LODGroup == TEXTUREGROUP_Terrain_Weightmap);
...
```

このように、TextureGroupのCharacterはTextrueStreaming内で優先されます。たまに、「TextureGroup_WorldとTextureGroup_Characterの設定に差がないので、キャラクターのテクスチャも一律TextureGroup_Wolrdに設定しています」という話を聞きますが、そうするとテクスチャストリーマはキャラクターのテクスチャも背景オブジェクトのテクスチャも同じ優先度で読み込んでしまい、背景のテクスチャがはっきりしているのに、キャラクターのテクスチャーぼやけたまま。。などのシーンが数フレーム出てしまったりということが起こりやすくなってしまうかもしれません。

ですので、テクスチャストリーミングを意識すると、TextureGroup設定は以下の様に言えると思います。
##### Texture Streamingを考慮したTexture Groupの設定方法  

* __もしもWorldとCharacterのTextureGroupで差がなくても、（仲間など特に重要な)キャラクターが使用するTextureのTextureGroupはCharacter/ChracterNormalMap/CharacterSpecularなどに設定する。__
* __ProjectGroupなどProjectで追加拡張できるTextureGroupを作成した場合など、独自で優先的にストリームされるTextureGroupを制御したい場合、StreamingTexture.cppのソースコード内部を変更することで対応が可能となる__


小さなことですが、簡単にまとめさせていただきました。