【Unity】Unite 2015「MOBIUS FINAL FANTASYにおけるUnity開発事例」レポート


# レポート一覧

- [Unity パフォーマンス・チューニング](http://qiita.com/baba_s/items/c536b923b6cdd919e73e)
- [Unityプロジェクトをひも解き把握するには](http://qiita.com/baba_s/items/446fa7a040f09bcd0ac6)
- [エディター拡張マニアクス 2015](http://qiita.com/baba_s/items/8abfebb18f43fcc5d319)
- [MOBIUS FINAL FANTASYにおけるUnity開発事例](http://qiita.com/baba_s/items/ce6b11a5a8952ecf2485)
- [白猫プロジェクトの裏側！～パフォーマンスチューニングとリアルタイム通信の全て～](http://qiita.com/baba_s/items/7c5680b4b808defddcb7)
- [Unity × Sprite Animation](http://qiita.com/baba_s/items/a410ca070a2d3d037ff8)
- [Unityを利用したスマートフォン向けゲームアプリ開発へのアプローチ方法](http://qiita.com/baba_s/items/34d97d970b7f8b17a568)

# 講演ファイル

http://japan.unity3d.com/unite/unite2015/files/DAY2_1500_room2_Hamaguchi.pdf

# モバイル端末でHDクオリティを実現するには？

## 1. 大規模開発でUnityを使うときの心得

- 小規模開発と小規模開発で根本的に違うこと
	- 同じファイルを同時に触る人が増える
- 例えばアニメーションに付加されるタイムライン

### Unityは複数人で同時にデータ編集するのが苦手

- HierarchyやInspectorで*.sceneや*.prefabを同時に複数の人が編集できない

### Unityで同時にデータ編集するための工夫

- Hierarchyでprefabを複製せずに、  
Inspectorでアセットとして依存関係を構築するなど

```cs
public class PrefabResourceComponent: MonoBehaviour
{
	public GameObject[] prefabData;
}
```

### 依存関係が定義されたprefabはHookサーバーが更新する

1. Commitを検知してHockサーバーがatack.prefabを更新する
2. 最新の依存関係が更新されたattack.prefabをコミット

- Unityでのファイルの依存関係は.metaに記載されているguidによって構築されているので  
UnityEditorを使用しなくても、自作のプログラムから比較的容易にprefabを作り出すことができる

### Assetとして依存関係を設定するとHierarchyでの視認性が落ちてしまう…

- なので、ツールを作成した
- 各担当のprefabの内容を一覧で確認できる方が圧倒的に作業効率がいいため  
HierarchyやInspectorでは編集をあきらめて専用のタイムラインツールを開発
- C#のdllからUnityEditorを参照設定して  
UnityEditor.AssetDatabaseを使ってアセットファイルの読み込み書き出しを行う

### MOBIUSの開発環境

- GUIツール：NGUI
- エフェクトツール：FX Maker
- DCCツール：Maya, SI, MotionBuilder
- 揺れもの物理&IKの設定ツール
- エクセルコンバーター
- タイムラインツール
- サウンドツール

### その他

- 定期的にリソースデータを集めてアセットバンドルを自動作成している
- MOBIUS規模のデータで3時間程度かかりる
- アセットバンドルが出来上がると、ゲームサーバー側のストレージにアップ

## 2. モバイル端末でHDクオリティのゲーム制作をするための心得

### Unityって遅いって言われるけど

- Unityが遅いというかC#の特性を知る必要がある

	1. structはスタックに確保されるが、classはヒープなのでgcの頻度を上げる
	2. 文字列操作は気を付けて、classやenumのtoString()は遅い
	3. foreachを使うとEnumerableがヒープ確保されるのでこれもgcの頻度を上げる
	4. Vector演算をまじめにやるとかなりきつい・・・

- 最適化をしたい場所はnative化を検討すること  
（MOBIUSではIKや揺れもの物理はnativeで実装）

	1. Asset/Pluginにdllを置いて簡単にnative呼び出しができる
	2. nativeとmanaged間でのデータの受け渡し

- C#はコーディングしやすいし適材適所を考えれば効率の良い開発ができると思う

### まずは敵を知るところから始めよう

- 同スペックの端末でもiOSのほうがAndroidに比べ性能が出やすいため  
両OSに対応するアプリの場合はAndroid先行で開発する方が失敗が少ない
- apkの作成は2~3分、ipaの作成は20分程度かかる
- Androidのほうが確認が早い

### 次にDLサイズは注意しよう

- データ量を減らすため圧縮版のAssetBundleを使用しています
- 品質はユーザーが選択可能

### テクスチャ形式によってデータサイズは影響する

|iOS|Android|
|:--|:--|
|不透明テクスチャ|RGB PVRTC 4bit|RGB ETC 4bit|
|半透明テクスチャ|RGBA PVRTC 4bit|RGBA ETC2 8bit|

### それぞれのGPUに最適なテクスチャ形式を選ぶ

|　|不透明テクスチャ|半透明テクスチャ|
|:--|:--|:--|
|PowerVR|RGBA PVRTC 4bit|RGBA PVRTC 4bit|
|Adreno|RGB ATC 4bit|RGBA ATC 8bit|
|Mali(ARM製のGPU)|RGB ETC 4bit|RGBA 32bit|
|Mali(T624以降)|RGB ASTC 6x6|RGBA ASTC 4x4|
|Tegra|DXT1|DXT5|

- Unityだと端末情報やGPU情報が取れるので、  
それによって読み込むデータを切り分けることができる
	- `SystemInfo.deviceModel`
	- `UnityEngine.iOS.Device.generation`

### しかし、デザイナーが管理する画像データは1つにしたい

- GPUごとにテクスチャフォーマットを変えたいけど、  
デザイナーがフォーマットごとにデータを用意したくない

### Unityで出力用の画像フォーマットを指定できるが...

- 現状Unityで対応しているのはプラットフォームに対して指定できるフォーマットは1つ
	- iOSはpvrtcのみでよいので問題ない ◎
	- Androidが複数のフォーマットを出力できないので問題 △

### アセットバンドルビルドサーバー側で対応

- GPUに合わせたアセットバンドルを作成するために、  
10台以上のアセットバンドルビルドサーバーが  
最新のデータを適切なテクスチャフォーマットに変更して  
アセットバンドルを作り続けている  
- MOBIUSはテクスチャフォーマットを変更するのに1日かかる

### キャッシュをごまかすテクニック

- UnityからUnityEngine.Texture2DのTextureFormatを変更するとキャッシュの作り直しになって  
AssetBundleを作るたびにテクスチャのキャッシュが作られると遅すぎて話にならない
- Unityを起動してアセットバンドルを作成する前に自前で作成したスクリプトなどを走らせて  
画像ファイルに付随しているmetaの画像フォーマットを想定のフォーマットに書き換えてからUnityを起動します
- そうすることで、各ビルドサーバーは最適なフォーマットのキャッシュファイルが作成され  
アセットバンドル作成の高速化になります

### Shaderは必ず1つにパックして初回に初期化

- ShaderはGPUのバージョンによって変わってくるため、  
コンソールの時のように事前にビルドしたデータをassetbundleに含めることができない
- アプリ実行時にshaderが読み込まれた時にビルドされます。しかも遅いです
- 同じシェーダを使っているのであればAssetBundleで参照設定をして  
無駄にシェーダのビルドが走らないようにしましょう

### その他

- アセットバンドルを作成したら出力されたログを見てみるべき
	- アセットバンドルの依存関係をちゃんと設定しないと  
1つのアセットが複数のアセットバンドルにコピーされて入ってしまっている