- Home /
Animation in World Space
Hi folks, I've got a common issue with what appears to be a hidden solution. I've got a game with tons of finished mo-cap animations for our characters and enemies. Many of these animations (transitional animations mostly...aka, the animations that play from one loop to another like idle to aggressive) shift the actual character off of the origin.
So when I play, for instance, the character's idle animation and then play the transition from idle to aggressive, he shifts off of the origin a bit (rotations, of course, end at arbitrary values also). If I then followed with an aggressive idle animation (gun up), he'll pop back to the local origin of the blank object above the rig in the hierarchy and animate from there. I obviously need to avoid that.
The only way I really see this being feasible is to have a root game object that the rest of the hierarchy is a child of. That game object sits between the characters feet and moves with him within the animation but is always on that floor plane between his feet (or, depending on the animation, an equivalent location). When one of these transitional animations is done, I take that root and zero him out so his position/orientation is 0,0,0.
The next time an animation plays (for instance the aggressive idle), the rest of the rig would still be correct relative to the parent, and the parent (being this floor plane root) will now start (first frame of that animation has the root at the origin of the scene) at the correct position, avoiding any popping.
I can only do this once that transitional animation has finished so I know the this floor plane root won't get animated off the center, thus causing a pop in the animation.
Does all of this make sense? My characters' animations move/rotate them in world space and when I play the next animation, I need them "back at the origin" so it plays correctly relative to their new location/orientation.
Any help would be immensely appreciated, I don't have a ton of time on this one. :) -Matt
Answer by Paulius-Liekis · May 22, 2012 at 07:27 PM
People usually make "in-place" animation to solve this problem.
Yes, the problem is that Unity can't handle motion delta automatically. Animation-curves are always absolute values within it's localspace.
In our project we also animated our character in-place and the characters movement code actually moves the root / parent. However i guess it should be possible to "extract" the motiondelta by using LateUpdate, read the offset of the inner model (which comes from the animation), move the inner object back to 0,0,0 and finally apply this offset accumulative to the parent object which makes the character move. In theory this should work, but i don't have tested it yet since our char doesn't have motion delta. Unfortunately I'm a programmer so i can't make my own model / animations ;)
Problem with your given solution is that you will be unable to blend animations.
You can also write an AssetPostprocessor and remove animation curves from your root node after import.
Answer by MOrlando · May 23, 2012 at 12:01 AM
Thanks Paulius, I thought I mentioned that we've been given hundreds of mo-capped animations. We don't really have the option to remake the animations, heh.
I do think we've got a potential solution on the horizon. It looks as though we were able to add a node that moves with our characters hips but sits on the floor between his feet. When an animation ends, I'll zero that node out (the rest of the rig is a child of this node) after moving the base node to that location. Then I'll play the next animation which should start with that node zero'd out, so there shouldn't be any hiccups in animation or anything.
We'll see...
Answer by MOrlando · May 24, 2012 at 06:08 PM
So we were able to implement world transforms/rotations with all of the mocap data we were given using a root node that tracked the global movement. I do, however, have a slightly unrelated problem...
Right now I determine if the enemy needs to go to a certain state (and therefore a certain animation) and so I call his transitional animation to get there. For instance, the enemy needs to go to an Alert State from his Idle state so I call the IdleToAlertIdle animation. I then have the following code inside an update (hardcoded the animation for ease of testing):
if( !m_Animator.IsPlaying( m_TransitionalAnimation ) )
{
m_TransitionalAnimation = null;
RecalibrateBase();
m_Animator.CrossFade( "ENY_M_Stand_CBR_AlertIdle" );
}
So the above code works fine. The RecalibrateBase() function handles moving my nodes around so if the transitional animation moved the mesh off of the origin, it's fixed. The problem is the cross-fading. Since technically there's no animation playing since the transitional animation finished, the enemy pops to the new alert idle. There's nothing to actually blend from.
Do I need to add a transitional animation for each of these scenarios? Is there a way to tell the enemy to blend to the new animation without needing an active animation? The enemy still remains in the final frame's bone positions since no animations are playing, he doesn't pop to a T-Pose. I literally just want him to blend from that final pose (from the just finished and no longer active transitional animation) to the new animation.
If anyone can help, that'd be fantastic. I tried CrossFade(), Blend(), and I tried setting the transitional animation's wrapmode to 'ClampForever' but the crossfade of the enemy blends between the new idle and the old animation (which still has the offset root so he blends from the wrong position/orientation).
Thanks for the help! -Matt
First of all: you shouldn't post comments as answers or questions as answers, that just confuses poeple who are trying to solve same problem later.
Look into clamp$$anonymous$$odes. You probably want to set wrap$$anonymous$$ode=ClampForever on your first animation, so it will keep sampling last frame and then you'll be able to do a simple crossfade to next animation.
Welcome to Unity Asnwers!
I apologize, I noticed afterward that I posted in the wrong location.
Anyway, as I mentioned in the post above, I did try ClampForever. The problem is that with the world animation, the last frame that's forever clamped is moved off the origin, while the new animation I'm playing needs to be centered at the origin. CrossFading between those 2 blends very incorrectly.
I think the solution right now is to have a 2 frame animation that is set to ClampForever that I play after the transitional animation that matches that animation but is zero'd out so the blending works ok.
Thanks for the posts, I appreciate the help.
Your answer
Follow this Question
Related Questions
Animation Shifting 1 Answer
Do animation rotations refuse to accept negative values? 2 Answers
Animation not looping 1 Answer
Create animation transitions via script. 0 Answers
The 'correct' way to deal with animations in a grid-based game? 1 Answer