Skip to content

v0.4.0

Choose a tag to compare

@mbrea-c mbrea-c released this 30 Jun 21:57
· 47 commits to master since this release
296f0d2

Highlights

Independent time signals, or the animate everything update

This is a foundational change that was important to lay the groundwork for animation state machines. Conceptually, the animation graph offers a way of describing a way of processing data that changes with time: when the animation player runs, it queries the graph using the time delta that has elapsed since the last frame. This delta then propagates backwards (i.e. left, if seen from the editor) in the graph as nodes receive it as input and use it to query the nodes upstream in the graph, possibly applying some transformation (e.g. the Speed node will apply a speed multiplier to the time delta before querying its parent node).

However, in the previous version only animation pose data could change with time. That is, the backwards propagation of time deltas was inherently linked to the forward propagation of animation pose data. Other data, such as f32, vec3 or other edges could not change with time (unless they were changed by gameplay logic and passed as graph input parameters, but that's orthogonal to this). This prevented legitimately useful constructs such as dynamic interpolation nodes between f32 or vec3 values, using for example a dampened spring-mass system to interpolate between the current and target values when the target can change dynamically. Such interpolation nodes would not output any animation pose data, but would need to receive a time delta in order to update the current value. Another example is event queues, which should be able to change over time (e.g. foot-down, foot-up events coming from an animation clip node): we wouldn't want to bundle this with animation pose data, because that would complicate the handling of events fed into the graph by gameplay logic (e.g., gameplay logic telling the graph that the character is now jumping via an event).

The solution we settled upon was to introduce separate time edges that control the backwards propagation of time deltas, and to stop considering animation pose data to be separate to other kinds of data. Now it's simple, "data" flows forward while "time" flows backwards. This is a bit unique among animation graph systems in popular engines and it does introduce some additional friction for simple operations (now you need to connect both a time and animation pose data edge rather than a single one) but it enables a lot of configurations that were difficult/impossible before. I'm looking forward to see how it works out.

So, if you just want to continue to use the graphs as usual what do you need to do now? Wherever there was a single pose input/output before, there will now be a time and pose separate pins, so you will need to connect them both:

out

Animation State Machines

This is a big one. There were certain things that were difficult to handle previously with the existing animation graph systems. For example, to switch between jumping and movement animations would require passing some sort of blend weight from the gameplay side of things. Now imagine you also have a aiming state and idle animations... you could end up managing an ad-hoc state machine in your gameplay logic, which would need to handle the transitions between states gracefully and without visual cuts. Ideally, the gameplay logic would indicate only which state the animation should go into via animation events fed into the graph, and the graph would handle states and transitions on its own. There might still be a state machine on the gameplay side, but only for gameplay state and it wouldn't care about animation states and transitions.

Well, this is exactly what we started to introduce here. State machines are represented as nodes within an animation graph. They have a separate editor tab with their own UI for editing. Each state is assigned an animation graph, and while that state is active the assigned animation graph will drive the output. Each transition is also assigned an animation graph, but this animation graph can query the respective assigned animation graphs for the transition's source and target states (e.g. to do blending). The transition animation graph is also fed data about the duration and elapsed percentage/time in the transition, which is useful for blending. Finally, the animation graph handling the transition is responsible for emitting events declaring the transition over.

AnimationGraphPlayer now has a send_event method to push an event into an event queue that will be made available to the graph in the user events input pin: the Send events editor tab is helpful in sending these events for testing/development, you can save event names so that they can be sent with one click.

Arbitrary inputs can be fed into a state machine node, and these inputs will be forwarded to all active states/transitions (a common application is forwarding character speed down to the state that handles locomotion animations).

locomotion_graph

Improve editor UI

The previous editor UI did the job, but was not very enjoyable to use. While there is still a lot to improve, a few things are better now:

  • Nodes now show runtime information (duration, logical time)
  • Active nodes are highlighted (i.e. nodes that were used in the current frame)
  • Pins are divided into two colums (input and output columns) to improve readability at a glance.
  • All inspectors have been condensed into a single tab.

Known issues/limitations

  • Copy-paste is currently not working in the editor.
  • There's no easy way to do global transitions, cancelling transitions, or stacking transitions when quickly switching between states. We're thinking of the best way to handle these.

Renaming the crate

Now that Bevy has a built-in animation graph feature, I'm thinking about renaming the crate to avoid confusion. I've got a few ideas but all suggestions are welcome :)

Changelog