bool UBlendSpaceBase::ValidateSampleInput(FBlendSample & BlendSample, int32 OriginalIndex) const { // make sure we get same kinds of samples(additive or nonadditive) if (SampleData.Num() > 0 && BlendSample.Animation) { if (IsValidAdditive() != (BlendSample.Animation->IsValidAdditive())) { UE_LOG(LogAnimation, Log, TEXT("Adding sample failed. Please add same kinds of sequence (additive/non-additive).")); return false; } } const USkeleton* MySkeleton = GetSkeleton(); if (BlendSample.Animation && (! MySkeleton || ! BlendSample.Animation->GetSkeleton()->IsCompatible(MySkeleton))) { UE_LOG(LogAnimation, Log, TEXT("Adding sample failed. Please add same kinds of sequence (additive/non-additive).")); return false; } SnapToBorder(BlendSample); // make sure blendsample is within the parameter range BlendSample.SampleValue = ClampBlendInput(BlendSample.SampleValue); if (IsTooCloseToExistingSamplePoint(BlendSample.SampleValue, OriginalIndex)) { UE_LOG(LogAnimation, Log, TEXT("Adding sample failed. Too close to existing sample point.")); return false; } return true; }
bool UBlendSpaceBase::EditSample(const FBlendSample& BlendSample, FVector& NewValue) { int32 NewIndex = SampleData.Find(BlendSample); if (NewIndex!=INDEX_NONE) { // edit is more work when we check if there is duplicate, so // just delete old one, and add new one, // when add it will verify if it isn't duplicate FBlendSample NewSample = BlendSample; NewSample.SampleValue = NewValue; if ( ValidateSampleInput(NewSample, NewIndex) == false ) { return false; } SampleData[NewIndex] = NewSample; #if WITH_EDITORONLY_DATA // fill upt PreviewBasePose if it does not set yet if ( IsValidAdditive() ) { if ( PreviewBasePose == NULL && NewSample.Animation ) { PreviewBasePose = NewSample.Animation->RefPoseSeq; } } // if not additive, clear pose else if ( PreviewBasePose ) { PreviewBasePose = NULL; } #endif // WITH_EDITORONLY_DATA // copy back the sample value, so it can display in the correct position NewValue = NewSample.SampleValue; MarkPackageDirty(); return true; } return false; }
void UAnimMontage::PostLoad() { Super::PostLoad(); // copy deprecated variable to new one, temporary code to keep data copied. Am deleting it right after this for ( auto SlotIter = SlotAnimTracks.CreateIterator() ; SlotIter ; ++SlotIter) { FAnimTrack & Track = (*SlotIter).AnimTrack; for ( auto SegIter = Track.AnimSegments.CreateIterator() ; SegIter ; ++SegIter ) { FAnimSegment & Segment = (*SegIter); if ( Segment.AnimStartOffset_DEPRECATED!=0.f ) { Segment.AnimStartTime = Segment.AnimStartOffset_DEPRECATED; Segment.AnimStartOffset_DEPRECATED = 0.f; } if ( Segment.AnimEndOffset_DEPRECATED!=0.f ) { Segment.AnimEndTime = Segment.AnimEndOffset_DEPRECATED; Segment.AnimEndOffset_DEPRECATED = 0.f; } } } for ( auto CompositeIter = CompositeSections.CreateIterator(); CompositeIter; ++CompositeIter ) { FCompositeSection & Composite = (*CompositeIter); if (Composite.StarTime_DEPRECATED!=0.f) { Composite.StartTime = Composite.StarTime_DEPRECATED; Composite.StarTime_DEPRECATED = 0.f; } } SortAnimBranchingPointByTime(); // find preview base pose if it can #if WITH_EDITORONLY_DATA if ( IsValidAdditive() && PreviewBasePose == NULL ) { for (int32 I=0; I<SlotAnimTracks.Num(); ++I) { if ( SlotAnimTracks[I].AnimTrack.AnimSegments.Num() > 0 ) { UAnimSequence * Sequence = Cast<UAnimSequence>(SlotAnimTracks[I].AnimTrack.AnimSegments[0].AnimReference); if ( Sequence && Sequence->RefPoseSeq ) { PreviewBasePose = Sequence->RefPoseSeq; MarkPackageDirty(); break; } } } } // verify if skeleton matches, otherwise clear it, this can happen if anim sequence has been modified when this hasn't been loaded. USkeleton* MySkeleton = GetSkeleton(); for (int32 I=0; I<SlotAnimTracks.Num(); ++I) { if ( SlotAnimTracks[I].AnimTrack.AnimSegments.Num() > 0 ) { UAnimSequence * Sequence = Cast<UAnimSequence>(SlotAnimTracks[I].AnimTrack.AnimSegments[0].AnimReference); if ( Sequence && Sequence->GetSkeleton() != MySkeleton ) { SlotAnimTracks[I].AnimTrack.AnimSegments[0].AnimReference = 0; MarkPackageDirty(); break; } } } #endif // WITH_EDITORONLY_DATA }
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(); }