ぼっちプログラマのメモ

UE4とかUE5とかについて書いたり書かなかったり。

UE4の物理アセット・クロスの荒ぶりを何とかする方法について (UE4.21版)

はじめに

この記事はUnreal Engine 4 その2 Advent Calendar 2018の20日目の記事です。
qiita.com

何を書こうか色々悩んだのですが、今年も物理と仲良くする(意味深)方法について書こうと思います。なお、去年の記事は以下の通り。(え、もうアレから一年経ったの!?)

UE4.18で生まれ変わった物理アセットエディタ(Physics Asset Editor)について」 と 「物理と少し仲良くなる方法について」
その1:http://pafuhana1213.hatenablog.com/entry/2017/12/13/000000
その2:http://pafuhana1213.hatenablog.com/entry/2017/12/13/000100
その3:http://pafuhana1213.hatenablog.com/entry/2017/12/13/003018

f:id:pafuhana1213:20181220151928g:plain

実験に付き合ってもらうのはいつものこの方々。左のOwenくんはクロス担当、右のグレイマンは物理アセット担当です。

なお、今回は物理アセット・クロスの設定を極力変えずに既存の機能で何とかすることを目標とします。何故なら去年の内容と被りますし、作業コスト高いですし、職人芸になりがちですし、、説明が大変だからです!(ドン!

物理の荒ぶりに対して、我々はどう立ち向かえばいいのか?

基本方針は以下の3つです!

  • 荒ぶりの原因になる挙動を無視させる
  • 物理をリセットして荒ぶりを消す
  • 荒ぶり前に物理を停止し、その後再開する

これらの対応を入れることで、(色々と許容しないといけない場合あったりしますが)、だいたいの物理の荒ぶりを回避できます。

具体的にどうすればいいのか、これから順に説明します。

荒ぶりの原因になる挙動を無視する方法

物理アセットの場合

まず…AnimGraphのRigid Bodyノードを使いましょう!物理アセットを直接使うのではなくRigidBodyノードを通ることで、処理負荷だけでなく物理挙動の安定化する上でも色々メリットがあります!
api.unrealengine.com

Rigid Bodyノードを仕様・表現的に使えないケースもあるかとは思いますが…今回は物理を抑えることが重要なので、以降の説明ではRigid Bodyノードを使っていることを前提にします。ご了承下さい…

Actorの位置が変化する場合

Actorの位置が大きく変更することで物理が荒ぶる場合は、RigidBodyノードのSimulation Space を Component Space にすることをおすすめします。この設定にすることで、物理アセットに関する処理が Skeletal Mesh Componentのローカル座標系で行われます。そのため、Skeletal Mesh Componentのワールド座標が変化しても物理挙動に影響しません。
f:id:pafuhana1213:20181220152259p:plain

ちなみに、Anim Dynamicsノードでも似たような設定が可能です。
f:id:pafuhana1213:20181220152155p:plain

ただ注意点としては、逆にActorの移動量を物理に反映したい場合はSkeletal Mesh Componentのワールド座標で物理の計算をして貰う必要があります。そのため、RigidBodyノードのSimulation SpaceをWorld Spaceにする必要があります。もしComponent Space にしておきたいけど、Actorの移動を物理に反映させたい場合は…Rigid BodyのExternal Forceを使ってそれっぽく外力をかける必要があるかと思います。
f:id:pafuhana1213:20181220152454p:plain:w300


RigidBodyノードのSimulation Space以外にも、Set Actor(World) Location / Rotation / Transform のTeleportフラグを有効にするという解決方法もあります。このフラグを有効にすることで、このSet Actor Locationノードによる位置(向き)の変化を物理が無視するようになります。そのため、Simulation SpaceをWorld Spaceに設定している場合はこのフラグが非常に有用です。
f:id:pafuhana1213:20181220152649p:plain

また、Reset Dynamicsノードを使って、明示的にそのフレームでの移動はTeleportとみなすこともできます。なお、Reset Dynamicsは物理アセット専用なのでクロスに対しては使えません
f:id:pafuhana1213:20181220152708p:plain

アニメーションによってRoot Boneの位置を変化させる場合

カットシーン用のアニメーションなどの場合、Root Boneを移動・ワープさせたりすることがしばしばあるかと思います。この場合は先程の Simulation Spaceを Component Spaceにしても荒ぶりを回避できません。何故なら、アニメーションによるBoneの移動は Skeletal Mesh Componentのローカル座標系で行われるからです。

更に、先ほど説明したTeleportフラグではこの問題を解決することはできません。例えば、Skeletal Mesh Componentに対して現ワールド座標と同じ座標をSet World Location(Teleportフラグ付き)で設定する処理をTickでしてみました。
f:id:pafuhana1213:20181220152909p:plain
こうなります
f:id:pafuhana1213:20181220152919p:plain
つらい


…正直な所、今回説明する中でこれが一番対応が面倒です。とはいえ、対策は…幾つかあります。

まずは後述する「荒ぶり前の状態に保存した後に物理を止める」方法です。リアルタイムに物理計算を行う場合、現時点ではこれが最も挙動が安定します。ただし問題が発生する場面毎に対応を入れる必要があるため、場合によっては対応コストがネックになる可能性があります。

次に同じく後述の「物理をリセットして荒ぶりを消す」も荒ぶりを抑えるという観点では有用です。ただし、リセットされるため動きの連続性がなくなるため、見た目に違和感が生じるケースが多いかと思います。

物理アセットの調整で荒ぶりを抑えることで解決する場合もあります。特に昨年の記事で紹介した「Inertia Tensor Scale」は効果的に働くはずです。とはいえ、どんな条件でも完全に荒ぶりを抑えられる訳ではないのでケースバイケースといった所です。
pafuhana1213.hatenablog.com

「どうしても荒ぶりを解決できない!でも荒ぶりは絶対回避しないといけない!」というケース、あると思います。そういった場合はUE4シーケンスレコーダーを使って物理挙動をベイクした方が幸せになれるかもしれません。
unrealengine.hatenablog.com

ただ「いや、リアルタイムで物理計算をしないといけないんだ!」というケース、あると思います…。その場合はアニメーションによってRoot Boneの位置を変更するフローを見直した方が幸せになれるかもしれません…

クロスの場合

Skeletal Mesh Component の Teleport Distance (Rotation) Threshold を 調整しましょう!ここで設定した値以上の移動(回転)が1フレームで行われた場合、クロスはTeleportしたと判断して無視するようになります。
f:id:pafuhana1213:20181220153152p:plain

なお、その上にある Reset After Teleportを有効にすると、さらにクロスのリセット処理が行われるようになります。しかし、リセット処理が働くことで見た目に違和感が発生する場合があります。
f:id:pafuhana1213:20181220153223p:plain
左がReset After Teleportを有効にした場合、右は無効にした場合です。リセット処理がかかるとクロスが働く前の状態に戻るため、左の画像では布の部分がピーンと伸びた状態になってしまっています。一方、右は動きを無視しただけでクロスは継続して働いているため、違和感の無い見た目になっています。

ただ常に無効にするのが正しいというわけではありません。例えば、ワープ前後でポーズが異なるようなケースの場合、リセットした方がクロスの挙動が安定するケースもあります。実際に試してみて、どちらが安定するか?挙動に違和感がないか?を確認することをおすすめします。

なお、これらのパラメータは物理アセットとは一切関係がありません。あくまで、クロス用のパラメータです。少しややこしいのでご注意下さい。


ちなみに、少し前に説明したSet Actor Location / Rotation / Transform のTeleportフラグ は クロスに対しても有効です。更に、クロスの場合は、Force Cloth Next Update Teleportノードを使うことで、明示的にTeleportしたと判断させることも可能です。
f:id:pafuhana1213:20181220153332p:plain

また、「アニメーションによってRoot Boneの位置を変化させる場合」に関しては、物理アセットのときはかなり辛い条件でしたが、クロスの場合は先程説明したTeleportに関するパラメータ・関数、全て有効なので対応が楽です!


物理・クロスの設定を調整したり、Teleportフラグを駆使することで物理の荒ぶりの大半は回避できるかと思います。しかし、あくまで物理なので、フレームレートの急激な低下などの悪条件が重なってくると荒ぶりやすくなってしまいます。とはいえ、ユーザに物理が破綻している様子が見えてしまうのは絶対に回避したい所です。

そこで候補に上がってくるのが、「物理・クロスのリセット」「物理・クロスの一時停止・再開」です。まずは前者について説明します。

物理をリセットして荒ぶりを消す方法

「荒ぶりがユーザに見えないように、物理適用前の状態にリセットしちゃおう!」という方法です。基本的にリセット用の処理を呼び出すだけなので、対応自体は簡単です。しかし、先程のReset After Teleportで説明した通り、場合によっては見た目に違和感が発生する場合があります。とはいえ、物理が荒ぶった際の見た目よりは断然マシなので導入の検討はすべきかと思います。

物理アセットの場合

Reset Dynamicsノードを使うことをおすすめします!先程はIn Teleport TypeをTeleport Physicsにしていましたが、今回はリセットなのでReset Physicsに設定します。このノードをどうしても物理が荒ぶってしまうタイミングに呼べば、最悪の事態は回避する事が可能です。
f:id:pafuhana1213:20181220153645p:plain

また、UE4.21からはReset Dynamicsを呼び出すAnim Notifyが追加されています。移動を伴うアニメーションの場合は、その移動タイミングにこのAnim Notifyを仕込んでおけばリセット処理が働くようになります。
f:id:pafuhana1213:20181220153827p:plain
Animation Notifications (Notifies)

ちなみに、このAnim Notifyの内部処理では Reset Physicsが指定されたReset Dynamics関数が呼ばれています。そのため、Teleport Physicsを指定したReset DynamicsをAnim Notifyで使用したい場合は、そのAnim Notifyを独自に用意する必要があります。

クロスの場合

まずは、Skeletal Mesh ComponentのReset After Teleport フラグを活用する方法があります。これに関しては既に説明済みなので割愛します。
次に、Force Cloth Next Update Teleport and Resetノードを呼び出す方法があります。察してる方も多いかと思いますが、Reset After Teleport が有効な状態で Teleport Distance (Rotation) Threshold 以上の移動・回転が生じた際のリセット処理を明示的に行うことができます。
f:id:pafuhana1213:20181220153936p:plain

ちなみに、このForce Cloth Next Update Teleport and Resetを呼び出すAnimNotifyもUE4.21で追加されています。便利!
f:id:pafuhana1213:20181220153953p:plain

荒ぶり前に物理を停止し、その後再開する方法

「物理の荒ぶりは回避したいけど、リセットするのは見た目的にいや! 物理処理は継続的に行いたい!」と思う方は多いかと思います。そんな方向けの方法がこの「物理を停止・再開」する方法です。

結局の所、荒ぶりが起きやすい状態で物理が有効になっているのが今回の問題の原因です。つまり、その状態の間だけ物理を切れば荒ぶりが発生することはなくなります。しかし、単純に物理を切ってしまうとリセット処理が走ってしまいます。それなら、物理を切るだけでなく、対象のメッシュ・アニメーションも一時停止しておいて、その後どちらも再開すれば荒ぶり回避できるし物理処理が継続して見えるじゃん!というのがこの方法です。

物理アセットの場合

物理を切ることは簡単です。Simulate PhysicsをOFFにしたり、RigidBodyノードのAlphaを0にしたりするだけです。問題は、物理を切る前の状態を保存することです。

結局の所、物理アセットは各ボーンを制御しているため、「アニメーションと物理が適用された状態のスケルトンの状態」を保存する必要があります。そこで便利というか、まさにその機能なのが Animation Pose Snapshotです。
f:id:pafuhana1213:20181220154317g:plain

使い方に関しては公式ドキュメントや動画にて解説されているので割愛します。
api.unrealengine.com
Unreal Japan Stream | ポーズスナップショットでラグドール回避アニメーション - YouTube

少し前に触れた通り、荒ぶりの原因となる物理を切っているので、リアルタイムに物理計算行う方法の中ではこれが最も挙動が安定します。ただし、Animation Pose Shapshotを使うための仕込みが必要なため、他の方法に比べて実装コストは少し高めです。

クロスの場合

クロスの場合は一時停止・再開用の機能が用意されています。一時停止はSuspend Clothing Simulation、再開はResume Clothing Simulationです。ちなみに、UE4.21でこれらをAnim Notifyから使うことも可能になりました!
f:id:pafuhana1213:20181220154424p:plain
f:id:pafuhana1213:20181220154434p:plain

その他

最後に、今回の内容と関連するパラメータやTipsについて少し紹介

Cloth Blend Weight

Skeletal Mesh Componentには、アニメーション結果とクロス処理の結果をどの程度ブレンドするかを制御するためのパラメータであるCloth Blend Weightが用意されています。このパラメータを調整することで、「見栄え的にクロスでひらひらさせたいけど、スカートの中が絶対に見えないようにボーンによる制御も同時に行いたい」といったケースに有用です。ただ、個人的にはパン(以下略

また、説明のため簡略化してますが、アニメーションにCloth Blend Weightを制御するためのカーブを埋め込んでおけば、アニメーション毎にクロスのブレンド率を調整することが可能です。
f:id:pafuhana1213:20181220154638p:plain
f:id:pafuhana1213:20181220154648p:plain

Sequencerで扱える物理・クロスに関するパラメータ

Sequencer上でSkeletal Mesh Componentなどの各コンポーネントが持つ各パラメータを制御することができます。そのため、物理・クロスに関する挙動をSequencer上で制御することは十分に可能です。
f:id:pafuhana1213:20181220154603p:plain

更に、Event Trackでリセット・テレポート用のノードを呼び出すことも可能です。更に更にUE4.20からAnimationBlueprintが持つプロパティも制御可能になったので、RigidBodyノードやPose Snapshot絡みの挙動もSequencer上で調整することが可能です!
www.unrealengine.com

SequencerのCamera Cut切り替えタイミングの取得

カメラカットの切り替わり時に、キャラクタの位置・向きを変えたいケースが多いかと思います。しかし、それは1フレームで急激に動かすことになるので、物理・クロスが荒ぶりがちです。そこで、カメラカット切り替えタイミングにTeleportやリセット処理を呼びたくなるはずです。

そんな方にご紹介したいのが、Sequence PlayerのOnCameraCutイベントです。このイベントはその名の通りカット切り替わり時に呼ばれるため、以下のようにして処理を紐付けることが可能です。ぜひぜひご活用くださいまし。
f:id:pafuhana1213:20181220154919p:plain

最後に

f:id:pafuhana1213:20181220155131j:plain
長くなりましたが、物理・クロスの荒ぶり対策について色々ご紹介しました。これらの方法を使用・併用することで、様々なパターンにおける荒ぶりを回避することができるかと…思い…ます…

ただ、繰り返しになりますが、あくまで物理なので今回紹介した方法でも抑え込めないケースもあるかと思います。その場合は、まず何が荒ぶりの原因になっているかを確認した後に、物理アセット・クロスの調整をしてみたり、そもそも荒ぶりやすい条件にならないよう仕様・設計を変えるなど検討したり、物理挙動をベイクしたりなどの方法を検討する必要があるかと思います。場合によっては、ある程度の割り切りも必要かもしれません…

ネガティブなことばかり並べましたが、物理・クロスを適用することで見栄えがリッチになるのは間違いありません。昨年と今年の記事が少しでも物理と仲良くする助けになれば幸いです。

明日は 紙パレット ( @kamipallet )さんによる 「ジラフとアンニカ」のジャンプアニメーションの解説 です!ジャンプアニメーション、いつも調整に苦労してるので凄く楽しみです!!!