Unite2016 参加レポート ～ハードウェア性能を引き出して60fpsを実現するプログラミング・テクニック～

Unite初参加！いや～人多かった(;^_^A

<font color="gray">VR多かったな～。PlayStationVRカッケー
Marzaが作った短編映像「THE GIFT」、大画面で迫力やばかったな～
Unity認定試験か。前から教育版のライセンスあったけど本気で力入れてるな～
Photon使ってみてー。C#でプラグイン書けるって魅力的だ・・・</font>

まぁ、いろいろありましたが、詳細は講演ガイドのPDFをご覧下さい(笑)
ここでは<font color=red>**ハードウェア性能を引き出して60fpsを実現するプログラミング・テクニック**</font>だけご紹介(一番面白かった)。

**[Unite 2016 Tokyo 講演ガイド](http://japan.unity3d.com/unite/unite2016/schedule)**
**[Unite2016第1日目リポート](http://nil-one.com/blog/articles/2016/04/06/Unite2016_Day1/)**
**[Unite2016第2日目リポート](http://nil-one.com/blog/articles/2016/04/07/Unite2016_Day2/)**

# ハードウェア性能を引き出して60fpsを実現するプログラミング・テクニック
一言でいうとプログラムのコアな部分のお話しｗ

Unityはゲームエンジン(フレームワーク)なのでどうしてもネイティブで作ったものより重たい。
派手なエフェクトを使ったぬるぬる動かすシューティングゲームで常時60fpsを出すにはどうしたら良いか？
そんな内容。

単純に内容が興味深かったっていうのもあるけど、なにより講演がコミカルで適度に笑いが起こり、とても面白かった☆

# ゲームを作るにあたって
- メインターゲットは PlayStationⓇVita (PS Vita)
- プラグインは書かない
- リリース済みのUnityを使用する。皆さんと同条件。開発開始時は5.3.3p1
- プラグインは書かない
- 製品のつもりで作る
- 実際の製品プロジェクトでの実現可能性を重視
- 現状・・・12～13FPS…!

さて、どうするか？

# 3つの工夫
**1.ゲームロジックを別スレッドで実行する**
**2.GPUを多用する**
**3.動的なメモリ確保をしない**

なるほど。直観的に分かりやすい。

# 1.ゲームロジックを別スレッドで実行する
**Unityはシングルスレッドで動作する。**そのためコアがたくさんあっても使いこなせていない。
ほとんどの場合 Main Thread が問題になる。
なのでゲームロジックを別スレッドに持っていく。具体的にはこんな感じ。

```csharp:
private Thread thread = null;

void Main()
{
    thread = new Thread(UpdateThread);
    thread.Start();
}

void UpdateThread()
{
    while(true)
    {
        // ゲームロジック
    }
} 
```

ちなみに**Unityのコルーチンも別スレッドに見えてシングルスレッドで動作することに注意**(停止ボタンでゲーム画面を停止できるのはこのため)。

## 別スレッドの問題
### MainThreadに情報を渡す経路が必要
**→ <font color="red">ダブルバッファでがんばる</font>**

### ゲームオブジェクトの機能が使えない(MonoBehaviour#Update等)
**→ <font color="red">タスク的な構造を自作する</font>**

### Unity API が使えない
**→ <font color="red">呼ばない</font>**

### コリジョンどうすんの
**→ <font color="red">自作する！</font>**

### 物理どうすんの
**→ <font color="red">自作する！！</font>**

### その他もろもろ
**→ <font color="red">がんばる！！！</font>**

　
*いや、皆さん、Unity使ってるともう無理だと思っちゃうでしょ。
意外とがんばれますから*

↑ この発言がめっちゃ印象的だったｗ確かになぁ(笑)

ポイントは Unity API が使えないので、C#の純正機能のみで実装すること。
MainThread と 別スレッドの同期はフレーム数をそれぞれ持たせ調整する、など。

# 2.GPUを多用する
CPUの負荷軽減 → GPUに任せれば良い

これは自分も最近やってることだが、普段**C#スクリプトのみ書いてると使われるのは全てCPU。**
特にピクセル描画処理は負荷が甚大で、それらを**Shaderに持っていけばGPUで処理される**ので段違いに速くなる。

### ポストエフェクト
https://bitbucket.org/Unity-Technologies/cinematic-image-effects

### GPUパーティクル
- Mesh.vertices を更新して描画
- MeshRenderer使用(DrawMeshと比較して採用)
- 同種のオブジェクトを一度に描画する
- なるべくシェーダに記述する

### 火花シェーダ
- 実態以上に高フレームレートに見せる工夫
- 派手に見せるためたくさん使用

### 裏ワザ
- 配列のシェーダ定数に値を渡す方法がある
- 今は undocumented だけど 5.4 で正式なものに
- 頂点ごとの属性をインデクス管理可能になる。頂点のカラー設定を撤廃できた！

いろんな工夫がなされていたようだが、ポイントはやっぱりShaderかな。
しかしShader、どこでエラー出てるか判別しづらく大変だと常々思う。。。

# 3.動的なメモリ確保をしない
- struct を多用
- オブジェクトの事前確保・使い回し
- GC.Collect を避ける。ゲームループ中の明示的な class new はゼロ！(ただし完全には難しい)

### 使われてしまう mono heap
- foreach 文でmono heapを使ってしまう。IEnumerator は class だから。今回 foreach は使用せず
- LinkedList.Add で LinkedListNode を確保してしまう。使用しない。
- Coroutine でゲームを書きたい(IEnumerator で mono heap を使ってしまう)。コルーチンっぽいものを自作。

懐かしいなぁ。自分もiアプリでRPG作ってた頃、GCが問題になって涙ぐましい努力をしたよ・・・。
徹底的に new しない。全て事前確保。結果、ソースがすごいことに(笑)
でも動作はすごく安定するよね。

# Unityを使う利点
「そんなに自作して、 Unity を使う意味あるの？」

そんな声が聞こえてきますね・・・。
あります！

　
**ポーズメニューが一瞬で完成！！**
　

wwwwwwwwww

その他にも

- レンダリングエンジン
- ビルドパイプライン
- 統合環境
- エディタ実行
- アセット配置
- マルチプラットフォーム

実際のところ、今回の講演内容は極端だったけど、それでもUnityを使うメリットは本当にあると思う。
マルチプラットフォーム対応。これに尽きる。
AndroidもiOSもネイティブで作ったことがあるから分かるけど、これがホント大変だからね。。。Unityがどれだけ優しいか(；_；)

# 最後に
**講演プロジェクト(GitHub)**
**[<font color=green>AnotherThread</font>](https://github.com/unity3d-jp/AnotherThread)**

Unite楽しかった～☆やっぱ開発者の生の声って大事だね。伝わってくるものが違う。
Marzaの「THE GIFT」とかホント感動したよ。。

今年もたくさんUnityるぞ～！