Animate in place?

Started by
8 comments, last by RobM 9 years, 5 months ago
In my animation system, I am currently playing animations with motion accumulation built into the animation. So, for instance, my walk forward animation has my player at 0,0,0 but the root bone of the skeleton moves the character forward as it contains relative offset translations from 0. In a looping animation such as walking forward, I keep the character position at 0 and when the animation loops back to frame/sample 0, I move the character's position to the last frame's root bone's position. This works okay.

For rotational accumulation, things aren't _quite_ as pretty. I do the same principle but instead of the root bone offset translation for movement, I store the effective yaw of the root bone at each frame. When the character turns to the right, the player entity's world yaw stays at 0 whilst the root bone is rotated by the accumulated rotation in the animation. When the animation loops, I set the player's yaw value to the previous frame's root bone yaw value,

I'm doing it this way as I do or will need the absolute position of the player for collision and foot placement on terrain, etc.

This does kind of work except I get a tiny little inconsistency with the rotation when it loops. I'm not asking for a fix for that because I can probably eek it out and mangle the code a bit more until it works. My question is more about whether this is the correct way to do it at all. The other option I've considered is to remove the translation and yaw from the root bone and place it alongside the animation set and move the player's entity position/yaw every frame. I feel this might be easier from a blending perspective because everything would be blended in the same local position and then the yaws of the root bone get blended.

The way I'm doing it at the moment just seems like it's attracting some pretty ugly code and dependencies in order to get it to work.

Any thoughts?
Advertisement


The way I'm doing it at the moment just seems like it's attracting some pretty ugly code and dependencies in order to get it to work.

Yeah, you've found something that technically works, but the further you go down this path the hackier and hackier the code is going to get. Don't put "motion accumulation" in your animation. Instead of messing with the root bone and syncing the game object to the proper position, just move the game object and the animation will follow. The same goes for rotating. Instead of rotating the animation, rotate the game object.

Once you do that, you'll need to make sure the movement speed and animation speed sync up or your avatar will look like she's ice skating instead of walking.

http://www.gamedev.net/topic/646774-matching-walkrun-animation-with-character-movement/

- Eck

EckTech Games - Games and Unity Assets I'm working on
Still Flying - My GameDev journal
The Shilwulf Dynasty - Campaign notes for my Rogue Trader RPG

Nearly all the major games I've worked on have followed the motion accumulation path. Animate the motion and then pop to the correct location.

Animators tend to understand how it works. If they struggle, they can put a marker in the last frame a flag that effectively says "put the root bone here", which works just as well.

Having the animation update the root mid-animation can have lots of subtle problems, especially when blending multiple animations together. Or, as Eck just mentioned above, if the animation and the engine motion are out of sync the character will slide or over-animate and the mismatch can be quite annoying. Better to have exactly one controller for it. Moving things in a game world can become expensive as you need to constantly update your spatial trees and navigation meshes and world boundaries.

Also, having lots of moving objects can make mid-animation updates very troublesome. It is much easier to have the code drop down a jig or stencil using an atomic test-and-set operation. It both tests to see if the area is clear and also tells the world "this area is in use". The area is now reserved for the avatar to do whatever animation needs to them to do. If the test-and-set operation fails then you know something is in the way, such as a wall or another object, and you can handle it rather than starting down the path of your animation and suddenly realizing the path is blocked.

Animators tend to understand how it works. If they struggle, they can put a marker in the last frame a flag that effectively says "put the root bone here", which works just as well.

Thanks both. I feel like I'm on the right path with the motion accumulation (based on one of your previous replies to another post, Frob). Conceptually, and taking into account the various blending I'm doing, it does feel like the right solution but lining up the rotations feels a bit hacky the way I'm doing it (ignoring translations for now because they work fine):

When I export my animations from COLLADA into my own format, I compute the yaw (y rotation when my y is 'up') of the root bone in every frame.

I use this for two things, firstly for blending animations together to bring the one with rotation (e.g. Turning on the spot) into the same space as the one that isn't (e.g. Idling) - this works great. Secondly, I use it to 'pop' the characters rotation after the animation loops.

