float UAnimInstance::GetSlotWeight(FName SlotNodeName) { float TotalSum = 0.f; #if DEBUGMONTAGEWEIGHT float TotalDesiredWeight = 0.f; #endif // first get all the montage instance weight this slot node has for (int32 I = 0; I < MontageInstances.Num(); ++I) { FAnimMontageInstance* MontageInstance = MontageInstances[I]; if (MontageInstance && MontageInstance->IsValid() && MontageInstance->Montage->IsValidSlot(SlotNodeName)) { TotalSum += MontageInstance->Weight; #if DEBUGMONTAGEWEIGHT TotalDesiredWeight += MontageInstance->DesiredWeight; #endif } } // this can happen when it's blending in OR when newer animation comes in with shorter blendtime // say #1 animation was blending out time with current blendtime 1.0 #2 animation was blending in with 1.0 (old) but got blend out with new blendtime 0.2f // #3 animation was blending in with the new blendtime 0.2f, you'll have sum of #1, 2, 3 exceeds 1.f if (TotalSum > 1.f + ZERO_ANIMWEIGHT_THRESH) { // first get all the montage instance weight this slot node has for (int32 I=0; I<MontageInstances.Num(); ++I) { FAnimMontageInstance * MontageInstance = MontageInstances[I]; if (MontageInstance && MontageInstance->IsValid() && MontageInstance->Montage->IsValidSlot(SlotNodeName)) { MontageInstance->Weight/=TotalSum; } } } #if DEBUGMONTAGEWEIGHT else if (TotalDesiredWeight == 1.f && TotalSum < 1.f - ZERO_ANIMWEIGHT_THRESH) { // this can happen when it's blending in OR when newer animation comes in with longer blendtime // say #1 animation was blending out time with current blendtime 0.2 #2 animation was blending in with 0.2 (old) but got blend out with new blendtime 1.f // #3 animation was blending in with the new blendtime 1.f, you'll have sum of #1, 2, 3 doesn't meet 1.f UE_LOG(LogAnimation, Warning, TEXT("[%s] Montage has less weight. Blending in?(%f)"), *SlotNodeName.ToString(), TotalSum); } #endif return FMath::Clamp<float>(TotalSum, 0.f, 1.f); }
void UAnimInstance::UpdateRootMotionMontageInstance() { FAnimMontageInstance * ActiveMontageInstance = GetActiveMontageInstance(); const bool bValidRootMotionInstance = (ActiveMontageInstance && ActiveMontageInstance->IsValid() && ActiveMontageInstance->Montage && (ActiveMontageInstance->Montage->bEnableRootMotionTranslation || ActiveMontageInstance->Montage->bEnableRootMotionRotation) ); RootMotionMontageInstance = bValidRootMotionInstance ? ActiveMontageInstance : NULL; }
FAnimMontageInstance* UAnimInstance::GetActiveMontageInstance() { if ( MontageInstances.Num() > 0 ) { FAnimMontageInstance * RetVal = MontageInstances.Last(); if ( RetVal->IsValid() ) { return RetVal; } } return NULL; }
void UAnimInstance::SlotEvaluatePose(FName SlotNodeName, const FA2Pose & SourcePose, FA2Pose & BlendedPose, float SlotNodeWeight) { SCOPE_CYCLE_COUNTER(STAT_AnimNativeEvaluatePoses); if ( SlotNodeWeight > ZERO_ANIMWEIGHT_THRESH ) { // final output of slot pose FA2Pose SlotPose; SlotPose.Bones.AddUninitialized(SourcePose.Bones.Num()); /// blend helper variables TArray<FA2Pose> MontagePoses; TArray<float> MontageWeights; TArray<FAnimMontageInstance *> ValidMontageInstances; // first pass we go through collect weights and valid montages. for (auto Iter = MontageInstances.CreateConstIterator(); Iter; ++Iter) { FAnimMontageInstance * MontageInstance = (*Iter); // @todo make this struct? if (MontageInstance->IsValid() && MontageInstance->Montage->IsValidSlot(SlotNodeName)) { int32 NewIndex = MontageWeights.AddUninitialized(1); MontagePoses.AddZeroed(1); ValidMontageInstances.Add(MontageInstance); MontagePoses[NewIndex].Bones.AddUninitialized(BlendedPose.Bones.Num()); MontageWeights[NewIndex] = MontageInstance->Weight; } } // clean up the MontageWeights to see if they're not summing up correctly float TotalSum = 0.f; for (int32 I=0; I<MontageWeights.Num(); ++I) { // normalize I TotalSum += MontageWeights[I]; } // if it has any valid weight if ( TotalSum > ZERO_ANIMWEIGHT_THRESH ) { // but not 1.f. If 1.f it's useless if (FMath::IsNearlyEqual(TotalSum, 1.f) == false) { for (int32 I=0; I<MontageWeights.Num(); ++I) { // normalize I MontageWeights[I] /= TotalSum; } } } else { FAnimationRuntime::FillWithRefPose(BlendedPose.Bones, RequiredBones); // nothing else to do here, there is no weight return; } // if not, something went wrong. It should have something check (ValidMontageInstances.Num() > 0); // second pass, we fill up MontagePoses with valid data to be full pose for (int32 I=0; I<ValidMontageInstances.Num(); ++I) { FAnimMontageInstance * MontageInstance = ValidMontageInstances[I]; const FAnimTrack * AnimTrack = MontageInstance->Montage->GetAnimationData(SlotNodeName); // find out if this is additive animation EAdditiveAnimationType AdditiveAnimType = AAT_None; if (AnimTrack->IsAdditive()) { AdditiveAnimType = AnimTrack->IsRotationOffsetAdditive()? AAT_RotationOffsetMeshSpace : AAT_LocalSpaceBase; } // get the pose data, temporarily use SlotPose FAnimExtractContext ExtractionContext(MontageInstance->Position, false, MontageInstance->Montage->bEnableRootMotionTranslation, MontageInstance->Montage->bEnableRootMotionRotation, MontageInstance->Montage->RootMotionRootLock); FAnimationRuntime::GetPoseFromAnimTrack(*AnimTrack, RequiredBones, SlotPose.Bones, ExtractionContext); // if additive, we should blend with source to make it fullbody if (AdditiveAnimType == AAT_LocalSpaceBase) { ApplyAdditiveSequence(SourcePose,SlotPose,MontageWeights[I],MontagePoses[I]); } else if (AdditiveAnimType == AAT_RotationOffsetMeshSpace) { BlendRotationOffset(SourcePose,SlotPose,MontageWeights[I],MontagePoses[I]); } else { CopyPose(SlotPose, MontagePoses[I]); } } // allocate for blending FTransformArrayA2** BlendingPoses = new FTransformArrayA2*[MontagePoses.Num()]; for (int32 I=0; I<MontagePoses.Num(); ++I) { BlendingPoses[I] = &MontagePoses[I].Bones; } // now time to blend all montages FAnimationRuntime::BlendPosesTogether(MontagePoses.Num(), (const FTransformArrayA2**)BlendingPoses, (const float*)MontageWeights.GetData(), RequiredBones, SlotPose.Bones); // clean up memory delete[] BlendingPoses; // now blend with Source if ( SlotNodeWeight > 1-ZERO_ANIMWEIGHT_THRESH ) { BlendedPose = SlotPose; } else { // normal non-additive animations BlendSequences(SourcePose, SlotPose, SlotNodeWeight, BlendedPose); } } else { BlendedPose = SourcePose; } }