【Unity】テクスチャーのインポート設定を自動で行う

Unityでは以下のように、テクスチャー(画像ファイル)の`インポート設定`があります。これを上手く設定しないと画像がぼやける、容量が無駄に増える、そもそも表示されないなどの問題が生じます。
![インポート設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318712/35abacc5-8eb5-035a-65d6-77bff8562927.png)

見ての通り、設定すべき項目が多いです。
問題はこれをインポートする度に行わなくてはならない事であり、画像毎に設定に差異が生じる場合があります。複数人で開発を行っている場合は差異が生じる可能性が大きく上昇するでしょう。
しかし、差異を無くすために画像をインポートする度にCtrl+Aで全選択し、設定するのも時間が掛かってしまいます。

そこで、この記事ではUnityのエディター拡張を行い、画像のインポート時に設定を自動で行うようにします。

# 画像のインポート設定を自動で設定する
## エディター拡張用ファイルを作る
画像の`インポート時とインポート設定を変えた時`に呼ばれる関数である、`AssetPostprocessor`クラスの`OnPreprocessTexture`メソッドと画像のインポート設定を変更する`TextureImporter`クラスを使用します。
この記事では特に設定すべきであろう物だけ紹介します。他の設定も見たい場合は[TextureImporterのスクリプトリファレンス](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporter.html)も参照してください。

## 使用例
`Assetフォルダ`以下に`Editorフォルダ`を作成し、そこに`ImportManager.cs`ファイルを作ってみましょう。
4つのフォルダが登場しますが、フォルダの説明は以下の通りです。

- BackGround：背景画像のフォルダ。長辺サイズが1500前後のjpgファイルが入っている。
- Character：キャラクターの立ち絵のフォルダ。長辺サイズが600前後の透過pngファイルが入っている。
- Dot：ドット絵のフォルダ。長辺サイズが16または24の透過pngまたはgifファイルが入っている。
- Effect：エフェクトアニメーションのフォルダ。長辺サイズが800前後の透過pngファイルが入っている。

```c#:ImportManager.cs
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Reflection; // MethodInfoやBindingFlagsで必要

public class ImportProcess : AssetPostprocessor
{
    private readonly object [] TextureSize = new object [2] { 0, 0 };
    private readonly MethodInfo GetSizeMethod = typeof (TextureImporter).GetMethod ("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance);

	// 画像のインポート時、インポート設定変更時に実行される関数
	void OnPreprocessTexture ()
	{
		// assetImporterにインポートするオブジェクトが入る。それをテクスチャ型にキャスト
		TextureImporter ti = assetImporter as TextureImporter;

        // 各種Packageの画像や、TextureTypeがSingleChannelの画像は変えたらエラーが出る可能性があるのでここで終了
        if (ti.assetPath.StartsWith ("Packages/") || ti.textureType == TextureImporterType.SingleChannel)
        {
	        return;
        }

		//今回は全てスプライト扱いにする
		ti.textureType = TextureImporterType.Sprite;
        ti.mipmapEnabled = false;
        ti.textureCompression = TextureImporterCompression.Compressed;

		//ここからはインポートするテクスチャがどのフォルダ内にあるかで処理を変える
		if (ti.assetPath.Contains ("Assets/Resources/Pictures/BackGround"))
		{
			ti.spriteImportMode = SpriteImportMode.Single;
			ti.filterMode = FilterMode.Bilinear;
		}
		else if (ti.assetPath.Contains ("Assets/Resources/Pictures/Character"))
		{
			ti.spriteImportMode = SpriteImportMode.Single;
			ti.filterMode = FilterMode.Bilinear;
		}
		else if (ti.assetPath.Contains ("Assets/Resources/Pictures/Dot"))
		{
			ti.spriteImportMode = SpriteImportMode.Single;
			ti.filterMode = FilterMode.Point; // Bilinearにすると変にぼやけてドット絵の良さが失われるので、これだけPoint
		}
		else if (ti.assetPath.Contains ("Assets/Resources/Pictures/Effect"))
		{
			ti.spriteImportMode = SpriteImportMode.Multiple; // スプライトエディターで画像を切り分けるので、これだけMultiple
			ti.filterMode = FilterMode.Bilinear;
		}

        int textureWidth;
        int textureHeight;
        int maxTextureSize;
        
        // 画像のサイズを取得
        GetSizeMethod.Invoke (ti, TextureSize);
        textureWidth = (int)TextureSize [0];
        textureHeight = (int)TextureSize [1];
        // 画像のサイズに応じてmaxTextureSizeを変える
        if (textureWidth <= 32 && textureHeight <= 32)
        {
	        maxTextureSize = 32;
        }
        else if (textureWidth <= 64 && textureHeight <= 64)
        {
	        maxTextureSize = 64;
        }
        else if (textureWidth <= 128 && textureHeight <= 128)
        {
	        maxTextureSize = 128;
        }
        else if (textureWidth <= 256 && textureHeight <= 256)
        {
	        maxTextureSize = 256;
        }
        else if (textureWidth <= 512 && textureHeight <= 512)
        {
	        maxTextureSize = 512;
        }
        else if (textureWidth <= 1024 && textureHeight <= 1024)
        {
	        maxTextureSize = 1024;
        }
        else if (textureWidth <= 2048 && textureHeight <= 2048)
        {
	        maxTextureSize = 2048;
        }
        else if (textureWidth <= 4096 && textureHeight <= 4096)
        {
	        maxTextureSize = 4096;
        }
        else
        {
	        maxTextureSize = 8192;
        }
        ti.maxTextureSize = maxTextureSize;

        // 圧縮フォーマットが高品質であるか。今回はDefaultのFormatがRGBA32の画像、Dotディレクトリの画像を高品質にする
        bool isHighQuality = ti.GetDefaultPlatformTextureSettings ().format == TextureImporterFormat.RGBA32 || ti.assetPath.Contains ("Assets/Resources/Pictures/Dot");
        TextureImporterFormat format = isHighQuality ? TextureImporterFormat.RGBA32 : TextureImporterFormat.RGBA16;

        // プラットフォームごとに設定を上書きする
        // メモリとHDDが潤沢なスタンドアロンはテクスチャを綺麗に見せる事を優先し、それ以外のプラットフォームはテクスチャの容量を小さくすることを優先している
        // Standaloneは最高画質限定
        ti.SetPlatformTextureSettings (new TextureImporterPlatformSettings { overridden = true, name = "Standalone", maxTextureSize = maxTextureSize, format = TextureImporterFormat.RGBA64 });
        ti.SetPlatformTextureSettings (new TextureImporterPlatformSettings { overridden = true, name = "iPhone", maxTextureSize = maxTextureSize, format = format });
        ti.SetPlatformTextureSettings (new TextureImporterPlatformSettings { overridden = true, name = "Android", maxTextureSize = maxTextureSize, format = format });
        // WebGLでRGBA16を使おうとするとエラーが出る
        ti.SetPlatformTextureSettings (new TextureImporterPlatformSettings { overridden = true, name = "WebGL", maxTextureSize = maxTextureSize, format = isHighQuality ? TextureImporterFormat.RGBA32 : TextureImporterFormat.ARGB16 });
	}
}

```

