Files
UnrealEngineUWP/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_Mirror.cpp
timothy daoust a4e3872935 Added support for mirroring sync markers
#rb thomas.sarkanen

[CL 15741120 by timothy daoust in ue5-main branch]
2021-03-18 16:18:00 -04:00

138 lines
4.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimNodes/AnimNode_Mirror.h"
#include "Animation/AnimInstanceProxy.h"
#include "Animation/AnimNode_Inertialization.h"
#include "AnimationRuntime.h"
#include "Animation/MirrorSyncScope.h"
#define LOCTEXT_NAMESPACE "AnimNode_Mirror"
FAnimNode_Mirror::FAnimNode_Mirror()
: MirrorDataTable(nullptr)
, BlendTimeOnMirrorStateChange(0.0f)
, bMirror(true)
, bResetChildOnMirrorStateChange(false)
, bMirrorState(false)
, bMirrorStateIsValid(false)
{
}
#if WITH_EDITOR
UMirrorDataTable* FAnimNode_Mirror::GetMirrorDataTable() const
{
return MirrorDataTable.Get();
}
void FAnimNode_Mirror::SetMirrorDataTable(UMirrorDataTable* MirrorTable)
{
MirrorDataTable = MirrorTable;
}
#endif
void FAnimNode_Mirror::Initialize_AnyThread(const FAnimationInitializeContext& Context)
{
FAnimNode_Base::Initialize_AnyThread(Context);
Source.Initialize(Context);
}
void FAnimNode_Mirror::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context)
{
Source.CacheBones(Context);
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(CacheBones_AnyThread)
Super::CacheBones_AnyThread(Context);
if (MirrorDataTable && Context.AnimInstanceProxy)
{
const FBoneContainer& BoneContainer = Context.AnimInstanceProxy->GetRequiredBones();
bool bSharesSkeleton = BoneContainer.GetSkeletonAsset() == MirrorDataTable->Skeleton;
bool bIdenticalJointCount = BoneContainer.GetReferenceSkeleton().GetNum() == MirrorDataTable->BoneToMirrorBoneIndex.Num();
if (bSharesSkeleton && bIdenticalJointCount)
{
MirrorDataTable->FillCompactPoseMirrorBones(BoneContainer, MirrorDataTable->BoneToMirrorBoneIndex, CompactPoseMirrorBones);
}
else
{
TArray<int32> MirrorBoneIndexes;
MirrorDataTable->FillMirrorBoneIndexes(BoneContainer.GetReferenceSkeleton(), MirrorBoneIndexes);
MirrorDataTable->FillCompactPoseMirrorBones(BoneContainer, MirrorBoneIndexes, CompactPoseMirrorBones);
}
const int32 NumBones = BoneContainer.GetCompactPoseNumBones();
ComponentSpaceRefRotations.SetNumUninitialized(NumBones);
ComponentSpaceRefRotations[FCompactPoseBoneIndex(0)] = BoneContainer.GetRefPoseTransform(FCompactPoseBoneIndex(0)).GetRotation();
for (FCompactPoseBoneIndex BoneIndex(1); BoneIndex < NumBones; ++BoneIndex)
{
const FCompactPoseBoneIndex ParentBoneIndex = BoneContainer.GetParentBoneIndex(BoneIndex);
ComponentSpaceRefRotations[BoneIndex] = ComponentSpaceRefRotations[ParentBoneIndex] * BoneContainer.GetRefPoseTransform(BoneIndex).GetRotation();
}
}
else
{
CompactPoseMirrorBones.Reset();
ComponentSpaceRefRotations.Reset();
}
}
void FAnimNode_Mirror::Update_AnyThread(const FAnimationUpdateContext& Context)
{
GetEvaluateGraphExposedInputs().Execute(Context);
if (bMirrorStateIsValid && bMirrorState != bMirror)
{
if (BlendTimeOnMirrorStateChange > SMALL_NUMBER)
{
// Inertialize when switching between mirrored and unmirrored states to smooth out the pose discontinuity
UE::Anim::IInertializationRequester* InertializationRequester = Context.GetMessage<UE::Anim::IInertializationRequester>();
if (InertializationRequester)
{
InertializationRequester->RequestInertialization(BlendTimeOnMirrorStateChange);
InertializationRequester->AddDebugRecord(*Context.AnimInstanceProxy, Context.GetCurrentNodeId());
}
else
{
FAnimNode_Inertialization::LogRequestError(Context, Source);
}
}
// Optionally reinitialize the source when the mirror state changes
if (bResetChildOnMirrorStateChange)
{
FAnimationInitializeContext ReinitializeContext(Context.AnimInstanceProxy);
Source.Initialize(ReinitializeContext);
}
}
UE::Anim::TOptionalScopedGraphMessage<UE::Anim::FMirrorSyncScope> Message(bMirror, Context, Context, MirrorDataTable);
bMirrorState = bMirror;
bMirrorStateIsValid = true;
Source.Update(Context);
}
void FAnimNode_Mirror::Evaluate_AnyThread(FPoseContext& Output)
{
Source.Evaluate(Output);
if (bMirrorState && MirrorDataTable)
{
FAnimationRuntime::MirrorPose(Output.Pose, MirrorDataTable->MirrorAxis, CompactPoseMirrorBones, ComponentSpaceRefRotations);
FAnimationRuntime::MirrorCurves(Output.Curve, *MirrorDataTable);
}
}
void FAnimNode_Mirror::GatherDebugData(FNodeDebugData& DebugData)
{
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += FString::Printf(TEXT("(Mirrored: %s)"), (bMirrorState) ? TEXT("true") : TEXT("false"));
DebugData.AddDebugItem(DebugLine);
Source.GatherDebugData(DebugData);
}
#undef LOCTEXT_NAMESPACE