Files
UnrealEngineUWP/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_PoseBlendNode.cpp
thomas sarkanen a897f0439a Skeleton compatibility improvements
Skeleton compatibility is now bi-directional. Specifying a compatible skeleton A -> B now implies B -> A.
Skeleton compatibility is now an editor-only concern. The runtime will attempt to do the 'best it can' via name -> name mappings. Only the editor will prevent assigning incompatible skeletons in (e.g.) asset pickers etc.
Skeleton compatibility checks in editor can now be disabled in the editor preferences (and each asset picker now has a checkbox option in its view settings that allows for quick access to this).

Moves FSkeletonRemapping to its own file (which is now private).
Skeleton remappings are now generated on demand on worker threads just before animation decompression and stored in a registry, guarded by FRWScopeLock for thread-safety.

Fixed some anim BP compiler edge cases where asset references on pins were not getting preloaded correctly, causing skeletons to be erroneously reported as missing.

Exposed the current asset registry filter in SAssetView so that menu extensions can access it (and use it to provide context)

#jira UE-166054
#jira UE-167355
#rb Jurre.deBaare,John.vanderBerg
#preflight 635902602e6690262afa86f9
#preflight 6372ad7a0c74adb48b472b38
#p4v-cherrypick 22878911
#preflight 6374b3c51d25fe8b931b8d7b

[CL 23152671 by thomas sarkanen in ue5-main branch]
2022-11-16 07:21:38 -05:00

105 lines
3.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimNodes/AnimNode_PoseBlendNode.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(AnimNode_PoseBlendNode)
/////////////////////////////////////////////////////
// FAnimPoseByNameNode
FAnimNode_PoseBlendNode::FAnimNode_PoseBlendNode()
: CustomCurve(nullptr)
{
BlendOption = EAlphaBlendOption::Linear;
}
void FAnimNode_PoseBlendNode::Initialize_AnyThread(const FAnimationInitializeContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Initialize_AnyThread)
FAnimNode_PoseHandler::Initialize_AnyThread(Context);
SourcePose.Initialize(Context);
}
void FAnimNode_PoseBlendNode::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(CacheBones_AnyThread)
FAnimNode_PoseHandler::CacheBones_AnyThread(Context);
SourcePose.CacheBones(Context);
}
void FAnimNode_PoseBlendNode::UpdateAssetPlayer(const FAnimationUpdateContext& Context)
{
FAnimNode_PoseHandler::UpdateAssetPlayer(Context);
SourcePose.Update(Context);
}
void FAnimNode_PoseBlendNode::Evaluate_AnyThread(FPoseContext& Output)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Evaluate_AnyThread)
ANIM_MT_SCOPE_CYCLE_COUNTER(PoseBlendNodeEvaluate, !IsInGameThread());
FPoseContext SourceData(Output);
SourcePose.Evaluate(SourceData);
bool bValidPose = false;
const UPoseAsset* CachedPoseAsset = CurrentPoseAsset.Get();
if (CachedPoseAsset && PoseExtractContext.PoseCurves.Num() > 0 && CachedPoseAsset->GetSkeleton() != nullptr)
{
FPoseContext CurrentPose(Output);
// only give pose curve, we don't set any more curve here
for (int32 PoseIdx = 0; PoseIdx < PoseExtractContext.PoseCurves.Num(); ++PoseIdx)
{
FPoseCurve& PoseCurve = PoseExtractContext.PoseCurves[PoseIdx];
// Get value of input curve
float InputValue = SourceData.Curve.Get(PoseCurve.UID);
// Remap using chosen BlendOption
float RemappedValue = FAlphaBlend::AlphaToBlendOption(InputValue, BlendOption, CustomCurve);
PoseCurve.Value = RemappedValue;
}
FAnimationPoseData CurrentAnimationPoseData(CurrentPose);
if (CachedPoseAsset->GetAnimationPose(CurrentAnimationPoseData, PoseExtractContext))
{
// once we get it, we have to blend by weight
if (CachedPoseAsset->IsValidAdditive())
{
Output = SourceData;
FAnimationPoseData BaseAnimationPoseData(Output);
FAnimationRuntime::AccumulateAdditivePose(BaseAnimationPoseData, CurrentAnimationPoseData, 1.f, EAdditiveAnimationType::AAT_LocalSpaceBase);
}
else
{
FAnimationPoseData OutputAnimationPoseData(Output);
const FAnimationPoseData SourceAnimationPoseData(SourceData);
FAnimationRuntime::BlendTwoPosesTogetherPerBone(SourceAnimationPoseData, CurrentAnimationPoseData, BoneBlendWeights, OutputAnimationPoseData);
}
bValidPose = true;
}
}
// If we didn't create a valid pose, just copy SourcePose to output (pass through)
if(!bValidPose)
{
Output = SourceData;
}
}
void FAnimNode_PoseBlendNode::GatherDebugData(FNodeDebugData& DebugData)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(GatherDebugData)
FAnimNode_PoseHandler::GatherDebugData(DebugData);
SourcePose.GatherDebugData(DebugData.BranchFlow(1.f));
}