Skip to content

Instantly share code, notes, and snippets.

@rmerkushin
Created October 12, 2020 07:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmerkushin/b3f9d6a3a39ba35d66e1a8ea651c33dd to your computer and use it in GitHub Desktop.
Save rmerkushin/b3f9d6a3a39ba35d66e1a8ea651c33dd to your computer and use it in GitHub Desktop.
Get time by value from curve compressed with Uniform Indexable
#include "Animation/AnimInstanceBase.h"
#include "Animation/AnimCurveCompressionCodec_UniformIndexable.h"
DEFINE_LOG_CATEGORY(LogAnimInstanceBase)
float UAnimInstanceBase::GetCurveTime(const UAnimSequence* AnimationSequence, const FName CurveName, const float CurveValue)
{
if (AnimationSequence == nullptr)
{
UE_LOG(LogAnimInstanceBase, Error, TEXT("Invalid Animation Sequence ptr"));
return 0.0f;
}
// Get curve SmartName
FSmartName CurveSmartName;
AnimationSequence->GetSkeleton()->GetSmartNameByName(USkeleton::AnimCurveMappingName, CurveName, CurveSmartName);
// Create a buffered access to times and values in curve
const FAnimCurveBufferAccess CurveBuffer = FAnimCurveBufferAccess(AnimationSequence, CurveSmartName.UID);
// The number of elements in curve
const int NumSamples = static_cast<int>(CurveBuffer.GetNumSamples());
const int LastIndex = NumSamples - 1;
if (NumSamples < 2)
{
return 0.0f;
}
// Corner cases
if (CurveValue <= CurveBuffer.GetValue(0))
{
return CurveBuffer.GetTime(0);
}
if (CurveValue >= CurveBuffer.GetValue(LastIndex))
{
return CurveBuffer.GetTime(LastIndex);
}
// Binary search
int32 NextIndex = 1;
int32 Count = LastIndex - NextIndex;
while (Count > 0)
{
const int32 Step = Count / 2;
const int32 Middle = NextIndex + Step;
if (CurveValue > CurveBuffer.GetValue(Middle))
{
NextIndex = Middle + 1;
Count -= Step + 1;
}
else
{
Count = Step;
}
}
const int32 PrevIndex = NextIndex - 1;
const float PrevCurveValue = CurveBuffer.GetValue(PrevIndex);
const float NextCurveValue = CurveBuffer.GetValue(NextIndex);
const float PrevCurveTime = CurveBuffer.GetTime(PrevIndex);
const float NextCurveTime = CurveBuffer.GetTime(NextIndex);
// Find time by two nearest known points on the curve
const float Diff = NextCurveValue - PrevCurveValue;
const float Alpha = !FMath::IsNearlyZero(Diff) ? (CurveValue - PrevCurveValue) / Diff : 0.0f;
return FMath::Lerp(PrevCurveTime, NextCurveTime, Alpha);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment