PostEvaluateAnimationがコールされるタイミングに関する質問

私が記憶する限りPostEvaluateAnimationはその名前の通り、アニメーション適用後にコールされるイベントであり、以前は再現方法の手順でモーション適用前の骨の位置と適用後の位置を比較できたと思います。

しかし現在(5.5.1 5.5.4)ではPostEvaluateAnimationがコールされるタイミングにおいてもアニメーションが適用される前の骨の情報が取得されます。

恐らく、以前はUSkeletalMeshComponent::PostAnimEvaluationでUSkeletalMeshComponent::FinalizeAnimationUpdateが呼ばれた後にUSkeletalMeshComponent::DoInstancePostEvaluationが呼ばれていたのではないかと推測しています。

ここで表題の質問となるのですが、PostEvaluateAnimationイベントではアニメーション適用後の骨の位置が取得できることが保証されておりますでしょうか?

つまり、この現象は不具合であるのか、修正される予定があるかを知りたいです。

再現手順

  1. ThirdPersonTemplateからプロジェクトを作成します。
  2. アニメーションブループリントを作成し、BP_ThirdPersonCharacterのメッシュに設定します。
    1. アニメーショングラフで任意のアニメーションシーケンス(MM_Run_Fwdなど)をループ再生するようにします。
    2. アニメーションブループリントのUpdateAnimationでGetSocketLocationを使用して取得した、アニメーションによって動作する骨(hand_rなど)の位置をDrawDebugSphereなどを使用して表示します。
    3. 同様に、PostEvaluateAnimationで同じ骨の位置を表示します。
  3. それぞれ2-b、2-cで表示した骨の位置が完全に一致することを確認します。

Hi, in answer to your specific question:

> This leads to the question in the title: is it guaranteed that the PostEvaluateAnimation event can obtain the positions of bones after animation is applied?

No, if you call GetSocketLocation from PostEvaluateAnimation you will get the bone transform from the previous frame. The reason for this is that PostEvaluateAnimation is called via USkeletalMesh::DoInstancePostEvaluation. And that method is called prior to FinalizeAnimationUpdate, which is where the double-buffered transforms on the mesh are flipped. If you call GetSocketLocation before FinalizeAnimationUpdate has been called, you will index into the previous frame’s transform buffer on the mesh (ie. ComponentSpaceTransformsArray[CurrentReadComponentTransforms]).

If you want to add code or blueprint that is guaranteed to run after the transforms on the mesh have been updated, the best approach is likely to add a tick prerequisite on the mesh. This will guarantee that the mesh has been updated for the current frame, and so the double-buffered transforms have been flipped so that GetSocketLocation returns the expected data.

Let me know if this works for you.

Thanks for the extra information, it’s useful to get more context on issues like these. It could be that some of the ordering of the code has changed since 4.26, although it does look like PostEvaluateAnimation has been in the current place in the code for quite some time. But it sounds like having a tick dependency on the mesh component should give you what you need for your use case.

I’ll close out this thread. If you run into further problems, you can reopen it.

ご回答ありがとうございます。

PostEvaluateAnimationイベントで取得できる骨のトランスフォームが前フレームのものであるということを理解しました。

また、メッシュのTickの依存関係を設定することでポーズ更新後の骨のトランスフォームを取得することができています。

補足として、この件を質問するに至った経緯を説明します。(必要でなければ読む必要はありません)

私のプロジェクトにおいてIK処理で目標位置がずれることがありました。その原因を調査するためにIKの対象となるメッシュのABPのBlueprintUpdateAnimationとBlueprintPostEvaluateAnimationそれぞれにGetSocketLocationで取得した位置を出力しました。さらにIKを行うキャラクターメッシュのABPのBlueprintUpdateAnimationでIKの目標とする位置を出力して比較することでIKの対象とする位置がポーズ適用前のものか、後のものか、それともどちらでもないのかを判別しようとしました。この方法は以前同じ問題に直面したときに正しく動作しました。(確かその時はUE4.26くらいだったと思います)。なのでBlueprintPostEvaluateAnimationで当然のようにポーズ適用後のトランスフォームが取得できると思っておりました。しかし今回試したところ結果が異なっていたので知見を深めるために質問いたしました。