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);
		}

	}
}
예제 #4
0
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();
}
예제 #5
0
void FAnimNode_Trail::Update(const FAnimationUpdateContext& Context)
{
	FAnimNode_SkeletalControlBase::Update(Context);

	ThisTimstep = Context.GetDeltaTime();
}
예제 #6
0
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();
}
예제 #9
0
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));
			}
		}
	}
}