• Unity
  • implement root motion in special way

Harald wrote
yinmo wrote

But one thing worths noting is how and when you scale the X/Y parameters. Imagine an animation of a character crunches down for a few frames then Jumps for a few frames. If you allocate the extended distance evenly for every frame, the character would start to move at the crunching phase.

Scaling root motion during the crunch-down part would just scale 0 root motion by a factor, still leaving it at 0. I never meant to add an evenly distibuted compensation offset, hence the name Root Motion Scale X/Y.

yinmo wrote

BTW, is there any way to Calculate the total distance automatically from the animations in runtime? I'm making a game with an emphasis on animation priority, sometimes I don`t want the movement stretched, yet I need the movement data to help AI to make decisions. e.g Get the distance between the target and the AI object, then get all the movement distance from each available attack animation, pick out the ones that can reach the target, then randomly choose one.

We will add some methods to retrieve the total root motion distance for an animation, I have created an issue ticket here:
[unity] Root motion scale and delta compensation · #1754
Explaining it in the necessary detail would take just as long. We will let you know when the feature is implemented.

Good to know, thanks a lot

The additional methods and parameters have been added.

From the changelog:

Added Root Motion Scale X/Y parameters to SkeletonRootMotionBase subclasses (SkeletonRootMotion and SkeletonMecanimRootMotion). Also providing AdjustRootMotionToDistance() and other methods to allow for easy delta compensation. Delta compensation can be used to e.g. stretch a jump to a given distance. Root motion can be adjusted at the start of an animation or every frame via skeletonRootMotion.AdjustRootMotionToDistance(targetPosition - transform.position, trackIndex);.

New 3.8 unitypackages can now be downloaded here as usual:
Spine Unity Download

We hope you like it! :nerd: Please let us know whether the additions satisfy your requirements for your use cases.

Here is an additional inofficial example Component that shows how AdjustRootMotionToDistance() can be used to compensate root motion to the position of a Transform.

Harald wrote

The additional methods and parameters have been added.

From the changelog:

Added Root Motion Scale X/Y parameters to SkeletonRootMotionBase subclasses (SkeletonRootMotion and SkeletonMecanimRootMotion). Also providing AdjustRootMotionToDistance() and other methods to allow for easy delta compensation. Delta compensation can be used to e.g. stretch a jump to a given distance. Root motion can be adjusted at the start of an animation or every frame via skeletonRootMotion.AdjustRootMotionToDistance(targetPosition - transform.position, trackIndex);.

New 3.8 unitypackages can now be downloaded here as usual:
Spine Unity Download

We hope you like it! :nerd: Please let us know whether the additions satisfy your requirements for your use cases.

Here is an additional inofficial example Component that shows how AdjustRootMotionToDistance() can be used to compensate root motion to the position of a Transform.

