Hello, when we have a skeletal animation track in sequencer with a frame keyed as zero weight (such as at the start of the sequence where we are blending into the animation associated with this track), we notice that the dynamic montage is terminated. This appears to happen because of this code in AnimMontage.cpp:
void FAnimMontageInstance::Advance(float DeltaTime, struct FRootMotionMovementParams* OutRootMotionParams, bool bBlendRootMotion) { ... // If this Montage has no weight, it should be terminated. if (IsStopped() && (Blend.IsComplete())) { // nothing else to do Terminate(); return; }
IsStopped is defined in AnimMontage.h
bool IsStopped() const { return Blend.GetDesiredValue() == 0.f; }
When the MovieSceneSkeletalAnimationSystem evaluates next, it attempts to set the sequencer montage position and reaches the following block of code:
`UAnimMontage* FAnimMontageInstance::SetSequencerMontagePosition(FName SlotName, UAnimInstance* AnimInstance, int32& InOutInstanceId, UAnimSequenceBase* InAnimSequence, float InFromPosition, float InToPosition, float Weight, bool bLooping, bool bInPlaying)
{
UAnimInstance* AnimInst = AnimInstance;
if (AnimInst)
{
UAnimMontage* PlayingMontage = nullptr;
FAnimMontageInstance* MontageInstanceToUpdate = AnimInst->GetMontageInstanceForID(InOutInstanceId);
if (!MontageInstanceToUpdate)
{
…`At this point the MontageInstanceToUpdate hasn’t been cleaned up yet, so it’s still != nullptr even though the underlying montage has been destroyed due to termination, so sequencer performs its updates to the MontageInstanceToUpdate (effectively not updating the montage for a frame). The next time we arrive at this function, the MontageInstanceToUpdate has been cleaned up so this code properly detects that we no longer have a valid montage and creates a new DynamicMontage in order to continue updates.
So a couple things that we see as a problem:
- Does it make sense to terminate montages just based on a zero blend weight? Especially in the sequencer case this seems less than ideal given that it forces another dynamic montage to be created. We could ‘work around’ this by adding a slightly greater than 0 weight on our level sequence’s skeletalAnimationTracks but ideally a 0 weight would be valid.
- In the above case, sequencer shouldn’t attempt to update a Montage Instance if its montage isn’t valid.
To get around the second issue we could change the conditional check in SetSequencerMontagePosition to be:
if (!MontageInstanceToUpdate || !MontageInstanceToUpdate->IsValid())
This would ensure the new dynamic montage is created immediately instead of wasting an update. But ideally we don’t arrive at this state in the first place.