• Unity
  • implement root motion in special way

Related Discussions
...
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 ^^

RemDust wrote

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 ^^)

I tried radically different BoxCollider2D offset to the root bone, but didn't see any vertical "position fighting". Nevertheless, I could reproduce enough jitter in a jump animation which is dealt with in the aforementioned issue ticket, it might perhaps fix the other issue as well.

RemDust wrote

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 ^^

Thanks for posting the image, this is indeed problematic. I wonder if this is due to similar problems as in the ticket above, or if it's maybe due to any physics effects being applied (although I don't think that the Linear Drag or other friction effects should lead to this result). Anyway, we will see one the above problem is solved, let's hope it's all due to the same problem.

Let's hope it all comes from the same issue :whew:
Would you ping me when you'll have it updated ?

As always thank you for your hard work 🙂

I will post here on the forum once a new unitypackage has been published. You can also subscribe to the issue ticket, then you will receive additional notifications upon any progress (and any associated commit).

Harald wrote

I will post here on the forum once a new unitypackage has been published. You can also subscribe to the issue ticket, then you will receive additional notifications upon any progress (and any associated commit).

Awesome, thank you ??

A bugfix for moving the Rigidbody and Rigidbody2D components has just been released, it should now work very smoothly without any jitter at all. It has been a bit tricky, but should now also respect scale at every level of the skeleton.

New 3.8 and 4.0-beta spine-unity unitypackages have been released and are available here as usual:
Spine Unity Download

Unfortunately after testing high gravity scale on a Rigidbody2D, I could reproduce your reported "distance is not the same as without a rigidbody" issue reported above. This is not present at all when setting Gravity Scale to zero, and the effect gets larger the more I increase this value, so it seems to be the cause of this problem. The RootMotion components use Rigidbody2D.MovePosition() which unfortunately states:

Rigidbody2D.MovePosition.html wrote

"Note: MovePosition is intended for use with kinematic rigidbodies. "

https://docs.unity3d.com/ScriptReference/Rigidbody2D.MovePosition.html
So this seems to be a mainly Unity related problem, unfortunately I don't yet know what to use instead of Rigidbody2D.MovePosition() when using non-kinematic dynamic rigidbodies. Admittedly I would have expected no friction or similar effect to take place when using MovePosition() with the resulting absolute position value.

If anyone knows any workarounds or insights regarding this subject, please let me know, any input is greatly appreciated!

2ヶ月 後

Hey Harald !
Sorry for the very late reply. A lot of work lately.

Thanks for the fix of the jitterring :clap:

So I tried to reduce the gravity scale and this is indeed the source of the distance problem.
Good thing is we know what is it, bad thing is we don't know how to tackle this right now.

I need to be able to increase the gravity scale for huge ennemies. I'm gonna post on Unity forum for an alternative for MovePosition but I'm afraid that moving the position of a non kinematic rigidbody in Unity is intended by adding forces...

I guess the REAL solution would be to get rid off Unity physics and hardcode my own "physics" and collisions but it seems like a pain at this stage ^^'

[EDIT & WORKAROUND]
So !
I've been investing a bit and I was almost sure it had something to do with friction.
I was making the assumption that no physics material in Rigidbody would set friction to zero (specially with linear and angular drag set to zero in rigidbody properties).
Actually creating a 2D material with zero friction for the rigidbody with a root motion solves the "distance problem".
I can see cases where a no friction material can be an issue : an enemy standing on a non horizontal ground would be sliding...

So here is what I can think of :
Set material to rigidbody, friction to whatever, let's say 1.
When using root motion, simply set friction to zero, and revert it back when the movement is done.
What do you think ?
Does it make sense to have it as a default behaviour in the RootMotion script Harald ?

Thanks for the detailled writeup!

RemDust wrote

When using root motion, simply set friction to zero, and revert it back when the movement is done.
What do you think ?
Does it make sense to have it as a default behaviour in the RootMotion script Harald ?

Unfortunately I'm afraid this is not an option for being overridden by the RootMotion component all the time, as there are situations as you've mentioned in which you would want to have friction set to a non-zero value. Unfortunately movement is also never done, so it's hard to decide when to set friction back to the normal value. So I'm afraid this solution would cause another group of problems. :wounded: