void FAnimationRuntime::BlendPosesTogetherPerBone(const TArray<FCompactPose>& SourcePoses, const TArray<FBlendedCurve>& SourceCurves, const UBlendSpaceBase* BlendSpace, const TArray<FBlendSampleData>& BlendSampleDataCache, /*out*/ FCompactPose& ResultPose, /*out*/ FBlendedCurve& ResultCurve) { check(SourcePoses.Num() > 0); const TArray<FBoneIndexType> & RequiredBoneIndices = ResultPose.GetBoneContainer().GetBoneIndicesArray(); TArray<int32> PerBoneIndices; PerBoneIndices.AddUninitialized(ResultPose.GetNumBones()); for (int32 BoneIndex = 0; BoneIndex < PerBoneIndices.Num(); ++BoneIndex) { PerBoneIndices[BoneIndex] = BlendSpace->GetPerBoneInterpolationIndex(RequiredBoneIndices[BoneIndex], ResultPose.GetBoneContainer()); } BlendPosePerBone<ETransformBlendMode::Overwrite>(PerBoneIndices, BlendSampleDataCache[0], ResultPose, SourcePoses[0]); for (int32 i = 1; i < SourcePoses.Num(); ++i) { BlendPosePerBone<ETransformBlendMode::Accumulate>(PerBoneIndices, BlendSampleDataCache[i], ResultPose, SourcePoses[i]); } // Ensure that all of the resulting rotations are normalized ResultPose.NormalizeRotations(); if (SourceCurves.Num() > 0) { TArray<float> SourceWeights; SourceWeights.AddUninitialized(BlendSampleDataCache.Num()); for (int32 CacheIndex=0; CacheIndex<BlendSampleDataCache.Num(); ++CacheIndex) { SourceWeights[CacheIndex] = BlendSampleDataCache[CacheIndex].TotalWeight; } BlendCurves(SourceCurves, SourceWeights, ResultCurve); } }
void FAnimationRuntime::BlendPosesTogether( const TArray<const FCompactPose*>& SourcePoses, const TArray<const FBlendedCurve*>& SourceCurves, const TArray<float>& SourceWeights, /*out*/ FCompactPose& ResultPose, /*out*/ FBlendedCurve& ResultCurve) { check(SourcePoses.Num() > 0); BlendPose<ETransformBlendMode::Overwrite>(*SourcePoses[0], ResultPose, SourceWeights[0]); for (int32 PoseIndex = 1; PoseIndex < SourcePoses.Num(); ++PoseIndex) { BlendPose<ETransformBlendMode::Accumulate>(*SourcePoses[PoseIndex], ResultPose, SourceWeights[PoseIndex]); } // Ensure that all of the resulting rotations are normalized if (SourcePoses.Num() > 1) { ResultPose.NormalizeRotations(); } if(SourceCurves.Num() > 0) { BlendCurves(SourceCurves, SourceWeights, ResultCurve); } }
void FAnimationRuntime::AccumulateAdditivePose(FCompactPose& BasePose, const FCompactPose& AdditivePose, FBlendedCurve& BaseCurve, const FBlendedCurve& AdditiveCurve, float Weight, enum EAdditiveAnimationType AdditiveType) { if (AdditiveType == AAT_RotationOffsetMeshSpace) { AccumulateMeshSpaceRotationAdditiveToLocalPose(BasePose, AdditivePose, BaseCurve, AdditiveCurve, Weight); } else { AccumulateLocalSpaceAdditivePose(BasePose, AdditivePose, BaseCurve, AdditiveCurve, Weight); } // if curve exists, accumulate with the weight, BaseCurve.Accumulate(AdditiveCurve, Weight); // normalize BasePose.NormalizeRotations(); }
void FAnimationRuntime::BlendTwoPosesTogether( const FCompactPose& SourcePose1, const FCompactPose& SourcePose2, const FBlendedCurve& SourceCurve1, const FBlendedCurve& SourceCurve2, const float WeightOfPose1, /*out*/ FCompactPose& ResultPose, /*out*/ FBlendedCurve& ResultCurve) { BlendPose<ETransformBlendMode::Overwrite>(SourcePose1, ResultPose, WeightOfPose1); BlendPose<ETransformBlendMode::Accumulate>(SourcePose2, ResultPose, 1.f - WeightOfPose1); // Ensure that all of the resulting rotations are normalized ResultPose.NormalizeRotations(); ResultCurve.Blend(SourceCurve1, SourceCurve2, 1.f - WeightOfPose1); }
void UBlendSpaceBase::GetAnimationPose(TArray<FBlendSampleData>& BlendSampleDataCache, /*out*/ FCompactPose& OutPose, /*out*/ FBlendedCurve& OutCurve) { SCOPE_CYCLE_COUNTER(STAT_BlendSpace_GetAnimPose); FScopeCycleCounterUObject BlendSpaceScope(this); if(BlendSampleDataCache.Num() == 0) { OutPose.ResetToRefPose(); return; } const int32 NumPoses = BlendSampleDataCache.Num(); TArray<FCompactPose, TInlineAllocator<8>> ChildrenPoses; ChildrenPoses.AddZeroed(NumPoses); TArray<FBlendedCurve, TInlineAllocator<8>> ChildrenCurves; ChildrenCurves.AddZeroed(NumPoses); TArray<float, TInlineAllocator<8>> ChildrenWeights; ChildrenWeights.AddZeroed(NumPoses); for(int32 ChildrenIdx=0; ChildrenIdx<ChildrenPoses.Num(); ++ChildrenIdx) { ChildrenPoses[ChildrenIdx].SetBoneContainer(&OutPose.GetBoneContainer()); ChildrenCurves[ChildrenIdx].InitFrom(OutCurve); } // get all child atoms we interested in for(int32 I = 0; I < BlendSampleDataCache.Num(); ++I) { FCompactPose& Pose = ChildrenPoses[I]; if(SampleData.IsValidIndex(BlendSampleDataCache[I].SampleDataIndex)) { const FBlendSample& Sample = SampleData[BlendSampleDataCache[I].SampleDataIndex]; ChildrenWeights[I] = BlendSampleDataCache[I].GetWeight(); if(Sample.Animation) { const float Time = FMath::Clamp<float>(BlendSampleDataCache[I].Time, 0.f, Sample.Animation->SequenceLength); // first one always fills up the source one Sample.Animation->GetAnimationPose(Pose, ChildrenCurves[I], FAnimExtractContext(Time, true)); } else { Pose.ResetToRefPose(); } } else { Pose.ResetToRefPose(); } } TArrayView<FCompactPose> ChildrenPosesView(ChildrenPoses); if (PerBoneBlend.Num() > 0) { if (IsValidAdditive()) { if (bRotationBlendInMeshSpace) { FAnimationRuntime::BlendPosesTogetherPerBoneInMeshSpace(ChildrenPosesView, ChildrenCurves, this, BlendSampleDataCache, OutPose, OutCurve); } else { FAnimationRuntime::BlendPosesTogetherPerBone(ChildrenPosesView, ChildrenCurves, this, BlendSampleDataCache, OutPose, OutCurve); } } else { FAnimationRuntime::BlendPosesTogetherPerBone(ChildrenPosesView, ChildrenCurves, this, BlendSampleDataCache, OutPose, OutCurve); } } else { FAnimationRuntime::BlendPosesTogether(ChildrenPosesView, ChildrenCurves, ChildrenWeights, OutPose, OutCurve); } // Once all the accumulation and blending has been done, normalize rotations. OutPose.NormalizeRotations(); }