So in order to test, I changed my turning animation so that only the root bone rotates in the y axis, no other bones move so my character is in a kind of idle position all the way through the animation to 90 degrees or there abouts (it shouldn't need to be exact).

The yaw for frame 0 was calulated as -1.1 degrees (in deg for convenience here) and the final frame was 86.4 - so not quite a 90 degree turn but the roughness of the figures shouldn't matter as no animation angles will be exact.

My animations use tweening too, so I use a factor to blend between the frames either side of my current time position within the animation. This also works fine.

When popping the player's main rotation after looping, I'm having to try and work out the exact amount of rotation to apply which may or may not be the yaw value associated with the last frame of animation - due to the time tweening.

As I mentioned, I can work through this and make sure the values match up exactly but it felt so fiddly that I was thinking it's the wrong approach. Am I on roughly the right track or am I missing a trick?

Edit: it's worth adding that this blip in popping is pretty small - small enough that I can barely see it if I turn my character with a non-moving camera. When I use my following camera which basically just sits a few units behind the character using its yaw to transform, you can see the distant terrain pop slightly at around the 90 degree marks.

One thing I thought of to stop this was to have my following camera glide into a snapped angle position close to the player's yaw so you would effectively see a smooth rotation but when you stop rotating, the camera would smoothly snap to the closest angle (in increments of say 1-3 degrees). That might actually look nice, but feels like a plaster over the issue


Animators tend to understand how it works.

so its done that way because its easier for the artists?


Nearly all the major games I've worked on have followed the motion accumulation path.

which method do you personally consider superior? or is it like everything else in game development - it depends?

i've always done animation-in-place, and translate/rotate the object as needed while the animation plays. granted, you end up with animation info in two places: limb/bone movements in the animation file, and object translations and rotations in the controlling code, but it seems it would be the easier way to handle things. well defined tasks: the animation moves the bones, and the game (as usual) moves the object.

what are the trade-offs of each approach?

the location and orientation fixup at the end is the only real difference? and even if you have to suddenly switch animations in the middle of playing one back, you just do the fixup and start the new one?

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

i've always done animation-in-place, and translate/rotate the object as needed while the animation plays. granted, you end up with animation info in two places: limb/bone movements in the animation file, and object translations and rotations in the controlling code, but it seems it would be the easier way to handle things. well defined tasks: the animation moves the bones, and the game (as usual) moves the object.

I've been mulling this over today. To have non-feet sliding animations (which is the only option for me) you have to have motion accumulation of some type. If you extract the motion data (hereon in a yaw/heading value and xyz position) beforehand and play your animation at the origin, you can use the extracted data to move the position and rotation of the object/character. In this case, I'm not sure lining up looping animations would be quite as tricky to get right.

On the other hand, you extract the motion data, play the animation from the player position and let the motion data/root bone move the bones/vertices relative the origin. When the animation loops or stops at a particular frame, you move the characters world position to the motion data for that frame. This (as I've found out) is tricky to get right and attracts dodgy code.

Option 1 is quite nice because it allows you to blend any number of animations together without having to first move them to the origin if they have rotation/translation motion data. I think the downside would be that you may introduce accuracy issues in terms of player position rotation.

I'm not sold on either option yet although my code so far is option 2 because it felt more natural to allow the animation to do is things as the artist intended (ala frob). I'm just trying to get it working without any glitches and then I'll refactor it down to something that is a bit more elegant.

The problem is, if your turning animation starts at -1.1 degrees and ends up at 85 (so 86.1 total rotation), what do you set the rotation of the player to at the end? 85? If so, the next frame (frame zero after a loop) will immediately appear 1.1 degrees lower, 85-1.1 so that's what I'm currently trying to get my head around

Edit: thinking about this further, I think I have to set the player's yaw value to the last frame's less the first frame's.

So looping when the animation finishes at 85 degrees and setting it to that would mean the next frame of animation would actually start at 83.9. If I subtract the -1.1, I end up with 86.1 meaning the animation would start effectively at 85.

This would also work if the turn animation started at 1.1 degrees and finished at 85. 85 less 1.1 gives 83.9 and it I start with 1.1 I get 85,

It's simple maths of course but it always helps to write it out (especially when you're on a packed train daydreaming about animations!)


I've been mulling this over today. To have non-feet sliding animations (which is the only option for me) you have to have motion accumulation of some type.

is this due to your blending?

i've found that i'm able to sync animation walk/run speeds to character movement rates pretty well (better than madden 15 when they turn in place), as long as those speeds are known constant values. the major limitation is the resolution of the time for a frame (sometimes 4 frames between keyframes is a bit too fast and five is a bit too slow, that kind of idea) now that i've added all sorts of things that affect movement rate such as fatigue, damage, slope in the direction of travel, etc, i'm thinking of moving to a procedurally generated animation that takes movement rate as input. there was another thread a while back that discussed continuous variable speed stand/walk/run animations.


The problem is, if your turning animation starts at -1.1 degrees and ends up at 85 (so 86.1 total rotation), what do you set the rotation of the player to at the end? 85? If so, the next frame (frame zero after a loop) will immediately appear 1.1 degrees lower, 85-1.1 so that's what I'm currently trying to get my head around

that sounds like a simple case of needing "resting postions" between animations. in this case, its a resting direction though. it would seem to me that all turn animations should start with a player heading of zero.


Edit: thinking about this further, I think I have to set the player's yaw value to the last frame's less the first frame's.

i believe that would be the same idea.


It's simple maths of course but it always helps to write it out (especially when you're on a packed train daydreaming about animations!)

