Files
UnrealEngineUWP/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_Slot.cpp
Thomas Sarkanen 1dee2903c0 Added schematic view of animation graphs
Initial basic implementation, more features to follow.
Accessed via the context menu of a graph track.
Shows anim graph nodes in a linearized tree similar to ShowDebug ANIMATION.
Select a node to 'pin' all the properties that it traced (multi select supported) to the bottom of the window.
Scrub the timeline to see those properties change over time.
Asset references use clickable hyperlinks to go to the specified asset editor.

#rb Jurre.deBaare

[CL 11041140 by Thomas Sarkanen in Dev-Core branch]
2020-01-17 03:32:34 -05:00

116 lines
4.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimNodes/AnimNode_Slot.h"
#include "Animation/AnimInstanceProxy.h"
#include "Animation/AnimTrace.h"
/////////////////////////////////////////////////////
// FAnimNode_Slot
void FAnimNode_Slot::Initialize_AnyThread(const FAnimationInitializeContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Initialize_AnyThread)
FAnimNode_Base::Initialize_AnyThread(Context);
Source.Initialize(Context);
WeightData.Reset();
// If this node has not already been registered with the AnimInstance, do it.
if (!SlotNodeInitializationCounter.IsSynchronized_Counter(Context.AnimInstanceProxy->GetSlotNodeInitializationCounter()))
{
SlotNodeInitializationCounter.SynchronizeWith(Context.AnimInstanceProxy->GetSlotNodeInitializationCounter());
Context.AnimInstanceProxy->RegisterSlotNodeWithAnimInstance(SlotName);
}
}
void FAnimNode_Slot::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(CacheBones_AnyThread)
Source.CacheBones(Context);
}
void FAnimNode_Slot::Update_AnyThread(const FAnimationUpdateContext& Context)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Update_AnyThread)
// Update weights.
Context.AnimInstanceProxy->GetSlotWeight(SlotName, WeightData.SlotNodeWeight, WeightData.SourceWeight, WeightData.TotalNodeWeight);
// Update cache in AnimInstance.
Context.AnimInstanceProxy->UpdateSlotNodeWeight(SlotName, WeightData.SlotNodeWeight, Context.GetFinalBlendWeight());
const bool bUpdateSource = bAlwaysUpdateSourcePose || FAnimWeight::IsRelevant(WeightData.SourceWeight);
if (bUpdateSource)
{
const float SourceWeight = FMath::Max(FAnimWeight::GetSmallestRelevantWeight(), WeightData.SourceWeight);
Source.Update(Context.FractionalWeight(SourceWeight));
}
#if ANIM_TRACE_ENABLED
TRACE_ANIM_NODE_VALUE(Context, TEXT("Name"), SlotName);
TRACE_ANIM_NODE_VALUE(Context, TEXT("Slot Weight"), WeightData.SlotNodeWeight);
TRACE_ANIM_NODE_VALUE(Context, TEXT("Pose Source"), (WeightData.SourceWeight <= ZERO_ANIMWEIGHT_THRESH));
Context.AnimInstanceProxy->TraceMontageEvaluationData(Context, SlotName);
#endif
}
void FAnimNode_Slot::Evaluate_AnyThread(FPoseContext & Output)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Evaluate_AnyThread)
// If not playing a montage, just pass through
if (WeightData.SlotNodeWeight <= ZERO_ANIMWEIGHT_THRESH)
{
Source.Evaluate(Output);
}
else
{
FPoseContext SourceContext(Output);
if (WeightData.SourceWeight > ZERO_ANIMWEIGHT_THRESH)
{
Source.Evaluate(SourceContext);
}
Output.AnimInstanceProxy->SlotEvaluatePose(SlotName, SourceContext.Pose, SourceContext.Curve, WeightData.SourceWeight, Output.Pose, Output.Curve, WeightData.SlotNodeWeight, WeightData.TotalNodeWeight);
checkSlow(!Output.ContainsNaN());
checkSlow(Output.IsNormalized());
}
}
void FAnimNode_Slot::GatherDebugData(FNodeDebugData& DebugData)
{
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(GatherDebugData)
FString DebugLine = DebugData.GetNodeName(this);
DebugLine += FString::Printf(TEXT("(Slot Name: '%s' Weight:%.1f%%)"), *SlotName.ToString(), WeightData.SlotNodeWeight*100.f);
bool const bIsPoseSource = (WeightData.SourceWeight <= ZERO_ANIMWEIGHT_THRESH);
DebugData.AddDebugItem(DebugLine, bIsPoseSource);
Source.GatherDebugData(DebugData.BranchFlow(WeightData.SourceWeight));
for (FAnimMontageInstance* MontageInstance : DebugData.AnimInstance->MontageInstances)
{
if (MontageInstance->IsValid() && MontageInstance->Montage->IsValidSlot(SlotName))
{
if (const FAnimTrack* const Track = MontageInstance->Montage->GetAnimationData(SlotName))
{
if (const FAnimSegment* const Segment = Track->GetSegmentAtTime(MontageInstance->GetPosition()))
{
float CurrentAnimPos;
if (UAnimSequenceBase* Anim = Segment->GetAnimationData(MontageInstance->GetPosition(), CurrentAnimPos))
{
FString MontageLine = FString::Printf(TEXT("Montage('%s') Anim('%s') P(%.2f) W(%.0f%%)"), *MontageInstance->Montage->GetName(), *Anim->GetName(), CurrentAnimPos, WeightData.SlotNodeWeight*100.f);
DebugData.BranchFlow(1.0f).AddDebugItem(MontageLine, true);
break;
}
}
}
}
}
}
FAnimNode_Slot::FAnimNode_Slot()
: SlotName(FAnimSlotGroup::DefaultSlotName)
, bAlwaysUpdateSourcePose(false)
{
}