New Animation System!!

Look at the title of this post.

Now look at it again.

Read it out loud!

Yes!

There’s a new animation system in Crimild. And, most importantly, it actually works!

I’m really, really happy with what I managed to achieve over the course of the last weeks for the new animation system. Not only it provides a clean and simple to use interface, but it’s also powerful enough to achieve different blending and post-processing operations.

Just take a look at the new animation system in all its glory:

Low-Level API

The new animation system has been designed to work as a low level API for animations, not only for skeletal meshes, but for any quantity that you want to animate over time. The rationale behind this design is to be able to integrate the animation system with other systems like controllers, behavior trees or shader graphs (spoiler!).

The core classes related with the new animation system are:

Channel: Contains keyframe data and times for each key. For example, it may hold positions or rotations data over time. It is also responsible for evaluating such data at any given time and performing interpolations if needed.

Clip: Contains one or more clip for a given animation. For example, a clip that represents a walking animation for a skinned mesh should contain the position and rotation channels for each bone in the skeleton.

Animation: Computes an animation based on a clip and other params, like duration or frame rate. It also contains all accumulated values for a given point in time. Two or more animations can be chained to achieve different results like blending or masking.

Accumulator: Holds the result for a single accumulated value after computing an animation. For a given skeleton, for example, each accumulator will be associated with a bone.

Skeleton: Contains a set of bones and the animations associated with them. A skeleton may contain multiple animations, like walking, running and jumping.

An example

Let’s consider a simple animation, like rotating a triangle around the Y axis:

animating_triangle.gif

The pseudo-code for achieving such animation will look like this:

/* Scene Setup */
crimild::Quaternion4 keys[] = { /* Rotations over time */ };
crimild::Real32 times[] = { /* Time for each rotation */ };
Channel *rotations = new Quaternion4fChannel( "rotation", times, keys );
Clip *clip = new Clip();
clip->addChannel( rotations );
Animation *animation = new Animation( clip );
Geometry *triangle = ...

/* Update Loop */
Clock c = /* get current frame's clock */
animation->update( c )->getValue( "rotation", triangle->local().rotate() );

Notice the update step: First we update the animation by passing the clock for the current frame. Then, we get the computed value for the rotation channel and apply it to the transformation for the triangle.

Chaining Animations

As I mentioned before, the new animation system allows animations to be chained together if needed. This allows to compute new animations procedurally by combining existing ones.

For example, the following chain:

Animation *walk = ...
Animation *run = ...
crimild::Real32 speed = 0.5f;
Animation *result = walk->update( clock )->lerp( run, speed );

Will result in an animation that’s half way between walking and running. First, we need to update the base animation (walking) for a specific point in time. Then, we interpolate it with the second animation (running) using the value of speed. The function lerp automatically synchronizes the two animations together before computing the interpolation.

You can keep chaining animations, adding or interpolating them to achieve different effects as show below.

Post-processing

The demo shown at the beginning of this post was implemented by using additive blending to perform head tracking for the character. Additive blending is an animation technique that combines animations by computing a “difference clip”, the result of subtracting a known pose from an exiting animation data, and adding that to a third animation.

In other words, the walking animation above is combined with the one that results from subtracting the idle pose to the head turning animation, which is nothing more than just a bunch of rotations for the neck.

The head tracking animation itself is computed by interpolating from five other animations (look up, down, left right and center) using the mouse position as the interpolation factor.

But wait! There’s more:

This is a classical animation blending demo that computes transitions between different clips.

Each wolf has four animations pre-defined: idle, stalk, walk and run. Based on the value of a variable “speed” (itself controlled by user’s input), two or more of those animations are linearly interpolated, resulting in smoother transitions.

For reference purposes, the wolf on the right does not perform any interpolation at all. Notice how it just “jumps” from one state to the next, making the changes in animations to be quite visible.

This is only the beginning

What I achieved so far is just the barebones for a true animation system. There are still many enhancements that will be implemented over time, like inverse kinematics, locomotion controller, custom interpolators, integration with behavior trees…

The road ahead will be a lot of fun.

 

 

Advertisements

Rendering to Texture

Happy 2017! I know, it’s almost February, but better late than never, right?

[EDIT: I was so excited that this demo actually worked that I didn’t even realized this wasn’t the first post of the year]

Anyway, I just finished this demo and I wanted to share it with you. Simply put, I’m rendering lots of characters on screen using the impostor technique, which relies on rendering a single model in an offscreen buffer. Then, multiple quads are drawn using the output of that buffer as texture.

Et voilá!

In order to achieve this goal, I had to make some changes in how scenes are rendered (is this the first refactor of the year? No). Since we’re using multiple cameras, we needed a way to define which one is the main one (we cannot rely on the Simulation to that for us any longer). Also, a new render pass is required to draw the model on a texture. And so the OffscreenRenderPass (were you expecting something else?) was born. But that’s pretty much it.

As usual, this is a new feature and therefore… unstable. Do not try it at home (yet).

Bye!

 

Weekend in the Woods

This post is NOT about Metal. I promise.

I’ve been working on a little side project during the last couple of weeks using two of the newest Crimild’s improvements. Here, take a look:

So, what’s going on here? The game idea is pretty obvious: it’s a platform game. You walk or run and then jump to reach another platform. Or you can fall into the abyss until MAX_FLOAT happens.

But there are two mayor “new” features working together here for the first time: animations and physics.

I introduced the new scene importer earlier this year, now supporting FBX and other file formats thanks to the Assimp library. What’s different in this demo is the use of a new Animator component, allowing us to set states and transitions between poses based on predefined rules.

For example, you can transition from idle to walk animation by linking them with the current horizontal speed. Or, you gan go from any given state to jump if the vertical speed changes. All this is combined with a character controller that reacts to user input.

On the other hand, the Physics system has been improved by supporting different colliders (like box, capsule or mesh). The RigidBodyComponent has been greatly enhanced, too. And all physical objects can now be created from Lua scripts as well.

At the moment, both features are in the “experimental” phase but I’m assuming they’ll be production ready before the end of this year.

That’s it. Let’s go back to Metal…