Saturday, February 4, 2023

Idle Animations and Animation Blending of People

I discussed the new model animation system I wrote for people and zombies in the last post from November. (Wow, has it really been that long since my last post? I've been busy with holidays, work, changes to my schedule, etc.) During that time I've added idle animations and blending between multiple animations, among other unrelated tasks. I'll briefly describe the improvements I've made to 3DWorld's animation of people below.

First, I had to add config file support for specifying named animations loaded from model files. These are attached to previously loaded models that contain the actual vertex and bone data. Next, I added support for storing multiple animations within the same model class instance and selecting between them at rendering time. This was followed by implementing an animation blending system that took two named animations, two animation times, and a weight to use for blending between them. I then found good animations for people and zombies on Mixamo.

This turned out to be a bit more difficult than I originally expected due to the way animation time was tracked. People walked more quickly when crossing the street, and zombies moved faster when chasing the player. I had implemented running by increasing the animation rate of time, but I wanted idle animations to play back at a fixed rate, which meant I needed to track two different animation times for these cases and do something more complex when blending.

This solution mostly works, but there are still some problems. One issue is that the transition may happen mid-animation when the person's foot is raised, and interpolating from that position to the idle pose with both feet on the ground is unnatural. A second problem is that the animation state change isn't known in advance. People can stop suddenly to avoid a collision. Zombies will stop when the player blocks them with a closed door or object. Zombies will instantly transition from idle to running when they see the player. The AI controller doesn't do any prediction for these things, and the animation system has no way of blocking the AI state machine until the animation transition is complete. The two operations are even running in different threads! One of the outcomes of this is an apparent sliding when the person starts moving while the idle animation is still playing. To counter this, I had to reduce the animation transition time to only 250ms. This mostly prevents the sliding problem, but makes the first issue with the raised foot more of a problem. There's a delicate balance between these two.

Overall I think it's okay though. I don't really even notice these limitations when being chased by zombies. Maybe I'll come up with a better solution in the future, possibly when I get around to adding zombie attacks or other animations. I've attempted to implement this system in a way that makes it flexible and easy to modify later.

This video shows the people and zombies I've added to 3DWorld's buildings with their new walk and idle animations. These animation pairs are mostly different per-model, and are blended over 250ms when switching between walking vs. stopped. I had to disable collision detection and "fly" outside the house to get the zombies to stay idle rather than chasing after me. Also, sorry the camera movements are so jittery - I have my mouse sensitivity set too high for this recording.


I just realized while watching the video that shadows don't always update when playing idle animations. This is due to the optimization I added that skips regenerating room shadows when nothing is moving. In this case, the shadow maps are reused from the previous frame. The way I check for moving objects is to hash the position of every movable/animated scene object inside the light's volume, which includes the player and people in the building. This way the hash will change any time something has moved from the previous frame and will tell the lighting system to regenerate the shadow map. However, the position of a person doesn't change when they're standing idle, so the hash doesn't change either. The fix is to include the frame counter in the hash of people who are playing idle animations. I could have used the animation time, but as I said earlier there are actually two animation times, and that would have been more complex.

What's next? I like the custom procedural animations I have for rats, spiders, and snakes, so that can stay. It might be interesting to animate cars to allow their wheels to move properly when turning. I also may get back to helicopters at some point and replace my simple system that stores the blades and body as different objects and rotates the blades relative to the body to make them spin. Not that I have any idea where to get animations for these mechanical objects...


5 comments:

  1. For the mechanical objects, I think using seperate objects is a great solution. The only reason you'd need skeletal animations is if you wanted deforming models (like characters) or complex procedural IK animation (like industrial robot arms or complex kinematics). I suppose you could do semi-procedural impact damage using armatures? But lattice deformation would probably work better in that case.

    I want to stress for anyone else reading this: Character animation and animation blending is a tremendously difficult feature to implement. Even when using existing libraries, there are so many places it can go wrong. Congratulations to Frank for this very serviceable solution!

    So... how long until we get ragdolling after collisions? :P

    ReplyDelete
    Replies
    1. I now have objects such as doors slowly open and close rather than having only two states. I really would love to improve objects that rotate like helicopters, ceiling fans, and office chairs. Right now I'm limited to either rotating the entire model, or using only models that have separate sub-objects for the rotating parts. I need to figure out a workflow that separates out the different parts in a way that I can individually transform in code. Unfortunately, many of the current models are OBJ files with a single object, which makes this difficult.

      I have no experience with ragdoll physics. And currently the zombies and people in buildings can't fall or die, only the player can. But the player can't see their own model except in mirrors. I would definitely be interested in adding this if a situation came up where it would be useful.

      Just curious, do you know how I can animate a bird? I want to have birds flying around the city. Right now I have a static bird model and some bird-like shapes high up in the sky that do fly but are modeled as spheres. Wings seem very difficult to procedurally animate the way they fold up. Most free 3D models I can find have the wings at rest and merged with the body with no separate wing vertices/bones.

      Thanks.

      Delete
    2. I'm making a list of things to work on for this project. I'll add splitting up the OBJ files, and animating the bird models to the list.

      Delete
    3. Thanks! But I was only asking if there were existing tools for this sort of thing. Something for beginners since I have little experience working with 3D models in modeling tools.

      Delete
    4. Sure! I would use Blender, and I made you a short video detailing how to do it.
      https://youtu.be/c6URo6RUCyo

      Delete