LDelayen
(LDelayen)
February 5, 2016, 7:49pm
33
Hi ,
Thanks again for sharing those with us !
Help me to clarify things a little bit please.
So, You loop from 0 to animation-time-length and using float Value = FRichCurve::Eval(float Time) to evaluate the curve and get the value. When Value is equal to your current capsule rotation (for example, assuming that we are doing this for the turn animation) then you finish the search and evaluate the anim sequence using that Time.
This is the idea ? and you do this inside the Tick ? is not a problem in term of consuming CPU or the binary search algorithm is enough to find very quickly the value ?
Please, help me to clarify this.
PD: Sorry for my english
Thanks so mush !!
>> So, You loop from 0 to animation-time-length and using float Value = FRichCurve::Eval(float Time) to evaluate the curve and get the value.
no, I do a binary search on the keys directly. Evaluating the curve is slow, and we assume linear interpolation in between keys. So I just need to find the bounding keys, and do a lerp.
We don’t have that many keys in these animations, so the binary search is pretty fast. It hasn’t shown up on our profiles as something significant.
The basic idea is my distance to the marker is 12 units, I want to find the position in the animation where the distance curve is 12.
I do a binary search for the bounding keys around that value. Let’s say I find Key3 (9) and Key4(13). I then do a lerp to find the correct time in the animation,
Here’s the code for that function, it’s fairly straight forward:
float FindPositionFromDistanceCurve(const FFloatCurve& DistanceCurve, const float& Distance, UAnimSequenceBase* InAnimSequence)
{
const TArray<FRichCurveKey>& Keys = DistanceCurve.FloatCurve.GetConstRefOfKeys();
const int32 NumKeys = Keys.Num();
if (NumKeys < 2)
{
return 0.f;
}
// Some assumptions:
// - keys have unique values, so for a given value, it maps to a single position on the timeline of the animation.
// - key values are sorted in increasing order.
#if ENABLE_ANIM_DEBUG
if (bDebugLocomotion)
{
// verify assumptions in DEBUG
bool bIsSortedInIncreasingOrder = true;
bool bHasUniqueValues = true;
TMap<float, float> UniquenessMap;
UniquenessMap.Add(Keys[0].Value, Keys[0].Time);
for (int32 KeyIndex=1; KeyIndex < Keys.Num(); KeyIndex++)
{
if (UniquenessMap.Find(Keys[KeyIndex].Value) != nullptr)
{
bHasUniqueValues = false;
}
UniquenessMap.Add(Keys[KeyIndex].Value, Keys[KeyIndex].Time);
if (Keys[KeyIndex].Value < Keys[KeyIndex - 1].Value)
{
bIsSortedInIncreasingOrder = false;
}
}
if (!bIsSortedInIncreasingOrder || !bHasUniqueValues)
{
PrintDebugString(FString::Printf(TEXT("ERROR: BAD DISTANCE CURVE: %s, bIsSortedInIncreasingOrder: %d, bHasUniqueValues: %d"),
*GetNameSafe(InAnimSequence), bIsSortedInIncreasingOrder, bHasUniqueValues));
}
}
#endif
int32 first = 1;
int32 last = NumKeys - 1;
int32 count = last - first;
while (count > 0)
{
int32 step = count / 2;
int32 middle = first + step;
if (Distance > Keys[middle].Value)
{
first = middle + 1;
count -= step + 1;
}
else
{
count = step;
}
}
const FRichCurveKey& KeyA = Keys[first - 1];
const FRichCurveKey& KeyB = Keys[first];
const float Diff = KeyB.Value - KeyA.Value;
const float Alpha = !FMath::IsNearlyZero(Diff) ? ((Distance - KeyA.Value) / Diff) : 0.f;
return FMath::Lerp(KeyA.Time, KeyB.Time, Alpha);
}