// Copyright Epic Games, Inc. All Rights Reserved. #include "HierarchyTableBlendProfile.h" #include "SkeletonHierarchyTableType.h" #include "HierarchyTableDefaultTypes.h" #include "MaskProfile/HierarchyTableTypeMask.h" void FBlendProfileStandaloneCachedData::UnpackCachedData() { CurveBlendWeights.Reserve(SerializedCurveBlendWeights.Num()); for (const FMaskedCurveWeightSerialised SerializedCurve : SerializedCurveBlendWeights) { CurveBlendWeights.Add(SerializedCurve.CurveName, SerializedCurve.Weight); } AttributeBlendWeights.Reserve(SerializedAttributeBlendWeights.Num()); for (const FMaskedAttributeWeightSerialised& SerializedAttribute : SerializedAttributeBlendWeights) { UE::Anim::FAttributeId AttributeId(SerializedAttribute.AttributeName, SerializedAttribute.AttributeIndex, SerializedAttribute.AttributeNamespace); AttributeBlendWeights.Add(FMaskedAttributeWeight(AttributeId, SerializedAttribute.Weight)); } } void FBlendProfileStandaloneCachedData::Init(TObjectPtr InHierarchyTable, const EBlendProfileMode InMode) { Mode = InMode; const FHierarchyTable_TableType_Skeleton& TableMetadata = InHierarchyTable->GetTableMetadata(); Skeleton = TableMetadata.Skeleton; const FReferenceSkeleton RefSkeleton = Skeleton->GetReferenceSkeleton(); const int32 BoneCount = RefSkeleton.GetNum(); BoneBlendWeights.Reserve(BoneCount); if (InHierarchyTable->IsElementType()) { for (int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex) { if (const FHierarchyTableEntryData* EntryData = InHierarchyTable->GetTableEntry(BoneIndex)) { BoneBlendWeights.Add(EntryData->GetValue()->Value); } else { BoneBlendWeights.Add(0.0f); } } } else if (InHierarchyTable->IsElementType()) { // Update bone weights for (int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex) { if (const FHierarchyTableEntryData* EntryData = InHierarchyTable->GetTableEntry(BoneIndex)) { BoneBlendWeights.Add(EntryData->GetValue()->Value); } else { BoneBlendWeights.Add(0.0f); } } // Update curve and attribute weights { CurveBlendWeights.Empty(); AttributeBlendWeights.Empty(); for (const FHierarchyTableEntryData& Entry : InHierarchyTable->GetTableData()) { if (Entry.TablePayload.Get().EntryType == ESkeletonHierarchyTable_TablePayloadEntryType::Curve) { const float EntryWeight = Entry.GetValue()->Value; CurveBlendWeights.Add({ Entry.Identifier, EntryWeight }); } else if (Entry.TablePayload.Get().EntryType == ESkeletonHierarchyTable_TablePayloadEntryType::Attribute) { const FHierarchyTableEntryData* ParentEntry = InHierarchyTable->GetTableEntry(Entry.Parent); check(ParentEntry && ParentEntry->GetMetadata().EntryType == ESkeletonHierarchyTable_TablePayloadEntryType::Bone); UE::Anim::FAttributeId Attribute(Entry.Identifier, Entry.Parent, TEXT("bone")); const float EntryWeight = Entry.GetValue()->Value; AttributeBlendWeights.Add(FMaskedAttributeWeight(Attribute, EntryWeight)); } } } } else { ensureMsgf(false, TEXT("Unsupported hierarchy table type, use Float or Mask element type instead")); for (int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex) { BoneBlendWeights.Add(1.0f); } } } TObjectPtr FBlendProfileStandaloneCachedData::GetSkeleton() const { return Skeleton; } const TArray& FBlendProfileStandaloneCachedData::GetBoneBlendWeights() const { return BoneBlendWeights; } const UE::Anim::TNamedValueArray& FBlendProfileStandaloneCachedData::GetCurveBlendWeights() const { return CurveBlendWeights; } const TArray& FBlendProfileStandaloneCachedData::GetAttributeBlendWeights() const { return AttributeBlendWeights; } void FBlendProfileStandaloneCachedData::ConstructBlendProfile(const TObjectPtr OutBlendProfile) const { OutBlendProfile->SetSkeleton(Skeleton); OutBlendProfile->Mode = Mode; for (int32 BoneIndex = 0; BoneIndex < BoneBlendWeights.Num(); ++BoneIndex) { const float BlendWeight = BoneBlendWeights[BoneIndex]; OutBlendProfile->SetBoneBlendScale(BoneIndex, BlendWeight, false /* bRecurse */, true /* bCreate */); } } void FBlendProfileStandaloneCachedData::Reset() { Skeleton = nullptr; BoneBlendWeights.Empty(); CurveBlendWeights.Empty(); AttributeBlendWeights.Empty(); } bool FBlendProfileStandaloneCachedData::IsValidBoneIndex(const int32 BoneIndex) const { return BoneBlendWeights.IsValidIndex(BoneIndex); } FHierarchyTableBlendProfile::FHierarchyTableBlendProfile(TObjectPtr InHierarchyTable, const EBlendProfileMode InMode) : Mode(InMode) { const FHierarchyTable_TableType_Skeleton& TableMetadata = InHierarchyTable->GetTableMetadata(); Skeleton = TableMetadata.Skeleton; const FReferenceSkeleton RefSkeleton = Skeleton->GetReferenceSkeleton(); const int32 BoneCount = RefSkeleton.GetNum(); BoneBlendWeights.Reserve(BoneCount); if (InHierarchyTable->IsElementType()) { for (int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex) { if (const FHierarchyTableEntryData* EntryData = InHierarchyTable->GetTableEntry(BoneIndex)) { BoneBlendWeights.Add(EntryData->GetValue()->Value); } else { BoneBlendWeights.Add(0.0f); } } } else if (InHierarchyTable->IsElementType()) { // Update bone weights for (int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex) { if (const FHierarchyTableEntryData* EntryData = InHierarchyTable->GetTableEntry(BoneIndex)) { BoneBlendWeights.Add(EntryData->GetValue()->Value); } else { BoneBlendWeights.Add(0.0f); } } // Update curve and attribute weights { CurveBlendWeights.Empty(); AttributeBlendWeights.Empty(); for (const FHierarchyTableEntryData& Entry : InHierarchyTable->GetTableData()) { if (Entry.TablePayload.Get().EntryType == ESkeletonHierarchyTable_TablePayloadEntryType::Curve) { const float EntryWeight = Entry.GetValue()->Value; CurveBlendWeights.Add({ Entry.Identifier, EntryWeight }); } else if (Entry.TablePayload.Get().EntryType == ESkeletonHierarchyTable_TablePayloadEntryType::Attribute) { const FHierarchyTableEntryData* ParentEntry = InHierarchyTable->GetTableEntry(Entry.Parent); check(ParentEntry && ParentEntry->GetMetadata().EntryType == ESkeletonHierarchyTable_TablePayloadEntryType::Bone); UE::Anim::FAttributeId Attribute(Entry.Identifier, Entry.Parent, TEXT("bone")); const float EntryWeight = Entry.GetValue()->Value; AttributeBlendWeights.Add(FMaskedAttributeWeight(Attribute, EntryWeight)); } } } } else { ensureMsgf(false, TEXT("Unsupported hierarchy table type, use Float or Mask element type instead")); for (int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex) { BoneBlendWeights.Add(1.0f); } } } FHierarchyTableBlendProfile::FHierarchyTableBlendProfile(const TObjectPtr InSkeleton, const EBlendProfileMode InMode) : Mode(InMode) { if (InSkeleton) { Skeleton = InSkeleton; const int32 BoneCount = Skeleton->GetReferenceSkeleton().GetNum(); BoneBlendWeights.SetNumZeroed(BoneCount); } else { Skeleton = nullptr; BoneBlendWeights.SetNumZeroed(0); } } float FHierarchyTableBlendProfile::GetBoneBlendScale(int32 InBoneIdx) const { return BoneBlendWeights[InBoneIdx]; } int32 FHierarchyTableBlendProfile::GetNumBlendEntries() const { return BoneBlendWeights.Num(); } int32 FHierarchyTableBlendProfile::GetPerBoneInterpolationIndex(const FCompactPoseBoneIndex& InCompactPoseBoneIndex, const FBoneContainer& BoneContainer, const IInterpolationIndexProvider::FPerBoneInterpolationData* Data) const { return InCompactPoseBoneIndex.GetInt(); } int32 FHierarchyTableBlendProfile::GetPerBoneInterpolationIndex(const FSkeletonPoseBoneIndex InSkeletonBoneIndex, const USkeleton* TargetSkeleton, const IInterpolationIndexProvider::FPerBoneInterpolationData* Data) const { return InSkeletonBoneIndex.GetInt(); } TObjectPtr FHierarchyTableBlendProfile::GetSkeleton() const { return Skeleton; } const UE::Anim::TNamedValueArray& FHierarchyTableBlendProfile::GetCurveBlendWeights() const { return CurveBlendWeights; } const TArray& FHierarchyTableBlendProfile::GetAttributeBlendWeights() const { return AttributeBlendWeights; } EBlendProfileMode FHierarchyTableBlendProfile::GetMode() const { return Mode; } void FHierarchyTableBlendProfile::ConstructBlendProfile(const TObjectPtr OutBlendProfile) const { OutBlendProfile->SetSkeleton(Skeleton); OutBlendProfile->Mode = Mode; for (int32 BoneIndex = 0; BoneIndex < BoneBlendWeights.Num(); ++BoneIndex) { const float BlendWeight = BoneBlendWeights[BoneIndex]; OutBlendProfile->SetBoneBlendScale(BoneIndex, BlendWeight, false /* bRecurse */, true /* bCreate */); } } bool FHierarchyTableBlendProfile::IsValidBoneIndex(const int32 BoneIndex) const { return BoneBlendWeights.IsValidIndex(BoneIndex); }