ほげたつブログ

プログラムとアニメーションをかじって生きてる

アニメーション圧縮検証(UE4.20/4.21)

こちらは「Unreal Engine 4 (UE4) Advent Calendar 2018」5日目の記事です。✌︎('ω'✌︎ )

Unreal Engine 4 (UE4) Advent Calendar 2018 - Qiita


UE4におけるアニメーション圧縮機能について

何ができるのか、どういったメリット/デメリットが存在するのか、どうやって使うのか等は次のスライドが参考になります。アニメーション圧縮についての言及は 40 ~ 47 ページにあります。

www.slideshare.net


UE4 では FBX 等からアニメーションをインポートする際、内部的には全てのフレームにキーをベイクして中間データ(uasset)を作成しています。ただしそれではランタイムで扱うアセットサイズが大きくなってしまうため、ベイクされたキーをエディタもしくはコマンドレットから圧縮し、サンプリングする際に圧縮解除するという方式を取っています。

パッケージでは Cook 時にリダクションしますが、エディタ上で uasset を利用する場合は圧縮に関するデータは DDC に格納されるため、DDC を共有しておけば作業マシン毎に圧縮を行う必要もありません。

Unreal Engine | 派生データのキャッシュ


圧縮設定

圧縮設定には次の種類があります。

Bitwise Compress Only

Bitwise Compress Only はプロジェクト側で何も変更していない時に使用されるデフォルト設定です。こちらの圧縮設定では一部の例外を除いてアニメーションのキーを削除する事はありませんが、キーの圧縮フォーマットを変えることでリダクションを行います。利用可能な圧縮フォーマットについては後述します。

一部の例外と書きましたが、この例外には Trival Keys が含まれます。Trival Keys とは複数のキーによる動きが一定であり、削除しても影響が無いキーのことを指します。ちなみに Bitwise Compress と Trival Keys の削除は全ての圧縮設定で行われます。

Least Destructive

公式ドキュメントには「アニメーションを生データに復元し、アニメーション圧縮を元に戻します。」との記載があるのですが、厳密には最低限の圧縮を行う Bitwise Compress Only の圧縮フォーマット固定版です。Trival Keys の削除も行うため完全な非圧縮データとはならないのですが、あくまで見た目に影響しない圧縮のみを行うので、利用する際には非圧縮として扱っても問題は起きないと思います。

Remove Trivial Keys

その名の通り Trival Keys を削除します。ただし前述の通り Bitwise Compress も行うので、実際の動作は Bitwise Compress Only と同じです。コードを読んでみると Trival Keys の削除時に移動/回転/スケールそれぞれに削除時の閾値を設定できるようになっているのですが、実際にはユーザーが設定した閾値が使われず Bitwise Compress Only と同じ閾値を使っているため、全ての挙動が Bitwise Compress Only と同様になっているように見えます。(UE4.21 の場合、AnimCompress_RemoveTrivalKeys.cpp : 31 でプロパティに設定した閾値が使われるようになれば意図した挙動になりそうなのでバグっぽい感じはします)

Remove Every Second Key

アニメーションのキーを一つ飛ばしで削除します。ただし Trival Keys の削除後にアニメーションのキーを間引くため、アルゴリズムとしては単純ですが、使用時は元のアニメーションを維持できているのかどうかの確認が必要です。

Remove Linear Keys

End Effector(末端ボーン)の移動/回転/スケールが設定された閾値を超えないように、周囲のキーの線形補間となっているキーを削除するアルゴリズムです。End Effector の閾値チェックを行うため、上記アルゴリズムと比較して圧縮時間は増加します。また関連コード全てに目を通してはいないのですが、圧縮解除時もサンプリング毎にトラック内でキーの検索が入るとのことなので、ランタイムで処理するコストも上記アルゴリズムと比較して高くなります。

Per Track Compression

Remove Linear Keys の拡張版で、線形補間となっているキーの削除に加え、トラック単位でキーの圧縮フォーマットを変更します。圧縮時は Remove Linear Keys と同様に End Effector の閾値チェックを行いながら候補の中から圧縮フォーマットを決定します。このため圧縮時間は Remove Linear Keys と比較して増加しますが、圧縮解除時にサンプリング毎にかかる検索コストは Remove Linear Keys と同じだと思われます。

Automatic

細かい設定はさておき、片っ端から圧縮アルゴリズムとパラメータを変えて圧縮してみて一番良い結果を使うという力技です。設定も楽で結果も良いのですが、圧縮時間が他の圧縮設定に比べて非常に長くなります。コマンドレットから圧縮する際には Project Settings の設定を元に Automatic で圧縮されます。

圧縮設定比較

目安程度ですが、大雑把な比較です。

種類 圧縮率 圧縮時間の短さ 圧縮解除時間の短さ 調整項目の少なさ
Bitwise Compress Only ★★ ★★★★★ ★★★★★ ★★★★★
Least Destructive ★★★★★ ★★★★★ ★★★★★
Remove Trivial Keys ★★ ★★★★★ ★★★★★ ★★★★★
Remove Every Second Key ★★★ ★★★★ ★★★★ ★★★★★
Remove Linear Keys ★★★★ ★★★ ★★ ★★
Per Track Compression ★★★★★ ★★ ★★
Automatic ★★★★★ ★★ ★★★★

 

キーの圧縮フォーマット

アニメーションのキーは三つのアトリビュート(移動/回転/スケール)で構成され、移動は XYZ の 96 bit 、回転は XYZW の 128 bit 、スケールは XYZ の 96 bit で表せます。Bitwise Compress ではこれらの bit 数を削減することでリダクションしています。キーの圧縮フォーマットには次の種類があります。

None

非圧縮フォーマットで、移動/回転/スケールをそのままの bit 数で扱います。サイズは大きくなりますが、アニメーションが破綻する心配はありません。

