Files
UnrealEngineUWP/Engine/Source/Runtime/AnimGraphRuntime/Private/BoneControllers/AnimNode_SkeletalControlBase.cpp
danny chapman 343371096b Analysis for BlendSpace. Also includes:
Tweaks to the rendering of blendspaces, including separating the graph from the buttons
Context menu changes for the sample details
Changes to AnimationBlueprintLibrary and AnimPose from Jurre to help get the poses during analysis

#jira UE-114512
#rb thomas.sarkanen

#ROBOMERGE-SOURCE: CL 16356830 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v804-16311228)

[CL 16356839 by danny chapman in ue5-release-engine-test branch]
2021-05-17 15:04:09 -04:00

156 lines
5.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BoneControllers/AnimNode_SkeletalControlBase.h"
#include "Animation/AnimInstanceProxy.h"
#include "Engine/SkeletalMeshSocket.h"
/////////////////////////////////////////////////////
// FAnimNode_SkeletalControlBase
void FAnimNode_SkeletalControlBase::Initialize_AnyThread(const FAnimationInitializeContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Initialize_AnyThread)
FAnimNode_Base::Initialize_AnyThread(Context);
ComponentPose.Initialize(Context);
AlphaBoolBlend.Reinitialize();
AlphaScaleBiasClamp.Reinitialize();
}
void FAnimNode_SkeletalControlBase::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(CacheBones_AnyThread)
FAnimNode_Base::CacheBones_AnyThread(Context);
InitializeBoneReferences(Context.AnimInstanceProxy->GetRequiredBones());
ComponentPose.CacheBones(Context);
}
void FAnimNode_SkeletalControlBase::UpdateInternal(const FAnimationUpdateContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(UpdateInternal)
}
void FAnimNode_SkeletalControlBase::UpdateComponentPose_AnyThread(const FAnimationUpdateContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(UpdateComponentPose_AnyThread)
ComponentPose.Update(Context);
}
void FAnimNode_SkeletalControlBase::Update_AnyThread(const FAnimationUpdateContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Update_AnyThread)
UpdateComponentPose_AnyThread(Context);
ActualAlpha = 0.f;
if (IsLODEnabled(Context.AnimInstanceProxy))
{
GetEvaluateGraphExposedInputs().Execute(Context);
// Apply the skeletal control if it's valid
switch (AlphaInputType)
{
case EAnimAlphaInputType::Float :
ActualAlpha = AlphaScaleBias.ApplyTo(AlphaScaleBiasClamp.ApplyTo(Alpha, Context.GetDeltaTime()));
break;
case EAnimAlphaInputType::Bool :
ActualAlpha = AlphaBoolBlend.ApplyTo(bAlphaBoolEnabled, Context.GetDeltaTime());
break;
case EAnimAlphaInputType::Curve :
if (UAnimInstance* AnimInstance = Cast<UAnimInstance>(Context.AnimInstanceProxy->GetAnimInstanceObject()))
{
ActualAlpha = AlphaScaleBiasClamp.ApplyTo(AnimInstance->GetCurveValue(AlphaCurveName), Context.GetDeltaTime());
}
break;
};
// Make sure Alpha is clamped between 0 and 1.
ActualAlpha = FMath::Clamp<float>(ActualAlpha, 0.f, 1.f);
if (FAnimWeight::IsRelevant(ActualAlpha) && IsValidToEvaluate(Context.AnimInstanceProxy->GetSkeleton(), Context.AnimInstanceProxy->GetRequiredBones()))
{
UpdateInternal(Context);
}
}
TRACE_ANIM_NODE_VALUE(Context, TEXT("Alpha"), ActualAlpha);
}
bool ContainsNaN(const TArray<FBoneTransform> & BoneTransforms)
{
for (int32 i = 0; i < BoneTransforms.Num(); ++i)
{
if (BoneTransforms[i].Transform.ContainsNaN())
{
return true;
}
}
return false;
}
void FAnimNode_SkeletalControlBase::EvaluateComponentPose_AnyThread(FComponentSpacePoseContext& Output)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(EvaluateComponentPose_AnyThread)
// Evaluate the input
ComponentPose.EvaluateComponentSpace(Output);
}
void FAnimNode_SkeletalControlBase::EvaluateComponentSpaceInternal(FComponentSpacePoseContext& Context)
{
}
void FAnimNode_SkeletalControlBase::EvaluateComponentSpace_AnyThread(FComponentSpacePoseContext& Output)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(EvaluateComponentSpace_AnyThread)
// Cache the incoming node IDs in a base context
FAnimationBaseContext CachedContext(Output);
EvaluateComponentPose_AnyThread(Output);
#if WITH_EDITORONLY_DATA
// save current pose before applying skeletal control to compute the exact gizmo location in AnimGraphNode
ForwardedPose.CopyPose(Output.Pose);
#endif // #if WITH_EDITORONLY_DATA
#if DO_CHECK
// this is to ensure Source data does not contain NaN
ensure(Output.ContainsNaN() == false);
#endif
// Apply the skeletal control if it's valid
if (FAnimWeight::IsRelevant(ActualAlpha) && IsValidToEvaluate(Output.AnimInstanceProxy->GetSkeleton(), Output.AnimInstanceProxy->GetRequiredBones()))
{
Output.SetNodeIds(CachedContext);
EvaluateComponentSpaceInternal(Output);
BoneTransforms.Reset(BoneTransforms.Num());
EvaluateSkeletalControl_AnyThread(Output, BoneTransforms);
if (BoneTransforms.Num() > 0)
{
const float BlendWeight = FMath::Clamp<float>(ActualAlpha, 0.f, 1.f);
Output.Pose.LocalBlendCSBoneTransforms(BoneTransforms, BlendWeight);
}
// we check NaN when you get out of this function in void FComponentSpacePoseLink::EvaluateComponentSpace(FComponentSpacePoseContext& Output)
}
}
void FAnimNode_SkeletalControlBase::AddDebugNodeData(FString& OutDebugData)
{
OutDebugData += FString::Printf(TEXT("Alpha: %.1f%%"), ActualAlpha*100.f);
}
void FAnimNode_SkeletalControlBase::EvaluateSkeletalControl_AnyThread(FComponentSpacePoseContext& Output, TArray<FBoneTransform>& OutBoneTransforms)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(EvaluateSkeletalControl_AnyThread)
PRAGMA_DISABLE_DEPRECATION_WARNINGS
// Call legacy implementation for backwards compatibility
EvaluateBoneTransforms(Output.AnimInstanceProxy->GetSkelMeshComponent(), Output.Pose, OutBoneTransforms);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}