Playables API - Mirroring Clips and DirectorUpdateMode.Manual

Hey guys! I’m in the process of converting my game from relying on Mecanim to simply utilizing the Playables API. I’m very excited to do so as it’s much better for the project on paper, but I’ve run into a couple of roadblocks that might be deal-breakers if I can’t find a solution (Google sure can’t).

-Is there a way to Mirror animation clips the way that Mecanim is able to? I was able to find and disable the “Foot IK” with AnimationClipPlayable.SetApplyFootIK (which is helpfully and secretly on by default), but there seems to be no such method for enable Mirroring.

-When setting PlayableGraph.SetTimeUpdateMode to Manual, its own description(link) says that “PlayerController.Tick” must be called to actually advance the time - however, no such method can be found in the Unity documentation (the web description doesn’t even link to the method), and the two other guys on the internet who have posted about this in English seem just as perplexed as I am.

Thanks in advance - and really hope I’m not being cast back into the flaming cesspits of Mecanim!

1 Like

Just checking to see if anything’s changed since my original post! The lack of any clear answer or acknowledgement of these two issues on the entire internet are enough to prevent me from making the making the switch to this system to which I’ve been very excited to migrate.

Mirroring is definitely missing and that’s a problem. I upvoted your feature request for that, but I hope it’s on the dev team’s TODO list anyhow.

Apart from that, it seems that the playables API has not quite matured yet, there are still fundamental bugs. One I reported (and which is confirmed) makes complex BlendShapes using script playables impossible at this moment. You can work with it, but if you have a working system already, I’d say don’t migrate yet.

Hi! It is quite disappointing that the documentation is completely misleading and incorrect. However (thankfully) after a little digging I found that you can in fact update a director manually.

director.time += Time.deltaTime;
director.Evaluate();

I’ve tested this myself and can confirm that it works as expected. I found that thanks to this forum thread . I’ve submitted a correction to the documentation, but doing so yourself might speed the process up.

Unity 2018.2 brings us the AnimationScriptPlayable. I’m pretty certain this can be used to mirror clips by overriding the muscle values and root motion.

I’ve tried this by inverting the muscle values for the Left/Right muscles of head and torso and by swapping the muscle values for left and right extremities - however that didn’t really work, I got strange looking results.

I’ll give it another try soon - but maybe somebody has a solution for this already?

you help me a lot! thank you very much!

It almost this, some muscle don’t need to be inverted, here a table that show how to invert them for the torso and the head, arm and leg dof only need to be swapped.

float[] BodyDoFMirror = new float[] {
    +1.0f,  // BodyDof.SpineFrontBack,
    -1.0f,  // BodyDof.SpineLeftRight,
    -1.0f,  // BodyDof.SpineRollLeftRight,
    +1.0f,  // BodyDof.ChestFrontBack,
    -1.0f,  // BodyDof.ChestLeftRight,
    -1.0f,  // BodyDof.ChestRollLeftRight,
    +1.0f,  // BodyDof.UpperChestFrontBack,
    -1.0f,  // BodyDof.UpperChestLeftRight,
    -1.0f   // BodyDof.UpperChestRollLeftRight,
};

float[] HeadDoFMirror = new float[] {
    +1.0f,  // HeadDof.NeckFrontBack,
    -1.0f,  // HeadDof.NeckLeftRight,
    -1.0f,  // HeadDof.NeckRollLeftRight,
    +1.0f,  // HeadDof.HeadFrontBack,
    -1.0f,  // HeadDof.HeadLeftRight,
    -1.0f,  // HeadDof.HeadRollLeftRight,
    +1.0f,  // HeadDof.LeftEyeDownUp,
    -1.0f,  // HeadDof.LeftEyeLeftRight,
    +1.0f,  // HeadDof.RightEyeDownUp,
    -1.0f,  // HeadDof.RightEyeLeftRight,
    +1.0f,  // HeadDof.JawDownUp,
    -1.0f   // HeadDof.JawLeftRight,
};

You also need to mirror the root and IK goal.

It would be pretty easy for us to add a method for this on AnimationHumanStream, something like
AnimationHumanStream.MirrorPose();

Thanks! I’ll give this a try.

But I guess this would be the most convenient way to solve it. :slight_smile:

OK, I tried to implement an IAnimationJob in the attached files.

  • Mirror head and body muscles according to what you provided.
  • Swap all arm, leg and finger muscles.
  • Mirror root motion (inverting local X position and local Y rotation should do the trick?).
  • IK is not implemented for now.

It doesn’t quite seem to be working - see GIF below (blue is normal, pink is supposed to be mirrored). Arm swapping looks fine, but apart from that, something is seriously going wrong. It’s exactly the same problem I had in my first attempt a few weeks back. Any ideas what the mistake could be?

3631168--295924--ezgif-2-24d15a0e0f.gif

