SlideShare ist ein Scribd-Unternehmen logo
1 von 82
Downloaden Sie, um offline zu lesen
【Unity/Burst】
CPUだけでペンギン一万体
アニメさせてみた
誰
村上 善紀
仙台高専(11年~)
DeNA(16年4月~)
アカツキ(19年4月~)
IL仙台(21年12月~)
視聴者の想定
難易度:Advanced
・コンシューマーの3Dゲーム開発の経験がある
・Unityでの3Dゲーム開発に詳しい
・Burstが何か知っている
ペンギンのハドル
皇帝ペンギンは寒さに対抗するために、ハドルと呼ばれる集まりを作る。ハドル
には数百ほどの数が集まるらしい
それはともかくとして、
ペンギンは一万体くらい 60 30FPSで
元気に動いていてほしい
一万体動かしたいペンギン
頂点1076 ボーン6
今回の実行環境
CPU:Ryzen 5950x (Stock)
GPU:Radeon 6800XT (Stock)
RAM:DDR4-3200 (CL14) 64GB
Unity:2022.2b3
Development Build(Faster Runtime) / IL2CPP Release
DX12 / Graphics Job Enabled / HDRP 3820x2160
そもそも標準のUnityではペンギン一万体動かないの?
Unityの標準実装ではどうなるか?
CPUスキニングとGPUスキニングについて
一万体全員が映るケースで検証してみる
1mおきにx軸とz軸について100x100で配置。カメラはこれらを収める位置に。
最良の結果を得るため、AnimatorのボーンOptimizeも利用する。
Unityの標準実装ではどうなるか?
・Animator+CPUスキニング
1フレームに掛かる時間
140-160ms
Animator関連 35ms程度
Skinning関連 105ms程度
(Render+Mainスレッド
の重ならない部分の合計)
Unityの標準実装ではどうなるか?
・Animator+GPUスキニング
1フレームに掛かる時間
55ms~60ms程度
Animator関連 35ms程度
Skinning関連 40ms程度
(Render+Mainスレッド
の重ならない部分の合計)
30FPSは、1フレームが33msに収まる必要がある
アニメーション~スキニングを
前述した問題を解決できるよう、Burstで実装してみよう。
ということで
そもそも。
アニメーションとスキニングとは
ポリゴンで表現される生物について、本来生物が骨の動作によって行う筋肉等
の移動を、簡易的にリアルタイムCGで行うためのもの。
アニメーションでは、ボーンという骨を表す表現の、回転値と位置を決定する。
スキニングでは、ボーンの位置に合わせて、ポリゴンの頂点を移動する。
Unityでのアニメーションとスキニングの具体的な仕様
・ボーン
Transformで表される。スキニングのロジック内では座標変換行列として扱わ
れる。
・アニメーション
Animatorによってボーンが挙動することで実現される。AnimationClipが、具体
的なアニメーション内容を持つ。
・スキニング
Skinned Meshという種類のポリゴン描画で実行する。
Unityのアニメーションとスキニングについて
動作が重い理由について分析する
動作が重い理由:アニメーション
アニメーションの問題は主に二つある
1.Transformが邪魔
2.Animatorが単純に重い
アニメーションの問題1. Transformが邪魔
Transformはパフォーマンス的には邪魔者
単純にオブジェクト指向的メモリ配置なため、重い。(連続していない)
また、階層構造で処理の並列化の可否が決定する。
https://forum.unity.com/threads/ijobparallelfortransform-15000-transforms-executed-on-single-job-thread-a
ny-hints.537723/
https://blog.unity.com/technology/best-practices-from-the-spotlight-team-optimizing-the-hierarchy
Transformはパフォーマンス的には邪魔者
一方で、作業上重要な役割も担っている。
AnimationClipを介したアニメーション再生で、Transformは使われることが前
提。
アニメーションの問題2. Animatorが単純に重い
2.Animatorが単純に重い
見た感じ、やってることに対して重すぎる。
(Unityの内部実装は確認できないため、Burstで一から実装したらもう少しパ
フォーマンス出るだろうという推測です。)
動作が重い理由:スキニング編
動作が重い理由:スキニング編
・そもそも、スキニングがロジックとして重い!
Unityは別に何か悪いことをしているわけではない。
強いて言えば、Skinned Meshでは16bitのメッシュをスキニングできない。今回
は精度的に16bitで十分なため、これはUnityの問題と言える?
これらをふまえて
独自実装の指針
独自実装の指針
・アニメーション
AnimationClipを利用できるようにしながら、Burstで一から
PlayableGraph(Animator)に相当する物をBurstで実装する。
・スキニング
16bitスキニングに対応して、Burstで実装する。
独自実装する:アニメーション編
独自実装する:アニメーション編
・AnimationClipの利用
・PlayableGraph(Animator)相当のもの
これらが必要
AnimationClip
AnimationClipの詳細
内部表現をエディタースクリプティングで確認することが出来る。
AnimationClipの詳細
AnimationClipの内部表現は、文字列とAnimationCurveで出来ている。
AnimationCurveとして時間軸上におけるアニメーションの値が表現され、文
字列で、そのCurveがどのプロパティに関連するか示されている。
※今回はボーンに対する挙動なので移動回転スケールができればいい
AnimationClipの評価をBurst化
・だがAnimationCurveはメインスレッドでしか評価できない。
https://forum.unity.com/threads/animationcurve-evaluate-can-only-be-calle
d-from-main-thread.531614/
移植するためには、内部ロジックが必要。
AnimationClipの評価をBurst化
UnityのCsReference内にAnimationCurveの図的表示に使われている部分の
ロジックがあったので、これをベースにスレッドセーフなものを実装する。
https://github.com/Unity-Technologies/UnityCsReference/blob/master/Edit
or/Mono/Animation/AnimationWindow/CurveEditor.cs
PlayableGraph相当の表現
PlayableGraph相当の表現
Clipをどのように評価し、最終的なボーンの出力にするかは、決して素朴なも
のではない。ブレンディングやレイヤーマスクなど、何をどのようにどの程度実
装するかはゲームに応じて決めていい。
その為、詳細は割愛します。
(自由に実装できるということ自体が
重要な個所)
スキニングの実装指針詳細
スキニング in 16bit
頂点バッファを16bit化して、それに合わせたロジックを書く。
今回はランタイムでUnityの通常のメッシュアセットを変換し、16bitになるように
調整する。
※UnityではBurstをつかって、VertexBufferのレイアウト等に対して細かく指示
しながらランタイムでメッシュを構築できる。
https://github.com/Unity-Technologies/MeshApiExamples
Unityでのアセット
Burstで利用するランタイム表現
実際に動かした
Unityエディターに移動します
パフォーマンス確認・改善
ボーンアニメ+スキニング
ペンギン1000体のパフォーマンス
・Burst実装     ・Animator+Unity CPU ・Animator+Unity GPU
ボーンアニメ+スキニング
ペンギン1000体のパフォーマンス
※スキニングとAnimation関連部分のみ
・Burst実装
約4.6ms
・Animator+Unity CPU
約13ms
・Animator+Unity GPU
約5ms
1000体でこれじゃあ、10000体むり
改善1 Burst Jobのスケジュールパフォーマンス
改善1 UnityのJobスケジュールパフォーマンス
スケジュールに掛かってる時間が長い(2ms以上)
改善1 UnityのJobスケジュールパフォーマンス
例えばスキニングの処理は、1メッシュの頂点バッファが一つのNativeArrayで
表される。
安全システムによってコレクションのコレクションは許可されておらず、通常では
複数の頂点バッファを一つのJobに対してまとめることができない。
つまりメッシュ数分のJobがスケジュールされる。これが重い。
UnityのJobスケジュールパフォーマンス
安全システムの回避方法として、ポインタのコレクションを扱うことができる。
NativeArrayはGetUnsafePtr()で要素先頭へのポインタを取得することができ
る。つまり「配列の先頭ポインタ」の「配列」は作れる。
これによって、複数の頂点バッファへの処理を単一のIJobParallelForで行うこ
とが出来る。
UnityのJobスケジュールパフォーマンス
2msほど要していたものが、0.3ms程度まで落ちた
改善2 ボーンアニメーションの評価速度
改善2 ボーンアニメーションの評価速度
ボーンAnimationの評価自体にも時間が掛かっている。(1msが31スレッド)
改善2 ボーンアニメーションの評価速度
直接の原因としてはAnimationCurve相当の処理評価がそれなりに重いこと。
改善2 ボーンアニメーションの評価速度
そもそもクリップがオーサリングされている以上の分解能で評価される必要が
あるのか?
ない。指定された分解能以上の評価が行われないようにしちゃおう!
モーションの評価が決まった回数ならば、ボーンアニメーション程度の情報量
はキャッシュできるのでは?
あるモーションのある特定のフレームは、初回の評価の結果をキャッシュして、
一度だけしか評価されないように実装してみる。
UnityのJobスケジュールパフォーマンス
1msほどの処理が0.1msほどに
ボーンアニメ+スキニング
ペンギン1000体のパフォーマンス
計測環境:Ryzen 9 5950x / Radeon 6800XT / DX12 / IL2CPP DEBUG
・Burst All実装改善後      ・Burst実装(さっきの)
2.3ms 4.6ms
改善3 スキニングをキャッシュ
改善3 スキニングをキャッシュ
AnimationClipが固定の分解能を持てるなら、スキニングもキャッシュを持て
る。
1フレーム当たりの情報量は
16bit x 4 x 3 = 192bit (24byte)
頂点数1076の場合約25KB
…まあ対象や条件を限定するなら。
ボーンアニメ+スキニング
約1000頂点ペンギン1001体のパフォーマンス
・Burst All実装(改善3あり)     ・Burst実装(改善3なし)
2.3ms
2.0ms
計算0なのに思ったより早くなってないのね
スキニングの処理自体は1.8ms -> 1.1ms
帯域の方が問題か。コア数が少ないCPUなら有意な差が出るかも。(ちゃんと
調べていない)
Jobスケジュールの複雑度が上がったオーバーヘッドもある。(0.4ms増)
追記:ポインタをもっと駆使していればもうちょい何とかなった。
尚、今回は各Mesh Rendererの利用するMeshの頂点バッファが、毎回CPU
側の処理としてキャッシュから値を受け取っていて、それぞれがGPUへのアッ
プロードをしている。
単体のアニメーションを再生するだけにしては無駄な処理で、重い。
メッシュ共通化によるスキニングキャッシュ
今回は行わないが、キャッシュ戦略を使うなら、常時、全てのメッシュが固有の
頂点バッファを使う必要はあまりない。
Batch Renderer Group 2022を利用することで、メッシュをintのIDで指定する
描画発行が行える。特定のアニメーションのあるフレームをメッシュとして保存
し、それをIDによって指定することで最速のスキニングが可能。
(ただし、モーフやブレンディング等の処理が追加で行われることが頻繁なら、
この指針ではつど明示的なインスタンス化の解決が必要になるため、実装は複
雑になるかもしれない。)
いよいよ一万体で勝負
ボーンアニメ+スキニング
ペンギン10000体のパフォーマンス
・Burst実装     ・Animator+Unity CPU ・Animator+Unity GPU
ボーンアニメ+スキニング
ペンギン10000体のパフォーマンス
フレーム時間トータル
・Burst実装
約65ms
・Animator+Unity CPU
約140-160ms
・Animator+Unity GPU
約55-60ms
標準のGPU実装に負けてるやん!
どういうこと?
スキニング+アニメーションの時間だけならGPU実装より早い
UnityのGPUスキニング
Animator関連 35ms程度
Skinning関連 40ms程度
Burstアニメ+スキニング
Animator相当 3ms程度
Skinning関連 25ms程度
どういうこと?
GPUとの情報同期にやたらとオーバーヘッドがある
UnityのAPIの構造上、GPU上のバッファに一度頂点相当情報を転送してから
さらにGPU内でVertexBufferにコピーする必要があり、一度余計なコピーが
走っている。これによって11ms程度のロスが発生…
https://forum.unity.com/threads/feature-request-vertex-buffer-with-lockbufferforwrite-when-po
ssible.1294395/#post-8387988
回避できないオーバーヘッドは仕方がない
フルコントロールしてる恩恵を使う
間引きをやる
登場しているキャラが多い場面などで、遠距離のキャラクターや動きの少ない
キャラクターについてはより少ない頻度でスキニング更新する。割と古くからあ
る最適化方法。
本来Unityではスキニングを一時停止させることは出来ず、この方法をパ
フォーマンス改善で利用できない。独自実装ではスキニングを明示的にコント
ロールしているため可能。
間引きをやる 動画
動画に移動します
間引きをやる 動画
間引きをやる 動画
間引きをやる 動画
間引きをやる 動画
間引きをやる
今回は高度な条件を入れず、1フレームごとに全体の半分ずつを更新してい
る。29-30FPSを達成
今後の展望・まとめ
今後の展望
・残念なオーバーヘッド含め、頂点アップロードの時間が掛かりすぎている。
Batch Renderer Group(BRG)によるMeshIDの指定によるスキニング結果の
ルックアップ方式を、使える場面では使った方がよさそう。
余談だがBRGで沢山の異なるメッシュを使った時に、パフォーマンスが過剰に
低くなる特性を発見し、公式と連携してバグ提出した。BRGは2022で大幅にリ
ニューアルされたホットなAPIなので注視必須。
https://forum.unity.com/threads/new-batchrenderergroup-api-for-2022-1.1230669/
まとめ
・Burstの登場でアセットの低レベルな表現を割と高速かつ自由にCPU側で扱
えるようになっている。
  >CPUは最低物理8コアが常識な時代。酷使していこう。
