void UAnimInstance::EvaluateAnimation(FPoseContext& Output) { // If bone caches have been invalidated, have AnimNodes refresh those. if( bBoneCachesInvalidated && RootNode ) { bBoneCachesInvalidated = false; IncrementContextCounter(); FAnimationCacheBonesContext UpdateContext(this); RootNode->CacheBones(UpdateContext); } // Evaluate native code if implemented, otherwise evaluate the node graph if (!NativeEvaluateAnimation(Output)) { if (RootNode != NULL) { SCOPE_CYCLE_COUNTER(STAT_AnimGraphEvaluate); RootNode->Evaluate(Output); } else { Output.ResetToRefPose(); } } }
void FAnimNode_SequencePlayer::Evaluate(FPoseContext& Output) { if ((Sequence != NULL) && (Output.AnimInstance->CurrentSkeleton->IsCompatible(Sequence->GetSkeleton()))) { Sequence->GetAnimationPose(Output.Pose, Output.Curve, FAnimExtractContext(InternalTimeAccumulator, Output.AnimInstance->ShouldExtractRootMotion())); } else { Output.ResetToRefPose(); } }
void FAnimNode_BlendSpacePlayer::Evaluate(FPoseContext& Output) { if ((BlendSpace != NULL) && (Output.AnimInstanceProxy->IsSkeletonCompatible(BlendSpace->GetSkeleton()))) { BlendSpace->GetAnimationPose(BlendSampleDataCache, Output.Pose, Output.Curve); } else { Output.ResetToRefPose(); } }
void FAnimNode_BlendSpacePlayer::Evaluate(FPoseContext& Output) { if ((BlendSpace != NULL) && (Output.AnimInstance->CurrentSkeleton->IsCompatible(BlendSpace->GetSkeleton()))) { Output.AnimInstance->BlendSpaceEvaluatePose(BlendSpace, BlendSampleDataCache, Output.Pose); } else { Output.ResetToRefPose(); } }
void FAnimNode_RefPose::Evaluate(FPoseContext& Output) { // I don't have anything to evaluate. Should this be even here? // EvaluateGraphExposedInputs.Execute(Context); switch (RefPoseType) { case EIT_LocalSpace: Output.ResetToRefPose(); break; case EIT_Additive: default: Output.ResetToIdentity(); break; } }
void FAnimNode_BlendListBase::Evaluate(FPoseContext& Output) { SCOPE_CYCLE_COUNTER(STAT_AnimNativeBlendPoses); const int32 MaxNumPoses = BlendPose.Num(); //@TODO: This is currently using O(NumPoses) memory but doesn't need to if ((MaxNumPoses > 0) && (BlendPose.Num() == BlendWeights.Num())) { TArray<FPoseContext> FilteredPoseContexts; FilteredPoseContexts.Empty(MaxNumPoses); FTransformArrayA2** FilteredPoses = new FTransformArrayA2*[MaxNumPoses]; float* FilteredWeights = new float[MaxNumPoses]; int32 NumActivePoses = 0; for (int32 i = 0; i < BlendPose.Num(); ++i) { const float BlendWeight = BlendWeights[i]; if (BlendWeight > ZERO_ANIMWEIGHT_THRESH) { FPoseContext& CurrentPoseContext = *(new (FilteredPoseContexts) FPoseContext(Output)); FPoseLink& CurrentPose = BlendPose[i]; CurrentPose.Evaluate(CurrentPoseContext); FilteredPoses[NumActivePoses] = &(CurrentPoseContext.Pose.Bones); FilteredWeights[NumActivePoses] = BlendWeight; NumActivePoses++; } } FAnimationRuntime::BlendPosesTogether(NumActivePoses, (const FTransformArrayA2**)FilteredPoses, (const float*)FilteredWeights, Output.AnimInstance->RequiredBones, Output.Pose.Bones); delete[] FilteredPoses; delete[] FilteredWeights; } else { Output.ResetToRefPose(); } }
void FAnimNode_AbilityAnimPlayer::Evaluate_AnyThread(FPoseContext& Output) { check(Output.AnimInstanceProxy); FAnimInstanceProxy* Proxy = Output.AnimInstanceProxy; if (m_SequenceToPlay && Proxy->IsSkeletonCompatible(m_SequenceToPlay->GetSkeleton())) { if (m_NextSequence && Proxy->IsSkeletonCompatible(m_NextSequence->GetSkeleton())) { FCompactPose Poses[2]; FBlendedCurve Curves[2]; float Weights[2]; const FBoneContainer& RequiredBone = Proxy->GetRequiredBones(); Poses[0].SetBoneContainer(&RequiredBone); Poses[1].SetBoneContainer(&RequiredBone); Curves[0].InitFrom(RequiredBone); Curves[1].InitFrom(RequiredBone); Weights[0] = 1.0f - m_NextSequenceBlendIn.GetBlendedValue(); Weights[1] = m_NextSequenceBlendIn.GetBlendedValue(); m_SequenceToPlay->GetAnimationPose(Poses[0], Curves[0], FAnimExtractContext(InternalTimeAccumulator, Proxy->ShouldExtractRootMotion())); m_NextSequence->GetAnimationPose(Poses[1], Curves[1], FAnimExtractContext(m_NextSequenceInternalTimeAccumulator, Proxy->ShouldExtractRootMotion())); FAnimationRuntime::BlendPosesTogether(Poses, Curves, Weights, Output.Pose, Output.Curve); } else { m_SequenceToPlay->GetAnimationPose(Output.Pose, Output.Curve, FAnimExtractContext(InternalTimeAccumulator, Output.AnimInstanceProxy->ShouldExtractRootMotion())); } m_CachedOutputSequence = m_SequenceToPlay; } else if (m_CachedOutputSequence) { m_CachedOutputSequence->GetAnimationPose(Output.Pose, Output.Curve, FAnimExtractContext(InternalTimeAccumulator, Output.AnimInstanceProxy->ShouldExtractRootMotion())); } else { Output.ResetToRefPose(); } }
void FPoseLink::Evaluate(FPoseContext& Output) { #if DO_CHECK checkf( !bProcessed, TEXT( "Evaluate already in progress, circular link for AnimInstance [%s] Blueprint [%s]" ), \ *Output.AnimInstanceProxy->GetAnimInstanceName(), *GetFullNameSafe(IAnimClassInterface::GetActualAnimClass(Output.AnimInstanceProxy->GetAnimClassInterface()))); TGuardValue<bool> CircularGuard(bProcessed, true); #endif #if WITH_EDITOR if ((LinkedNode == NULL) && GIsEditor) { //@TODO: Should only do this when playing back AttemptRelink(Output); } #endif #if ENABLE_ANIMGRAPH_TRAVERSAL_DEBUG checkf(InitializationCounter.IsSynchronizedWith(Output.AnimInstanceProxy->GetInitializationCounter()), TEXT("Calling Evaluate without initialization!")); checkf(UpdateCounter.IsSynchronizedWith(Output.AnimInstanceProxy->GetUpdateCounter()), TEXT("Calling Evaluate without Update for this node!")); checkf(CachedBonesCounter.IsSynchronizedWith(Output.AnimInstanceProxy->GetCachedBonesCounter()), TEXT("Calling Evaluate without CachedBones!")); EvaluationCounter.SynchronizeWith(Output.AnimInstanceProxy->GetEvaluationCounter()); #endif if (LinkedNode != NULL) { #if ENABLE_ANIMNODE_POSE_DEBUG CurrentPose.ResetToAdditiveIdentity(); #endif LinkedNode->Evaluate(Output); #if ENABLE_ANIMNODE_POSE_DEBUG CurrentPose.CopyBonesFrom(Output.Pose); #endif #if WITH_EDITOR Output.AnimInstanceProxy->RegisterWatchedPose(Output.Pose, LinkID); #endif } else { //@TODO: Warning here? Output.ResetToRefPose(); } // Detect non valid output #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (Output.ContainsNaN()) { // Show bone transform with some useful debug info for (const FTransform& Bone : Output.Pose.GetBones()) { if (Bone.ContainsNaN()) { ensureMsgf(!Bone.ContainsNaN(), TEXT("Bone transform contains NaN from AnimInstance:[%s] Node:[%s] Value:[%s]") , *Output.AnimInstanceProxy->GetAnimInstanceName(), LinkedNode ? *LinkedNode->StaticStruct()->GetName() : TEXT("NULL"), *Bone.ToString()); } } } if (!Output.IsNormalized()) { // Show bone transform with some useful debug info for (const FTransform& Bone : Output.Pose.GetBones()) { if (!Bone.IsRotationNormalized()) { ensureMsgf(Bone.IsRotationNormalized(), TEXT("Bone Rotation not normalized from AnimInstance:[%s] Node:[%s] Rotation:[%s]") , *Output.AnimInstanceProxy->GetAnimInstanceName(), LinkedNode ? *LinkedNode->StaticStruct()->GetName() : TEXT("NULL"), *Bone.GetRotation().ToString()); } } } #endif }