Upgrade to Pro — share decks privately, control downloads, hide ads and more …

VRMSpringBoneをJobSystem&ECSで最適化してみた話

mao
February 19, 2019

 VRMSpringBoneをJobSystem&ECSで最適化してみた話

第1回 VRM勉強会 登壇資料
https://vrm.connpass.com/event/116985/

・ サンプルプロジェクト
https://github.com/mao-test-h/VRMSpringBone-Optimize

----------------------------------------------------------------------------
▼ 参考リンク集

・【GTMF2018TOKYO】ハードウェアの性能を活かす為の、Unityの新しい3つの機能
https://www.slideshare.net/UnityTechnologiesJapan/gtmf2018tokyounity3

・【CEDEC2018】CPUを使い切れ! Entity Component System(通称ECS) が切り開く新しいプログラミング
https://www.slideshare.net/UnityTechnologiesJapan/cedec2018cpu-entity-component-systemecs

・Memory Management of C# with Unity Native Collections
https://www.slideshare.net/neuecc/memory-management-of-c-with-unity-native-collections

mao

February 19, 2019
Tweet

More Decks by mao

Other Decks in Technology

Transcript

  1. 第1回 VRM勉強会

    VRMSpringBoneを

    JobSystem & ECSで

    最適化してみた話


    View full-size slide

  2. 自己紹介

    mao ( @TEST_H_ )


    ・ プログラマー


    View full-size slide

  3. ▼ 今回話す内容

    dwango/UniVRMにあるVRMSpringBone(とそれに関連する機能)
    をUnityの新機能であるJobSystemや
    ECS(EntityComponentSystem)を用いて最適化出来ないか検証し
    てみたお話。

    ※VRMSpringBone : モデルの服や髪といった揺れ物を制御する機能。


    → 何通りか検証してみたので、

      検証結果や効率化に関するTipsなどをご共有。


    View full-size slide

  4. ▼ 今回話す内容

    ※Unityエンジニア向けの内容です。

    ※実装に関する詳細な情報まではお話しない想定。

    → 詳細な設計周り/JobSystem基礎/ECS基礎/etc…


    今回話すのは実装概要(簡単な設計)、パフォーマンスの計測結
    果、幾つかのTipsと言ったポイントまで。

    ※最後におまけとしてちょっとした補足や参考リンクを記載。


    View full-size slide

  5. ・ 資料は後日公開予定。

    ・ 実装したソースはGitHubにて公開済み。
    mao-test-h/VRMSpringBone-Optimize


    View full-size slide

  6. ▼ 注意点

    ・ 実装には幾つかのPreviewな機能を使っている。

    - ECSとか、あとBurstCompilerは基本有効にしている。


    ・ 実装についてはまだまだ手探りな部分が多い状態。。

    - 完全に理解できていないので、

       あくまで一例程度に留めて頂けると幸いです。。




    ※ちなみに全部プライベートでやっている趣味開発での検証内容。

     その為に実務導入を前提とした内容では無い事を一応追記。。


    View full-size slide

  7. ▼ 目次

     ▽ サンプルについて

     ▽ 実装内容とパフォーマンス

    - JobSystem (モデル毎に処理)

    - JobSystem (全モデル分を一括で処理)

    - ECS & JobSystem


     ▽ まとめ


    View full-size slide

  8. サンプルについて


    View full-size slide

  9. ▽ サンプルについて

    以下の環境にてニコニ立体ちゃんの
    VRMモデル256体を同時に動かして負
    荷計測してみた。


    ・ 実行環境はStandalone(Windows) + IL2CPP

    - CPU : Intel Core i7-8700K

     (Worker Threadは11本)

    ・ Unity標準のProfilerで計測 

    ・ 途中でモデル1体を動的に追加/削除 


    View full-size slide

  10. ※ オリジナルの挙動について


    View full-size slide

  11. ※ オリジナルの挙動について


    View full-size slide

  12. ※ オリジナルの挙動について

    ・ MainThreadベースで処理されている

      LateUpdateの負荷が支配的。

    → 大体13ms~は掛かっている印象。


    ・ 動的なモデルの増減については

      そこまで負荷は高くない。


    View full-size slide

  13. 実装1 : JobSystem

    (モデル毎に処理)


    View full-size slide

  14. ▽ JobSystem (モデル毎に処理)

    ・ モデル単位で「モデルが持つ全ての揺れ物対象のボーン」の

      情報を1箇所で管理。

    → こちらの集めたバッファを対象にJobを発行(Schedule)していく。


    → 物理演算を行うのと同時にTransformAcess経由で即時に更新。

    ※ Job(IJobParallelForTransform)の中でTransformの更新も行っている。


    ・ 今回の例で言うと、1モデルに付き必要な計算を行うJobが

      3つほど存在するので...「モデル256体 x 3つのJob」

    → 計763個のJobが発行されるイメージ


    View full-size slide

  15. ▼ データの簡易イメージ

    モデルが持つVRMSpringBone

    (髪、スカート、アクセサリーなど)

    View full-size slide

  16. ▼ データの簡易イメージ

    モデルが持つVRMSpringBone

    (髪、スカート、アクセサリーなど)

    Jobで使うデータ

    物理演算で使う値[] 

    Transform[]

    etc...

    ※Transformの配列はイメージ。正確に言うと「TransformAccessArray」を用いている。


    View full-size slide

  17. ▼ データの簡易イメージ

    モデルが持つVRMSpringBone

    (髪、スカート、アクセサリーなど)

    Jobで使うデータ

    物理演算で使う値[] 

    Jobで行う処理

    ・コリジョンの算出

    ・親の回転値の取得

    ・物理演算/反映

    Transform[]

    etc...

    ※Transformの配列はイメージ。正確に言うと「TransformAccessArray」を用いている。


    View full-size slide

  18. ▼ データの簡易イメージ

    モデルが持つVRMSpringBone

    (髪、スカート、アクセサリーなど)

    Jobで使うデータ

    物理演算で使う値[] 

    Jobで行う処理

    ・コリジョンの算出

    ・親の回転値の取得

    ・物理演算/反映

    Transform[]

    ・コリジョンの算出

    ・親の回転値の取得

    ・物理演算/反映

    ※モデル単位でデータが纏めれてJobの発行が行われる。

    etc...

    物理演算で使う値[] 

    Transform[]

    etc...


    View full-size slide

  19. ▽ JobSystem (モデル毎に処理)


    View full-size slide

  20. ▽ JobSystem (モデル毎に処理)


    View full-size slide

  21. ▽ JobSystem (モデル毎に処理)

    MainThreadの処理は5ms以内には収まった。

    ※但したまにスパイクがチラホラと...


    View full-size slide

  22. ▽ 結果

    ・ この結果だけ見るとマシにはなったけど....

      モデル毎にJobを発行している影響か、

      WorkerThreadの処理の並びが疎ら...。

    → もっと詰められないか?


    ・ 動的なモデルの増減については

     データがモデル単位で別れているためか、

     そこまで負荷は高くない印象。

    (スパイクは別の要因で発生している物)


    View full-size slide

  23. 実装2 : JobSystem

    (全モデル分を一括で処理)


    View full-size slide

  24. ▽ JobSystem (全モデル分を一括で処理)

    ・ 揺れ物対象のボーンをモデル単位ではなく

      全モデル分の情報を一箇所に纏めた上で処理。

    → こちらの集めたバッファを対象にJobを発行していく。



    全てのデータを1箇所で集中管理しているので

    発行されるJobは3つのみ。

    ※先程のやり方だと763回発行されていたので回数に大きな差。

     但しJobが処理するデータ数はその分増えているイメージ。


    View full-size slide

  25. ▼ データの簡易イメージ

    モデルが持つVRMSpringBone

    (髪、スカート、アクセサリーなど)

    Jobで使うデータ
 Jobで行う処理

    ・コリジョンの算出

    ・親の回転値の取得

    ・物理演算/反映

    ※全モデルのデータが1箇所に纏めれてJobの発行が行われる。

    物理演算で使う値[] 

    Transform[]

    etc...


    View full-size slide

  26. ▽ JobSystem (全モデル分を一括で処理)


    View full-size slide

  27. ▽ JobSystem (全モデル分を一括で処理)


    View full-size slide

  28. ▽ JobSystem (全モデル分を一括で処理)

    MainThreadの負荷が0.3ms~ぐらいに。

    →トータルで見ても0.8~1msぐらいな印象。


    ※ 但し...動的なモデルの増減については...

    次回 、「パフォーマンス死す」デュエルスタンバイ!


    View full-size slide

  29. ▽ JobSystem (全モデル分を一括で処理)


    View full-size slide

  30. ▽ JobSystem (全モデル分を一括で処理)


    View full-size slide

  31. ▽ JobSystem (全モデル分を一括で処理)

    動的なモデルの増減が重い。

    → 追加/削除周りで20ms~は掛かっている感...


    View full-size slide

  32. ▽ 結果

    ・ 処理速度自体は今回挙げた例の中で一番良い結果となった


    → データが揃っているのでJobの発行の負担も少なく、バッチ処理が効いている。



    ・ 但し動的なモデルの追加/削除における負荷はそれなり...


    → 理由としては単純で一箇所で管理しているバッファの再構築。

      ※ もう少し軽減できないかな...と思ったり(要検証)


    View full-size slide

  33. 実装3 : ECS & JobSystem


    View full-size slide

  34. ▽ ECS & JobSystem

    ・ 先に結論から言うと既存のSpringBoneがGameObjectと

      密接に関わってくるためにHybridベースにする必要があり、

      データの効率化が出来ていないという点で言えば

      ECSでなくても良い感良い感はあったり。。


    ※ ECS自体はその性質上、「意識せずともデータが纏められる上でComponentSystem側で効率よく
    バッチ処理を行える」「データの動的な増減自体も低コスト」というパフォーマンス的な利点があり、先
    程の例で言うとデータの集中管理に近いことを意識せずに行うことが出来るのだが...。

    Hybrid故の負荷が...(後述)


    View full-size slide

  35. ▽ ECS & JobSystem

    ・ 今回の実装例で言うと、正直先程挙げた

      JobSystemベース(集中管理型)でも十分感あるが、

      実装検証自体は出来ているので参考値としてご共有まで。


    ・ 設計周りについては長くなりそうなので割愛...。

    → やっている事は先程のデータの集中管理に近い。

      (データを一箇所で纏めて一気に処理していく的な)


    View full-size slide

  36. ▽ ECS & JobSystem


    View full-size slide

  37. ▽ ECS & JobSystem


    View full-size slide

  38. ▽ ECS & JobSystem

    MainThreadの負荷は0.15ms~ぐらい。

     ※ECSに分離したことで他のLateUpdateの負荷が無くなっている。 


    → トータルで見ても1~2msぐらいな印象。


    ※ちなみに...動的なモデルの増減については...


    View full-size slide

  39. ▽ ECS & JobSystem


    View full-size slide

  40. ▽ ECS & JobSystem

    DirtyTransformAccessArrayUpdate


    View full-size slide

  41. ▽ ECS & JobSystem

    再構築を行うデータが減っているので

    マシにはなっているがそれでも若干高い

    → 追加/削除周りで10~15msは掛かっている感...


    View full-size slide

  42. ▽ 結果

    ・ 増減の負荷はJobベースのやつと比べると少しマシに


    → それでもDirtyTransformAcecssArrayUpdate周りと言った

      データの再構築が負荷として残っている。



    ・ あくまで現時点の機能で実装した一例でしかないので

      将来的な変更によっては効率化出来るかもしれない。

      (希望的観測)

    → GameObjectがUnityEngine.Transformに依存しない構造になってくれるとか。
    そのうちガンにも効くようになるかもしれない。


    View full-size slide

  43. まとめ


    View full-size slide

  44. ・ JobSystemベースに関しては、

      状況に応じて使っていけそうな印象。

    → 但し一部PreviewPackageを用いているので注意。


    ・ ECSについては将来的な変更も含めて

      現時点では何とも言えないところがある。(要検証)

    → 完全なHybridベースの実装だとどうなるのか?

    → 将来的なGameObjectのデータの持ち方はどうなるのか?

    まとめ


    View full-size slide

  45. 後は今回の実装例についてはモデル256体を同時に動かすという
    負荷テストを前提とした計測結果なので、実際に使う際にはオリジ
    ナルの挙動含め、要件の規模に合わせて使い分けていけば良い
    かと思われる。

    まとめ


    View full-size slide

  46. ・ ECS & JobSystemについて


    - 【GTMF2018TOKYO】ハードウェアの性能を活かす為の、Unityの新しい3つの機能


    - 【CEDEC2018】CPUを使い切れ! Entity Component System(通称ECS) が切り開く新しいプログラ
    ミング


    ・ メモリとか


    - Memory Management of C# with Unity Native Collections

    おまけ : 参考リンク集


    View full-size slide