one often gains better understanding of a subject by explaining it to others. sometimes you just need someone to bounce ideas off of.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


Edit: thinking about this further, I think I have to set the player's yaw value to the last frame's less the first frame's.

So looping when the animation finishes at 85 degrees and setting it to that would mean the next frame of animation would actually start at 83.9. If I subtract the -1.1, I end up with 86.1 meaning the animation would start effectively at 85.

This would also work if the turn animation started at 1.1 degrees and finished at 85. 85 less 1.1 gives 83.9 and it I start with 1.1 I get 85,

It's simple maths of course but it always helps to write it out (especially when you're on a packed train daydreaming about animations!)

This concept works perfectly. My rotations are nice and smooth now. I'm still not convinced this is the best solution as it does feel a bit hacky, but then I guess we are talking about a pretty complex subject so maybe a some refactoring may make things more elegant.

Still a bit of work of to do where the camera is concerned. You can't directly link the camera to the player's yaw because it might be that the player's rotation doesn't start at 0 (as in my case) - you do get a little twitch at the start where it jumps back to -1.1 degrees and then rotates, but the animation loop pop is inperceptible now. I don't think anyone really wants to see a camera directly linked to the player's yaw anyway, I like a little damping on a camera so I think I'll try a few options but probably snap the camera direction to increments of 5 degrees and slide them into place. More exciting stuff to try!

Thanks guys - I'd still be interested in hearing more about any AAA experience on this and if there are any more elegant solutions.

Things are progressing and were looking great until I combined two animations with motion (not rotation). I decided to get my character to blend from walking to running and my animation state machine setup allowed me to do that very quickly. I simply added a walk-to-run transition to the walking state which is triggered when the left stick is pressed in and in the run state, a run-to-walk transition triggered when the left stick button is unpressed. Works great - if you're intending to have relatively complex animations, write yourself an animation state machine, it's very flexible.

Well, kind of flexible. So my walking animation clip has motion data and so does my running animation clip. Merging those two, in terms of positional data, is proving to be problematic.

When the transition begins, I have specified a half second blend, during which time I envisaged the walk position to fade down to zero (ie no root bone translation) and the run animation to increase from zero up to the correct position. Problem is, I'm trying to blend two absolute positions over time and in can't seem to find an acceptable algorithm.

Should the walk animation's accumulated position (ie the root bone's position) stop immediatey at the start of the translation (even though the bones are still fading from walk to run) whilst the run's accumulated position (ie root bone position) gives 100% to the model's absolute position?

Very tricky to explain but essentially, the run animation has root bone Z positions of, for ease of explanation, 0, 20, 40, 60, 80, 100 whereas the walk animation's root bone Z positions are 0, 10, 20, 30, 40, etc.

I know i have to line up the walking foot position with the running one but I was going to do that by just starting the run anim (assuming the first frame is left foot down) on the same frame in the walk animation when the left foot is down, but I'm not too sure how to blend the accumulated positions.

Any thoughts?
Sorry to keep labouring this point/thread but I've now come up against another issue I'm finding it hard to get my head around.

I keep flipping and refactoring between two solutions. The first is to keep absolute local position and rotation data within the animations and simply play them in place. I keep track of the accumulated position/rotation and at the end of the animation I snap the object position into the new position and restart the animation. Problem with this is my previous post where you're blending between two animations with varying ground coverage, eg walk and run.

The other solution (which I currently have) removes the rotation and motion from the root bone, plays the animation in place and moves the object's position forward by the delta amount of rotation/motion. This makes blending the walk/run animations easier but the delta rotation/motion values stored along with the animation clips are correct at the sample rate of the animation, eg 60fps. If you have a fixed timestep and variable render rate (I have 'fixed my timestep'), things can go wrong if your processor cannot run at the designated physics step time. Eg if your anims and time step is set at 1/60 of a second and for a short spell the PC runs at 1/40 of a second, you end up with synchronisation problems with the delta rotation/motion values.

I've spent a lot of time banging my head on this, trying to come to a decision on which of the above two solutions is the best way forward. Each seem to have their almost insurmountable issues but I'd rather be on the right path solving those issues than the wrong one.

Any thoughts?

Edit: with the second method, can I simply rely on my fixed step time? If I do, it becomes easy, if I'm running my timestep at the same time as the animation sample rate, I just use the delta value, if my time step is twice as fast (ie timestep is 1/60 of a second and animation sample rate is 1/30 then I just multiply the delta value by 0.5 each update?)

This topic is closed to new replies.

Advertisement