・ゲームにあったソリューション(間引き等)は汎用ゲームエンジン時代に取りづ
らいようだが、今はBurstやコンピュートシェーダがあり、1から実装すればビル
トインより高品質なものが割と作れる。検討すべきときはする。

Weitere ähnliche Inhalte

Was ist angesagt?

Was ist angesagt? (20)

脱Unity!? UE4でVR開発のここが変わった
脱Unity!? UE4でVR開発のここが変わった脱Unity!? UE4でVR開発のここが変わった
脱Unity!? UE4でVR開発のここが変わった
 
MagicOnion入門
MagicOnion入門MagicOnion入門
MagicOnion入門
 
Unityネイティブプラグインマニアクス #denatechcon
Unityネイティブプラグインマニアクス #denatechconUnityネイティブプラグインマニアクス #denatechcon
Unityネイティブプラグインマニアクス #denatechcon
 
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
 
ゲームAI・実装事例の紹介
ゲームAI・実装事例の紹介ゲームAI・実装事例の紹介
ゲームAI・実装事例の紹介
 
新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編新入社員のための大規模ゲーム開発入門 サーバサイド編
新入社員のための大規模ゲーム開発入門 サーバサイド編
 
PlayStation®4向けARPGのUnity開発事例 最適化と効率化の秘密
PlayStation®4向けARPGのUnity開発事例 最適化と効率化の秘密PlayStation®4向けARPGのUnity開発事例 最適化と効率化の秘密
PlayStation®4向けARPGのUnity開発事例 最適化と効率化の秘密
 
