「第7回 GREE Tech Talk」に行って来ました
募集ページ
- 2015/03/25開催
[ヽ(^◇^*)/ 300名まで増枠!] GREE Tech Talk #07「Unity Performance Casual Talk」- #greetech07 : ATND
https://atnd.org/events/63402
Toggtterまとめ
第7回 GREE Tech Talk #greetech07 - Togetterまとめ
http://togetter.com/li/800364
Live2Dの描画の裏側の話
- 発表者:阿曽 直貴(株式会社Live2D)
以前のネイティブプラグインで作成したいた時代の話
Unityへの移植の検討
必要そうな情報を記録しておく
// Live2D描画する前にステンシルテストの状態を記憶して、 last_stencilTest = glIsEnabled(GL_STENCIL_TEST); // デプステストの状態を記憶して、 last_depthTest = glIsEnabled(GL_DEPTH_TEST); // 以下、延々と同様の処理
元に戻す
// 描画をUnityに戻す前にステンシルテストを元の状態に復元して、 if (last_stencilTest) glEnable(last_stencilTest); else glDisable(last_stencilTest); ...以下略
状態、バッファ、シェーディングプログラム、テクスチャなど思いつく限り復元する
デバッグが大変
- Unityの管理外なのでプロファイラなどは使えない
- Unityのバージョンアップで動かなくなる
ネイティブプラグインをやめてC#実装に変更
高速に2Dを描くにはどうすれば良いか調査
Graphics.DrawMeshが使えそう
Unity - スクリプティング API: Graphics.DrawMesh
http://docs.unity3d.com/ja/current/ScriptReference/Graphics.DrawMesh.html
Visual Sudioでコーディングしていると「使用しないで下さい」の警告が
Unity 5の更新情報にもこれは削除されるので「使用しないで下さい」の文字が
代わりに Graphics.DrawMeshNow を使う
Unity - スクリプティング API: Graphics.DrawMeshNow
http://docs.unity3d.com/ja/current/ScriptReference/Graphics.DrawMeshNow.html
Graphics.DrawMeshNow の特徴
- UpdateじゃなくてOnPostRenderで呼ぶ
- MaterialのPassの設定が必要(普通は0)
ドローコールは75になった。パーツの数だけドローコールが発生している様で有った
↓
Conbineでまとめる
メッシュをまとめてドローコールを削減
var combine = new CombineInstance[10]; for (int i = 0; i<combine.Length; i++) { combine[i].mesh = meshes[i]; } // このメッシュにすべての他のメッシュをまとめる mesh.CombineMeshes(combine);
Tips
Array.Reverseが遅かった
配列を反転させるためにArray.Reverseを使っていた
Array.Reverse(buf4, 0, 4); return BitConverter.ToSingle(buf4, 0);
大量に使うとかなり遅いことが分かったので、素直に自分で書いた。
tmp[0] = buf4[3]; tmp[1] = buf4[2]; tmp[2] = buf4[1]; tmp[3] = buf4[0]; return BitConverter.ToSingle(tmp, 0);
データ読み込み速度が20%くらいアップ
開発スピードとパフォーマンスの両立(仮)
- 発表者:稲森 亮介(グリー株式会社)
Application.targetFramerateを動的に変える
同時にfarClipの距離を調整して速度改善も図る
雲、Overdraw(同じ位置に重ねて描画される部分)多すぎ
パーティクルでやっていた
Prewarm(※)は重いのでロード時点で長めに流して対応
※表示された時に既にパーティクルが出てる様にしたい場合に使用するもの。使わないとパーティクルが放たれ始める部分がユーザの目に触れる
地形が複雑な時
遠景は大きなスプライト
中景はほどほどのサイズ
ライトは使わずテクスチャにグラデーション
傾ける&揺らす
パーティクル→自前のビルボード
Asset Storeを活用
そのまま使うのでは統一感が無くなる
元の素材は昼のシーンだったがゲームは夜のシーンなので調整
- Skyboxの変更
- フォグで夜っぽい色に調整
これだけでは違和感が有る(※)のでライティングを行いたい
※地形が昼の表現のまま
しかし、この素材はベイクされているにも関わらず、元のライトが削除されている
↓
ライトマップテクスチャ(OpenExrファイル)自体をPhotoshopで調整
動的にライトマップを解除
- 洞窟のシーンで明るいシーンと暗いシーンが有る。暗いシーンでは照準のカーソルがライトに成っていてライトが当たってる所だけ見えるという仕様
- 管理の都合上、洞窟の暗いシーンと明るいシーンは1つにしたかった
Renderer[] = renderers = FindeObjectsOfType<Renderer> (); foreach (var renderer in renderers) { renderer.liehgtmapIndex = -1; }
- lightmapIndexはLightmapSettings.lightmapsのインデックスだが、-1はライトマップが割り当てられてない事を示す初期値。これを設定する事でライトマップを動的にOFFに出来る
- 敵キャラは頂点ライトのみ
- Direction Lightのみだと流石に安っぽくなってしまうので、Point Lightを複数配置
敵キャラの動き
敵の位置が固定の場合、手付けで制御点を置く事が多い
今回は人数が少ないのでそれは使いたく無かった
手付けでは無く、計算式で実装。移動+回転の組み合わせなど
ドローコール伝説の終わり 〜新たなるパフォーマンスの道を求めて〜
StatsからDrawCallが無くなっている
ドローコールとは
CPUでやっている描画関連の処理はDrawCall以外にも色々有る
例えば頂点データ、テクスチャ、マトリックスの処理なども行う
厳密なDrawCallは矢印のCPUからGPUへ処理を渡す処理の部分のみ
この部分は昨今のドライバーの進化(Metal/Vulkanなど)でどんどん高速に
DrawCallは初回は遅いが、2回目以降は高速。小さなウェイトなので多少の数の場合には気にしなくてよいが流石に100回とかになってくると注意が必要
頂点をまとめる処理の方がコストが高くなってきている
Unity 5からStatic Batchingの処理にも変更が行われている
GPU側の描画の問題
Renderがいっぱい(ピクセル描画が重い)
Tilerがいっぱい(頂点量が多すぎ)
ドローコールを減らしても解決しない
Xcode & Instruments でチェック
GPU Profiler
PVRTCなどフォーマットの方がテクスチャのキャッシュにヒットしやすい
Cube mapのようなランダム・アクセスするテクスチャはキャッシュミスがヒドい
モバイルでUnityの新しいシェーダのライティングをするとCube mapの解像度が低いのはパフォーマンスが悪い為
ピクセル描きすぎ(オーバードロー)
Tilerがいっぱい
- 送信している頂点数が多すぎ
モバイルは半透明に弱い(discardのコストが高い)
- 2DはUnity 2Dを使う(半透明のピクセルを極限まで減らす)
【具体例】
※透過付きの2ポリゴンより、透過の無いポリゴン数が多いもの方が良い
頂点が多くなっても塗る範囲が減る最適化をする
重い描画と重くない描画の発見
Rendererがいっぱい
- fragment shaderを簡単にする/テクスチャのキャッシュミス→GPUベンダーのプロファイルでチェック
- ピクセル描きすぎ(オーバードロー)→フレームデバッガ/Xcode/シーンビューでチェック
Tilerがいっぱい
結論
- 描画が重い=ドローコールではない
- 重い原因に気を配ろう(重いドローコールと重くないドローコールの切り分け)
- 重い原因を解決しよう
- 原因の発見にはUnityのProfiler/Frame Debugger/GPUメーカーやベンダーのProfilerを使おう