Float 96 No W

アトリビュートを 96 bit で保存します。移動/スケールは元から 96 bit なので None と変わりませんが、回転は W 成分を除いた XYZ の 96 bit で保存されます。W 成分は bit 削減どころか保存すらしませんが、回転は正規化されたクォータニオンで扱われるため、XYZ 成分があれば次の式で計算することが可能です。W 成分が負の時は圧縮時に逆回転に変換します。

{ \displaystyle
W = \sqrt{1.0 - X^2 - Y^2 - Z^2}
}


ちなみに非圧縮設定の Least Destructive ですが、Bitwise Compress 時に移動/スケールは圧縮フォーマット None で扱っていますが、W 成分が安全に復元できるということもあり、回転については Float 96 No W で扱っているようです。また、プロジェクト新規作成時に圧縮設定がデフォルトで Bitwise Compress Only となっていますが、キーの圧縮フォーマットは移動/スケールが None 、回転が Float 96 No W となっているので、実際は非圧縮設定の Least Destructive と同じ動作となります。

Fixed 48 No W

回転を W 成分を除いた半精度の 48 bit で保存します。この圧縮フォーマットは移動/スケールをサポートしません。

Interval Fixed 32 No W

アトリビュートの値の範囲を減らして 11 + 11 + 10 の合計 32 bit で保存します。回転の W 成分は除かれます。

Fixed 32 No W

回転を W 成分を除いた 11 + 11 + 10 の合計 32 bit で保存します。この圧縮フォーマットは移動/スケールをサポートしません。

ちなみにこちらは PerTrackCompression で使用される DecompressSingleTrackRotationVectorized 関数内で次のようなコメントがあるのですが非推奨ですかね…?

This isn't used for compression anymore so making it fast isn't very important
これはもう圧縮には使用されないので、速くする事は重要ではない。

 

Float 32 No W

回転を W 成分を除いた 11 + 11 + 10 の合計 32 bit で保存します。指数部を 3 bit で扱うカスタムフォーマットのようです。この圧縮フォーマットは移動/スケールをサポートしません。

こちらも Fixed 32 No W と同様に非推奨を思わせるコメントが DecompressSingleTrackRotationVectorized 関数内にあります。

Identity

何も保存せず、移動/スケールなら FVector::ZeroVector を、回転なら FQuat::Identity を利用する圧縮フォーマットです。(個人的にはスケールなら OneVector を利用した方が使い勝手が良い気もしますが、そもそもキーが設定されていない場合でも Trival Keys の削減により単一のキーしか保存されない事もあり影響が小さいので、そもそもの用途が少ないのかもしれません)


圧縮フォーマット比較

種類 移動 (bit) 回転 (bit) スケール (bit) 注釈
None 96 128 96
Float 96 No W 96 96 96
Fixed 48 No W - 48 - 回転のみ
Interval Fixed 32 No W 32 32 32
Fixed 32 No W - 32 - 回転のみ / 非推奨?
Float 32 No W - 32 - 回転のみ / 非推奨?
Identity 0 0 0

 

圧縮時間検証

UE 4.21 にてアニメーション圧縮にかかる時間が大幅に短縮し、特にマルチコア環境では並列実行されるようになったとのことです。

New: Animation System Optimizations and Improvements
Animation Compression times are significantly reduced by using a whitelist of optimal codecs to avoid trying permutations that are unlikely to be selected which greatly reduces the number of codecs we attempt to compress with. On multicore systems, most of the codecs now evaluate in parallel during automatic compression, further reducing the time it takes to compress an animation sequence.

Unreal Engine 4.21 Release Notes

圧縮時間の検証として、いくつかのアニメーションに対して CompressAnimationsCommandlet を実行し、UE 4.20 と UE 4.21 の比較をしたいと思います。

検証環境

OS Windows 10 Pro
CPU AMD Ryzen 7 1700 Eight-Core Processor 3.00 GHz
アニメーション 2 ~ 20 秒 × 10 アセット

 

検証手順

  1. ランチャーから UE4 をインストール
  2. 検証対象のアニメーションと、それに紐づくアセットをインポート
  3. エディタ上でシェーダーコンパイル終了を待つ
  4. CompressAnimationsCommandlet を実行(一回実行してDDCに乗せる)
  5. DefaultEngine.ini で CompressCommandletVersion を変更
  6. CompressAnimationsCommandlet を実行
  7. コマンドレット実行時間(Execution of commandlet took: ~)を確認

 

検証結果

バージョン 圧縮時間 (sec)
UE 4.20.3 114.34
UE 4.21.0 25.31


UE 4.21 で大きく圧縮時間を短縮できていることが確認できました。Commandlet なので Jenkins 等でジョブにできるとはいえ、アセット数が多い時の恩恵は大きいと思います。


ちなみに圧縮時間は大幅に短縮できましたが、圧縮率については UE 4.20 と UE 4.21 では差が無いようです。

f:id:hogetatu:20181204234621p:plain

Automatic の設定はデフォルトのままで大体 10 % 程度には落ち着いているようですね。ちなみに Commandlet を実行せずデフォルト設定の Bitwise Compress Only のままの場合、圧縮率は大体 15 ~ 30 % くらいなので、基本的には Commandlet で圧縮しつつ問題が出るアセットがあれば個別に圧縮設定を変更し、Do Not Override Compression プロパティを ON にするという運用が良さそうです。

終わりに

本当は Paragon アセットで効果測定を行っていた Animation Compression Library (ACL) の検証までやりたかったのですが、時間切れなので今回はここまでにします。

GitHub - nfrechette/acl: Animation Compression Library


明日(6日目)は prince_ue4 さんによるエフェクト記事です。正座して待ちましょう。