You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Runtime notes: - Removes 'smart name' usage across the animation systems. - Changed curve blending from a uniform array (sized per skeleton) to a sparse array of sorted named values. Blends and other combiners are performed using a dual iteration 'tape merge'. - Skeleton curves are no longer guaranteed to cover all curve names that can be found at runtime. Editor notes: - Curve metadata (flags, bone links etc.) is still present on the skeleton, but can also now exist on a skeletal mesh - Curve metadata (for morph targets) is still populated on import - Curves can now be used arbitrarily at runtime New features: - New Find/Replace dialog that allows for batch-replacing curves and notifies across all of a project's assets - New curve debugger tab in various Persona editors that allows for viewing curve values live. This also now allows viewing curves for specific pose watches. - Pose watches now output curve tracks to the Rewind Debugger #rb Jurre.deBaare,Nicholas.Frechette,Sara.Schvartzman,Helge.Mathee,Kiaran.Ritchie,Jaime.Cifuentes,Martin.Wilson,Keith.Yerex,Andrean.Franc (and more!) #jira UE-167776 #jira UE-173716 #jira UE-110407 #preflight 63fc98c81206d91a2bc3ab90 #preflight 63f3ad4f81646f1f24c240c2 [CL 24421496 by Thomas Sarkanen in ue5-main branch]
140 lines
4.5 KiB
C++
140 lines
4.5 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "AnimNodes/AnimNode_CurveSource.h"
|
|
#include "AnimationRuntime.h"
|
|
#include "Animation/AnimCurveUtils.h"
|
|
#include "Animation/AnimInstanceProxy.h"
|
|
#include "Animation/AnimTrace.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(AnimNode_CurveSource)
|
|
|
|
FAnimNode_CurveSource::FAnimNode_CurveSource()
|
|
: SourceBinding(ICurveSourceInterface::DefaultBinding)
|
|
, Alpha(1.0f)
|
|
{
|
|
}
|
|
|
|
void FAnimNode_CurveSource::PreUpdate(const UAnimInstance* AnimInstance)
|
|
{
|
|
// re-bind to our named curve source in pre-update
|
|
// we do this here to allow re-binding of the source without reinitializing the whole
|
|
// anim graph. If the source goes away (e.g. if an audio component is destroyed) or the
|
|
// binding changes then we can re-bind to a new object
|
|
if (CurveSource.GetObject() == nullptr || Cast<ICurveSourceInterface>(CurveSource.GetObject())->Execute_GetBindingName(CurveSource.GetObject()) != SourceBinding)
|
|
{
|
|
ICurveSourceInterface* PotentialCurveSource = nullptr;
|
|
|
|
auto IsSpecifiedCurveSource = [&PotentialCurveSource](UObject* InObject, const FName& InSourceBinding, TScriptInterface<ICurveSourceInterface>& InOutCurveSource)
|
|
{
|
|
PotentialCurveSource = Cast<ICurveSourceInterface>(InObject);
|
|
if (PotentialCurveSource && PotentialCurveSource->Execute_GetBindingName(InObject) == InSourceBinding)
|
|
{
|
|
InOutCurveSource.SetObject(InObject);
|
|
InOutCurveSource.SetInterface(PotentialCurveSource);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
AActor* Actor = AnimInstance->GetOwningActor();
|
|
if (Actor)
|
|
{
|
|
// check if our actor implements our interface
|
|
if (IsSpecifiedCurveSource(Actor, SourceBinding, CurveSource))
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (TFieldIterator<FObjectProperty> PropertyIt(Actor->GetClass(), EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
|
|
{
|
|
FObjectProperty* ObjProp = *PropertyIt;
|
|
UActorComponent* ActorComponent = Cast<UActorComponent>(ObjProp->GetObjectPropertyValue(ObjProp->ContainerPtrToValuePtr<void>(Actor)));
|
|
if (IsSpecifiedCurveSource(ActorComponent, SourceBinding, CurveSource))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
const TSet<UActorComponent*>& ActorOwnedComponents = Actor->GetComponents();
|
|
for (UActorComponent* OwnedComponent : ActorOwnedComponents)
|
|
{
|
|
if (IsSpecifiedCurveSource(OwnedComponent, SourceBinding, CurveSource))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class FExternalCurveScratchArea : public TThreadSingleton<FExternalCurveScratchArea>
|
|
{
|
|
public:
|
|
TArray<FNamedCurveValue> NamedCurveValues;
|
|
};
|
|
|
|
void FAnimNode_CurveSource::Evaluate_AnyThread(FPoseContext& Output)
|
|
{
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Evaluate_AnyThread)
|
|
SourcePose.Evaluate(Output);
|
|
|
|
if (CurveSource.GetInterface() != nullptr)
|
|
{
|
|
TArray<FNamedCurveValue>& NamedCurveValues = FExternalCurveScratchArea::Get().NamedCurveValues;
|
|
NamedCurveValues.Reset();
|
|
CurveSource->Execute_GetCurves(CurveSource.GetObject(), NamedCurveValues);
|
|
|
|
const float ClampedAlpha = FMath::Clamp(Alpha, 0.0f, 1.0f);
|
|
|
|
FBlendedCurve Curve;
|
|
UE::Anim::FCurveUtils::BuildUnsorted(Curve, NamedCurveValues.Num(),
|
|
[&NamedCurveValues](int32 InCurveIndex)
|
|
{
|
|
return NamedCurveValues[InCurveIndex].Name;
|
|
},
|
|
[&NamedCurveValues](int32 InCurveIndex)
|
|
{
|
|
return NamedCurveValues[InCurveIndex].Value;
|
|
});
|
|
|
|
#if ANIM_TRACE_ENABLED
|
|
for (FNamedCurveValue NamedValue : NamedCurveValues)
|
|
{
|
|
TRACE_ANIM_NODE_VALUE(Output, *NamedValue.Name.ToString(), NamedValue.Value);
|
|
}
|
|
#endif
|
|
|
|
Output.Curve.LerpTo(Curve, ClampedAlpha);
|
|
}
|
|
}
|
|
|
|
void FAnimNode_CurveSource::Update_AnyThread(const FAnimationUpdateContext& Context)
|
|
{
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Update_AnyThread)
|
|
// Evaluate any BP logic plugged into this node
|
|
GetEvaluateGraphExposedInputs().Execute(Context);
|
|
SourcePose.Update(Context);
|
|
}
|
|
|
|
void FAnimNode_CurveSource::Initialize_AnyThread(const FAnimationInitializeContext& Context)
|
|
{
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(Initialize_AnyThread)
|
|
FAnimNode_Base::Initialize_AnyThread(Context);
|
|
SourcePose.Initialize(Context);
|
|
}
|
|
|
|
void FAnimNode_CurveSource::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context)
|
|
{
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(CacheBones_AnyThread)
|
|
FAnimNode_Base::CacheBones_AnyThread(Context);
|
|
SourcePose.CacheBones(Context);
|
|
}
|
|
|
|
void FAnimNode_CurveSource::GatherDebugData(FNodeDebugData& DebugData)
|
|
{
|
|
DECLARE_SCOPE_HIERARCHICAL_COUNTER_ANIMNODE(GatherDebugData)
|
|
FAnimNode_Base::GatherDebugData(DebugData);
|
|
SourcePose.GatherDebugData(DebugData.BranchFlow(1.f));
|
|
}
|