live2dの描画の裏側の話

53
Live2Dの描画の 裏側の話 2015/03/25 GREE Tech Talk

Upload: naoki-aso

Post on 14-Jul-2015

3.785 views

Category:

Engineering


1 download

TRANSCRIPT

Page 1: Live2Dの描画の裏側の話

Live2Dの描画の裏側の話

2015/03/25 GREE Tech Talk

Page 2: Live2Dの描画の裏側の話

自己紹介

•株式会社 Live2D

•阿曽直貴

•広く浅く、ネイティブプラットフォームで書いてます

• Unity、iOS、Android、Flash、3DS、Vita

作ったアプリ

Page 3: Live2Dの描画の裏側の話

自己紹介 (直近1ヶ月)

• < 勉強会で発表しませんか?

• Unityでゲーム作った経験とかはないしどうしよう

• 「ドローコール」には苦労したし、テーマはドローコール削減にしよう

•開催概要の発表

ドローコール伝説の終わり (20:40~)

Page 4: Live2Dの描画の裏側の話

今日お話する内容

• Live2D for Unity

•ネイティブプラグインによる高速化

•スクリプトから高速にメッシュを描画する

Page 5: Live2Dの描画の裏側の話

Live2Dの紹介

Page 6: Live2Dの描画の裏側の話

Live2Dって?

• イラストをそのまま動かす技術

Demo

Page 7: Live2Dの描画の裏側の話

どんなところで使われてるの?

Page 8: Live2Dの描画の裏側の話

どうやって使うの?

• Live2D SDK for Unity

•無料で始められます

• Live2Dスタッフブログにまとめました。

Live2Dモデルデータ

Live2Dライブラリ

Page 9: Live2Dの描画の裏側の話

Unityの話に入る前に

Page 10: Live2Dの描画の裏側の話

技術的には3Dと何が違うのか

•基本的には3D技術の上に成り立っている

• ポリゴンの描画

•一般に3Dより描画は速いがメモリ消費は多め

•高機能なボーンのようなもの > デフォーマ

•行列ではない頂点変形がメイン

•半透明が重要

• クリッピングが大変

Page 11: Live2Dの描画の裏側の話

3Dとの違い1

•頂点の形状変形が常にある

Page 12: Live2Dの描画の裏側の話

3Dとの違い2

•半透明合成が重要

Page 13: Live2Dの描画の裏側の話

3Dとの違い3

• メッシュでリアルタイムクリッピングが必要

変形する

目からはみ出ないようにマスクしたい

* クリッピングは次期バージョンで対応

Page 14: Live2Dの描画の裏側の話

3Dとの違い4

• テクスチャのクオリティが必要

適当にPVRTC圧縮すると劣化する。パーツの境界、半透明の部分で特に著しい

完全透明部分の色情報も必要

Page 15: Live2Dの描画の裏側の話

それらを踏まえて

• 3D技術の延長ではあるけど、3Dからするとマニアックすぎて情報が少ない

• 3D技術で再現できるけど、最適化されてないので極端に遅かったりする

•具体的にUnity上で試行錯誤した話

Page 16: Live2Dの描画の裏側の話

ネイティブプラグインによる高速化

Page 17: Live2Dの描画の裏側の話

注意

• Unity 3.5とかの時代です

•ネイティブプラグインとOpenGLについての話

•現在とは状況が異なると思います

Page 18: Live2Dの描画の裏側の話

Live2Dの当時の状況

•約3年前 (2012年初旬)

• Android,iOSのネイティブなライブラリはある (C++とJava)

•パフォーマンスについてもすでに作りこんである

•実際Android2.2やiPhone3GSやPSPくらいでもちゃんと動く

Page 19: Live2Dの描画の裏側の話

Unityへの移植の検討

• C#? 速いの?

• OpenGLもDirectXも使えない? 速いの?

• ネイティブプラグインで今までの資産が動く !

• ネイティブのOpenGLが遅いはずがない !

Page 20: Live2Dの描画の裏側の話

ネイティブプラグイン + OpenGL

描画終了

描画開始

描画に割り込み(C++)

C#スクリプト

C#スクリプト

C#スクリプト

Page 21: Live2Dの描画の裏側の話

必要そうな情報を記憶しておく

//Live2D描画する前に…

//ステンシルテストの状態を記憶して、

last_stencilTest = glIsEnabled(GL_STENCIL_TEST) ;

//デプステストの状態を記憶して、

last_depthTest = glIsEnabled(GL_DEPTH_TEST) ;

//以下長々と同様の処理

Page 22: Live2Dの描画の裏側の話

元に戻す

//描画をUnityに戻す前に…

//ステンシルテストの状態を復元して、

if(last_stencilTest) glEnable(last_stencilTest)

else glDisable(last_stencilTest) ;

...以下略

状態、バッファ、シェーダプログラム、テクスチャなどに対して思いつく限り復元する

Page 23: Live2Dの描画の裏側の話

結果

•動いた!

•確かに速いように思える。

•見かけのドローコールは1 (意味は無い)

Page 24: Live2Dの描画の裏側の話

でも

• プラットフォームごとに自分で書かないといけない

• デバッグが非常に大変

Page 25: Live2Dの描画の裏側の話

デバッグが大変

• Unityの管理外なのでプロファイラなどは使えない

• OpenGLの状態を正しく復元しないといけない

• Unityのバージョンアップで動かなくなる

•内部処理の影響を受けるのでそもそも情報公開されてない可能性有り

Page 26: Live2Dの描画の裏側の話

ネイティブプラグインは自己責任

エラー! エラー!

え? 自分のせいじゃないし...

描画終了

描画開始

Unityから不可視

C#スクリプト

C#スクリプト

C#スクリプト

Page 27: Live2Dの描画の裏側の話

まとめ

•当時としてはチャレンジングなプラグインだった

•高速だけどメンテナンスが大変

• Android機種依存とかは自力対応しないと…

• ネイティブによりすぎて、Unityの能力を活かしきれなかった

Page 28: Live2Dの描画の裏側の話

スクリプトから高速にメッシュを描画する

Page 29: Live2Dの描画の裏側の話

注意

• Unityでゲームを作ったわけではないので、制作のほうはわかりません

• GameObjectと関係なく、スクリプトからメッシュを描画する方法について

Page 30: Live2Dの描画の裏側の話

C#で書きなおすために調査

Page 31: Live2Dの描画の裏側の話

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.

メッシュの数が多くても、ゲームオブジェクトの管理が楽になる、ということらしい

Page 32: Live2Dの描画の裏側の話

VisualStudioいわく

Page 33: Live2Dの描画の裏側の話

Unity5の更新情報

http://japan.unity3d.com/unity/whats-new/unity-5.0

Page 34: Live2Dの描画の裏側の話

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);

}

Page 35: Live2Dの描画の裏側の話

結果

テクスチャ1枚マテリアル一つ

パーツの数だけドローコールが増えてる

Page 36: Live2Dの描画の裏側の話

ドローコールのための基本事項

• とにかく同じ描画設定で描く

そのために

• マテリアルは最小数にする

• テクスチャもまとめて一枚にする

Page 37: Live2Dの描画の裏側の話

メッシュは自分でまとめよう

Page 38: Live2Dの描画の裏側の話

Mesh.CombineMeshes

var combine = new CombineInstance[10];

for (int i = 0; i < combine.Length; i++){

combine[i].mesh =meshes[i];

}

//このメッシュにすべての他のメッシュをまとめる

mesh.CombineMeshes(combine);

Page 39: Live2Dの描画の裏側の話

結果2

Page 40: Live2Dの描画の裏側の話

本当に速くなったのか検証

Live2Dキャラクターを11体表示ドローコール 800超15FPS以下

ドローコール削減前

Page 41: Live2Dの描画の裏側の話

本当に速くなったのか検証

キャラクターを同じ数表示ドローコール 1230FPS以上

ドローコール削減後

Page 42: Live2Dの描画の裏側の話

正直思った以上に違う

ただし、純粋な検証ではなく、あくまでLive2D上での比較です。

ドローコール 800以上 ドローコール 12回

Page 43: Live2Dの描画の裏側の話

パフォーマンスのためのTips

Page 44: Live2Dの描画の裏側の話

Tips1. テクスチャアトラス

• テクスチャを一枚にまとめる

• Live2D SDKは次期バージョン(2.1)で対応予定

• Live2Dエディタは対応しないのでアトラス化は別なソフトで

Page 45: Live2Dの描画の裏側の話

Tips2. GCの最適化

1キャラクター描画するときに毎フレーム約40KBメモリ確保していた

Page 46: Live2Dの描画の裏側の話

Tips2. GCの最適化

• 40KB*60フレーム = 毎秒 2.4MB の消費 !

• Mesh.verticiesをやり取りするときにコピーが発生

•配列はキャッシュしておく

• newしてないつもりでも、どこかでメモリ確保されうる

Page 47: Live2Dの描画の裏側の話

Tips3. Array.Reverseが遅かった

大量に使うと遅いことがわかったので、素直に自分で書いた

配列を反転するためにArray.Reverseを使っていた

データ読み込み速度が20%くらいアップ

Page 48: Live2Dの描画の裏側の話

Tips4 プロファイラに頼らない方法

お手軽に計測できるような簡易クラスを作っておくと便利

Page 49: Live2Dの描画の裏側の話

まとめ

• Live2D for Unityでどんなことをやっているか

• 2Dだけど、レンダリング技術的には3D技術です

• Unityでの開発は苦労したとはいえ、ネイティブ言語での開発よりはだいぶ効率的でした

Page 50: Live2Dの描画の裏側の話

ミドルウェアとして

• Live2Dは現在5言語、10以上のプラットフォーム

•専門部隊がいるわけではない

•効率的にやらないといけない

•特定のプラットフォームに依存しないこと

•自力で多数のプラットフォームに対応すること

•普遍的な技術であるために

Page 51: Live2Dの描画の裏側の話

Live2D Cubism 2.1

• クリッピングの対応

•便利になったPSDインポート

•編集効率の向上

Page 52: Live2Dの描画の裏側の話

Live2D Euclidhttp://www.live2d.com/news/euclid_development

Page 53: Live2Dの描画の裏側の話

ありがとうございました