KybernetikGames / animancer

Documentation for the Animancer Unity Plugin.
66 stars 8 forks source link

Two layers with root motion animations don't combine right #302

Closed virtushda closed 1 year ago

virtushda commented 1 year ago

Environment

Description

I have an override layer for the base layer, which does my translation animations and applies root motion. Then I have an additive layer as the second layer which is dedicated to doing the rotational animations and also applying root motion.

Previously, I had one layer and one giant mixer that blended in the rotation and it worked but was too restrictive.

What's happening with the two-layer approach is that the additive layer's animation just doesn't seem to apply any lasting root motion. The creature translates as best it can, and tries to turn, but keeps snapping back to its starting orientation.

Am I doing this right? Or is this unsupported? If the latter case is true, how can I achieve this?

image

https://streamable.com/zyejeo

KybernetikGames commented 1 year ago

Unfortunately, root motion and layer blending is handled internally by the Playables API so there probably isn't anything Animancer can do about it by default.

If you update to Animancer v7.3 and replace the default layer mixer with a custom script like the Weighted Mask Mixer in this post it should be possible to modify its WeightedMaskMixerJob struct to do what you want:

Doing that would mean you need to give it all the Transforms you want it to control, which would be a bit tedious to set up, but I've never found a way to have a job automatically apply to everything the animations want to control. Though since you don't need to associate a specific weight value with each bone, you could probably just use GetComponentsInChildren<Transform>() to get everything.

virtushda commented 1 year ago

Thanks for replying so quickly!

I don't particularly understand how that new feature works, but I can give it a go!

While looking around your wonderful documentation, I also had another idea : Could I 'override' the root motion and add in the rotational velocity from the clip?

Conveniently, I already have baked out the root motion curves of all the clips I need them for, and it seems like it should be relatively simple to compute based on the weights of that linear mixer doing the turning animations. Do you think that would work?

KybernetikGames commented 1 year ago

Yeah, Animation Jobs are pretty convoluted and painful to use.

If you've already extracted the root motion curves and don't mind managing the curve <-> clip association yourself, then implementing an OnAnimatorMove method to add to the root motion could be much easier to implement than using jobs. The Redirect Root Motion scripts would probably be a good baseline to start with.

virtushda commented 1 year ago

I'm sorry to bother you again, but I looked at the job approach again and figured I could just modify the root motion rotation in a super simple job, but it's not even close to working... I can find absolutely zero documentation on how ProcessRootMotion works. :(

The 'VUnsafeRef' is basically just a NativeReference, the rotation being supplied is very simple, has been verified with a debugger, and definitely isn't affecting the root motion in any sort of logical way. (I'm seeing unwanted translation actually, no Y rotation! lol)

Does this look wrong in any way? image image image

KybernetikGames commented 1 year ago

Maybe try getting and setting the local rotation instead of world. Other than that, it looks like it should work.

virtushda commented 1 year ago

I've been hammering away at this all day and it's really close, but also somehow off by a factor of 8... lol

The root motion data I'm reading should be accurate, as it's the same data I was using previous to this two-layer approach and it was working beautifully. I'm trying to sample the previous frames root motion rotation, and pass along the difference from the current frames sampled root motion rotation. I'm turning the animals transform, and then de-rotating the actual root bone, and it's stay synchronized, but the resulting root motion rotation is ~8x as fast as it should be.

I'm hoping you might see some way I'm calculating the step wrong as I'm interfacing with your code a lot here. image

EDIT: I actually tried caching the normalized time values from the last frame and it's exactly the same, if not worse. I'm not even sure what I don't understand now. haha

KybernetikGames commented 1 year ago

Nothing jumps out at me as looking obviously wrong. If you want to send a minimal reproduction project to animancer@kybernetik.com.au I'd be happy to take a look at it.

virtushda commented 1 year ago

Unfortunately it's practically impossible for me to lift this out as a standalone example. :\

I've updated to 7.4.2 though, and I'm going to try keeping root motion on one layer, because this whole approach introduced a number of other issues. What I'm going to do differently is use animation jobs to add procedural turning to running, which is what I was really trying to do in the first place.

I'm curious if what I was trying to do could work right, but being on a pretty tight deadline I'm going to have to give it up and avoid all the other problems. (Backwards feet, way over-animating, wrapping the root motion stuff,etc)

I really appreciate your timely responses though, and I've been introduced to IAnimationJob nicely by your weightedmixer stuff which is of tremendous benefit to my use case.

PS: Gotta say I wish you were developing the new DOTS animation stuff, given that you made Mecanim usable for me. I'm kinda scared to see what Unity ends up putting out.