Unityでオニオンアーキテクチャ
UnityでオニオンアーキテクチャUnityでオニオンアーキテクチャ
Unityでオニオンアーキテクチャ
 
【Unity道場 2月】シェーダを書けるプログラマになろう
【Unity道場 2月】シェーダを書けるプログラマになろう【Unity道場 2月】シェーダを書けるプログラマになろう
【Unity道場 2月】シェーダを書けるプログラマになろう
 
UE4におけるレベル制作事例
UE4におけるレベル制作事例  UE4におけるレベル制作事例
UE4におけるレベル制作事例
 
大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化
 
モバイルアプリにおけるアーティストフレンドリーな水面表現戦略
モバイルアプリにおけるアーティストフレンドリーな水面表現戦略モバイルアプリにおけるアーティストフレンドリーな水面表現戦略
モバイルアプリにおけるアーティストフレンドリーな水面表現戦略
 
メカアクションゲーム『DAEMON X MACHINA』 信念と血と鋼鉄の開発事例
メカアクションゲーム『DAEMON X MACHINA』 信念と血と鋼鉄の開発事例メカアクションゲーム『DAEMON X MACHINA』 信念と血と鋼鉄の開発事例
メカアクションゲーム『DAEMON X MACHINA』 信念と血と鋼鉄の開発事例
 
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
 
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
【Unite 2018 Tokyo】そろそろ楽がしたい!新アセットバンドルワークフロー&リソースマネージャー詳細解説
 
