【Unity】アプリに含めるアセットを抑えて、アプリサイズを小さくする
今回は、Unityプロジェクトからアプリケーションをビルドした際、Unityプロジェクトに含まれるアセットについてです。
Assets以下のアセットは全て含まれる訳ではない
Unityはアセット(TextureやModelやAudioやScript等)を使用する場合、Assetsフォルダ以下に配置する必要があります。
偶に、Assets以下に含まれるアセットは全てビルドしたゲームに含まれると考えている人がいますが、それは間違いです。
アプリ内に含まれるアセット群については、アプリケーションのビルド後にEditor.Logで確認出来ます。Console > 三 > Open Editor Logで実際に開いて確認してみると、Assets以下に含めたアセットと比較して減っている事が分かります。
とりあえず探すときは、一番下からComplete sizeを検索すると、すぐ見つかります。
アプリに含まれるアセットの数(特に大きいアセット)が減れば減るほど、アプリサイズは当然小さくなります。逆に、未使用なアセットが沢山含まれていれば大きくなります。
ここに含まれるには、どういった条件があるのかを確認してみました。
Resourcesフォルダ以下のアセット
まずResourcesフォルダ以下に含まれるアセットは基本的に全てアプリに含まれます。これはEditorフォルダ以下にResourcesフォルダを設定した場合もです。
ここで注目すべきは、Resourcesに含めたアセットが参照しているアセットも含まれる…という事です。例えば、PrefabがShaderやMaterial、AudioやAnimation等のデータを参照している場合、それらも全て含まれます。
例えば下のPrefabの場合、キャラクターの持つSprite及びAnimationController、AnimationControllerが持つAnimationClip達と、AnimationClipが持つSprite等が含まれています。
Resourcesは使わないサブアセットも全て含める
また、Textureの持つSpriteやFBXの持つMeshやAnimationClip Avater等の情報も丸ごと含まれます。これは物によっては非常に勿体のない事になります。
例えば下の例の場合、HumanoidCrouchのFBXを丸ごとResourcesに含めると、FBXのサイズは393kbになりますが、HumanoidCrouchIdleのみを参照するPrefabをResourcesに配置した場合、33kbまで小さくなります。また、ロード時間も(僅かに)短縮されます。
上は極端な例で、全てのAnimationとMeshとAvaterを使用してるなら差は殆どありません。しかし、Resourcesフォルダ以下に配置したファイルが多ければ多いほど起動時間が伸びるので、その辺りも考えて配置する必要があります。
Spriteは少しルールが異なる
サブアセットの参照についての例外は、Spriteです。
AnimationとFBXの場合、上に書いたとおりAnimationClipが参照しているアセットのみをアプリに含めます。しかし、Spriteの場合は少しルールが異なります。
まず特定のSpriteを参照する事でアプリに含めた場合です。
Spriteを効率的に表現するには、単一のTextureに幾つかのSpriteを含めTextureの数を減らす事が重要になります。そのため、多くのケースではAtlas化(複数のSpriteを一つのTextureに纏める)を行います。
つまり、Textureが沢山のSpriteを持つ訳です。
Spriteの情報(Textureへの参照やUV情報)は未使用ならばゲームに含まれませんが、Textureはどれか一つでも参照があれば含まれてしまいます。
このため、参照を用いてアセットへ参照をかけても、あまりアプリサイズに影響しません。(Spriteのサイズ分は減ります)
またSprite Tagを使用している場合、Spriteを直接参照している場合と比較してEditor.logに出力されるファイルサイズ表記が変化します。
Sprite tagを使用していない場合はTextureとSpriteのサイズが乗りますが、SpriteTagを使用している場合はSpriteのアセット分のみが乗ります。
なおSpriteのTagはResourcesでは使えません。その為、Atlas化してドローコールを減らしたい場合、外部アセットでテクスチャをAtlas化してMultiple Spriteを設定する必要があります。
読めない(インポート出来ない)アセットは含まれない
Resourcesは基本的に全ての「アセット」を含めますが、Unityがアセットと認識出来ないファイルは含まれません。
例えばxlsやxlsx、dbといった拡張子のファイル郡です。
一応bytesやassetと拡張子を変更する事でアプリ内に含める事は可能です。その場合、TextAssetにて読み込みbytesを引っ張り出します。
自分でデコードする処理を考える必要はありますが、上手くすればUnity非対応のフォーマットやpng等のファイルを実行時にロード(メモリリッチな方法)出来ます。
BuildSettingsに含まれているSceneが参照するアセット
Sceneサイドでは、BuildSettingsに含まれるSceneが参照しているアセットがゲームに含まれます。
Sceneから参照されている条件は、Sceneに配置したGameObjectのコンポーネントから参照されている事が条件になります。
アプリに含まれるのはあくまでBuild Settingsに含まれている(ScenLoadで呼び出せる)シーンのみで、それ以外のシーンに関しては、アプリに含まれません。
PreloadAssetsやAlwaysIncludeShaderで指定
ResourcesやScene以外でのケースではPreloadAssets(モバイル)やAlwaysIncludeShaderといった物があります。
PreloadAssetsはアプリの起動時に事前にアセットをロードしておく機能です。このアセットをPreloadAssetsに設定しておくことで、ゲーム起動時にアセットを事前読込したり、Sceneに依存しない共有インスタンスとして使用出来ます。
tsubakit1.hateblo.jpAlwaysIncludeShaderは、指定のシェーダーをアプリに常に含める事が出来ます。
(それを使うかどうかはまた話は別なのが面倒な所ですが)
StreamingAssetsとPluginsはそのまま含まれる
StreamingAssetsやPlugins/iOSやPlugins/Androidに含めたファイルは、そのまま含まれます。
Plugins/iOSやPlugins/AndroidはプラットフォームがiOS/Androidだった場合、直下のアセットをそのまま含んでくれるので、プラットフォーム依存したファイルを云々したい場合には使えるかもしれません。この動作NativePlugins(objective-cやjar)等からアクセスする用といった気配がします。
StreamingAssetsはAndroidだとFileクラス等でアクセス出来ないので、アクセスするにはWWWでロードするか自分でapkを解凍するかしないといけません。
スクリプトは大体含まれる
スクリプトは全部含まれます。
但し、Editorフォルダ以下のスクリプトは含まれません。
エンジン側のコード(及び多分個別にDLL化したコード)は、スクリプトが参照している場合は含まれます。
(スクリプトは全部含まれるので、場合によっては余計なコードがストリップを抑制する事もある。AssetBundleや全体をDLL化したせいでストリップされ過ぎる事もある)
また、.DLLの場合はPlatformの指定にチェックが入っている場合に含まれます。
アプリサイズを減らす為には
上のルールを元に、使用していないアセットをアプリに含まれるのを防ぐのがアプリサイズを減らす上で重要な要素になりそうです。
例えばReference Viewerを使用して、該当のアセットが何故含まれているかを確認したり、AssetCleanerでそもそも使用してないコードやアセット群を削除してしまう等です。
アセットレベルでのストリップはルールをちゃんと把握していればビルドサイズ的なメリットは余り無いですが、ビルド時間的には超意味があるので、その辺りも含めて。