3631168–295912–AnimationHumanStreamExtensions.cs (494 Bytes)
3631168–295915–MirrorPoseJob.cs (3.73 KB)

Bumping since there hasn’t been anything for a year.
Lots of views in those files but no replies (probably lots of bot views too). Did anybody solve this?

If it is easy, would be a nice-to-have for 2019.3?

Hi,

Unfortunately the feature is not planned right now in our road map. We are working on other priority.

Alright, I understand that, but there’s apparently nothing we can do to implement this ourselves.

The mirroring you proposed doesn’t work as intended (see GIF above, still the same in 2019.1). I can’t see anything wrong with that or my code even after a year, so I’m puzzled.

Is there any chance mirroring will be implemented in playables? It seems like a massive, handy feature to miss out on.

1 Like

Have it implemented this feature yet?
The spec has changed a lot since then, but with a few changes to the script it worked almost perfectly.

However, the current BodyDof does not support Hip, so this is not the only support.

hip ->NG
spine ->OK
chest ->OK
upper chest ->OK

As a result, the upper body appears to vibrate badly in motions that move the hips a lot.

Also, since the Global Position is inverted, the actual coordinates and the coordinates of the animation will be different.
(If you do not invert Global’s bodyPosition and bodyRotation, you will end up jumping to the left but moving to the right.)

6827078–793484–MirrorPoseJob.cs (6.42 KB)

Fixed.

-BodyLocalRotation is only the rotation of the “Hip”.
The only way to reverse the orientation of the entire body is to reverse the bodyRotation.

-BodyLocalPosition is also only the position of the “Hip” relative to the base position of the model, not the position of the model itself.
Even if this is reversed, the motion that “moves to the left” only “moves to the left”.
Therefore, it is necessary to invert the bodyPosition.

As a result, it is necessary to invert the body Position and body Rotation in order to invert the position and movement of the body.
Since it is inverted by global, there is no need to change bodyLocalRotation and bodyLocalPosition.

IK also needs to use GetGoalPosition and GetGoalRotation accordingly.

The IAnimationJob can control the “apparent position and rotation (not the actual position) of the model in global coordinates”.
I don’t think I can control the actual movement and rotation of the model itself.

If you don’t want the apparent position to fly at the flipped timing, you can flip the actual position and angle.

this.transform.position = new Vector3(-this.transform.position.x, this.transform.position.y, this.transform.position.z);
this.transform.eulerAngles = new Vector3(this.transform.eulerAngles.x, -this.transform.eulerAngles.y, this.transform.eulerAngles.z);

It’s annoying because all coordinate calculations, such as collider and event positions, need to be flipped on the x-axis.

If I want to avoid this problem

  • Prepare another motion for reversal from the beginning (Use twice the capacity)
  • Invert the scale.x of the model itself to -1 (It cannot be used unless model is symmetrical.)
  • Does not consider orientation or movement for motion data.
    Is there any other solution?

6830060–793985–MirrorPoseJob.cs (7.45 KB)

1 Like

Oh, hey Me From 4 Years Ago at the Top of my own Google Search for “unity playables api mirror”! Looks like I’m still hacking together an ugly workaround that doesn’t involve Playables.

I still have hope that one day, a rogue Unity dev will risk it all to port this already-existing functionality into a system that’s far less annoying to have to use.

4 Likes

Another year passed, and I would just like to quote this:

It’s also really ironic because this was said 4 years ago:

It can’t be hard to implement, it’s already there. You just have to port it. Please just do it, or give us a working alternative.

Alright, here goes:

  • Create an AnimatorController with a single state and check its Mirror flag.
  • Assign to it an empty dummy animation clip called “Mirror”.
  • Do this:
var overrideController = new AnimatorOverrideController(MirrorController);
overrideController["Mirror"] = _theClipToBeMirrored;
var playable = AnimatorControllerPlayable.Create(_myGraph, overrideController);

All that’s needed is that dummy controller and clip, you only need to create them once in your project and keep a static reference to the controller (MirrorController). At runtime, to avoid garbage, the AnimatorOverrideController can be pooled: it has a setter where you can set the overridden controller.

So despite how ugly this is, it’s working and it should actually be quite efficient. It can easily be wrapped into something like a MirroredAnimationClipPlayable this way.

Note that for whatever reason, I also had to set the “cycle offset” to 0.5 in the Mirror state of the dummy controller, otherwise the animation started playing halfway in. I don’t know whether that’s a bug with mirroring in Mecanim, but I’m sure it’s unrelated to the playable.

1 Like

Haha! That’s a hacky whacky solution :hushed: but you got it work! :sunglasses:
That’s what it’s come to though huh? Animation really is in bad shape with zero signs of getting any better.
I have a lot of mirrored animations in my project. I do the mirroring in Houdini, so those clips end up being duplicate clips (which has it’s own set of problems). This is something that should be able to be automated.

1 Like

It’s been another two years, unity, please??