2021-08-07 09:38:59 +00:00
|
|
|
|
// Copyright 2017-2021 Rexocrates. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "MASFunctionLibrary.h"
|
|
|
|
|
|
|
|
|
|
#include "MirrorTable.h"
|
|
|
|
|
|
|
|
|
|
#include "Animation/AnimSequence.h"
|
|
|
|
|
|
|
|
|
|
#include "Misc/PackageName.h"
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
#include "AssetToolsModule.h"
|
2024-12-04 00:49:59 +00:00
|
|
|
|
#include "AssetRegistry/AssetRegistryModule.h"
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
#include "Framework/Notifications/NotificationManager.h"
|
|
|
|
|
#include "Widgets/Notifications/SNotificationList.h"
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "MASUtils.h"
|
|
|
|
|
#include "AnimationRuntime.h"
|
|
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "MASLibrary"
|
|
|
|
|
|
|
|
|
|
UMASFunctionLibrary::UMASFunctionLibrary(const FObjectInitializer& ObjectInitializer)
|
|
|
|
|
: Super(ObjectInitializer)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
void UMASFunctionLibrary::BulkMirrorEditorOnly(const TArray<UAnimSequence*> SourceAnims,
|
|
|
|
|
const UMirrorTable* MirrorTable, TArray<UAnimSequence*>& OutNewAnims)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if (SourceAnims.Num() == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (MirrorTable == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
|
|
|
|
|
|
|
|
|
|
for (int32 i = 0; i < SourceAnims.Num(); i++)
|
|
|
|
|
{
|
|
|
|
|
// Create the asset
|
|
|
|
|
FString Name;
|
|
|
|
|
FString PackageName;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FString Suffix = TEXT("_Mirrored");
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
AssetToolsModule.Get().CreateUniqueAssetName(SourceAnims[i]->GetOutermost()->GetName(), Suffix, /*out*/
|
|
|
|
|
PackageName, /*out*/ Name);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
const FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UObject* NewAsset = AssetToolsModule.Get().DuplicateAsset(Name, PackagePath, SourceAnims[i]);
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if (NewAsset != nullptr)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
|
|
|
|
UAnimSequence* MirrorAnimSequence = Cast<UAnimSequence>(NewAsset);
|
|
|
|
|
CreateMirrorSequenceFromAnimSequence(MirrorAnimSequence, MirrorTable);
|
|
|
|
|
|
|
|
|
|
OutNewAnims.Add(MirrorAnimSequence);
|
|
|
|
|
|
|
|
|
|
// Notify asset registry of new asset
|
|
|
|
|
FAssetRegistryModule::AssetCreated(MirrorAnimSequence);
|
|
|
|
|
|
|
|
|
|
// Display notification so users can quickly access
|
|
|
|
|
if (GIsEditor)
|
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
FNotificationInfo Info(FText::Format(
|
|
|
|
|
LOCTEXT("AnimationMirrored", "Successfully Mirrored Animation"),
|
|
|
|
|
FText::FromString(MirrorAnimSequence->GetName())));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
Info.ExpireDuration = 8.0f;
|
|
|
|
|
Info.bUseLargeFont = false;
|
|
|
|
|
//Info.Hyperlink = FSimpleDelegate::CreateLambda([=]() { FAssetEditorManager::Get().OpenEditorForAssets(TArray<UObject*>({ MirrorAnimSequence })); });
|
2025-02-07 14:04:52 +00:00
|
|
|
|
Info.Hyperlink = FSimpleDelegate::CreateLambda([=]()
|
|
|
|
|
{
|
|
|
|
|
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAssets(TArray<UObject*>({
|
|
|
|
|
MirrorAnimSequence
|
|
|
|
|
}));
|
|
|
|
|
});
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
Info.HyperlinkText = FText::Format(
|
|
|
|
|
LOCTEXT("OpenNewAnimationHyperlink", "Open {0}"), FText::FromString(MirrorAnimSequence->GetName()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TSharedPtr<SNotificationItem> Notification = FSlateNotificationManager::Get().AddNotification(Info);
|
|
|
|
|
if (Notification.IsValid())
|
|
|
|
|
{
|
|
|
|
|
Notification->SetCompletionState(SNotificationItem::CS_Success);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIRRORANIMATIONSYSTEMDEV_API void UMASFunctionLibrary::BulkMirror_CS_EditorOnly(
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const TArray<UAnimSequence*> SourceAnims,
|
|
|
|
|
const TEnumAsByte<EAxis::Type> MirrorAxis, const FString Substring_A, const FString Substring_B,
|
|
|
|
|
const bool Symmetrical, TArray<UAnimSequence*>& OutNewAnims)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if (SourceAnims.Num() == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (MirrorAxis == EAxis::None)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
|
|
|
|
|
|
|
|
|
|
for (int32 i = 0; i < SourceAnims.Num(); i++)
|
|
|
|
|
{
|
|
|
|
|
// Create the asset
|
|
|
|
|
FString Name;
|
|
|
|
|
FString PackageName;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FString Suffix = TEXT("_Mirrored");
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
AssetToolsModule.Get().CreateUniqueAssetName(SourceAnims[i]->GetOutermost()->GetName(), Suffix, /*out*/
|
|
|
|
|
PackageName, /*out*/ Name);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
const FString PackagePath = FPackageName::GetLongPackagePath(PackageName);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UObject* NewAsset = AssetToolsModule.Get().DuplicateAsset(Name, PackagePath, SourceAnims[i]);
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if (NewAsset != nullptr)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
|
|
|
|
UAnimSequence* MirrorAnimSequence = Cast<UAnimSequence>(NewAsset);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
CreateMirrorSequenceFromAnimSequence_CS(MirrorAnimSequence, MirrorAxis, Substring_A, Substring_B,
|
|
|
|
|
Symmetrical);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
OutNewAnims.Add(MirrorAnimSequence);
|
|
|
|
|
|
|
|
|
|
// Notify asset registry of new asset
|
|
|
|
|
FAssetRegistryModule::AssetCreated(MirrorAnimSequence);
|
|
|
|
|
|
|
|
|
|
// Display notification so users can quickly access
|
|
|
|
|
if (GIsEditor)
|
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
FNotificationInfo Info(FText::Format(
|
|
|
|
|
LOCTEXT("AnimationMirrored", "Successfully Mirrored Animation"),
|
|
|
|
|
FText::FromString(MirrorAnimSequence->GetName())));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
Info.ExpireDuration = 8.0f;
|
|
|
|
|
Info.bUseLargeFont = false;
|
|
|
|
|
//Info.Hyperlink = FSimpleDelegate::CreateLambda([=]() { FAssetEditorManager::Get().OpenEditorForAssets(TArray<UObject*>({ MirrorAnimSequence })); });
|
2025-02-07 14:04:52 +00:00
|
|
|
|
Info.Hyperlink = FSimpleDelegate::CreateLambda([=]()
|
|
|
|
|
{
|
|
|
|
|
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAssets(TArray<UObject*>({
|
|
|
|
|
MirrorAnimSequence
|
|
|
|
|
}));
|
|
|
|
|
});
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
Info.HyperlinkText = FText::Format(
|
|
|
|
|
LOCTEXT("OpenNewAnimationHyperlink", "Open {0}"), FText::FromString(MirrorAnimSequence->GetName()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TSharedPtr<SNotificationItem> Notification = FSlateNotificationManager::Get().AddNotification(Info);
|
|
|
|
|
if (Notification.IsValid())
|
|
|
|
|
{
|
|
|
|
|
Notification->SetCompletionState(SNotificationItem::CS_Success);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
void UMASFunctionLibrary::CreateMirrorSequenceFromAnimSequence(UAnimSequence* MirrorSequence,
|
|
|
|
|
const UMirrorTable* MirrorTable)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
|
|
|
|
//Check if it's valid
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if ((MirrorSequence != nullptr) && (MirrorTable != nullptr) && (MirrorSequence->GetSkeleton() != nullptr))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
|
|
|
|
//Make the duplicate that I will edit
|
|
|
|
|
//UAnimSequence* MirrorSequence = FromAnimSequence;
|
|
|
|
|
const auto& Skel = MirrorSequence->GetSkeleton()->GetReferenceSkeleton();
|
|
|
|
|
|
|
|
|
|
int NumMirrorBones = MirrorTable->MirrorBones.Num();
|
|
|
|
|
|
|
|
|
|
int NumFrames = MirrorSequence->GetNumberOfFrames();
|
2024-12-04 00:49:59 +00:00
|
|
|
|
IAnimationDataController& MirrorSequenceController = MirrorSequence->GetController();
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const TArray<FBoneAnimationTrack>& SourceBoneAnimData = MirrorSequenceController.GetModel()->
|
|
|
|
|
GetBoneAnimationTracks();
|
2024-12-04 00:49:59 +00:00
|
|
|
|
/************* SourceRawAnimDatas should be replaced by SourceBoneAnimData ************/
|
|
|
|
|
// TArray<FRawAnimSequenceTrack> SourceRawAnimDatas = MirrorSequence->GetRawAnimationData();
|
2025-02-07 14:04:52 +00:00
|
|
|
|
|
|
|
|
|
TArray<FName>* TrackNames = new TArray<FName>;
|
|
|
|
|
MirrorSequenceController.GetModel()->GetBoneTrackNames(*TrackNames);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 0; i < NumMirrorBones; i++)
|
|
|
|
|
{
|
|
|
|
|
FMirrorBone CurrentBone = MirrorTable->MirrorBones[i];
|
|
|
|
|
|
|
|
|
|
if (Skel.FindBoneIndex(CurrentBone.BoneName) == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CurrentBone.IsTwinBone)
|
|
|
|
|
{
|
|
|
|
|
if (Skel.FindBoneIndex(CurrentBone.TwinBoneName) == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
int32 TrackIndex = TrackNames->IndexOfByKey(CurrentBone.BoneName);
|
|
|
|
|
int32 TwinTrackIndex = TrackNames->IndexOfByKey(CurrentBone.TwinBoneName);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
if (TrackIndex == INDEX_NONE && TwinTrackIndex == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
TArray<FVector3f> MirrorPosKeys;
|
|
|
|
|
TArray<FQuat4f> MirrorRotKeys;
|
|
|
|
|
TArray<FVector3f> MirrorScaleKeys;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
TArray<FVector3f> TwinMirrorPosKeys;
|
|
|
|
|
TArray<FQuat4f> TwinMirrorRotKeys;
|
|
|
|
|
TArray<FVector3f> TwinMirrorScaleKeys;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
// Original Bone
|
|
|
|
|
if (TrackIndex != INDEX_NONE)
|
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
check(SourceBoneAnimData.Num()>0);
|
2024-12-04 00:49:59 +00:00
|
|
|
|
auto& MirroredRawTrack = SourceBoneAnimData[TrackIndex];
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
for (int u = 0; u < NumFrames; u++)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f MirrorTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
bool bSetPos = false;
|
|
|
|
|
bool bSetRot = false;
|
|
|
|
|
bool bSetScale = false;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (MirroredRawTrack.InternalTrackData.PosKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetTranslation(MirroredRawTrack.InternalTrackData.PosKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
bSetPos = true;
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (MirroredRawTrack.InternalTrackData.RotKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetRotation(MirroredRawTrack.InternalTrackData.RotKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
bSetRot = true;
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (MirroredRawTrack.InternalTrackData.ScaleKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetScale3D(MirroredRawTrack.InternalTrackData.ScaleKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
bSetScale = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MirrorTM.Mirror(CurrentBone.MirrorAxis, CurrentBone.FlipAxis);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FRotator3f BoneNewRotation = MirrorTM.Rotator(); // quaternion to rotator
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
BoneNewRotation.Yaw += CurrentBone.RotationOffset.Yaw;
|
|
|
|
|
BoneNewRotation.Roll += CurrentBone.RotationOffset.Roll;
|
|
|
|
|
BoneNewRotation.Pitch += CurrentBone.RotationOffset.Pitch;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetRotation(BoneNewRotation.Quaternion());
|
2021-08-07 09:38:59 +00:00
|
|
|
|
MirrorTM.SetScale3D(MirrorTM.GetScale3D().GetAbs());
|
|
|
|
|
MirrorTM.NormalizeRotation();
|
|
|
|
|
|
|
|
|
|
if (bSetPos)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorPosKeys.Add(FVector3f(MirrorTM.GetTranslation()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
if (bSetRot)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorRotKeys.Add(FQuat4f(MirrorTM.GetRotation()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
if (bSetScale)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorScaleKeys.Add(FVector3f(MirrorTM.GetScale3D()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto RefTM = Skel.GetRefBonePose()[Skel.FindBoneIndex(CurrentBone.BoneName)];
|
|
|
|
|
|
|
|
|
|
RefTM.Mirror(CurrentBone.MirrorAxis, CurrentBone.FlipAxis);
|
|
|
|
|
|
|
|
|
|
FRotator BoneNewRotation = RefTM.Rotator();
|
|
|
|
|
|
|
|
|
|
BoneNewRotation.Yaw += CurrentBone.RotationOffset.Yaw;
|
|
|
|
|
BoneNewRotation.Roll += CurrentBone.RotationOffset.Roll;
|
|
|
|
|
BoneNewRotation.Pitch += CurrentBone.RotationOffset.Pitch;
|
|
|
|
|
|
|
|
|
|
RefTM.SetRotation(FQuat(BoneNewRotation));
|
|
|
|
|
RefTM.SetScale3D(RefTM.GetScale3D().GetAbs());
|
|
|
|
|
RefTM.NormalizeRotation();
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorPosKeys.Add(FVector3f(RefTM.GetTranslation()));
|
|
|
|
|
MirrorRotKeys.Add(FQuat4f(RefTM.GetRotation()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Twin Bone
|
|
|
|
|
if (TwinTrackIndex != INDEX_NONE)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
auto& TwinMirroredRawTrack = SourceBoneAnimData[TwinTrackIndex];
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
for (int u = 0; u < NumFrames; u++)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f TwinMirrorTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
bool TwinbSetPos = false;
|
|
|
|
|
bool TwinbSetRot = false;
|
|
|
|
|
bool TwinbSetScale = false;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (TwinMirroredRawTrack.InternalTrackData.PosKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorTM.SetTranslation(TwinMirroredRawTrack.InternalTrackData.PosKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TwinbSetPos = true;
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (TwinMirroredRawTrack.InternalTrackData.RotKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorTM.SetRotation(TwinMirroredRawTrack.InternalTrackData.RotKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TwinbSetRot = true;
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (TwinMirroredRawTrack.InternalTrackData.ScaleKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorTM.SetScale3D(TwinMirroredRawTrack.InternalTrackData.ScaleKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TwinbSetScale = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TwinMirrorTM.Mirror(CurrentBone.MirrorAxis, CurrentBone.FlipAxis);
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FRotator3f TwinBoneNewRotation = TwinMirrorTM.Rotator();
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
TwinBoneNewRotation.Yaw += CurrentBone.RotationOffset.Yaw;
|
|
|
|
|
TwinBoneNewRotation.Roll += CurrentBone.RotationOffset.Roll;
|
|
|
|
|
TwinBoneNewRotation.Pitch += CurrentBone.RotationOffset.Pitch;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorTM.SetRotation(TwinBoneNewRotation.Quaternion());
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TwinMirrorTM.SetScale3D(TwinMirrorTM.GetScale3D().GetAbs());
|
|
|
|
|
TwinMirrorTM.NormalizeRotation();
|
|
|
|
|
|
|
|
|
|
if (TwinbSetPos)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorPosKeys.Add(FVector3f(TwinMirrorTM.GetTranslation()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
if (TwinbSetRot)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorRotKeys.Add(FQuat4f(TwinMirrorTM.GetRotation()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
if (TwinbSetScale)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorScaleKeys.Add(FVector3f(TwinMirrorTM.GetScale3D()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
auto RefTM = Skel.GetRefBonePose()[Skel.FindBoneIndex(CurrentBone.TwinBoneName)];
|
|
|
|
|
|
|
|
|
|
RefTM.Mirror(CurrentBone.MirrorAxis, CurrentBone.FlipAxis);
|
|
|
|
|
|
|
|
|
|
FRotator TwinBoneNewRotation = RefTM.Rotator();
|
|
|
|
|
|
|
|
|
|
TwinBoneNewRotation.Yaw += CurrentBone.RotationOffset.Yaw;
|
|
|
|
|
TwinBoneNewRotation.Roll += CurrentBone.RotationOffset.Roll;
|
|
|
|
|
TwinBoneNewRotation.Pitch += CurrentBone.RotationOffset.Pitch;
|
|
|
|
|
|
|
|
|
|
RefTM.SetRotation(FQuat(TwinBoneNewRotation));
|
|
|
|
|
RefTM.SetScale3D(RefTM.GetScale3D().GetAbs());
|
|
|
|
|
RefTM.NormalizeRotation();
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
TwinMirrorPosKeys.Add(FVector3f(RefTM.GetTranslation()));
|
|
|
|
|
TwinMirrorRotKeys.Add(FQuat4f(RefTM.GetRotation()));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Original Bone -> Twin Bone
|
|
|
|
|
{
|
|
|
|
|
FRawAnimSequenceTrack NewTrack;
|
|
|
|
|
|
|
|
|
|
NewTrack.PosKeys = CurrentBone.MirrorTranslation ? MirrorPosKeys : TwinMirrorPosKeys;
|
|
|
|
|
NewTrack.RotKeys = MirrorRotKeys;
|
|
|
|
|
NewTrack.ScaleKeys = MirrorScaleKeys;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
//MirrorSequence->AddNewRawTrack(CurrentBone.TwinBoneName, &NewTrack);
|
|
|
|
|
MirrorSequenceController.AddBoneTrack(CurrentBone.TwinBoneName);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
MirrorSequenceController.SetBoneTrackKeys(CurrentBone.BoneName, NewTrack.PosKeys, NewTrack.RotKeys,
|
|
|
|
|
NewTrack.ScaleKeys);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Twin Bone -> Original Bone
|
|
|
|
|
{
|
|
|
|
|
FRawAnimSequenceTrack NewTrack;
|
|
|
|
|
|
|
|
|
|
NewTrack.PosKeys = CurrentBone.MirrorTranslation ? TwinMirrorPosKeys : MirrorPosKeys;
|
|
|
|
|
NewTrack.RotKeys = TwinMirrorRotKeys;
|
|
|
|
|
NewTrack.ScaleKeys = TwinMirrorScaleKeys;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorSequenceController.AddBoneTrack(CurrentBone.BoneName);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
MirrorSequenceController.SetBoneTrackKeys(CurrentBone.BoneName, NewTrack.PosKeys, NewTrack.RotKeys,
|
|
|
|
|
NewTrack.ScaleKeys);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if (TrackNames) { continue; }
|
|
|
|
|
int32 TrackIndex = TrackNames->IndexOfByKey(CurrentBone.BoneName);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
if (TrackIndex == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FBoneAnimationTrack MirroredRawTrack = SourceBoneAnimData[TrackIndex];
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
//MirrorAllFrames
|
2025-02-07 14:04:52 +00:00
|
|
|
|
TArray<FVector3f> MirrorPosKeys;
|
|
|
|
|
TArray<FQuat4f> MirrorRotKeys;
|
|
|
|
|
TArray<FVector3f> MirrorScaleKeys;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
for (int u = 0; u < NumFrames; u++)
|
|
|
|
|
{
|
|
|
|
|
//Mirror Transform
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f MirrorTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
bool bSetPos = false;
|
|
|
|
|
bool bSetRot = false;
|
|
|
|
|
bool bSetScale = false;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (MirroredRawTrack.InternalTrackData.PosKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetTranslation(MirroredRawTrack.InternalTrackData.PosKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
bSetPos = true;
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (MirroredRawTrack.InternalTrackData.RotKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetRotation(MirroredRawTrack.InternalTrackData.RotKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
bSetRot = true;
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
if (MirroredRawTrack.InternalTrackData.ScaleKeys.IsValidIndex(u))
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetScale3D(MirroredRawTrack.InternalTrackData.ScaleKeys[u]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
bSetScale = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MirrorTM.Mirror(CurrentBone.MirrorAxis, CurrentBone.FlipAxis);
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FRotator3f BoneNewRotation = MirrorTM.Rotator();
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
BoneNewRotation.Yaw += CurrentBone.RotationOffset.Yaw;
|
|
|
|
|
BoneNewRotation.Roll += CurrentBone.RotationOffset.Roll;
|
|
|
|
|
BoneNewRotation.Pitch += CurrentBone.RotationOffset.Pitch;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrorTM.SetRotation(BoneNewRotation.Quaternion());
|
2021-08-07 09:38:59 +00:00
|
|
|
|
//MirrorTM.NormalizeRotation();
|
|
|
|
|
MirrorTM.SetScale3D(MirrorTM.GetScale3D().GetAbs());
|
|
|
|
|
|
|
|
|
|
MirrorTM.NormalizeRotation();
|
|
|
|
|
|
|
|
|
|
//Setting it up Main
|
|
|
|
|
if (bSetPos)
|
|
|
|
|
{
|
|
|
|
|
MirrorPosKeys.Add(MirrorTM.GetTranslation());
|
|
|
|
|
}
|
|
|
|
|
if (bSetRot)
|
|
|
|
|
{
|
|
|
|
|
MirrorRotKeys.Add(MirrorTM.GetRotation());
|
|
|
|
|
}
|
|
|
|
|
if (bSetScale)
|
|
|
|
|
{
|
|
|
|
|
MirrorScaleKeys.Add(MirrorTM.GetScale3D());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirroredRawTrack.InternalTrackData.PosKeys = MirrorPosKeys;
|
|
|
|
|
MirroredRawTrack.InternalTrackData.RotKeys = MirrorRotKeys;
|
|
|
|
|
MirroredRawTrack.InternalTrackData.ScaleKeys = MirrorScaleKeys;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
//Finally Setting it in the AnimSequence
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
//MirrorSequenceController.AddBoneTrack(CurrentBone.BoneName, &MirroredRawTrack);
|
|
|
|
|
MirrorSequenceController.AddBoneCurve(CurrentBone.BoneName);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
MirrorSequenceController.SetBoneTrackKeys(CurrentBone.BoneName,
|
|
|
|
|
MirroredRawTrack.InternalTrackData.PosKeys,
|
|
|
|
|
MirroredRawTrack.InternalTrackData.RotKeys,
|
|
|
|
|
MirroredRawTrack.InternalTrackData.ScaleKeys);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
//MirrorSequence->ClearBakedTransformData();
|
|
|
|
|
MirrorSequenceController.RemoveAllCurvesOfType(ERawCurveTrackTypes::RCT_Transform);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
MirrorSequence->MarkPackageDirty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
static FTransform3f GetAnimBoneTM(UAnimSequence* AnimSeq, const int32 BoneTreeIndex, const float AnimTime)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
|
|
|
|
USkeleton* Skeleton = AnimSeq->GetSkeleton();
|
|
|
|
|
//int32 BoneTreeIndex = Skeleton->GetSkeletonBoneIndexFromMeshBoneIndex(SkelMesh, BoneTreeIndex);
|
|
|
|
|
int32 BoneTrackIndex = Skeleton->GetRawAnimationTrackIndex(BoneTreeIndex, AnimSeq);
|
|
|
|
|
if (BoneTrackIndex == INDEX_NONE)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
return FTransform3f(Skeleton->GetReferenceSkeleton().GetRefBonePose()[BoneTreeIndex]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
FTransform BoneTM = FTransform::Identity;
|
|
|
|
|
AnimSeq->GetBoneTransform(BoneTM, BoneTrackIndex, AnimTime, true);
|
2024-12-04 00:49:59 +00:00
|
|
|
|
return FTransform3f(BoneTM);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
static FTransform3f GetAnimBoneCSTM(UAnimSequence* AnimSeq, const int32 BoneTreeIndex, const float AnimTime)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
|
|
|
|
USkeleton* Skeleton = AnimSeq->GetSkeleton();
|
|
|
|
|
const auto& RefSkeleton = Skeleton->GetReferenceSkeleton();
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f BoneTMWS = GetAnimBoneTM(AnimSeq, BoneTreeIndex, AnimTime);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
int32 CurrBone = BoneTreeIndex;
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
const int32 Parent(RefSkeleton.GetParentIndex(CurrBone));
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if (Parent < 0)
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
break;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
2025-02-07 14:04:52 +00:00
|
|
|
|
BoneTMWS = BoneTMWS * GetAnimBoneTM(AnimSeq, Parent, AnimTime);
|
|
|
|
|
|
|
|
|
|
CurrBone = Parent;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
return BoneTMWS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIRRORANIMATIONSYSTEMDEV_API void UMASFunctionLibrary::CreateMirrorSequenceFromAnimSequence_CS(
|
|
|
|
|
UAnimSequence* MirrorSequence,
|
|
|
|
|
const TEnumAsByte<EAxis::Type> MirrorAxis,
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const FString Substring_A,
|
|
|
|
|
const FString Substring_B,
|
2021-08-07 09:38:59 +00:00
|
|
|
|
const bool Symmetrical)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
IAnimationDataController& Controller = MirrorSequence->GetController();
|
|
|
|
|
const int32 NumFrames = Controller.GetModel()->GetNumberOfFrames();
|
|
|
|
|
const float DT = MirrorSequence->GetPlayLength() / NumFrames;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
USkeleton* Skeleton = MirrorSequence->GetSkeleton();
|
|
|
|
|
const auto& RefSkeleton = Skeleton->GetReferenceSkeleton();
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
|
|
|
|
|
TArray<bool> Already;
|
|
|
|
|
Already.SetNumZeroed(Skeleton->GetReferenceSkeleton().GetRawBoneNum());
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
TArray<FIntPoint> TwinPairs;
|
|
|
|
|
TArray<int32> NonTwinIDs;
|
|
|
|
|
TArray<EAxis::Type> NonTwinFlipAxis;
|
2025-02-07 14:04:52 +00:00
|
|
|
|
FMASUtils::CSMirrorSettings(RefSkeleton, MirrorAxis, Substring_A, Substring_B, TwinPairs, NonTwinIDs,
|
|
|
|
|
NonTwinFlipAxis);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
const bool DeltaStep = !Symmetrical;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FVector3f TwinMirrorScale = FVector3f(1.f);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
FVector TargetAxis = FVector::ZeroVector;
|
|
|
|
|
|
|
|
|
|
check(MirrorAxis != EAxis::None);
|
|
|
|
|
{
|
|
|
|
|
TwinMirrorScale[MirrorAxis - 1] = -1.f;
|
|
|
|
|
TargetAxis[MirrorAxis - 1] = 1.f;
|
|
|
|
|
}
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f TwinMirrorModTM(FQuat4f::Identity, FVector3f::ZeroVector, TwinMirrorScale);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TMap<int32, FRawAnimSequenceTrack> BoneTracks;
|
2025-02-07 14:04:52 +00:00
|
|
|
|
|
2021-08-07 09:38:59 +00:00
|
|
|
|
for (int32 i = 0; i < RefSkeleton.GetNum(); i++)
|
|
|
|
|
{
|
|
|
|
|
BoneTracks.Add(i, FRawAnimSequenceTrack());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int32 j = 0; j < NumFrames; j++)
|
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
TArray<FTransform3f> NewCSTMs;
|
|
|
|
|
NewCSTMs.SetNum(RefSkeleton.GetNum());
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
for (int32 i = 0; i < NonTwinIDs.Num(); i++)
|
|
|
|
|
{
|
|
|
|
|
int32 BoneTreeIndex = NonTwinIDs[i];
|
|
|
|
|
int32 BoneTrackIndex = Skeleton->GetRawAnimationTrackIndex(BoneTreeIndex, MirrorSequence);
|
|
|
|
|
|
|
|
|
|
if (BoneTrackIndex == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
const int32 ParentIndex = RefSkeleton.GetParentIndex(BoneTreeIndex);
|
|
|
|
|
if (ParentIndex != INDEX_NONE)
|
|
|
|
|
{
|
2025-02-07 14:04:52 +00:00
|
|
|
|
NewCSTMs[BoneTreeIndex] = FTransform3f(RefSkeleton.GetRefBonePose()[BoneTreeIndex]) * NewCSTMs[
|
|
|
|
|
ParentIndex];
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
NewCSTMs[BoneTreeIndex] = FTransform3f(RefSkeleton.GetRefBonePose()[BoneTreeIndex]);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f CSTM = GetAnimBoneCSTM(MirrorSequence, BoneTreeIndex, DT * j);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
CSTM.Mirror(MirrorAxis, NonTwinFlipAxis[i]);
|
|
|
|
|
|
|
|
|
|
NewCSTMs[BoneTreeIndex] = CSTM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int32 i = 0; i < TwinPairs.Num(); i++)
|
|
|
|
|
{
|
|
|
|
|
const int32 BoneIndex = TwinPairs[i].X;
|
|
|
|
|
const FCompactPoseBoneIndex CmptBoneIndex(BoneIndex);
|
|
|
|
|
|
|
|
|
|
const int32 TwinBoneIndex = TwinPairs[i].Y;
|
|
|
|
|
|
|
|
|
|
const FCompactPoseBoneIndex TwinCmptBoneIndex(TwinBoneIndex);
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const FTransform3f RefTM = FTransform3f(
|
|
|
|
|
FAnimationRuntime::GetComponentSpaceTransformRefPose(RefSkeleton, BoneIndex));
|
|
|
|
|
const FTransform3f TwinRefTM = FTransform3f(
|
|
|
|
|
FAnimationRuntime::GetComponentSpaceTransformRefPose(RefSkeleton, TwinBoneIndex));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const FTransform3f TM = GetAnimBoneCSTM(MirrorSequence, BoneIndex, DT * j);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
//Output.Pose.GetComponentSpaceTransform(CmptBoneIndex);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const FTransform3f TwinTM = GetAnimBoneCSTM(MirrorSequence, TwinBoneIndex, DT * j);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
//Output.Pose.GetComponentSpaceTransform(TwinCmptBoneIndex);
|
|
|
|
|
|
|
|
|
|
const int32 ParentIndex = RefSkeleton.GetParentIndex(BoneIndex);
|
|
|
|
|
const int32 TwinParentIndex = RefSkeleton.GetParentIndex(TwinBoneIndex);
|
|
|
|
|
|
|
|
|
|
const bool SameParent = ParentIndex == TwinParentIndex;
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
// twin 1<>
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
const UE::Math::TTransform<float> MirrRef = RefTM * TwinMirrorModTM;
|
|
|
|
|
const FTransform3f Delta = TwinRefTM.GetRelativeTransform(MirrRef);
|
|
|
|
|
const FQuat4f DeltaQuat = Delta.GetRotation();
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f MirrTM = TM * TwinMirrorModTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
MirrTM.SetRotation(MirrTM.GetRotation() * FQuat4f(DeltaQuat));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
MirrTM.SetScale3D(TwinTM.GetScale3D());
|
|
|
|
|
|
|
|
|
|
if (DeltaStep)
|
|
|
|
|
{
|
|
|
|
|
if (SameParent)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f RefBS = RefTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
RefBS = RefBS * TwinMirrorModTM;
|
2024-12-04 00:49:59 +00:00
|
|
|
|
const FVector3f PosDelta = MirrTM.GetLocation() - RefBS.GetLocation();
|
|
|
|
|
MirrTM.SetLocation(FVector3f(TwinRefTM.GetLocation()) + PosDelta);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
const FTransform3f& ParentTwinTM = NewCSTMs[RefSkeleton.GetParentIndex(TwinBoneIndex)];
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const FTransform3f& IParentTM =
|
|
|
|
|
// Output.Pose.GetComponentSpaceTransform(FCompactPoseBoneIndex(ParentIndex));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
GetAnimBoneCSTM(MirrorSequence, ParentIndex, DT * j);
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f RefBS = FTransform3f(RefSkeleton.GetRefBonePose()[BoneIndex]) * IParentTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
RefBS = RefBS * TwinMirrorModTM;
|
|
|
|
|
RefBS.SetRotation(RefBS.GetRotation() * DeltaQuat);
|
|
|
|
|
RefBS.SetScale3D(TwinTM.GetScale3D());
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
MirrTM = (MirrTM.GetRelativeTransform(RefBS) * FTransform3f(
|
|
|
|
|
RefSkeleton.GetRefBonePose()[TwinBoneIndex])) * ParentTwinTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NewCSTMs[TwinBoneIndex] = MirrTM;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
// twin 2<>
|
2021-08-07 09:38:59 +00:00
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f TwinMirrRef = TwinRefTM * TwinMirrorModTM;
|
|
|
|
|
const FQuat4f TwinDeltaQuat = TwinMirrRef.GetRotation().Inverse() * RefTM.GetRotation();
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f TwinMirrTM = TwinTM * TwinMirrorModTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
TwinMirrTM.SetRotation(TwinMirrTM.GetRotation() * TwinDeltaQuat);
|
|
|
|
|
TwinMirrTM.SetScale3D(TM.GetScale3D());
|
|
|
|
|
|
|
|
|
|
if (DeltaStep)
|
|
|
|
|
{
|
|
|
|
|
if (SameParent)
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f TwinRefBS = TwinRefTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TwinRefBS = TwinRefBS * TwinMirrorModTM;
|
2024-12-04 00:49:59 +00:00
|
|
|
|
const FVector3f PosDelta = TwinMirrTM.GetLocation() - TwinRefBS.GetLocation();
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TwinMirrTM.SetLocation(RefTM.GetLocation() + PosDelta);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-12-04 00:49:59 +00:00
|
|
|
|
const FTransform3f& ParentTM = NewCSTMs[RefSkeleton.GetParentIndex(BoneIndex)];
|
2025-02-07 14:04:52 +00:00
|
|
|
|
const FTransform3f& IParentTwinTM =
|
|
|
|
|
//Output.Pose.GetComponentSpaceTransform(FCompactPoseBoneIndex(TwinParentIndex));
|
2021-08-07 09:38:59 +00:00
|
|
|
|
GetAnimBoneCSTM(MirrorSequence, TwinParentIndex, DT * j);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
FTransform3f TwinRefBS = FTransform3f(RefSkeleton.GetRefBonePose()[TwinBoneIndex]) *
|
|
|
|
|
IParentTwinTM;
|
2021-08-07 09:38:59 +00:00
|
|
|
|
TwinRefBS = TwinRefBS * TwinMirrorModTM;
|
|
|
|
|
TwinRefBS.SetRotation(TwinRefBS.GetRotation() * TwinDeltaQuat);
|
|
|
|
|
TwinRefBS.SetScale3D(TM.GetScale3D());
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
TwinMirrTM = (TwinMirrTM.GetRelativeTransform(TwinRefBS) * FTransform3f(
|
|
|
|
|
RefSkeleton.GetRefBonePose()[BoneIndex]) * ParentTM);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NewCSTMs[BoneIndex] = TwinMirrTM;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int32 i = 0; i < NewCSTMs.Num(); i++)
|
|
|
|
|
{
|
|
|
|
|
const int32 ParentIndex = RefSkeleton.GetParentIndex(i);
|
2024-12-04 00:49:59 +00:00
|
|
|
|
FTransform3f BSTM;
|
2025-02-07 14:04:52 +00:00
|
|
|
|
if (ParentIndex != INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
BSTM = NewCSTMs[i].GetRelativeTransform(NewCSTMs[ParentIndex]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BSTM = NewCSTMs[i];
|
|
|
|
|
}
|
2021-08-07 09:38:59 +00:00
|
|
|
|
|
|
|
|
|
auto& BoneTrack = BoneTracks[i];
|
|
|
|
|
BoneTrack.PosKeys.Add(BSTM.GetLocation());
|
|
|
|
|
BoneTrack.RotKeys.Add(BSTM.GetRotation());
|
|
|
|
|
BoneTrack.ScaleKeys.Add(BSTM.GetScale3D());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto Pair : BoneTracks)
|
|
|
|
|
{
|
|
|
|
|
const FName TrackName = Skeleton->GetReferenceSkeleton().GetBoneName(Pair.Key);
|
2024-12-04 00:49:59 +00:00
|
|
|
|
//MirrorSequence->AddNewRawTrack(TrackName, &Pair.Value);
|
|
|
|
|
Controller.AddBoneCurve(TrackName);
|
2025-02-07 14:04:52 +00:00
|
|
|
|
Controller.SetBoneTrackKeys(TrackName, Pair.Value.PosKeys, Pair.Value.RotKeys, Pair.Value.ScaleKeys);
|
2021-08-07 09:38:59 +00:00
|
|
|
|
}
|
|
|
|
|
// Have to also apply to pelvis and spine_01
|
2024-12-04 00:49:59 +00:00
|
|
|
|
|
2021-08-07 09:38:59 +00:00
|
|
|
|
MirrorSequence->MarkPackageDirty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-02-07 14:04:52 +00:00
|
|
|
|
#undef LOCTEXT_NAMESPACE
|