live2dの描画の裏側の話
TRANSCRIPT
Live2Dの描画の裏側の話
2015/03/25 GREE Tech Talk
自己紹介
•株式会社 Live2D
•阿曽直貴
•広く浅く、ネイティブプラットフォームで書いてます
• Unity、iOS、Android、Flash、3DS、Vita
作ったアプリ
自己紹介 (直近1ヶ月)
• < 勉強会で発表しませんか?
• Unityでゲーム作った経験とかはないしどうしよう
• 「ドローコール」には苦労したし、テーマはドローコール削減にしよう
•開催概要の発表
ドローコール伝説の終わり (20:40~)
今日お話する内容
• Live2D for Unity
•ネイティブプラグインによる高速化
•スクリプトから高速にメッシュを描画する
Live2Dの紹介
Live2Dって?
• イラストをそのまま動かす技術
Demo
どんなところで使われてるの?
どうやって使うの?
• Live2D SDK for Unity
•無料で始められます
• Live2Dスタッフブログにまとめました。
Live2Dモデルデータ
Live2Dライブラリ
Unityの話に入る前に
技術的には3Dと何が違うのか
•基本的には3D技術の上に成り立っている
• ポリゴンの描画
•一般に3Dより描画は速いがメモリ消費は多め
•高機能なボーンのようなもの > デフォーマ
•行列ではない頂点変形がメイン
•半透明が重要
• クリッピングが大変
3Dとの違い1
•頂点の形状変形が常にある
3Dとの違い2
•半透明合成が重要
3Dとの違い3
• メッシュでリアルタイムクリッピングが必要
変形する
目からはみ出ないようにマスクしたい
* クリッピングは次期バージョンで対応
3Dとの違い4
• テクスチャのクオリティが必要
適当にPVRTC圧縮すると劣化する。パーツの境界、半透明の部分で特に著しい
完全透明部分の色情報も必要
それらを踏まえて
• 3D技術の延長ではあるけど、3Dからするとマニアックすぎて情報が少ない
• 3D技術で再現できるけど、最適化されてないので極端に遅かったりする
•具体的にUnity上で試行錯誤した話
ネイティブプラグインによる高速化
注意
• Unity 3.5とかの時代です
•ネイティブプラグインとOpenGLについての話
•現在とは状況が異なると思います
Live2Dの当時の状況
•約3年前 (2012年初旬)
• Android,iOSのネイティブなライブラリはある (C++とJava)
•パフォーマンスについてもすでに作りこんである
•実際Android2.2やiPhone3GSやPSPくらいでもちゃんと動く
Unityへの移植の検討
• C#? 速いの?
• OpenGLもDirectXも使えない? 速いの?
• ネイティブプラグインで今までの資産が動く !
• ネイティブのOpenGLが遅いはずがない !
ネイティブプラグイン + OpenGL
描画終了
描画開始
描画に割り込み(C++)
C#スクリプト
C#スクリプト
C#スクリプト
必要そうな情報を記憶しておく
//Live2D描画する前に…
//ステンシルテストの状態を記憶して、
last_stencilTest = glIsEnabled(GL_STENCIL_TEST) ;
//デプステストの状態を記憶して、
last_depthTest = glIsEnabled(GL_DEPTH_TEST) ;
//以下長々と同様の処理
元に戻す
//描画をUnityに戻す前に…
//ステンシルテストの状態を復元して、
if(last_stencilTest) glEnable(last_stencilTest)
else glDisable(last_stencilTest) ;
...以下略
状態、バッファ、シェーダプログラム、テクスチャなどに対して思いつく限り復元する
結果
•動いた!
•確かに速いように思える。
•見かけのドローコールは1 (意味は無い)
でも
• プラットフォームごとに自分で書かないといけない
• デバッグが非常に大変
デバッグが大変
• Unityの管理外なのでプロファイラなどは使えない
• OpenGLの状態を正しく復元しないといけない
• Unityのバージョンアップで動かなくなる
•内部処理の影響を受けるのでそもそも情報公開されてない可能性有り
ネイティブプラグインは自己責任
エラー! エラー!
え? 自分のせいじゃないし...
描画終了
描画開始
Unityから不可視
C#スクリプト
C#スクリプト
C#スクリプト
まとめ
•当時としてはチャレンジングなプラグインだった
•高速だけどメンテナンスが大変
• Android機種依存とかは自力対応しないと…
• ネイティブによりすぎて、Unityの能力を活かしきれなかった
スクリプトから高速にメッシュを描画する
注意
• Unityでゲームを作ったわけではないので、制作のほうはわかりません
• GameObjectと関係なく、スクリプトからメッシュを描画する方法について
C#で書きなおすために調査
Graphics.DrawMesh
公式リファレンスより
Use DrawMesh in situations where you want to draw large amount of meshes, but don't want the overhead of creating and managing game objects.
メッシュの数が多くても、ゲームオブジェクトの管理が楽になる、ということらしい
VisualStudioいわく
Unity5の更新情報
http://japan.unity3d.com/unity/whats-new/unity-5.0
Graphics.DrawMeshNow
• UpdateじゃなくてOnPostRenderで呼ぶ
• MaterialのPassの設定が必要 (普通は0)
public Mesh mesh; public Material mat; public void OnPostRender() {
// set first shader pass of the material mat.SetPass(0); // draw mesh at the origin Graphics.DrawMeshNow(mesh, Vector3.zero, Quaternion.identity);
}
結果
テクスチャ1枚マテリアル一つ
パーツの数だけドローコールが増えてる
ドローコールのための基本事項
• とにかく同じ描画設定で描く
そのために
• マテリアルは最小数にする
• テクスチャもまとめて一枚にする
メッシュは自分でまとめよう
Mesh.CombineMeshes
var combine = new CombineInstance[10];
for (int i = 0; i < combine.Length; i++){
combine[i].mesh =meshes[i];
}
//このメッシュにすべての他のメッシュをまとめる
mesh.CombineMeshes(combine);
結果2
本当に速くなったのか検証
Live2Dキャラクターを11体表示ドローコール 800超15FPS以下
ドローコール削減前
本当に速くなったのか検証
キャラクターを同じ数表示ドローコール 1230FPS以上
ドローコール削減後
正直思った以上に違う
ただし、純粋な検証ではなく、あくまでLive2D上での比較です。
ドローコール 800以上 ドローコール 12回
パフォーマンスのためのTips
Tips1. テクスチャアトラス
• テクスチャを一枚にまとめる
• Live2D SDKは次期バージョン(2.1)で対応予定
• Live2Dエディタは対応しないのでアトラス化は別なソフトで
Tips2. GCの最適化
1キャラクター描画するときに毎フレーム約40KBメモリ確保していた
Tips2. GCの最適化
• 40KB*60フレーム = 毎秒 2.4MB の消費 !
• Mesh.verticiesをやり取りするときにコピーが発生
•配列はキャッシュしておく
• newしてないつもりでも、どこかでメモリ確保されうる
Tips3. Array.Reverseが遅かった
大量に使うと遅いことがわかったので、素直に自分で書いた
配列を反転するためにArray.Reverseを使っていた
データ読み込み速度が20%くらいアップ
Tips4 プロファイラに頼らない方法
お手軽に計測できるような簡易クラスを作っておくと便利
まとめ
• Live2D for Unityでどんなことをやっているか
• 2Dだけど、レンダリング技術的には3D技術です
• Unityでの開発は苦労したとはいえ、ネイティブ言語での開発よりはだいぶ効率的でした
ミドルウェアとして
• Live2Dは現在5言語、10以上のプラットフォーム
•専門部隊がいるわけではない
•効率的にやらないといけない
•特定のプラットフォームに依存しないこと
•自力で多数のプラットフォームに対応すること
•普遍的な技術であるために
Live2D Cubism 2.1
• クリッピングの対応
•便利になったPSDインポート
•編集効率の向上
Live2D Euclidhttp://www.live2d.com/news/euclid_development
ありがとうございました