CEDEC 2020 - 高品質かつ低負荷な3Dライブを実現するシェーダー開発 ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スク...
CEDEC 2020 - 高品質かつ低負荷な3Dライブを実現するシェーダー開発 ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スク...CEDEC 2020 - 高品質かつ低負荷な3Dライブを実現するシェーダー開発 ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スク...
CEDEC 2020 - 高品質かつ低負荷な3Dライブを実現するシェーダー開発 ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スク...
 
Unityネットワーク通信の基盤である「RPC」について、意外と知られていないボトルネックと、その対策法
Unityネットワーク通信の基盤である「RPC」について、意外と知られていないボトルネックと、その対策法Unityネットワーク通信の基盤である「RPC」について、意外と知られていないボトルネックと、その対策法
Unityネットワーク通信の基盤である「RPC」について、意外と知られていないボトルネックと、その対策法
 
Addressables で大量のリソース管理・困りどころと解消法
Addressables で大量のリソース管理・困りどころと解消法Addressables で大量のリソース管理・困りどころと解消法
Addressables で大量のリソース管理・困りどころと解消法
 
バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~
バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~
バイキング流UE4活用術 ~BPとお別れするまでの18ヶ月~
 
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
【Unity道場スペシャル 2017札幌】最適化をする前に覚えておきたい技術 -札幌編-
 

Mehr von infinite_loop

Mehr von infinite_loop (20)

ChatGPT触ってみた
ChatGPT触ってみたChatGPT触ってみた
ChatGPT触ってみた
 
社内ソフトスキルを考える
社内ソフトスキルを考える社内ソフトスキルを考える
社内ソフトスキルを考える
 
3Dプリンタって いいね
3Dプリンタって いいね3Dプリンタって いいね
3Dプリンタって いいね
 
VRChatでお酒が注げる飲み物アセットの紹介
VRChatでお酒が注げる飲み物アセットの紹介VRChatでお酒が注げる飲み物アセットの紹介
VRChatでお酒が注げる飲み物アセットの紹介
 
I ❤ Virtual Machines 仮想環境をより便利に使うツールたち
I ❤ Virtual Machines 仮想環境をより便利に使うツールたちI ❤ Virtual Machines 仮想環境をより便利に使うツールたち
I ❤ Virtual Machines 仮想環境をより便利に使うツールたち
 
500万行のPHPプロジェクトにおけるログ出力の歩み
500万行のPHPプロジェクトにおけるログ出力の歩み500万行のPHPプロジェクトにおけるログ出力の歩み
500万行のPHPプロジェクトにおけるログ出力の歩み
 
ADRという考えを取り入れてみて
ADRという考えを取り入れてみてADRという考えを取り入れてみて
ADRという考えを取り入れてみて
 
リファクタリングで実装が○○分短縮した話
リファクタリングで実装が○○分短縮した話リファクタリングで実装が○○分短縮した話
リファクタリングで実装が○○分短縮した話
 
ゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せますゲームのインフラをAwsで実戦tips全て見せます
ゲームのインフラをAwsで実戦tips全て見せます
 
楽しいVR空間を作る技術と支える技術 #osc19do
楽しいVR空間を作る技術と支える技術 #osc19do楽しいVR空間を作る技術と支える技術 #osc19do
楽しいVR空間を作る技術と支える技術 #osc19do
 
Start rl with_unity_machine_learning_agents
Start rl with_unity_machine_learning_agentsStart rl with_unity_machine_learning_agents
Start rl with_unity_machine_learning_agents
 
UniRx の1歩目
UniRx の1歩目UniRx の1歩目
UniRx の1歩目
 
がんばれ PHP Fiber
がんばれ PHP Fiberがんばれ PHP Fiber
がんばれ PHP Fiber
 
心に残った名前ランキング
心に残った名前ランキング心に残った名前ランキング
心に残った名前ランキング
 
プログラムと名前にまつわる座談会
プログラムと名前にまつわる座談会プログラムと名前にまつわる座談会
プログラムと名前にまつわる座談会
 
名は体を表していますか
名は体を表していますか名は体を表していますか
名は体を表していますか
 
名前の力
名前の力名前の力
名前の力
 
大切な名前[Intro]公開版
大切な名前[Intro]公開版大切な名前[Intro]公開版
大切な名前[Intro]公開版
 
JupyterNotebookとMySQLでゼロからはじめるデータサイエンス
JupyterNotebookとMySQLでゼロからはじめるデータサイエンスJupyterNotebookとMySQLでゼロからはじめるデータサイエンス
JupyterNotebookとMySQLでゼロからはじめるデータサイエンス
 
複数拠点における開発効率の維持・向上
複数拠点における開発効率の維持・向上複数拠点における開発効率の維持・向上
複数拠点における開発効率の維持・向上
 

アニメーションとスキニングをBurstで独自実装する.pdf