//@Todo curve flags won't transfer over - it only overwritees void FBlendedCurve::Blend(const FBlendedCurve& A, const FBlendedCurve& B, float Alpha) { check(A.Num()==B.Num()); if(FMath::Abs(Alpha) <= ZERO_ANIMWEIGHT_THRESH) { // if blend is all the way for child1, then just copy its bone atoms Override(A); } else if(FMath::Abs(Alpha - 1.0f) <= ZERO_ANIMWEIGHT_THRESH) { // if blend is all the way for child2, then just copy its bone atoms Override(B); } else { InitFrom(A); for(int32 CurveId=0; CurveId<A.Elements.Num(); ++CurveId) { Elements[CurveId].Value = FMath::Lerp(A.Elements[CurveId].Value, B.Elements[CurveId].Value, Alpha); Elements[CurveId].Flags |= (A.Elements[CurveId].Flags | B.Elements[CurveId].Flags); } } ValidateCurve(this); }
void UAnimComposite::GetAnimationPose(FCompactPose& OutPose, FBlendedCurve& OutCurve, const FAnimExtractContext& ExtractionContext) const { AnimationTrack.GetAnimationPose(OutPose, OutCurve, ExtractionContext); FBlendedCurve CompositeCurve; CompositeCurve.InitFrom(OutCurve); EvaluateCurveData(CompositeCurve, ExtractionContext.CurrentTime); // combine both curve OutCurve.Combine(CompositeCurve); }
FORCEINLINE void BlendCurves(const TArray<const FBlendedCurve*>& SourceCurves, const TArray<float>& SourceWeights, FBlendedCurve& OutCurve) { if(SourceCurves.Num() > 0) { OutCurve.Override(*SourceCurves[0], SourceWeights[0]); for(int32 CurveIndex=1; CurveIndex<SourceCurves.Num(); ++CurveIndex) { OutCurve.Accumulate(*SourceCurves[CurveIndex], SourceWeights[CurveIndex]); } } }
void FRawCurveTracks::EvaluateCurveData( FBlendedCurve& Curves, float CurrentTime ) const { // evaluate the curve data at the CurrentTime and add to Instance for(auto CurveIter = FloatCurves.CreateConstIterator(); CurveIter; ++CurveIter) { const FFloatCurve& Curve = *CurveIter; Curves.Set(Curve.CurveUid, Curve.Evaluate(CurrentTime), Curve.GetCurveTypeFlags()); } }
FORCEINLINE void BlendCurves(const TArray<const FBlendedCurve*>& SourceCurves, const TArray<float>& SourceWeights, FBlendedCurve& OutCurve, ECurveBlendOption::Type BlendOption) { if(SourceCurves.Num() > 0) { if (BlendOption == ECurveBlendOption::Type::BlendByWeight) { BlendCurves(SourceCurves, SourceWeights, OutCurve); } else if (BlendOption == ECurveBlendOption::Type::NormalizeByWeight) { float SumOfWeight = 0.f; for (const auto& Weight : SourceWeights) { SumOfWeight += Weight; } if (SumOfWeight > ZERO_ANIMWEIGHT_THRESH) { TArray<float> NormalizeSourceWeights; NormalizeSourceWeights.AddUninitialized(SourceWeights.Num()); for(int32 Idx=0; Idx<SourceWeights.Num(); ++Idx) { NormalizeSourceWeights[Idx] = SourceWeights[Idx] / SumOfWeight; } BlendCurves(SourceCurves, NormalizeSourceWeights, OutCurve); } else { BlendCurves(SourceCurves, SourceWeights, OutCurve); } } else { OutCurve.Override(*SourceCurves[0], SourceWeights[0]); for(int32 CurveIndex=1; CurveIndex<SourceCurves.Num(); ++CurveIndex) { OutCurve.Combine(*SourceCurves[CurveIndex]); } } } }
void FBlendedCurve::ConvertToAdditive(const FBlendedCurve& BaseCurve) { check(bInitialized); check(Num()==BaseCurve.Num()); for(int32 CurveId=0; CurveId<Elements.Num(); ++CurveId) { Elements[CurveId].Value -= BaseCurve.Elements[CurveId].Value; Elements[CurveId].Flags |= BaseCurve.Elements[CurveId].Flags; } ValidateCurve(this); }
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 FBlendedCurve::Accumulate(const FBlendedCurve& AdditiveCurve, float Weight) { check(bInitialized); check(Num()==AdditiveCurve.Num()); if (Weight > ZERO_ANIMWEIGHT_THRESH) { for(int32 CurveId=0; CurveId<Elements.Num(); ++CurveId) { Elements[CurveId].Value += AdditiveCurve.Elements[CurveId].Value * Weight; Elements[CurveId].Flags |= AdditiveCurve.Elements[CurveId].Flags; } } ValidateCurve(this); }
void FBlendedCurve::Combine(const FBlendedCurve& CurveToCombine) { check(bInitialized); check(Num()==CurveToCombine.Num()); for(int32 CurveId=0; CurveId<CurveToCombine.Elements.Num(); ++CurveId) { // if target value is non zero, we accpet target's value // originally this code was doing max, but that doesn't make sense since the values can be negative // we could try to pick non-zero, but if target value is non-zero, I think we should accept that value // if source is non zero, it will be overriden if (CurveToCombine.Elements[CurveId].Value != 0.f) { Elements[CurveId].Value = CurveToCombine.Elements[CurveId].Value; } Elements[CurveId].Flags |= CurveToCombine.Elements[CurveId].Flags; } ValidateCurve(this); }
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; }