MotionWarpingComponent/RootMotionModifier doesn't seem to handle blend-out correctly

We’re testing a simple turn-to-specified-rotation motion warp on an idle anim that has root motion enabled but no actual root motion.

If I have an AnimMontage with a motion warp notify that runs to near the end of the montage, if the blend out time overlaps that notify, then it consistently undershoots the rotation - as if the motion warp stopped when it hit the blend.

Does blending not work with this or are we doing something else wrong?

Thanks

[Attachment Removed]

Steps to Reproduce[Attachment Removed]

Hey there,

Motion Warping is subject to whatever montage or animation is dominant in the context of what is playing. So once the threshold of the animation that is blending out hits the point where the animation that is being blended in is dominant, URootMotionModifier::Update will mark the modifier (in this case motion warp) as MarkedForRemoval and not be evaluated anymore.

If this is behaviour you would want to change, you need to modify the way that RootMotionModifiers are evaluated for removal in that function I mentioned.

Dustin

[Attachment Removed]

Hey apologies for the delay, been looking into this a bit and I cannot repro what you’re saying. Would you be able to share a repro of the setup that shows the issue?

In the case where we stop playing a montage it’s because the remaining playtime is less than the blend out time. If you’re blend time is set to 0, then it could still trigger if the remaining time is less than 0.00001 or UE_REALLY_SMALL_NUMBER. But looking at the data you’ve sent over, your case would be larger than that.

[Attachment Removed]

Hey there,

Thanks for the repro, just wanted to let you know that we’re investigating still and I’m chatting with the dev team on it.

Dustin

[Attachment Removed]

Hey there,

I’ve chatted with the dev team, and I have a few answers, thoughts, and options for you.

First this is somewhat by design by the dev team. The issue is that there are many cases where a motion warp can be interrupted, including end of play that we don’t/can’t account for, so often times we recommend doing your warp mid movement and then have a settle at the end of your animation. Second, both in regard to your first question and your second question where there is a blend or there isn’t a blend it is expected that you won’t hit the full rotation. This is due to how we remove the warp from the stack, especially in the case where root motion only is extracted from montages. If you don’t have any root motion to extract from in your blend out case, then you can get into odd spots with warps in general.

So, in terms of workarounds, on top of the workflow I suggested earlier, the easiest adjustment would be to pull your warp window back by at least a frame. The issue is, though, that you are still at the whim of your framerate for whether or not you handle the warp in full. For us, when a montage ends, we often force and teleport to the position we want the actor to be.

Overall though, if this is something that you want to tackle, you will want to take a look at the code that handles removing the RootmotionModifier from the active stack of modifiers. We do this in URootMotionModifier::Update where there are a couple of branches of removal. If you like you can add a different heuristic to drive when we remove the root motion modifer because we often look at the last frame and the current contexts (read as montage playing) position in the animation to do so.

Dustin

[Attachment Removed]

Thanks - I’ll look there for blend issues.

But there’s a related issue which is probably exacerbating this. If your notify goes up to the end of the montage, then even with 0 blend time the montage will end in UAnimInstance::Montage_Advance and then will not have an anim for the URootMotionModifer::Update so it will not do the last frame of updates.

for instance the MotionWarping log might show this:

LogMotionWarping (Verbose) MotionWarping: Marking RootMotionModifier for removal. Reason: Animation is not valid. Char: <The character> Current Animation: None. Window: Animation: <turn left 90> [0.000000 0.399800] [0.333333 0.366667]

Where it has updated the motion modifier for the 0.33->0.366667 portion of the anim, but did not complete for the 0.366667->0.399800(end) portion of the anim

EDIT: You can end it early and use “subtract remaining root motion” but for any root motion that you primarily want from the modifier (and not from the underlying anim) this forces you to do it faster, in a smaller chunk of the anim.

[Attachment Removed]

I looked at when the blend ends, and the issue seems not to be in the Update but when you advance a montage and tell it to stop (with BlendSettings), it calls

>	UnrealEditor-Engine.dll!UAnimInstance::ClearMontageInstanceReferences(FAnimMontageInstance & InMontageInstance) Line 3326	C++
 	UnrealEditor-Engine.dll!UAnimInstance::OnMontageInstanceStopped(FAnimMontageInstance & StoppedMontageInstance) Line 3296	C++
 	UnrealEditor-Engine.dll!FAnimMontageInstance::Stop(const FMontageBlendSettings & InBlendOutSettings, bool bInterrupt) Line 1560	C++
 	UnrealEditor-Engine.dll!FAnimMontageInstance::Stop(const FAlphaBlend & InBlendOut, bool bInterrupt) Line 1636	C++
 	UnrealEditor-Engine.dll!FAnimMontageInstance::Advance(float DeltaTime, FRootMotionMovementParams * OutRootMotionParams, bool bBlendRootMotion) Line 2564	C++
 	UnrealEditor-Engine.dll!UAnimInstance::Montage_Advance(float DeltaSeconds) Line 1970	C++

and then in ClearMontageInstanceReferencers it sets RootMotionMontageInstance to nullptr which means that the update cannot continue (we no longer have info on CurrentPosition etc)

Also, BlendIn doesn’t have this issue of “which is more prevalent” If I have a blend-in time it will start doing root motion from the beginning (in both cases I have no other active montages - it is possible that something would be different in those cases)

[Attachment Removed]

I will see if I can generate a repro of the setup in Vanilla Unreal, may take a bit.

[Attachment Removed]

I reproduced it in Vanilla Unreal.

I took 5.6.0 (that’s the pristine version I had) and opened the QAGame project, and opened the level QA-AI

I modified the SeekerBT to play an anim montage that I created, which was just the MF_Idle anim, with a motion warping state (rotation only). I turned off all blending, and turned on Root motion for the MF_Idle anim.

I set the BPAICharacter to set the motion warp target to point straight down the Y axis (took the starting coordinates, modified Y, and gave that as the facing point for motion warp)

On Tick I had it log the facing to the VLOG (forward vector) and if the motion warp runs to the end, it doesn’t quite make the turn complete and if it ends one frame early, it does make the turn.

New File:

/Game/Developers/aduran/TurnInPlaceAnim.TurnInPlaceAnim

Modified Files:

/Game/Characters/Mannequins/Animations/Quinn/MF_Idle.MF_Idle

/Game/AI/RunAndSeek/SeekerBT.SeekerBT

/Game/AI/RunAndSeek/BPAICharacter.BPAICharacter

(The level shouldn’t need any modification)

Attached are the files - object paths listed above, if you need them.

[Attachment Removed]

Ok thanks. Yeah we’re working around it by just pulling back farther from the end - (by more than a frame) - maybe we’ll need to do the teleport as well.

It’s a shame it’s kind of a hidden gotcha though.

[Attachment Removed]