Files
UnrealEngineUWP/Engine/Source/Runtime/AnimGraphRuntime/Private/AnimNodes/AnimNode_ModifyCurve.cpp
Joe Graf 0801907f5f Added weighted moving average smoothing functions
#rb: none
#fyi: jeff.farris

[CL 5035282 by Joe Graf in Dev-VR branch]
2019-02-16 14:21:17 -05:00

112 lines
3.1 KiB
C++

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#include "AnimNodes/AnimNode_ModifyCurve.h"
#include "AnimationRuntime.h"
#include "Animation/AnimInstanceProxy.h"
FAnimNode_ModifyCurve::FAnimNode_ModifyCurve()
{
ApplyMode = EModifyCurveApplyMode::Blend;
Alpha = 1.f;
}
void FAnimNode_ModifyCurve::Initialize_AnyThread(const FAnimationInitializeContext& Context)
{
Super::Initialize_AnyThread(Context);
SourcePose.Initialize(Context);
// Init our last values array to be the right size
if (ApplyMode == EModifyCurveApplyMode::WeightedMovingAverage)
{
LastCurveValues.Reset(CurveValues.Num());
LastCurveValues.AddZeroed(CurveValues.Num());
}
}
void FAnimNode_ModifyCurve::CacheBones_AnyThread(const FAnimationCacheBonesContext& Context)
{
Super::CacheBones_AnyThread(Context);
SourcePose.CacheBones(Context);
}
void FAnimNode_ModifyCurve::Evaluate_AnyThread(FPoseContext& Output)
{
FPoseContext SourceData(Output);
SourcePose.Evaluate(SourceData);
Output = SourceData;
// Morph target and Material parameter curves
USkeleton* Skeleton = Output.AnimInstanceProxy->GetSkeleton();
check(CurveNames.Num() == CurveValues.Num());
for (int32 ModIdx = 0; ModIdx < CurveNames.Num(); ModIdx++)
{
FName CurveName = CurveNames[ModIdx];
SmartName::UID_Type NameUID = Skeleton->GetUIDByName(USkeleton::AnimCurveMappingName, CurveName);
if (NameUID != SmartName::MaxUID)
{
float CurveValue = CurveValues[ModIdx];
float CurrentValue = Output.Curve.Get(NameUID);
// Use ApplyMode enum to decide how to apply
if (ApplyMode == EModifyCurveApplyMode::Add)
{
Output.Curve.Set(NameUID, CurrentValue + CurveValue);
}
else if (ApplyMode == EModifyCurveApplyMode::Scale)
{
Output.Curve.Set(NameUID, CurrentValue * CurveValue);
}
else if (ApplyMode == EModifyCurveApplyMode::WeightedMovingAverage)
{
check(LastCurveValues.Num() == CurveValues.Num());
const float LastCurveValue = LastCurveValues[ModIdx];
const float WAvg = FMath::WeightedMovingAverage(CurrentValue, LastCurveValue, Alpha);
// Update the last curve value for next run
LastCurveValues[ModIdx] = WAvg;
Output.Curve.Set(NameUID, WAvg);
}
else if (ApplyMode == EModifyCurveApplyMode::RemapCurve)
{
const float RemapScale = 1.f / FMath::Max(1.f - CurveValue, 0.01f);
const float RemappedValue = FMath::Min(FMath::Max(CurrentValue - CurveValue, 0.f) * RemapScale, 1.f);
Output.Curve.Set(NameUID, RemappedValue);
}
else // Blend
{
float UseAlpha = FMath::Clamp(Alpha, 0.f, 1.f);
Output.Curve.Set(NameUID, FMath::Lerp(CurrentValue, CurveValue, UseAlpha));
}
}
}
}
void FAnimNode_ModifyCurve::Update_AnyThread(const FAnimationUpdateContext& Context)
{
// Run update on input pose nodes
SourcePose.Update(Context);
// Evaluate any BP logic plugged into this node
GetEvaluateGraphExposedInputs().Execute(Context);
}
#if WITH_EDITOR
void FAnimNode_ModifyCurve::AddCurve(const FName& InName, float InValue)
{
CurveValues.Add(InValue);
CurveNames.Add(InName);
}
void FAnimNode_ModifyCurve::RemoveCurve(int32 PoseIndex)
{
CurveValues.RemoveAt(PoseIndex);
CurveNames.RemoveAt(PoseIndex);
}
#endif // WITH_EDITOR