## 共通設定
### Texture Type
[`Texture Type`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterType.html)は画像が何に使われるのかを設定します。この設定を誤ると最悪画像が表示されません。

```c#
ti.textureType = TextureImporterType.Sprite; // スプライト(主に2D用)
ti.textureType = TextureImporterType.GUI; // GUI(主に3D用)
```

### Generate Mip Maps
`Generate Mip Maps`はテクスチャのミップマップの生成を設定します。遠くからスプライトを見る場面があればtrueにすれば良い感じだと思います。

```c#
ti.mipmapEnabled = true; // ミップマップをtrueに設定する
```

### Asset Path
[`Asset Path`](https://docs.unity3d.com/ja/current/ScriptReference/AssetImporter-assetPath.html)はテクスチャのパスを取得します。読み取り専用。

```c#
Debug.Log (ti.assetPath); // テクスチャの置かれているパスを取得し、ログに表示する
						  // Assets/Resources/Pictures/hogehoge/hugahuga.pngのようなstringが取得可能
```

### Filter Mode
[`Filter Mode`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporter-filterMode.html)はテクスチャのフィルタリングモードを設定します。ドット絵はPoint、それ以外はBilinearにすれば画像が綺麗になると思います。

```c#
ti.filterMode = FilterMode.Bilinear; // Bilinear
ti.filterMode = FilterMode.Point; // Point
```

### Max Size
[`Max Texture Size`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporter-maxTextureSize.html)はテクスチャの最大サイズを設定します。長辺が設定したサイズ以上の場合は設定値へとスケールダウンされます。設定値は32～8192までの2のべき乗限定です。

```c#
ti.maxTextureSize = 1024; // 長辺のサイズを1024までに制限する
ti.maxTextureSize = 2048; // 長辺のサイズを2048までに制限する
```

### Compression
[`Texture Importer Compression`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterCompression.html)はテクスチャの圧縮タイプを設定します。この設定はプラットフォームごとの設定によっては上書きされます(詳しくは後述)。

```c#
ti.textureCompression = TextureImporterCompression.Compressed; // 圧縮タイプをNormal Qualityに設定する
ti.textureCompression = TextureImporterCompression.CompressedHQ; // 圧縮タイプをHigh Qualityに設定する(高品質、メモリ使用増)
```

## Sprite専用設定
### Sprite Mode
[`Sprite Mode`](https://docs.unity3d.com/ja/current/ScriptReference/SpriteImportMode.html)はスプライトのインポートモードを設定します。エフェクトなどのアニメーションはMultiple、立ち絵や背景はSingleと言った感じです。

```c#
ti.spriteImportMode = SpriteImportMode.Single; // シングル
ti.spriteImportMode = SpriteImportMode.Multiple; // マルチタイプ
```

## プラットフォームごとの設定
ここからはプラットフォームごとの個別設定について解説します。
「スタンドアロンでは容量が大きくなっても良いから画像を綺麗にしたいが、他のプラットフォームでは画像が多少荒くなっても良いから容量を小さくしたい」という感じに設定をこだわりたい人向けの内容です。

[`SetPlatformTextureSettings()`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporter.SetPlatformTextureSettings.html)関数の引数に[`TextureImporterPlatformSettings`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings.html)クラスを渡して設定を行います。

```c#
ti.SetPlatformTextureSettings (new TextureImporterPlatformSettings
{
	overridden = true,
	name = "Android",
	maxTextureSize = 1024,
	format = TextureImporterFormat.RGBA16,
	textureCompression = TextureImporterCompression.Compressed,
	resizeAlgorithm = TextureResizeAlgorithm.Mitchell
});
```

ここで設定したmaxTextureSizeなどは上書きされ、共通設定で設定した値よりもここで設定した値が優先されます。
この記事では特に設定すべきであろう物だけ紹介します。他の設定も見たい場合は[TextureImporterPlatformSettingsのスクリプトリファレンス](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings.html)も参照してください。

### overridden
[`overridden`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings-overridden.html)がtrueならプラットフォームで設定を上書きし、falseならデフォルトの設定を用います。falseにする意味は無いに等しいので実質true一択でしょう。

```c#
overridden = true,
```

### name
[`name`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings-name.html)は設定を上書きしたいプラットフォームです。stringで指定してください。

```c#
name = "Android",
name = "iPhone",
name = "Standalone", // PCのスタンドアロン
name = "WebGL",
```

### maxTextureSize
[`maxTextureSize`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings-maxTextureSize.html)はテクスチャの最大サイズを設定します。共通設定で説明したのと同じ役割を果たします。

```c#
maxTextureSize = 1024,
maxTextureSize = 2048,
```

### format
[`format`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings-format.html)は圧縮するテクスチャの形式を設定します。この設定次第でテクスチャの綺麗さや容量の大きさが変わるので<font color = "red">**最も重要な設定項目**</font>であると言えるでしょう。

```c#
format = TextureImporterFormat.RGB24,
format = TextureImporterFormat.RGBA32, // Standaloneなど
format = TextureImporterFormat.RGBA16, // Android、iPhoneなど
format = TextureImporterFormat.ARGB16, // WebGLなど
```

この設定で厄介なのは、本来は選択不可能なフォーマットもスクリプト上で選択できてしまう点です。例えばAndroidでARGB16、WebGLでRGBA16が選択できてしまいます。もし選択した場合はフォーマットはデフォルトの物(DXT1など)になってしまうので注意が必要です。

### textureCompression
[`textureCompression`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings-textureCompression.html)はテクスチャの圧縮タイプを設定します。共通設定で説明したのと同じ……はずですが、いざ設定してもエディター上では特に何も表示されないのでこの設定は本当に有効なのかは怪しいです。

```c#
textureCompression = TextureImporterCompression.Uncompressed, // 圧縮無し
textureCompression = TextureImporterCompression.Compressed, // 圧縮
textureCompression = TextureImporterCompression.CompressedHQ, // 高品質、低速圧縮
textureCompression = TextureImporterCompression.CompressedLQ, // 高速、低品質圧縮
```

### resizeAlgorithm
[`resizeAlgorithm`](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings-resizeAlgorithm.html)はテクスチャのリサイズアルゴリズムを設定します。迷ったらデフォルト設定のMitchellで良いでしょう。

```c#
resizeAlgorithm = TextureResizeAlgorithm.Mitchell,
resizeAlgorithm = TextureResizeAlgorithm.Bilinear,
```

# 補足
執筆時のUnityのバージョンは**2023.2**です。

# 外部リンク
[TextureImporterのスクリプトリファレンス](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporter.html)
[TextureImporterPlatformSettingsのスクリプトリファレンス](https://docs.unity3d.com/ja/current/ScriptReference/TextureImporterPlatformSettings.html)
[テクスチャのマニュアル](https://docs.unity3d.com/ja/current/Manual/class-TextureImporter.html)