void UAnimSingleNodeInstance::InternalBlendSpaceEvaluatePose(class UBlendSpaceBase* BlendSpace, TArray<FBlendSampleData>& BlendSampleDataCache, struct FA2Pose& Pose, bool bIsLooping)
{
	USkeletalMeshComponent* Component = GetSkelMeshComponent();

	if (BlendSpace->IsValidAdditive())
	{
		FA2Pose BasePose;
		FA2Pose AdditivePose;
		BasePose.Bones.AddUninitialized(Pose.Bones.Num());
		AdditivePose.Bones.AddUninitialized(Pose.Bones.Num());

#if WITH_EDITORONLY_DATA
		if (BlendSpace->PreviewBasePose)
		{
			BlendSpace->PreviewBasePose->GetBonePose(/*out*/ BasePose.Bones, RequiredBones, FAnimExtractContext(PreviewPoseCurrentTime, bIsLooping));
		}
		else
#endif // WITH_EDITORONLY_DATA
		{
			// otherwise, get ref pose
			FAnimationRuntime::FillWithRefPose(BasePose.Bones, RequiredBones);
		}

		FAnimationRuntime::GetPoseFromBlendSpace(
			BlendSpace,
			BlendSampleDataCache, 
			bIsLooping,
			RequiredBones,
			/*out*/ AdditivePose.Bones);

		if (BlendSpace->IsA(UAimOffsetBlendSpace::StaticClass()) ||
			BlendSpace->IsA(UAimOffsetBlendSpace1D::StaticClass()) )
		{
			BlendRotationOffset(BasePose, AdditivePose, 1.f, Pose);
		}
		else
		{
			ApplyAdditiveSequence(BasePose, AdditivePose, 1.f, Pose);
		}
	}
	else
	{
		FAnimationRuntime::GetPoseFromBlendSpace(
			BlendSpace,
			BlendSampleDataCache, 
			bIsLooping,
			RequiredBones,
			/*out*/ Pose.Bones);
	}
}
Ejemplo n.º 2
0
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;
	}
}
bool UAnimSingleNodeInstance::NativeEvaluateAnimation(FPoseContext& Output)
{
	if (CurrentAsset != NULL)
	{
		//@TODO: animrefactor: Seems like more code duplication than we need
		if (UBlendSpaceBase* BlendSpace = Cast<UBlendSpaceBase>(CurrentAsset))
		{
			InternalBlendSpaceEvaluatePose(BlendSpace, BlendSampleData, Output.Pose);
		}
		else if (UAnimSequence* Sequence = Cast<UAnimSequence>(CurrentAsset))
		{
			if (Sequence->IsValidAdditive())
			{
				FA2Pose BasePose;
				FA2Pose AdditivePose;

				BasePose.Bones.AddUninitialized(Output.Pose.Bones.Num());
				AdditivePose.Bones.AddUninitialized(Output.Pose.Bones.Num());

				FAnimExtractContext ExtractionContext(CurrentTime);
				Sequence->GetAdditiveBasePose(BasePose.Bones, RequiredBones, ExtractionContext);
				Sequence->GetAnimationPose(AdditivePose.Bones, RequiredBones, ExtractionContext);
				if (Sequence->AdditiveAnimType == AAT_LocalSpaceBase)
				{
					ApplyAdditiveSequence(BasePose, AdditivePose, 1.0f, Output.Pose);
				}
				else
				{
					BlendRotationOffset(BasePose, AdditivePose, 1.0f, Output.Pose);
				}
			}
			else
			{
				// if sekeltalmesh isn't there, we'll need to use skeleton
				FAnimationRuntime::GetPoseFromSequence(Sequence, RequiredBones, Output.Pose.Bones, FAnimExtractContext(CurrentTime, Sequence->bEnableRootMotion));
			}
		}
		else if (UAnimComposite* Composite = Cast<UAnimComposite>(CurrentAsset))
		{
			const FAnimTrack& AnimTrack = Composite->AnimationTrack;

			// find out if this is additive animation
			EAdditiveAnimationType AdditiveAnimType = AAT_None;
			if (AnimTrack.IsAdditive())
			{
				FA2Pose AdditivePose;
				FA2Pose BasePose;

				BasePose.Bones.AddUninitialized(Output.Pose.Bones.Num());
				AdditivePose.Bones.AddUninitialized(Output.Pose.Bones.Num());
				AdditiveAnimType = AnimTrack.IsRotationOffsetAdditive()? AAT_RotationOffsetMeshSpace : AAT_LocalSpaceBase;
				
				// get base pose - for now we only support ref pose as base
				FAnimationRuntime::FillWithRefPose(BasePose.Bones, RequiredBones);
				
				//get the additive pose
				FAnimationRuntime::GetPoseFromAnimTrack(AnimTrack, RequiredBones, AdditivePose.Bones, FAnimExtractContext(CurrentTime, RootMotionMode == ERootMotionMode::RootMotionFromEverything));

				// if additive, we should blend with source to make it fullbody
				if (AdditiveAnimType == AAT_LocalSpaceBase)
				{
					ApplyAdditiveSequence(BasePose,AdditivePose,1.f,Output.Pose);
				}
				else if (AdditiveAnimType == AAT_RotationOffsetMeshSpace)
				{
					BlendRotationOffset(BasePose,AdditivePose,1.f,Output.Pose);
				}
			}
			else
			{
				//doesn't handle additive yet
				FAnimationRuntime::GetPoseFromAnimTrack(AnimTrack, RequiredBones, Output.Pose.Bones, FAnimExtractContext(CurrentTime, RootMotionMode == ERootMotionMode::RootMotionFromEverything));
			}
		}
		else if (UAnimMontage* Montage = Cast<UAnimMontage>(CurrentAsset))
		{
			// for now only update first slot
			// in the future, add option to see which slot to see
			if (Montage->SlotAnimTracks.Num() > 0)
			{
				FA2Pose SourcePose;
				SourcePose.Bones.AddUninitialized(Output.Pose.Bones.Num());
				if (Montage->IsValidAdditive())
				{
#if WITH_EDITORONLY_DATA
					// if montage is additive, we need to have base pose for the slot pose evaluate
					if (Montage->PreviewBasePose && Montage->SequenceLength > 0.f)
					{
						Montage->PreviewBasePose->GetBonePose(SourcePose.Bones, RequiredBones, FAnimExtractContext(CurrentTime));
					}
					else
#endif // WITH_EDITORONLY_DATA
					{
						FAnimationRuntime::FillWithRefPose(SourcePose.Bones, RequiredBones);				
					}
				}
				else
				{
					FAnimationRuntime::FillWithRefPose(SourcePose.Bones, RequiredBones);				
				}

				SlotEvaluatePose(Montage->SlotAnimTracks[0].SlotName, SourcePose, Output.Pose, 1.f);
			}
		}
	}

	if(CurrentVertexAnim != NULL)
	{
		VertexAnims.Add(FActiveVertexAnim(CurrentVertexAnim, 1.f, CurrentTime));
	}

	return true;
}