void FAnimNode_AbilityAnimPlayer::UpdateAssetPlayer(const FAnimationUpdateContext& Context) { EvaluateGraphExposedInputs.Execute(Context); if (m_SequenceToPlay && m_SequenceToPlay->SequenceLength - InternalTimeAccumulator < KINDA_SMALL_NUMBER) { if (m_NextSequence) { SwapToNextSequence(); } else { m_SequenceToPlay = nullptr; } } if (m_SequenceToPlay && Context.AnimInstanceProxy->IsSkeletonCompatible(m_SequenceToPlay->GetSkeleton())) { if (m_NextSequence && m_NextSequenceBlendIn.IsComplete()) { SwapToNextSequence(); } InternalTimeAccumulator = FMath::Clamp(InternalTimeAccumulator, 0.f, m_SequenceToPlay->SequenceLength); if (m_NextSequence) { m_NextSequenceBlendIn.Update(Context.GetDeltaTime()); m_NextSequenceInternalTimeAccumulator += Context.GetDeltaTime(); m_NextSequenceInternalTimeAccumulator = FMath::Clamp(m_NextSequenceInternalTimeAccumulator, 0.0f, m_NextSequence->SequenceLength); } if (FAnimInstanceProxy* Proxy = Context.AnimInstanceProxy) { FAnimGroupInstance* SyncGroup; FAnimTickRecord& SequenceTickRecord = Proxy->CreateUninitializedTickRecord(NAME_None, SyncGroup); float CurrentBlendValue = m_NextSequenceBlendIn.GetBlendedValue(); float SequenceBlendRate = m_NextSequence ? 1.0f - CurrentBlendValue : 1.0f; Proxy->MakeSequenceTickRecord(SequenceTickRecord, const_cast<UAnimSequence*>(m_SequenceToPlay), false, m_PlayRate, SequenceBlendRate, InternalTimeAccumulator, MarkerTickRecord); if (m_NextSequence) { FAnimTickRecord& NextSequenceTickRecord = Proxy->CreateUninitializedTickRecord(NAME_None, SyncGroup); Proxy->MakeSequenceTickRecord(NextSequenceTickRecord, const_cast<UAnimSequence*>(m_NextSequence), false, m_NextPlayRate, CurrentBlendValue, m_NextSequenceInternalTimeAccumulator, m_NextSequenceMarkerTickRecord); } } //CreateTickRecordForNode(Context, const_cast<UAnimSequence*>(m_SequenceToPlay), false, m_PlayRate); } else if (m_CachedOutputSequence && Context.AnimInstanceProxy->IsSkeletonCompatible(m_CachedOutputSequence->GetSkeleton())) { InternalTimeAccumulator = FMath::Clamp(InternalTimeAccumulator, 0.0f, m_CachedOutputSequence->SequenceLength); if (FAnimInstanceProxy* Proxy = Context.AnimInstanceProxy) { FAnimGroupInstance* SyncGroup; FAnimTickRecord& SequenceTickRecord = Proxy->CreateUninitializedTickRecord(NAME_None, SyncGroup); Proxy->MakeSequenceTickRecord(SequenceTickRecord, const_cast<UAnimSequence*>(m_CachedOutputSequence), false, m_PlayRate, 1.0, InternalTimeAccumulator, MarkerTickRecord); } } }
void FAnimationActiveTransitionEntry::Update(const FAnimationUpdateContext& Context, int32 CurrentStateIndex, bool& bOutFinished) { bOutFinished = false; // Advance time if (bActive) { ElapsedTime += Context.GetDeltaTime(); Blend.Update(Context.GetDeltaTime()); float QueryAlpha = 1.0f; // If non-zero, calculate the query alpha if (CrossfadeDuration > 0.0f) { QueryAlpha = ElapsedTime / CrossfadeDuration; } Alpha = FAlphaBlend::AlphaToBlendOption(QueryAlpha, Blend.GetBlendOption(), Blend.GetCustomCurve()); if(Blend.IsComplete()) { bActive = false; bOutFinished = true; } // Update state blend data (only when we're using per-bone) if(BlendProfile) { for(int32 Idx = 0 ; Idx < 2 ; ++Idx) { bool bForwards = Idx == 0; FBlendSampleData& CurrentData = StateBlendData[Idx]; CurrentData.TotalWeight = (bForwards) ? Alpha : 1.0f - Alpha; for(int32 PerBoneIndex = 0 ; PerBoneIndex < CurrentData.PerBoneBlendData.Num() ; ++PerBoneIndex) { float& BoneBlend = CurrentData.PerBoneBlendData[PerBoneIndex]; float WeightScale = BlendProfile->GetEntryBlendScale(PerBoneIndex); if(!bForwards) { WeightScale = 1.0f / WeightScale; } BoneBlend = CurrentData.TotalWeight * WeightScale; } } FBlendSampleData::NormalizeDataWeight(StateBlendData); } } }
void FAnimationActiveTransitionEntry::Update(const FAnimationUpdateContext& Context, int32 CurrentStateIndex, bool& bOutFinished) { bOutFinished = false; // Advance time if (bActive) { ElapsedTime += Context.GetDeltaTime(); if (ElapsedTime >= CrossfadeDuration) { bActive = false; bOutFinished = true; } if(CrossfadeDuration <= 0.0f) { Alpha = 1.0f; } else { Alpha = CalculateAlpha(ElapsedTime / CrossfadeDuration); } } }
void FAnimNode_SpringBone::Update(const FAnimationUpdateContext& Context) { FAnimNode_SkeletalControlBase::Update(Context); RemainingTime += Context.GetDeltaTime(); const USkeletalMeshComponent* SkelComp = Context.AnimInstance->GetSkelMeshComponent(); const UWorld* World = SkelComp->GetWorld(); check(World->GetWorldSettings()); // Fixed step simulation at 120hz FixedTimeStep = (1.f / 120.f) * World->GetWorldSettings()->GetEffectiveTimeDilation(); }
void FAnimNode_Trail::Update(const FAnimationUpdateContext& Context) { FAnimNode_SkeletalControlBase::Update(Context); ThisTimstep = Context.GetDeltaTime(); }
void FAnimNode_LookAt::Update(const FAnimationUpdateContext& Context) { FAnimNode_SkeletalControlBase::Update(Context); AccumulatedInterpoolationTime = FMath::Clamp(AccumulatedInterpoolationTime+Context.GetDeltaTime(), 0.f, InterpolationTime);; }
void FAnimNode_StateMachine::Update(const FAnimationUpdateContext& Context) { if (FBakedAnimationStateMachine* Machine = GetMachineDescription()) { if (Machine->States.Num() == 0) { return; } } else { return; } SCOPE_CYCLE_COUNTER(STAT_AnimStateMachineUpdate); bool bFoundValidTransition = false; int32 TransitionCountThisFrame = 0; int32 TransitionIndex = INDEX_NONE; // Look for legal transitions to take; can move across multiple states in one frame (up to MaxTransitionsPerFrame) do { bFoundValidTransition = false; FAnimationPotentialTransition PotentialTransition; { SCOPE_CYCLE_COUNTER(STAT_AnimStateMachineFindTransition); // Evaluate possible transitions out of this state //@TODO: Evaluate if a set is better than an array for the probably low N encountered here TArray<int32, TInlineAllocator<4>> VisitedStateIndices; FindValidTransition(Context, GetStateInfo(), /*Out*/ PotentialTransition, /*Out*/ VisitedStateIndices); } // If transition is valid and not waiting on other conditions if (PotentialTransition.IsValid()) { bFoundValidTransition = true; // let the latest transition know it has been interrupted if ((ActiveTransitionArray.Num() > 0) && ActiveTransitionArray[ActiveTransitionArray.Num()-1].bActive) { Context.AnimInstance->AddAnimNotifyFromGeneratedClass(ActiveTransitionArray[ActiveTransitionArray.Num()-1].InterruptNotify); } const int32 PreviousState = CurrentState; const int32 NextState = PotentialTransition.TargetState; // Fire off Notifies for state transition if (!bFirstUpdate) { Context.AnimInstance->AddAnimNotifyFromGeneratedClass(GetStateInfo(PreviousState).EndNotify); Context.AnimInstance->AddAnimNotifyFromGeneratedClass(GetStateInfo(NextState).StartNotify); } // Get the current weight of the next state, which may be non-zero const float ExistingWeightOfNextState = GetStateWeight(NextState); // Push the transition onto the stack const FAnimationTransitionBetweenStates& ReferenceTransition = GetTransitionInfo(PotentialTransition.TransitionRule->TransitionIndex); FAnimationActiveTransitionEntry* NewTransition = new (ActiveTransitionArray) FAnimationActiveTransitionEntry(NextState, ExistingWeightOfNextState, PreviousState, ReferenceTransition); NewTransition->InitializeCustomGraphLinks(Context, *(PotentialTransition.TransitionRule)); #if WITH_EDITORONLY_DATA NewTransition->SourceTransitionIndices = PotentialTransition.SourceTransitionIndices; #endif if (!bFirstUpdate) { Context.AnimInstance->AddAnimNotifyFromGeneratedClass(NewTransition->StartNotify); } SetState(Context, NextState); TransitionCountThisFrame++; } } while (bFoundValidTransition && (TransitionCountThisFrame < MaxTransitionsPerFrame)); if (bFirstUpdate) { //Handle enter notify for "first" (after initial transitions) state Context.AnimInstance->AddAnimNotifyFromGeneratedClass(GetStateInfo().StartNotify); // in the first update, we don't like to transition from entry state // so we throw out any transition data at the first update ActiveTransitionArray.Reset(); bFirstUpdate = false; } StatesUpdated.Empty(StatesUpdated.Num()); // Tick the individual state/states that are active if (ActiveTransitionArray.Num() > 0) { for (int32 Index = 0; Index < ActiveTransitionArray.Num(); ++Index) { // The custom graph will tick the needed states bool bFinishedTrans = false; // The custom graph will tick the needed states ActiveTransitionArray[Index].Update(Context, CurrentState, /*out*/ bFinishedTrans); if (bFinishedTrans) { // only play these events if it is the last transition (most recent, going to current state) if (Index == (ActiveTransitionArray.Num() - 1)) { Context.AnimInstance->AddAnimNotifyFromGeneratedClass(ActiveTransitionArray[Index].EndNotify); Context.AnimInstance->AddAnimNotifyFromGeneratedClass(GetStateInfo().FullyBlendedNotify); } } else { // transition is still active, so tick the required states UpdateTransitionStates(Context, ActiveTransitionArray[Index]); } } // remove finished transitions here, newer transitions ending means any older ones must complete as well for (int32 Index = (ActiveTransitionArray.Num()-1); Index >= 0; --Index) { // if we find an inactive one, remove all older transitions and break out if (!ActiveTransitionArray[Index].bActive) { ActiveTransitionArray.RemoveAt(0, Index+1); break; } } } //@TODO: StatesUpdated.Contains is a linear search // Update the only active state if there are no transitions still in flight if (ActiveTransitionArray.Num() == 0 && !IsAConduitState(CurrentState) && !StatesUpdated.Contains(CurrentState)) { StatePoseLinks[CurrentState].Update(Context); } ElapsedTime += Context.GetDeltaTime(); }
void FAnimNode_AnimDynamics::UpdateInternal(const FAnimationUpdateContext& Context) { FAnimNode_SkeletalControlBase::UpdateInternal(Context); NextTimeStep = Context.GetDeltaTime(); }
void FAnimNode_BlendListBase::Update(const FAnimationUpdateContext& Context) { EvaluateGraphExposedInputs.Execute(Context); const int NumPoses = BlendPose.Num(); checkSlow((BlendTime.Num() == NumPoses) && (BlendWeights.Num() == NumPoses)); if (NumPoses > 0) { // Handle a change in the active child index; adjusting the target weights const int32 ChildIndex = GetActiveChildIndex(); if (ChildIndex != LastActiveChildIndex) { bool LastChildIndexIsInvalid = (LastActiveChildIndex == INDEX_NONE); LastActiveChildIndex = ChildIndex; const float CurrentWeight = BlendWeights[ChildIndex]; const float DesiredWeight = 1.0f; const float WeightDifference = FMath::Clamp<float>(FMath::Abs<float>(DesiredWeight - CurrentWeight), 0.0f, 1.0f); // scale by the weight difference since we want always consistency: // - if you're moving from 0 to full weight 1, it will use the normal blend time // - if you're moving from 0.5 to full weight 1, it will get there in half the time const float RemainingBlendTime = LastChildIndexIsInvalid ? 0.0f : ( BlendTime[ChildIndex] * WeightDifference ); for (int32 i = 0; i < RemainingBlendTimes.Num(); ++i) { RemainingBlendTimes[i] = RemainingBlendTime; } } // Advance the weights //@TODO: This means we advance even in a frame where the target weights/times just got modified; is that desirable? float SumWeight = 0.0f; for (int32 i = 0; i < RemainingBlendTimes.Num(); ++i) { float& RemainingBlendTime = RemainingBlendTimes[i]; float& BlendWeight = BlendWeights[i]; const float DesiredWeight = (i == ChildIndex) ? 1.0f : 0.0f; FAnimationRuntime::TickBlendWeight(Context.GetDeltaTime(), DesiredWeight, BlendWeight, RemainingBlendTime); SumWeight += BlendWeight; } // Renormalize the weights if ((SumWeight > ZERO_ANIMWEIGHT_THRESH) && (FMath::Abs<float>(SumWeight - 1.0f) > ZERO_ANIMWEIGHT_THRESH)) { float ReciprocalSum = 1.0f / SumWeight; for (int32 i = 0; i < BlendWeights.Num(); ++i) { BlendWeights[i] *= ReciprocalSum; } } // Update our active children for (int32 i = 0; i < BlendPose.Num(); ++i) { const float BlendWeight = BlendWeights[i]; if (BlendWeight > ZERO_ANIMWEIGHT_THRESH) { BlendPose[i].Update(Context.FractionalWeight(BlendWeight)); } } } }