Additive Animations Quandary

I’m familiar with animation blending and mixing systems, and have written several for various game engines in the past. Lately I’ve been working with Unity’s animation system, and I have found the design throughly confusing. The documentation is, as with many other areas, correct but quite lacking in technical detail. Additive animations seem particularly difficult to use for any case other than the “lean left / right” sample that is included with the docs. Here I’ll summarize my understanding of the system.

Combining animations is a common problem. We’d like to have, say, a run, a punch, and a running punch, and it would sure be nice if the running punch could be generated by blending the run and the punch together so that the punch takes over a subset of bones (probably the upper body). Unity can do this easily with AnimationState.AddMixingTransform(), which allows you to specify a subset of a skeleton for an animation to control. In combination with layers, you can then play two animations simultaneously and have one control the blend weights for some bones and the other control the blend weights for other bones. Great.

The problem with this is that you need to know which bones are influenced by the animation. You must hard-code the names of these bones, and perhaps the path through the hierarchy to reach them, into your script so that calls to AddMixingTransform() are effective. In a game with lots of animations in which the animator needs to be able to modify and create content without the constant involvement of a programmer, this is an unacceptable dependency.

The other way that Unity enables animation combination is via additive animations. In this case, you specially prepare an animation such that the first frame is a “reference” pose (which should be the bind pose, I guess; that’s how the Character Animation sample with lean left and lean right works). When an animation is marked as additive, Unity calculates the delta between the first frame pose and all subsequent poses. That means you don’t have to manually hard-code the names of all animated bones. Hooray!

Except that additive animations ALSO seem to change the way that layers are blended. The documentation says,

When making additive animations, Unity will calculate the difference between the first frame in the animation clip and the current frame. Then it will apply this difference on top of all other playing animations.

(my emphasis). The problem is that “apply” does not mean “calculate a weighted blend as normal.” It’s not clear exactly what it means, but the output looks a whole lot like a weighted add where the additive animation is given 50% weight and all subsequent layers fill in the remaining 50%. This is true even if the additive animation’s weight is set to 1.0.

Here’s an example. Say we have a character with two animations, a run and a punch. Run is on layer 0, and is a normal blended animation. Punch is on layer 1. We set punch to enabled, weight 1.0, play type clamp forever.

animation["run"].layer = 0;

animation["punch"].layer = 1;
animation["punch"].blendMode = AnimationBlendMode.Blend;
animation["punch"].AddMixingTransform(punchRootBone);
animation["punch"].weight = 1.0f;
animation["punch"].enabled = true;

animation.Play("run");

If we play this animation with AddMixingTransform() and manually specify the bone at which Punch should take over, it works as we expect; the bones controlled by the Punch animation get 100% of the blend weight (because the Punch weight is 1) and the rest of the bones are animated at 100% blend weight by Run.

Now we modify Punch so that the first frame of the animation is the bind pose. And we remove AddMixingTransform() and change the blend type to Additive. We leave the blend weight at 1.0.

animation["run"].layer = 0;

animation["punch"].layer = 1;
animation["punch"].blendMode = AnimationBlendMode.Additive;
animation["punch"].weight = 1.0f;
animation["punch"].enabled = true;

animation.Play("run");

In this case, I would expect Unity to use the first frame to calculate delta rotations for all subsequent frames, subtract that delta from the animated output, and then blend the resulting bone matrix normally based on the layer and the animation’s blend weight.

What (apparently) happens instead is that the Punch animation is only given 50% contribution to the blend weight. Perhaps that’s what “additive” means, but it is extremely counterintuitive. Why can I specify the blend weight if it will be ignored? (Actually, in this case, the blend weight is not ignored; setting it to something less than 1.0 gives less than 50% contribution).

Other than the lean left / right case, which is exceedingly simple (only one bone is moving!), I don’t see how this behavior is useful for combining animations. This system should allow me to completely overwrite animation on certain bones while ignoring other bones; ideally it would use the delta between the first frame of the animation and subsequent frames to automatically figure out which bones to call AddMixingTransform() on. Then you could generate current behavior just by setting the weight of the additive animation to 0.5.

So, before I go write up a feature request for this: have I understood the system correctly? Is there a way to use additive animations such that I can blend partial-skeleton animations in and out without having to manually specify the names of the bones that should be influencing the model? Is the behavior I’m seeing correct output or the result of a bug?

Thanks.

Hmm, we don’t used additive animations yet, but i have to admit that some things are not that well explained. However the 50% / 50% thing is more or less explained here:

“Blend weights are always normalized
before being applied”

I don’t have that much experience with additive animations, but from what the docs say i would suggest that you can’t play an additive animation as standalone animation. It just applies relative motion so it needs a base on which it’s operating. If you put an additive animation on a seperate layer and it’s the only animation on this layer the result would be garbage. I guess Unity ignores the layer in this case but as i said haven’t tried somethin glike that yet :wink:

It’s just what i can “read” out of the docs.

edit

I just made two small animations (inside Unity I’m just a coder :wink: ). My results are:

  • Additive animations are not affected by layers in any way, except when it comes to Play() or CrossFade so they don’t get stopped.
  • Addidive animations are applied after all other animations have been aplied.
  • Additive animations are not affected by weights, they are added afterwards to apply some additional movement like if you would use Rotate from a script in LateUpdate but they can be much more complex of course ;).
  • Setting a mixing transform is always just a hard-cut at this point. The animation will only be applied to this bone (and childs if rec = true).

If you want to use an animation only on a part (AddMixingTransform) but you want to mix this partial animation with the base animation you have to:

  • Set both animations to the same layer.
  • Start them manually by setting enabled = true.
  • Set your mixing transform on the partial animation
  • lower the weight of the full base animation to produce your desired weight of the partial animation.

If you have set your base animation to 0.33 and your partial to 0.66 the weights gets mixed as expected. On the rest of your model where only the base animation affects the bones will be a 100% weight since it get’s normalized to 1.0