Distance Matching Locomotion : Giving it a shot!

I haven’t the slightest idea yet of how to take into account all the things you’ve mentioned. The only small things I’ve tried are:

  1. blending N,E,S,W start animations using an alpha based on a ratio between a primary and secondary cardinal angle;
  2. creating a WarpAlpha curve that controls whether warping is on or off depending on foot placement (for start and stop anims).

I’ve been working solely with walking animations for a while, so the base speed fluctuates between 163 and 178, according to the speed curve I extracted from the animation using the Root Motion Extractor. My base speed is much lower than what you’re currently working with, and I still have issues. I’ve considered applying foot-locking, but I think there are things I need to fix first. I’m stuck though, which is extremely frustrating. My game dev hobbyist squad needs characters who can walk. Haha.

Yup, I’m using Kubold animations. I mirrored some animations in Blender, since the Kubold pack didn’t come with everything I want. (And I also constrained the freakin’ ik_handgun bones.) The really annoying part is that Kubold didn’t include start and stop animations for left and right running. I’m not an animator, so I don’t know how I’m going to remedy my situation. (That is partly the reason I’m working with walking anims first, since WalkStartLeft and WalkStartRight are included.) Also, Kubold animations are kind of glitchy, which is unfortunate.

If I knew of other animations that were better, I would try those.

I have a video on my youtube of some basic animation and orientation warping of the kubold pack because someone wanted to see. It doesn’t look good at all and I wouldn’t recommend using them (the basic locomotion anyway).

Use these instead: https://www.unrealengine.com/marketp…ity-mocap-pack

They are the best on the marketplace, and they come with all the curve data pre baked like how the paragon anims are, which is nice. There is also a starter version for like $6 and a basic for $50.
I’m thinking of using these for my own game prototype until I can afford my own Mocap **** lol. (didn’t know there was profanity filter?)

I also thought about somehow using the ALSV4 animations but creating curves manually will be fiddly and time consuming at best since he doesn’t have any root motion to reference from.

I saw that, actually. I’ve been checking out everything from everyone who is making warping and distance matching stuff. Haha. But, yeah, the Kubold animations didn’t look good. In fact, they looked just as crappy with your setup as with mine, which doesn’t give me much hope with regard to the anims. I thought I was just doing something stupid in my own setup (which is still possible), but to see the same look in yours leads me to believe much of the ugliness is from the anims themselves.

Wow! Those MoCap Online animations look great! Dang… I wish I had purchased those instead. Though the small packs are tempting, I’d prefer to save up and purchase the big Mobility Pro pack for $100. I noticed turn-in-place in eight directions. I think there are also start/stop anims in eight directions, if I’m not mistaken. The Ninja Pro pack looks impressive and useful too.

I also considered adding curves manually to ALSv4 animations, since those animations are freakin’ great too, but I came to the same conclusion as you: the consumption of time may not be worth the effort. It’s possible I’ll change my mind, but ALSv4 doesn’t have stop/start anims, which are anims I need.

The new amplify animation pack looks promising. Root motion anims which means distance match compatible. Going to have to try it out. I might post a video if it looks decent.

@postman09 The variety looks great in that pack! The first thing I notice that I don’t like is the lack of strafing animations. I didn’t see any sort of right/left strafing. I’m not sure how big of a deal that is.

The GREAT thing is the variety. The blender source files are included, which is cool.

I look forward to seeing a video with the pack implemented with your plugin. I probably won’t be buying anything soon, since I’m making sure I can purchase your plugin when it’s released. :wink:

I just got home and tried his packaged demo. The anims are not really that good so I’m not going to bother trying to implement with them. There is some weird jitter with the sprint.

That’s unfortunate. It’s difficult to find good anims. It looks like MoCap Online is still the best route to go.

EDIT: Also, I rewatched the video and found strafing animations. I’m not sure how I missed those in my first viewing. But walk strafing is missing, though run strafing is present.

