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::AccumulateLocalSpaceAdditivePose(FCompactPose& BasePose, const FCompactPose& AdditivePose, FBlendedCurve& BaseCurve, const FBlendedCurve& AdditiveCurve, float Weight) { if (Weight > ZERO_ANIMWEIGHT_THRESH) { if (Weight >= (1.f - ZERO_ANIMWEIGHT_THRESH)) { // fast path, no need to weight additive. for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) { BasePose[BoneIndex].Accumulate(AdditivePose[BoneIndex]); } } else { // Slower path w/ weighting const ScalarRegister VBlendWeight(Weight); for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) { // copy additive, because BlendFromIdentityAndAccumulate modifies it. FTransform Additive = AdditivePose[BoneIndex]; FTransform::BlendFromIdentityAndAccumulate(BasePose[BoneIndex], Additive, VBlendWeight); } } } }
void FAnimationRuntime::FillWithRetargetBaseRefPose(FCompactPose& OutPose, const USkeletalMesh* Mesh) { // Copy Target Asset's ref pose. if (Mesh) { for (FCompactPoseBoneIndex BoneIndex : OutPose.ForEachBoneIndex()) { FMeshPoseBoneIndex PoseIndex = OutPose.GetBoneContainer().MakeMeshPoseIndex(BoneIndex); OutPose[BoneIndex] = Mesh->RetargetBasePose[PoseIndex.GetInt()]; } } }
void FAnimationRuntime::ConvertMeshRotationPoseToLocalSpace(FCompactPose& Pose) { // Convert all rotations to mesh space // only the root bone doesn't have a parent. So skip it to save a branch in the iteration. for (FCompactPoseBoneIndex BoneIndex(Pose.GetNumBones()-1); BoneIndex > 0; --BoneIndex) { const FCompactPoseBoneIndex ParentIndex = Pose.GetParentBoneIndex(BoneIndex); FQuat LocalSpaceRotation = Pose[ParentIndex].GetRotation().Inverse() * Pose[BoneIndex].GetRotation(); Pose[BoneIndex].SetRotation(LocalSpaceRotation); } }
void FAnimationRuntime::ConvertPoseToMeshRotation(FCompactPose& LocalPose) { // Convert all rotations to mesh space // only the root bone doesn't have a parent. So skip it to save a branch in the iteration. for (FCompactPoseBoneIndex BoneIndex(1); BoneIndex < LocalPose.GetNumBones(); ++BoneIndex) { const FCompactPoseBoneIndex ParentIndex = LocalPose.GetParentBoneIndex(BoneIndex); const FQuat MeshSpaceRotation = LocalPose[ParentIndex].GetRotation() * LocalPose[BoneIndex].GetRotation(); LocalPose[BoneIndex].SetRotation(MeshSpaceRotation); } }
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); } }
FORCEINLINE void BlendPose(const FCompactPose& SourcePose, FCompactPose& ResultPose, const float BlendWeight) { for (FCompactPoseBoneIndex BoneIndex : SourcePose.ForEachBoneIndex()) { BlendTransform<TRANSFORM_BLEND_MODE>(SourcePose[BoneIndex], ResultPose[BoneIndex], BlendWeight); } }
void FAnimationRuntime::BlendPosesTogetherPerBoneInMeshSpace(TArray<FCompactPose>& SourcePoses, const TArray<FBlendedCurve>& SourceCurves, const UBlendSpaceBase* BlendSpace, const TArray<FBlendSampleData>& BlendSampleDataCache, FCompactPose& ResultPose, FBlendedCurve& ResultCurve) { FQuat NewRotation; USkeleton* Skeleton = BlendSpace->GetSkeleton(); // all this is going to do is to convert SourcePoses.Rotation to be mesh space, and then once it goes through BlendPosesTogetherPerBone, convert back to local for (FCompactPose& Pose : SourcePoses) { for (const FCompactPoseBoneIndex BoneIndex : Pose.ForEachBoneIndex()) { const FCompactPoseBoneIndex ParentIndex = Pose.GetParentBoneIndex(BoneIndex); if (ParentIndex != INDEX_NONE) { NewRotation = Pose[ParentIndex].GetRotation()*Pose[BoneIndex].GetRotation(); NewRotation.Normalize(); } else { NewRotation = Pose[BoneIndex].GetRotation(); } // now copy back to SourcePoses Pose[BoneIndex].SetRotation(NewRotation); } } // now we have mesh space rotation, call BlendPosesTogetherPerBone BlendPosesTogetherPerBone(SourcePoses, SourceCurves, BlendSpace, BlendSampleDataCache, ResultPose, ResultCurve); // now result atoms has the output with mesh space rotation. Convert back to local space, start from back for (const FCompactPoseBoneIndex BoneIndex : ResultPose.ForEachBoneIndex()) { const FCompactPoseBoneIndex ParentIndex = ResultPose.GetParentBoneIndex(BoneIndex); if (ParentIndex != INDEX_NONE) { FQuat LocalBlendQuat = ResultPose[ParentIndex].GetRotation().Inverse()*ResultPose[BoneIndex].GetRotation(); ResultPose[BoneIndex].SetRotation(LocalBlendQuat); ResultPose[BoneIndex].NormalizeRotation(); } } }
void FAnimationRuntime::ConvertPoseToAdditive(FCompactPose& TargetPose, const FCompactPose& BasePose) { for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) { FTransform& TargetTransform = TargetPose[BoneIndex]; const FTransform& BaseTransform = BasePose[BoneIndex]; TargetTransform.SetRotation(TargetTransform.GetRotation() * BaseTransform.GetRotation().Inverse()); TargetTransform.SetTranslation(TargetTransform.GetTranslation() - BaseTransform.GetTranslation()); TargetTransform.SetScale3D(TargetTransform.GetScale3D() * BaseTransform.GetSafeScaleReciprocal(BaseTransform.GetScale3D())); TargetTransform.NormalizeRotation(); } }
void UAnimSingleNodeInstance::InternalBlendSpaceEvaluatePose(class UBlendSpaceBase* BlendSpace, TArray<FBlendSampleData>& BlendSampleDataCache, FPoseContext& OutContext) { USkeletalMeshComponent* Component = GetSkelMeshComponent(); if (BlendSpace->IsValidAdditive()) { FCompactPose& OutPose = OutContext.Pose; FBlendedCurve& OutCurve = OutContext.Curve; FCompactPose AdditivePose; FBlendedCurve AdditiveCurve; AdditivePose.SetBoneContainer(&OutPose.GetBoneContainer()); AdditiveCurve.InitFrom(OutCurve); #if WITH_EDITORONLY_DATA if (BlendSpace->PreviewBasePose) { BlendSpace->PreviewBasePose->GetBonePose(/*out*/ OutPose, /*out*/OutCurve, FAnimExtractContext(PreviewPoseCurrentTime)); } else #endif // WITH_EDITORONLY_DATA { // otherwise, get ref pose OutPose.ResetToRefPose(); } BlendSpace->GetAnimationPose(BlendSampleDataCache, AdditivePose, AdditiveCurve); enum EAdditiveAnimationType AdditiveType = BlendSpace->bRotationBlendInMeshSpace? AAT_RotationOffsetMeshSpace : AAT_LocalSpaceBase; FAnimationRuntime::AccumulateAdditivePose(OutPose, AdditivePose, OutCurve, AdditiveCurve, 1.f, AdditiveType); } else { BlendSpace->GetAnimationPose(BlendSampleDataCache, OutContext.Pose, OutContext.Curve); } }
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 BlendPosePerBone(const TArray<int32>& PerBoneIndices, const FBlendSampleData& BlendSampleDataCache, FCompactPose& ResultPose, const FCompactPose& SourcePose) { const float BlendWeight = BlendSampleDataCache.GetWeight(); TArray<float> PerBoneBlends; for (int32 i = 0; i < BlendSampleDataCache.PerBoneBlendData.Num(); ++i) { PerBoneBlends.Add(FMath::Clamp<float>(BlendSampleDataCache.PerBoneBlendData[i], 0.f, 1.f)); } for (FCompactPoseBoneIndex BoneIndex : SourcePose.ForEachBoneIndex()) { int32 PerBoneIndex = PerBoneIndices[BoneIndex.GetInt()]; if (PerBoneIndex == INDEX_NONE || !BlendSampleDataCache.PerBoneBlendData.IsValidIndex(PerBoneIndex)) { BlendTransform<TRANSFORM_BLEND_MODE>(SourcePose[BoneIndex], ResultPose[BoneIndex], BlendWeight); } else { BlendTransform<TRANSFORM_BLEND_MODE>(SourcePose[BoneIndex], ResultPose[BoneIndex], PerBoneBlends[PerBoneIndex]); } } }
void FAnimationRuntime::BlendLocalPosesPerBoneWeights( FCompactPose& BasePose, const TArray<FCompactPose>& BlendPoses, struct FBlendedCurve& BaseCurve, const TArray<struct FBlendedCurve>& BlendedCurves, const TArray<FPerBoneBlendWeight> & BoneBlendWeights, ECurveBlendOption::Type CurveBlendOption, /*out*/ FCompactPose& OutPose, /*out*/ struct FBlendedCurve& OutCurve) { check(BasePose.GetNumBones() == BoneBlendWeights.Num()); int32 PoseNum = BlendPoses.Num(); TArray<float> MaxPoseWeights; MaxPoseWeights.AddZeroed(PoseNum); for (FCompactPoseBoneIndex BoneIndex : BasePose.ForEachBoneIndex()) { const int32 PoseIndex = BoneBlendWeights[BoneIndex.GetInt()].SourceIndex; const FTransform& BaseAtom = BasePose[BoneIndex]; const float BlendWeight = FMath::Clamp(BoneBlendWeights[BoneIndex.GetInt()].BlendWeight, 0.f, 1.f); MaxPoseWeights[PoseIndex] = FMath::Max(MaxPoseWeights[PoseIndex], BlendWeight); if (BlendWeight < ZERO_ANIMWEIGHT_THRESH) { OutPose[BoneIndex] = BaseAtom; } else if ((1.0 - BlendWeight) < ZERO_ANIMWEIGHT_THRESH) { OutPose[BoneIndex] = BlendPoses[PoseIndex][BoneIndex]; } else // we want blend here { FTransform BlendAtom = BaseAtom; const FTransform& TargetAtom = BlendPoses[PoseIndex][BoneIndex]; BlendAtom.BlendWith(TargetAtom, BlendWeight); OutPose[BoneIndex] = BlendAtom; } } // time to blend curves // the way we blend curve per bone // is to find out max weight per that pose, and then apply that weight to the curve { TArray<const FBlendedCurve*> SourceCurves; TArray<float> SourceWegihts; SourceCurves.SetNumUninitialized(PoseNum+1); SourceWegihts.SetNumUninitialized(PoseNum+1); SourceCurves[0] = &BaseCurve; SourceWegihts[0] = 1.f; for (int32 Idx=0; Idx<PoseNum; ++Idx) { SourceCurves[Idx+1] = &BlendedCurves[Idx]; SourceWegihts[Idx+1] = MaxPoseWeights[Idx]; } BlendCurves(SourceCurves, SourceWegihts, OutCurve, CurveBlendOption); } }
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(); }
void UDebugSkelMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* TickFunction) { // Run regular update first so we get RequiredBones up to date. Super::RefreshBoneTransforms(NULL); // Pass NULL so we force non threaded work const bool bIsPreviewInstance = (PreviewInstance && PreviewInstance == AnimScriptInstance); BakedAnimationPoses.Empty(); if(bDisplayBakedAnimation && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid()) { if(UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset)) { BakedAnimationPoses.AddUninitialized(PreviewInstance->RequiredBones.GetNumBones()); bool bSavedUseSourceData = AnimScriptInstance->RequiredBones.ShouldUseSourceData(); AnimScriptInstance->RequiredBones.SetUseRAWData(true); AnimScriptInstance->RequiredBones.SetUseSourceData(false); PreviewInstance->EnableControllers(false); GenSpaceBases(BakedAnimationPoses); AnimScriptInstance->RequiredBones.SetUseRAWData(false); AnimScriptInstance->RequiredBones.SetUseSourceData(bSavedUseSourceData); PreviewInstance->EnableControllers(true); } } SourceAnimationPoses.Empty(); if(bDisplaySourceAnimation && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid()) { if(UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset)) { SourceAnimationPoses.AddUninitialized(PreviewInstance->RequiredBones.GetNumBones()); bool bSavedUseSourceData = AnimScriptInstance->RequiredBones.ShouldUseSourceData(); AnimScriptInstance->RequiredBones.SetUseSourceData(true); PreviewInstance->EnableControllers(false); GenSpaceBases(SourceAnimationPoses); AnimScriptInstance->RequiredBones.SetUseSourceData(bSavedUseSourceData); PreviewInstance->EnableControllers(true); } } UncompressedSpaceBases.Empty(); if (bDisplayRawAnimation && AnimScriptInstance && AnimScriptInstance->RequiredBones.IsValid()) { UncompressedSpaceBases.AddUninitialized(AnimScriptInstance->RequiredBones.GetNumBones()); AnimScriptInstance->RequiredBones.SetUseRAWData(true); GenSpaceBases(UncompressedSpaceBases); AnimScriptInstance->RequiredBones.SetUseRAWData(false); } // Non retargeted pose. NonRetargetedSpaceBases.Empty(); if( bDisplayNonRetargetedPose && AnimScriptInstance && AnimScriptInstance->RequiredBones.IsValid() ) { NonRetargetedSpaceBases.AddUninitialized(AnimScriptInstance->RequiredBones.GetNumBones()); AnimScriptInstance->RequiredBones.SetDisableRetargeting(true); GenSpaceBases(NonRetargetedSpaceBases); AnimScriptInstance->RequiredBones.SetDisableRetargeting(false); } // Only works in PreviewInstance, and not for anim blueprint. This is intended. AdditiveBasePoses.Empty(); if( bDisplayAdditiveBasePose && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid() ) { if (UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset)) { if (Sequence->IsValidAdditive()) { FCSPose<FCompactPose> CSAdditiveBasePose; { FCompactPose AdditiveBasePose; FBlendedCurve AdditiveCurve(PreviewInstance); AdditiveBasePose.SetBoneContainer(&PreviewInstance->RequiredBones); Sequence->GetAdditiveBasePose(AdditiveBasePose, AdditiveCurve, FAnimExtractContext(PreviewInstance->CurrentTime)); CSAdditiveBasePose.InitPose(AdditiveBasePose); } for (int32 i = 0; i < AdditiveBasePoses.Num(); ++i) { FCompactPoseBoneIndex CompactIndex = PreviewInstance->RequiredBones.MakeCompactPoseIndex(FMeshPoseBoneIndex(i)); AdditiveBasePoses[i] = CSAdditiveBasePose.GetComponentSpaceTransform(CompactIndex); } } } } }
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); } else if (UAnimSequence* Sequence = Cast<UAnimSequence>(CurrentAsset)) { if (Sequence->IsValidAdditive()) { FAnimExtractContext ExtractionContext(CurrentTime, Sequence->bEnableRootMotion); Sequence->GetAdditiveBasePose(Output.Pose, Output.Curve, ExtractionContext); FCompactPose AdditivePose; FBlendedCurve AdditiveCurve; AdditivePose.SetBoneContainer(&Output.Pose.GetBoneContainer()); AdditiveCurve.InitFrom(Output.Curve); Sequence->GetAnimationPose(AdditivePose, AdditiveCurve, ExtractionContext); FAnimationRuntime::AccumulateAdditivePose(Output.Pose, AdditivePose, Output.Curve, AdditiveCurve, 1.f, Sequence->AdditiveAnimType); Output.Pose.NormalizeRotations(); } else { // if SkeletalMesh isn't there, we'll need to use skeleton Sequence->GetAnimationPose(Output.Pose, Output.Curve, FAnimExtractContext(CurrentTime, Sequence->bEnableRootMotion)); } } else if (UAnimComposite* Composite = Cast<UAnimComposite>(CurrentAsset)) { FAnimExtractContext ExtractionContext(CurrentTime, ShouldExtractRootMotion()); const FAnimTrack& AnimTrack = Composite->AnimationTrack; // find out if this is additive animation if (AnimTrack.IsAdditive()) { #if WITH_EDITORONLY_DATA if (Composite->PreviewBasePose) { Composite->PreviewBasePose->GetAdditiveBasePose(Output.Pose, Output.Curve, ExtractionContext); } else #endif { // get base pose - for now we only support ref pose as base Output.Pose.ResetToRefPose(); } EAdditiveAnimationType AdditiveAnimType = AnimTrack.IsRotationOffsetAdditive()? AAT_RotationOffsetMeshSpace : AAT_LocalSpaceBase; FCompactPose AdditivePose; FBlendedCurve AdditiveCurve; AdditivePose.SetBoneContainer(&Output.Pose.GetBoneContainer()); AdditiveCurve.InitFrom(Output.Curve); Composite->GetAnimationPose(AdditivePose, AdditiveCurve, ExtractionContext); FAnimationRuntime::AccumulateAdditivePose(Output.Pose, AdditivePose, Output.Curve, AdditiveCurve, 1.f, AdditiveAnimType); } else { //doesn't handle additive yet Composite->GetAnimationPose(Output.Pose, Output.Curve, ExtractionContext); } } 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) { FCompactPose SourcePose; FBlendedCurve SourceCurve; SourcePose.SetBoneContainer(&Output.Pose.GetBoneContainer()); SourceCurve.InitFrom(Output.Curve); 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, SourceCurve, FAnimExtractContext(CurrentTime)); } else #endif // WITH_EDITORONLY_DATA { SourcePose.ResetToRefPose(); } } else { SourcePose.ResetToRefPose(); } SlotEvaluatePose(Montage->SlotAnimTracks[0].SlotName, SourcePose, SourceCurve, Output.Pose, Output.Curve, 1.f); } } } if(CurrentVertexAnim != NULL) { VertexAnims.Add(FActiveVertexAnim(CurrentVertexAnim, 1.f, CurrentTime)); } return true; }