SlideShare a Scribd company logo
【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から実装すればビル
トインより高品質なものが割と作れる。検討すべきときはする。

More Related Content

PPTX
猫でも分かる UE4のAnimation Blueprintの運用について
PDF
60fpsアクションを実現する秘訣を伝授 解析編
PPTX
ガルガンチュア on Oculus Quest - 72FPSへの挑戦 -
PDF
UE4のモバイル向け機能や最新情報などを改めて紹介!2019
PDF
猫でも分かるUE4のポストプロセスを使った演出・絵作り
PPTX
UE4におけるLoadingとGCのProfilingと最適化手法
PPTX
[CEDEC2018] UE4アニメーションシステム総おさらい
PDF
Nintendo Switch『OCTOPATH TRAVELER』はこうして作られた
猫でも分かる UE4のAnimation Blueprintの運用について
60fpsアクションを実現する秘訣を伝授 解析編
ガルガンチュア on Oculus Quest - 72FPSへの挑戦 -
UE4のモバイル向け機能や最新情報などを改めて紹介!2019
猫でも分かるUE4のポストプロセスを使った演出・絵作り
UE4におけるLoadingとGCのProfilingと最適化手法
[CEDEC2018] UE4アニメーションシステム総おさらい
Nintendo Switch『OCTOPATH TRAVELER』はこうして作られた

What's hot (20)

PDF
CEDEC 2020 - 高品質かつ低負荷な3Dライブを実現するシェーダー開発 ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スク...
PDF
シェーダーを活用した3Dライブ演出のアップデート ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スクスタ)の開発事例~​
PPTX
UE4のためのより良いゲーム設計を理解しよう!
PDF
【Unity道場 2月】シェーダを書けるプログラマになろう
PDF
Unreal Engine 5 早期アクセスの注目機能総おさらい Part 2
PDF
【Unite Tokyo 2019】SRPで一から描画フローを作ってみた! ~Unity描画フローからの脱却~
PDF
UE4プログラマー勉強会 in 大阪 -エンジンの内部挙動について
PPTX
【CEDEC2018】Scriptable Render Pipelineを使ってみよう
PDF
CEDEC2016: Unreal Engine 4 のレンダリングフロー総おさらい
PDF
猫でも分かる UE4の新しいサンプル「Action RPG」について
PDF
Unityアニメーションシステムの 今と未来の話
PPTX
なぜなにリアルタイムレンダリング
PDF
UE4.14.0 Forward Shadingのエンジン改造でセルシェードやってみた
DOCX
UE4でPerforceと連携するための手順
PDF
UE4におけるアニメーション制作事例
PDF
【UE4.25 新機能】ロードの高速化機能「IOStore」について
PDF
UE4のマテリアルを もっと楽しもう!~マテリアルでぐっと広がるリアルタイムCG表現の幅~
PPTX
Lightmassの仕組み ~Precomputed Light Volume編~ (Epic Games Japan: 篠山範明)
PPTX
[CEDEC2018] UE4で多数のキャラクターを生かすためのテクニック
CEDEC 2020 - 高品質かつ低負荷な3Dライブを実現するシェーダー開発 ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スク...
シェーダーを活用した3Dライブ演出のアップデート ~『ラブライブ!スクールアイドルフェスティバル ALL STARS』(スクスタ)の開発事例~​
UE4のためのより良いゲーム設計を理解しよう!
【Unity道場 2月】シェーダを書けるプログラマになろう
Unreal Engine 5 早期アクセスの注目機能総おさらい Part 2
【Unite Tokyo 2019】SRPで一から描画フローを作ってみた! ~Unity描画フローからの脱却~
UE4プログラマー勉強会 in 大阪 -エンジンの内部挙動について
【CEDEC2018】Scriptable Render Pipelineを使ってみよう
CEDEC2016: Unreal Engine 4 のレンダリングフロー総おさらい
猫でも分かる UE4の新しいサンプル「Action RPG」について
Unityアニメーションシステムの 今と未来の話
なぜなにリアルタイムレンダリング
UE4.14.0 Forward Shadingのエンジン改造でセルシェードやってみた
UE4でPerforceと連携するための手順
UE4におけるアニメーション制作事例
【UE4.25 新機能】ロードの高速化機能「IOStore」について
UE4のマテリアルを もっと楽しもう!~マテリアルでぐっと広がるリアルタイムCG表現の幅~
Lightmassの仕組み ~Precomputed Light Volume編~ (Epic Games Japan: 篠山範明)
[CEDEC2018] UE4で多数のキャラクターを生かすためのテクニック
Ad

More from infinite_loop (20)

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

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