Hi guys! I planned to share my solution, but I have no time to complete it, so I’m here to share a part of my solution. Many people ask me how I get time by distance from curve. Code below is not perfect, but I’m not a C++ programmer :slight_smile: This code works only if you compress curve with “Uniform Indexable” compression type!



#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);
}


P.S.: If you know how to improve code or found a bug, please let me know.
P.P.S: same in gist Get time by value from curve compressed with Uniform Indexable · GitHub

Thanks for sharing!

I tried implementing @'s code as a plugin, which I did successfully. And I added the “Uniform Indexable” compression type to my animation curves.

PluginPic.PNG

But whenever I Play, my editor crashes as soon I try to move at all. I can look around, but when I add movement input, the editor crashes.

EDIT: The below pic is the error I get.

Does anyone have any suggestions for how to fix the issue? I know almost nothing about c++.

Try to use this header file with my previous code:



#pragmaonce

#include"CoreMinimal.h"
#include"Animation/AnimInstance.h"
#include"AnimInstanceBase.generated.h"

DECLARE_LOG_CATEGORY_EXTERN(LogAnimInstanceBase, Verbose, All)

UCLASS(Abstract)
classPROTOTYPE_API UAnimInstanceBase : publicUAnimInstance
{
GENERATED_BODY()

public:
*  /***
*  * Returns the time of a named curve for corresponding value*
*  **
*  * Animation curve should be compressed with Uniform Indexable!*
*  **
*  * **@param**AnimationSequence*
*  * **@param**CurveName**          Named curve*
*  * **@param**CurveValue**         Curve value for search the corresponding time*
*  */*
UFUNCTION(BlueprintPure, Category="Animation")
staticfloatGetCurveTime(constclassUAnimSequence**AnimationSequence*, FName*CurveName*, float*CurveValue*);
};


Just create custom AnimInstance C++ class and inherit your BP AnimInstance from it and make sure you apply Uniform Indexable curve compression to your animations. Sometimes you need to reapply compression to animation curves, i don’t know why, but compression resets to default when I get my project from Git (when I copy my project to different folder or different PC)

Thanks for the feedback! I’ll try to implement that as suggested.

And I’ll also check on the curve compression, since I did move something things around. I may need to reapply the compression curves.

Thats not bad but if there arn’t alot of data points in the curve it won’t be that accurate since you are just lerping. The actual code for interpolation between points is much more sophisticated and takes into account tangents and what not, and still works with few data points.

What I did was just rite a quick animation modifier to swap the time and distance axis and save it as another curve so I could use the normal get float curve value function. That way I can use Epics black magic and not have to worry about the curve value being accurate.

@motorsep review this thread.

@postman09 Thanks for the idea! Thankfully, our current curves have a lot of data points, so the errors don’t seem highly noticeable. (But I’m not exactly sure what the errors would manifest as.) That said, the method you suggested will be added to the to-do list.

My current progress with distance matching is shown in the below video. The start transitions aren’t terrible. But, as you’ll see, the stop transitions are non-existent. The red/blue debug sphere show predicted stop location, but the error increases as character speed increases.
(Sorry if the video is loud. I’m still using the ALSv4 test level.)

The errors might not be too noticeable depending on the animation. All they would do is cause more foot sliding.

Hello everyone, I have a question after watching the Distance Matching video. When I switched from run to stop animation, I found the timestamp on the curve of the stop animation based on the distance to marker; however, my current pose did not match the pose of the stop animation that I found from the curve. To be more extreme, my left foot is in front during the transition period, but the stop animation frame found is right foot in front. How should I handle the transition between run and stop?

sounds like your distance calculation is wrong, or your curve is wrong, or your getting the wrong value for the curve. screen shots and videos help if you still need help.

How do you retrieve curve value by time? **Get Curve Value **- returns only value for current time. You still need to use FAnimCurveBufferAccess and power of C++ to extract value by time. Of course you can use Float Curve, but AnimModifiers can’t create objects of this type.

Anim modifiers can create float or vector curves inside animations. Create one to swap the x and y axis of the distance curve. Then get curve value will will give u time at certain distance.

you do need to make your own c++ func to get the value of the curve of a certain animation though.