【Unity】Crunch圧縮でロード時間は速くなるのか？

# はじめに
UnityにはCrunch圧縮という機能がありTextureのサイズを劇的に減らすことができます。
![crunch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526299/c6e17416-1efa-01e4-daa1-139ee69ef2f0.png)

ビルドサイズを削減するという点では非常に有効だと思うのですがロード時間の短縮と言う点ではどうなのでしょうか？
ビルドサイズが小さくなれば当然読み込み時間は短くなるでしょうが圧縮しているため解凍する必要があります。IOの高速化により短縮できる時間と解凍にかかる時間のどちらの方が大きいのかを測定してみました。
結論から言うとCrunch圧縮した方がいいぜって話です。

# 環境
OS:Windows10 64bit
ビルドターゲット:Windows(スタンドアロン) LZ4圧縮は無し
Unityバージョン:2019.2.0f1
プロセッサ:Corei3-6100U
CrystalDiskMark:
![crystaldiskmark.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526299/bbe474db-b3ec-fc7d-f385-0e3b2620b36c.png)

# 測定方法
こんな感じのシーンを作りました。
![scene.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526299/172aec29-edbf-135a-d0c4-f2ac79fe4921.png)

フルHDから4Kまでのテクスチャが存在しておりメモリ上には1.3GBのテクスチャが載っています。

![profiler.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526299/97730f6a-2a35-c8db-a471-d91df83b74dd.png)

このシーンをAssetBundleに格納し、ロードします。

以下のスクリプトでロード時間を測定します。

```C#:StartTimer.cs
using UnityEngine;
using UnityEngine.SceneManagement;
using System.IO;
using System.Collections;

public class StartTimer : MonoBehaviour
{
	private void Update()
	{
		if (Input.GetButtonDown("Jump"))
		{
			StartCoroutine(Load());
		}
	}


	IEnumerator Load()
    {
		File.AppendAllText(Application.streamingAssetsPath + "/result.txt", "LoadStart..." + Time.time+"\n");
		var result = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/sphere");

		yield return new WaitWhile(() => {
			return !result.isDone;
		});

		var assetbundle = result.assetBundle;

		File.AppendAllText(Application.streamingAssetsPath + "/result.txt", "ABLoadComplete..." + Time.time+"\n");
		string sceneName = Path.GetFileNameWithoutExtension(assetbundle.GetAllScenePaths()[0]);
		SceneManager.LoadScene(sceneName);
	}
}

```

```C#:CompleteTimer.cs
using UnityEngine;
using System.IO;

public class CompleteTimer : MonoBehaviour
{
    void Start()
    {
		File.AppendAllText(Application.streamingAssetsPath + "/result.txt", "LoadComplete..." + Time.time+"\n");
	}
}

```

(AssetBundleからのシーン読み込みの方法はこちらのブログを参考にさせていただきました。http://tsubakit1.hateblo.jp/entry/2016/08/23/233604)

開始時に読み込まれるシーンのGameObjectにStartTimer.csをアタッチし、CompleteTimer.csは先ほどのテクスチャいっぱいのシーンのGameObjectにアタッチしておきます。

この測定をCrunch圧縮なし/ありでそれぞれ行いロード時間を比較したいと思います。
なおCrunch圧縮のクオリティは50でやっていきます。

#結果
###Crunch圧縮無し

```result.txt
LoadStart...0.9617942
ABLoadComplete...32.18606
LoadComplete...32.20223
```
アセットバンドルサイズ : 267,533KB(267.5MB)

アセットバンドルのロードにかかった時間 : 31.2242658秒
アセットバンドルロード完了後にシーンの読み込みにかかった時間 : 0.01617秒
###Crunch圧縮あり

```result.txt
LoadStart...10.97006
ABLoadComplete...21.08436
LoadComplete...21.10166
```
アセットバンドルサイズ : 105,891KB(105.9MB)

アセットバンドルのロードにかかった時間 : 10.1143秒
アセットバンドルロード完了後にシーンの読み込みにかかった時間 : 0.0173秒


Crunch圧縮によりアセットバンドルのサイズは半分以下に、読み込み時間は3分の1ほどになりました。
シーンの読み込みにかかった時間はCrunch圧縮ありの方がほんのわずかに遅かったですが誤差レベル。人間には知覚できないでしょう。

#AssetBundle無し
それではアセットバンドルをビルドせずにシーンを直接組み込んだ場合はどうでしょうか。
環境及び計測方法は大体同じです。
###Crunch圧縮無し
```result.txt
LoadStart...1.388524
LoadComplete...1.41218
```
ビルドサイズ:652 MB
シーンのロード時間:0.023656

###Crunch圧縮あり
```result.txt
LoadStart...1.386678
LoadComplete...1.408058
```
ビルドサイズ:236 MB
シーンのロード時間:0.02138


ビルドサイズは3分の1ほどになりましたがシーンのロード時間はほぼ変わりませんでした。
またゲームの起動時間は測定方法が分からなかったので測定できませんでしたが体感には全く差は感じられませんでした。

#まとめ
Crunch圧縮をすることでビルドサイズが劇的に小さくなった上に解凍によるオーバーヘッドは全く感じられませんでした。特にアセットバンドルからのシーンロードの際にはCrunch圧縮した方が圧倒的にロードが速かったです。すべてのデータを毎度ネットワークからロードしてくるWebGLなどではさらに大きく差が開くことでしょうし、モバイルアプリにおいてもダウンロードサイズを抑えるための有効な手段になるはずです。
環境によっても変わってくるでしょうが基本的にはCrunch圧縮はしていく方向でいいのではないでしょうか。
ただしテクスチャの各辺の長さが4の倍数でなければ圧縮できませんし、Crunchは不可逆圧縮なので画像が劣化する可能性がある点は注意が必要です。