- Home /
Animation Blending Issue
I'm having an issue with getting animation blending to work (or not work).
I have a character model with an idle animation and a walk animation. The model was created and animated in Maya. The animations work fine in Unity and play as expected.
However, I am having a serious issue transitioning from the [idle] to the [walk] animation. I require [idle] to loop constantly until movement starts and then to transition from [idle] to [walk] and loop the [walk] animation once movement is detected. The problem I am having is that when the [walk] animation starts, the positions of the character's arms remain where they were during the [idle] animation when it stopped (the feet and head animate as expected).
I have tried using CrossFade, Play, CrossFadeQueued, Changing blend weights, Stopping previous animations before starting the next, resetting animation positions, etc, but can't seem to find a way to even just "reset" the arm positions before starting the walk (let alone transition smoothly between them). It appears that the animations are blending (with the walk only affecting the legs and head of the model) when I do not wish them to.
The important part of my code is below:
function Start()
{
/* I have tried WrapMode.Loop too */
animation["idle"].wrapMode = WrapMode.Once;
animation["walk"].wrapMode = WrapMode.Once;
}
function Update()
{
if(targetSpeed != 0)
animation.Play("walk");
else
animation.Play("idle");
}
Any help would be appreciated and I apologise if this is a frequent/silly question.
EDIT: Error appears to be a specific animation issue and not a unity issue.
Answer by Owen-Reynolds · May 19, 2012 at 03:39 PM
Are you sure that Walk plays the arms? Try just animation.Play("walk")
in Start, nothing else. You're describing exactly what would happen if walk were missing the arm bones.
For some imports, in the big animation list through the Inspector, I get duplicate animations. All but one plays various subsets of bones, and I have to trial&error the correct one. I've had it where Default was walk, but animation[2] in the list was the "other", wrong walk.
Also, Loop is correct (but since you're constantly running Play, your current code turns playOnce into Loop.)
Thanks for answering.
Using animation.Play("walk") in Start() animates correctly and the arms DO animate. I should have mentioned that transitioning from a [walk] -> [jump] works perfectly. However, [idle] -> [walk] and [idle] -> [jump] cause the problems I've been having. So, it seems to be a problem with the idle animation.
I've checked the inspector animation list and there are no duplicates and they all appear to be assigned correctly.
I've never heard of an animation "breaking" bones that way. If you substitute some random animation for idle (shoot?) is it still broken? (I'd guess it would be, and that exact idle isn't the problem.)
Is there anything else messing around with layers or mixing transforms?
I created a short simple animation of one arm rising and then lowering (I'm not an animator) called [shoot]. When transitioning from [shoot] to [walk] (or vice versa), it blends (with crossfade) or snaps (with play) perfectly (including the arms). However, transitioning from [idle] to [shoot] also exhibits the exact same problem with the arms. $$anonymous$$oving from [shoot] to [idle] works perfectly so the error seems to occur with [idle] -> [anything].
It's probably important to note that even with the error the arms do animate "correctly", in that they translate/rotate exactly as much as they should. However, the error is in the fact that they start off at the wrong location after interrupting/blending [idle].
I have checked and there is no animation related code except for animation.Play("idle") and animation.Play("shoot").
I will quickly import the model into a completely new, empty project with a single script for animating but I don't believe that will fix the problem.
Also, while not ideal, is it possible to snap the [idle] animation to its final frame before playing the next animation?
EDIT: I've just noticed that the idle animation appears to use a joint/bone that no other animation uses. I'm not the animator (but can sort of use $$anonymous$$aya) so am unsure if this will cause problems or how to fix it.
EDIT 2: Looking at it in $$anonymous$$aya I can't even tell how/where this extra joint is (or if it's perhaps some kind of vertex transform/warping ins$$anonymous$$d). I'm almost certain that this mysterious joint is what's causing the problem, and is thus not really a unity problem at all. :|
Don't worry about it, it took me a few months to properly house train my animator too :P
I think I'll just find a new one. :P
Thanks heaps for your help, Owen (and sorry for probably wasting your time :P). I'll talk to my animator this week and then report back with what exactly it was that he did in case anyone ends up having a similar issue.
Temporary Fix/Hack (snapping to a specific frame before playing next animation):
animation["idle"].normalizedTime = 0.95; yield WaitForEndOfFrame; model$$anonymous$$esh.animation.Play("walk");
Answer by Owen-Reynolds · May 20, 2012 at 04:19 PM
Yes -- an extra bone in idle would make it appear to break other animations. From Unity's point of view, every other animation is the problem, for not including that bone.
What happens is: idle rotates all bones, including mystery shoulder bone. For Walk, Unity thinks missing a bone is a specific instruction to leave that bone where it was. So, as idle crossfades into walk, mystery shoulder bone has no target in walk, so plays as in idle. When idle stops, mystery shoulder bone no has no target anywhere, so stays in that odd rotation.
I wouldn't be too hard on the animator. Most of them have only done things completely inside Max or Maya, where the rules are different. My kids sometimes export a model which looks really wrong, and I try to explain that it's in "rest pos", with no animations, and they've baked some scaling/rotations into the animation by mistake. The thing is, Max never wants to show you "rest pos," so they don't even know what I'm talking about.
Saying "every animation must include every bone" will probably solve a lot of problems (and you can "remove" bones from animations later, in Unity.)
You can move a bone yourself -- it's just a Transform (untested):
Transform B = transform.Find("body/spine/shoulder/idleShoulderhackBone");
Quaternion BstartRot = B.rotation;
if(gettingOutOfIdle) {
B.rotation = Quaternion.RotateTowards(B, BstartRot, 3);
if(B.rotation == BstartRot) gettingOutOfIdle=false;
}
Your answer
Follow this Question
Related Questions
Blended Animation offsetting 0 Answers
Having trouble having a player run and shoot at the same time.... 0 Answers
Softbody animations 1 Answer
Rotating arm with Animation Event 1 Answer