Wow, that`s way faster than I thought, impressive speed.

And yeah, the delta correction works perfectly as I desired.

Thank you very much.

But in regards to the method GetRemainingRootMotion(), it requires an animation applied to calculate the distance.
Is there a way to calculate the translation with a clip name? I need that info before animations are applied for some AI decisions.

You're welcome, glad it works as desired!

Regarding the clip name: please query it from SkeletonData:

Animation animation = skeletonData.FindAnimation(animationName);
Harald wrote

You're welcome, glad it works as desired!

Regarding the clip name: please query it from SkeletonData:

Animation animation = skeletonData.FindAnimation(animationName);

Thanks a lot

7 أشهر لاحقا

Hello Root Motion lovers :nerd:

I've been using the old experimental script for a while, with uneven results.
I consider upgrading for the new solution. 🙂

I have a few questions though :

1/ Do you guys have a nice and solid solution to enable/disable root motion exactly when needed ?

Right now I have marginal cases where my enemy jumps back n fourth during a single frame when switching from not Rooted to Rooted animations. I've been trying to use Start and Complete callbacks without really get rid off the problem completely.

2/ Delta compensation looks like a very nice feature but an actual exemple would be very helpful for beginners ^^

3/ Finally, if you guys already answered these questions or published guidelines or a tutorial on how to use this new component, please, shoot ! :grinteeth:

Thanks !!

RemDust wrote

1/ Do you guys have a nice and solid solution to enable/disable root motion exactly when needed ?

Right now I have marginal cases where my enemy jumps back n fourth during a single frame when switching from not Rooted to Rooted animations. I've been trying to use Start and Complete callbacks without really get rid off the problem completely.

I'm afraid this is a theoretical problem of switching between root motion and non-root motion animations. When switching to the non-root motion mode, the animation will immediately override the current position with an undesired one if the animation is not at the origin (0,0) position. As you said you tried using the Start and Complete callbacks: do your animations start at position (0,0)?

RemDust wrote

2/ Delta compensation looks like a very nice feature but an actual exemple would be very helpful for beginners ^^

Good point. I have created an issue ticket here:
https://github.com/EsotericSoftware/spine-runtimes/issues/1873
For now I can only offer a simple RootMotionDeltaCompensation example component, an example scene will take a bit longer to make (mostly because a skeleton asset requires added root motion animations and release for both 3.8 and 4.0-beta). The example component has been added on the 3.8 branch (4.0-beta will follow soon), a new 3.8 unitypackage is available for download here as usual:
Spine Unity Download
Please let us know if this component helps, or just ask straight ahead if you have any questions. Unfortunately changes for the 4.0-beta release are keeping us a bit too busy for creating the example scene and skeleton for now.

Harald wrote

As you said you tried using the Start and Complete callbacks: do your animations start at position (0,0)?

Hi Harald,
Yes, all my animations starts at (0,0), some finished quite far from there though.
What I'm doing so far is checking a property "isRootMotionAnimated" when I call SetAnimation(), the animation starts and enable/disable accordingly.
The problem occurs when I need to call AddAnimation, I can't seem to be able to get consistent start event callbacks then.
Right now I kinda workaround that taking out AddAnimation from my workflow and delaying SetAnimation accordingly :rolleyes:

Harald wrote

Please let us know if this component helps, or just ask straight ahead if you have any questions. Unfortunately changes for the 4.0-beta release are keeping us a bit too busy for creating the example scene and skeleton for now.

Thank you for providing this example !
I looked into it and while the compensation seems to make sense I can't actually get the SkeletonRootMotion to work, event without delta compensation :headwall:
The skeleton rushes in the wrong direction and doesn't stop until I disable root motion.

Before these tests, I was using Pharan's root motion with good results, I was able to set root motion bone and "fixed bones" (fairly complex to setup though).

Could it be the problem ? :
With the new official root motion script I can only define a root motion bone.

My in spine editor setup looks like :

  • Root


Root Motion Bone



Hips (and hips children bones)



IKLeg1



IKLeg2



.... more IKs

So yes, my root motion bone is not the Root, but a child bone containing everything else (we need to be able to rotate the skeleton without rotating the whole referential, but it could be bad practice ?)

RemDust wrote

The problem occurs when I need to call AddAnimation, I can't seem to be able to get consistent start event callbacks then.

The Start callback should be issued reliably right after a track has been started after being enqueued. There should be no difference to calling SetAnimation. Are you sure that you are handling everything within the callback, and not delaying something to the next Update or LateUpdate call?

RemDust wrote

Before these tests, I was using Pharan's root motion with good results, I was able to set root motion bone and "fixed bones" (fairly complex to setup though).

Thanks for reporting and sorry for the troubles! I just checked the root motion script, and it indeed seems to run incorrectly when choosing a non-root bone as Root Motion Bone. This is indeed a bug, I have created an issue ticket here: https://github.com/EsotericSoftware/spine-runtimes/issues/1876
We will let you know when it's fixed.

Thank you for the quick reply Harald !

I'll wait for this fix then 🙂
Could you ping me when it's done ?

Yes, I will post here on the forum when it's done. I hope it can be completed today, otherwise it should be done the next few workdays next week.


@RemDust
The implementation has just been completed. The improved implementation should now support arbitrary bones as Root Motion Bone. It now also respects Skeleton.ScaleX and .ScaleY and parent bone scale.

New 3.8 and 4.0-beta unitypackages are available for download:
Spine Unity Download

Please let us know if this resolves your issue and now works as desired.

Harald wrote

The implementation has just been completed. The improved implementation should now support arbitrary bones as Root Motion Bone. It now also respects Skeleton.ScaleX and .ScaleY and parent bone scale.

Please let us know if this resolves your issue and now works as desired.

Hi Harald, thank you for the light speed update. 🙂

1/ the fix seems to work really well. I'll let you know how stable it is moving forward. :nerd:

2/ Using Rigidbody2D root motion is easy in the X axis, but I'm not too sure if I'm using it well on Y axis, mixing gravity and root motion animation seems like a arguably bad idea ^^ :think:

3/ Delta compensation is absolutely great ! I have just started playing with it but I think having an option to separate extrapolation on X and Y axis could be useful :

For instance, I have this case where the enemy jumps from a distance towards the player. Right now Delta Compensation overrides the Y jump component (as enemy and player are on the same ground) so he looks like he is sliding towords the player.

-> I guess enemy should use X Delta compensation but not Y, at least not right away. Actually in this case I think it would make sense that the enemy ignore Y Delta Compensation for the first part of the jump, where he is going upward and trigger Y compensation while he's going down.

Does this make sense somehow ? :grinteeth:

You're welcome, thanks for reporting!

RemDust wrote

1/ the fix seems to work really well. I'll let you know how stable it is moving forward.

Very glad to hear!

RemDust wrote

2/ Using Rigidbody2D root motion is easy in the X axis, but I'm not too sure if I'm using it well on Y axis, mixing gravity and root motion animation seems like a arguably bad idea ^^

I don't see a problem yet as it's just adding a root motion delta to the position of the rigidbody via

rigidBody2D.MovePosition(new Vector2(transform.position.x, transform.position.y) + rigidbodyDisplacement);

So gravity should apply it's acceleration, and the rootmotion script should move the object an additional rootmotion-delta, both summing up additively. Admittedly I haven't thought this through completely though, did you encounter any problems?

RemDust wrote

3/ Delta compensation is absolutely great ! I have just started playing with it but I think having an option to separate extrapolation on X and Y axis could be useful :

Good point! This is missing in the method AdjustRootMotionToDistance in the root motion script. I will add it to both SkeletonRootMotionBase.AdjustRootMotionToDistance and the RootMotionDeltaCompensation example component.

For instance, I have this case where the enemy jumps from a distance towards the player. Right now Delta Compensation overrides the Y jump component (as enemy and player are on the same ground) so he looks like he is sliding towords the player.

If your animation starts at Y=0, has its high point at Y=1 and ends at Y=0 again, delta compensation of both X and Y should lead to the jump being adjusted only on the X axis and nothing changed on Y. I receive this at a local test setup. I wonder why you see a horizontal slide with Y motion being removed.

RemDust wrote

-> I guess enemy should use X Delta compensation but not Y, at least not right away. Actually in this case I think it would make sense that the enemy ignore Y Delta Compensation for the first part of the jump, where he is going upward and trigger Y compensation while he's going down.

Please note that delta compensation will scale your remaining animation so that the distance of position(now) to position(last_frame) fits the desired vector. So when you're at the first frame, it will scale the X and Y portions of the delta so that it reaches the target end point instead of the unscaled endpoint. There will be problems however if your target endpoint is at different Y and your animation does not change Y position from start to end, because no scaling can change a delta of 0.0 to e.g. 1.8. The easiest solution for this problem would be to create a jump animation that e.g. has an arc of Y values like: 0, 2, 1. This way the whole arc will be scaled, when e.g. delta compensating the jump to land at Y=3 it will become 0, 6, 3. Unfortunately this scaling solution does not yet solve the case for jumping down to e.g. -1 while using an upward animation, because it would then mirror the arc to a negative 0, -2, -1. Solutions to this problem could be

  • a) to enable delta-compensation later as you described, at the apex of the arc when moving downwards (although this will then look wrong, scaling only the downward half of the arc)
  • b) an additional more complex delta compensation method to allow for such adjustment automatically.

I have added functionality to separately apply delta compensation only for the X or Y component.

changelog.md wrote

Root motion delta compensation now allows to only adjust X or Y components instead of both. Adds two parameters to SkeletonRootMotionBase.AdjustRootMotionToDistance() which default to adjusting both X and Y as before. The RootMotionDeltaCompensation example component exposes these parameters as public attributes.

A commit has just been pushed to the 3.8 branch and a new unitypackage is available for download here as usual:
esotericsoftware.com/spine-unity-download
It will be integrated in the 4.0-beta branch soon.

Thank you very much for the new commit, can't wait to check it out !

About delta compensation. I gave some thoughts about this exemple :

The green is the movement as designed in Spine Editor. It's a fairly commun parabolic jump from enemy towards the payer.
In blue we can see the needed delta compensation, which is, in this case only on the X axis.

If I'm correct using Y delta compensation would override the Y part of the jump, correct ?

So in this case I guess we could simply don't use Y compensation but then even if the graphics display correctly my rigidbody2D would actually still be on the ground and "slide" towards the player. In this easy case of same ground/level it wouldn't be too problematic but i can see this being an issue going forward.

I have a lot on my plate right now, I hope I'll be able to elaborate and think more tomorrow !
As always, thank you for your help Harald 🙂

I will come up with a solution that covers the above jump use case. I will post here on the thread once this update is complete.

Can't ask for a better support, you rock :rock:

Thanks for your kind words 8).

A commit has just been pushed to the 3.8 branch.

changelog.md wrote

Root motion delta compensation now allows to also add translation root motion to e.g. adjust a horizontal jump upwards or downwards over time. This is necessary because a Y root motion of zero cannot be scaled to become non-zero.

The delta compensation example script should automatically have this Allow Y Translation parameter enabled, which should now adjust root motion automatically.

Along the way I also fixed scale of Transform, Skeleton, and parent bone not being respected by the delta compensation computations: delta compensation should now work consistently with arbitrary scaling.

A new spine-unity 3.8 package is available for download here as usual:
Spine Unity Download
Please let us know if this now works as desired for your use case. :nerd:

Harald wrote

Along the way I also fixed scale of Transform, Skeleton, and parent bone not being respected by the delta compensation computations: delta compensation should now work consistently with arbitrary scaling.

Please let us know if this now works as desired for your use case. :nerd:

Hi Harald,
thank you so much for putting the effort in making Root Motion better 🙂

Based on my quick new tests Delta compensation seems really good even with marginal cases now, thanks ! :nerd:

Now, about Ridigbody2D root motion I still have a problem. Not talking about delta compensation here.
I encounter conflicts between physics and root motion movement :upsidedown:

Let me explain a bit.

The root bone of the enemy is at (0,0) in editor, so basically right at the ground level.
Now back in Unit, I parent my skeleton to my actual GameObject Enemy containing physics and box2d. I have to size and match my box collider to fit the enemy, and make the unity gameobject root fit to the skeleton root. To make the issue obvious if I set box 2d/rigidbody too low (in y value) compares to the skeleton, root motion will constantly push my body 2d up in the air, even targeting a "neutral value" of (0,0) like an Idle animation. Opposite case, if my body 2D is too high above the root bone, root motion will tend to push the rigibody into the ground.

conclusion -> If my gameobject box 2d doesn't pixel perfect-match the ground level of the spine root I have a these cases where root motion conflicts with physics as physics and root doesn't "target the same ground level".

Does that make any sense to you ? How would you setup your gameobject and skeleton to avoid that ? I can try and make a quick drawing if that helps to explain the issue ^^

I suppose that I miss something obvious and that there is a usual way to make this all fit nicely :think:

[EDIT]
I tweaked the colliders a bit and even if I'm almost 100% sur that it fits, using Root Motion with Rigidbody2D gives me shorter jump attack that root motion only without physics. Changing the mass, linear or angular drag doesn't seem to affect the distance in any way.
Is this the expected behaviour ?

RemDust wrote

thank you so much for putting the effort in making Root Motion better 🙂

Based on my quick new tests Delta compensation seems really good even with marginal cases now, thanks !

Thanks for your kind words, glad it works better now! 8)

RemDust wrote

Now, about Ridigbody2D root motion I still have a problem. Not talking about delta compensation here.
I encounter conflicts between physics and root motion movement :upsidedown:

Unfortunately I could not reproduce your problem, or I simply misunderstood your setup. If I make the BoxCollider2D larger so that it intersects with a ground collider (reaches into the ground too deep) and play a horizontal jump animation, I see normal physics compensation behaviour moving the object smoothly upward out of the ground. Did you receive other behaviour? Could you then please prodive the mentioned drawing to explain things a bit more?

Apart from that, I noticed that the root motion script does not interact well enough with Rigidbody2D yet, as I noticed some jittering occur when playing a jump animation. Since it does not occur (or is not visible enough) on a walk animation, it remained unnoticed until now. I have created an issue ticket here:
https://github.com/EsotericSoftware/spine-runtimes/issues/1880

Harald wrote

Unfortunately I could not reproduce your problem, or I simply misunderstood your setup. If I make the BoxCollider2D larger so that it intersects with a ground collider (reaches into the ground too deep) and play a horizontal jump animation, I see normal physics compensation behaviour moving the object smoothly upward out of the ground. Did you receive other behaviour? Could you then please prodive the mentioned drawing to explain things a bit more?

Well I kinda fixed it, it came from a bad setup where the skeleton root bone is not perfectly aligned with the physics object root :
an animation of the root bone, even at (0,0) results in a constant "force" applied on the rigidbody.
I suppose because the rigidbody tries to reach the position of the skeleton root bone which (being a a child of the rigidbody,) is also moving, like a dog chaising it's tail ^^) :upsidedown:

A perfect alignement of root bone and physics object root get rid off this effect.

Harald wrote

Apart from that, I noticed that the root motion script does not interact well enough with Rigidbody2D yet, as I noticed some jittering occur when playing a jump animation. Since it does not occur (or is not visible enough) on a walk animation, it remained unnoticed until now. I have created an issue ticket here:
https://github.com/EsotericSoftware/spine-runtimes/issues/1880

Then it may be related to the real problem I'm facing : root motion with rigidbody gives me significantly different results than root motion without physics. Please see image below for better explanation ^^