Mirrored Animation

The character in WOTT is a humanoid, which provides a number of advantages. One is that animations don’t have to share the same rig as the final character. That gives me the flexibility to make changes to the rig without having to remake previous animations, and also provides the ability to create animations using a variety of software packages if needed.

Another big advantage is that humanoid animations can be mirrored in Unity with a single checkbox. This halves the animation workload for unilateral, or Left/Right exercises which is important because there will eventually be thousands of exercise animations in WOTT.

With so many animations, it’s important that the users only download the animations they need for the routines they use – there’s no point downloading or storing animations they don’t use. To accomplish this I needed a way to create animation graphs on the fly which can’t be done with Unity’s Mecanim animation system. The only way to do this with the necessary flexibility is to use AnimationPlayables. So I needed to create my own animation system.

I originally had a month scheduled to create the animation system in WOTT, after which I had a month scheduled to create the database and backend. After a month I didn’t get everything done that I had planned, but I was happy enough with where the animation system was.

The fundamental elements of WOTT’s animation system are the ability to create downloadable animations, and then plug them into an animation graph when needed. Completing the animation system was always a long term project, but for now I just needed those fundamentals working so I could create exercise animations while I worked on the backend. Then, in a month, once the backend was done I could continue working on the animation system.

There were just two problems with that plan. The first was finding the time to create animations while trying to get the backend working as quickly as possible – two competing goals that the backend usually won. The second problem kind of snuck up on me around the time I felt like the backend was getting close to being complete, 5 months after starting work on it.

The backend took way longer than I’d anticipated, or scheduled, and I couldn’t just abandon it the way I’d done with the animation system because it is so important to the core functionality of the app. Then there was public testing and, long story short, nearly a year after I abandoned the animation system I started animating a unilateral move before realizing I hadn’t added support for mirrored animations. I’d thought about it a lot, but hadn’t actually done anything about it. So instead of creating animations, it was time to add support for mirrored animations.

Thanks to Unity’s built in support for mirroring humanoid animation, it didn’t take too long to add that to the animation system. Unfortunately using Animation Playables instead of Mecanim means that I can’t just set a clip to be mirrored at run-time, so I need to include mirrored clips in the data. Then it’s just a matter of deciding which variation to use. I realized that also needed to add another type of animation, to swap from left to right without leaving the exercise (in case there is little or no rest between left/right sets, or for intermittent left/right reps).

For animation that doesn’t need IK, I’m done. This is working great. But lots of animations need IK so the next step was to mirror the animation of the IK targets.

The IK targets are an odd hierarchy to support future character customization so it wasn’t as easy as it would be if all the IK targets had the same parent.

First I tried swapping values between the left and right sides, reversing the relevant channels. That didn’t work because, as I realized, their starting rotations aren’t mirrored which means, because it’s a hierarchy, their starting positions aren’t either.

Then I thought if I record the starting position of each target, then get the vector of change from the starting position to the current position, I could use the mirror of that vector to add to the opposite target. Unfortunately that didn’t work either. It was close, but the rotations still weren’t right, and it was getting complex trying to manage the parent/child relationships.

I realized that a solution that I’d been avoiding, because it seemed to have more elements, would actually be much simpler and completely avoid the issues with hierarchy. Here’s what I ended up with:

This is just my test, but extended to arrays of transforms it works to mirror any hierarchy, anywhere in the scene. It does this by moving each transform into the equivalent of local space, mirroring along the x axis, then moving the transform back to it’s parent space.

You can test this code by only applying the mirrored position/rotation to the left side. Then you can move the right side to see the left object mirror the motion.

You could also store the offsets as MiniTransforms which would allow you to offset position and rotation.

It took me a while to wrap my head around all this. My first pass worked perfectly when the character rotation was (0,0,0), but broke when the character turned. That prompted me to learn what Transform.TransformPoint and Transform.InverseTransformPoint are for.

There was also some trial and error involved in getting the right order for the Quaternion operations. Speaking of which, I should also note that there seems to be two ways to mirror quaternions, complex and simple (mathematicians probably call these correct and incorrect). This uses the simple way, because we’re mirroring along a world axis. If you need to mirror across an arbitrary plane, you need to use the more complex method which is discussed in this forum thread.

I’m looking forward to updating to Unity 2018 so I can hopefully make all this a whole lot more efficient, but for now I can mirror animations whether they use IK or not, which is awesome.

Mirrored Animation

Leave a Reply

Your email address will not be published. Required fields are marked *