4 releases (2 breaking)
0.3.0 | Mar 17, 2024 |
---|---|
0.2.0 | Feb 1, 2024 |
0.1.0 | Dec 20, 2023 |
0.1.0-alpha.4 | Dec 3, 2023 |
#1056 in Game dev
50 downloads per month
Used in bevy_animation_graph_edit…
250KB
5.5K
SLoC
Bevy Animation Graph
This crate contains the library side of this project. This is what loads and runs the animation graphs in your game.
lib.rs
:
Bevy Animation Graph
Bevy Animation Graph provides a graph-based animation system for Bevy.
Introduction
There are three kinds of assets introduced by this library:
GraphClip
, which are defined in*.anim.ron
files. These assets contain animation data, similarly to Bevy'sAnimationClip
. The*.anim.ron
files don't contain the actual animation data, but rather point to the source for the animation. Currently, animation from a Gltf file identified by their name label are supported. For example:( source: GltfNamed( // Asset path of the (root) gltf asset path: "models/Fox.glb", // Name of the animation within that asset animation_name: "Walk", ), )
AnimationGraph
, defined in*.animgraph.ron
files. These assets are the core of the library and specify the nodes, edges, inputs, outputs and default parameters of an animation graph. The animation player (AnimationGraphPlayer
) uses a handle to an animation graph for playback, and can also pass inputs to the graph via input overlays. The preferred way of programmatically setting graph paramters is thus using theAnimationGraphPlayer
's API, as doing it this way will not actally mutate the graph. This enables the same graph to be used by multiple animation players at once. See the examples section for a developed example. The preferred way of editing graphs is using the visual editor: after installing the editor, run the command
to start the editor on the given assets folder. At the moment the editor only supports creating and modifying animation graphs, but it can present a live preview of anbevy_animation_graph_editor -a <PATH_TO_ASSETS_DIRECTORY>
AnimatedScene
asset.AnimatedScene
, defined in*.animscn.ron
files. These assets solve the ergonomics problem of spawning in a scene that is animated via an animation graph. WithoutAnimatedScene
, you would have to spawn the scene, manually find and remove remove Bevy'sAnimationPlayer
, replace it with aAnimationGraphPlayer
and set it to play a desiredAnimationGraph
. An*.animscn.ron
file specifies a target scene file to spawn, the path to theAnimationPlayer
to replace (using entityName
s) and the asset path of the animation graph to play. For example:
We can now simply instantiate an( source: "models/Fox.glb#Scene0", path_to_player: ["root"], animation_graph: "animation_graphs/fox.animgraph.ron", )
AnimatedSceneBundle
with the givenAnimatedScene
handle, just like we would do with a regular scene:
Once the animated scene is finished successfully spawning, an//... commands.spawn(AnimatedSceneBundle { animated_scene: asset_server.load("animated_scenes/character.animscn.ron"), ..default() }); //...
AnimatedSceneInstance
component will be added to it. For convenience, this component contains the entity id of the child containing theAnimationGraphPlayer
, in case the user decides to manually set some animation graph parameters. If the animated scene spawning fails, (e.g. because the givenpath_to_player
is incorrect), an error will be printed and theAnimatedSceneFailed
component will be added instead.
Nodes
The currently implemented graph nodes are:
ClipNode
: Plays back an animation clip.ChainNode
: Chains (plays one after the other) two animation inputs.BlendNode
: Blends two animation inputs linearly based on an input factor.FlipLRNode
: Mirrors an animation on the X axis, based on the bone names havingL
andR
suffixes to specify which side they are on.LoopNode
: Loops an animation input indefinitely.SpeedNode
: Adjust the playback speed of an animation input.GraphNode
: Nested animation graph. The node inputs and outputs match the nested graph'sRotationNode
: Applies a (quaternion) rotation to a set of bones from the input pose defined using a bone mask. inputs and outputs.- Parameter arithmetic:
Editor installation
The editor is in a separate crate, appropriately named bevy_animation_graph_editor
. Install
it just like you would install any other cargo binary. In order to install the latest version
published to crates.io, run:
cargo install bevy_animation_graph_editor
To install the latest version from the git repository, run:
cargo install --git 'https://github.com/mbrea-c/bevy_animation_graph.git' bevy_animation_graph_editor
Finally, to install from a local version of the workspace, run
cargo install --path <PATH_TO_WORKSPACE> bevy_animation_graph_editor
Graphviz .dot
export
While the editor now provides a more convenient way of visualizing, creating and editing
graphs, there's also the option of exporting the graph to a .dot
file for visualization. This
crate provides a binary utility show_graph
which does just that:
show_graph <GRAPH ASSET PATH> <OUTPUT FILE PATH>
If <OUTPUT FILE PATH>
is -
, then show_graph
will output to STDOUT. The output can be
processed into a pdf with:
show_graph <GRAPH ASSET PATH> - | dot -Tpdf > graph.pdf
assuming that the command dot
is installed. If you have the zathura pdf reader installed
you don't need to save the pdf into a file either, you can just open the file from STDIN:
show_graph <GRAPH ASSET PATH> - | dot -Tpdf | zathura -
If you would prefer not to install the show_graph
command but do have bevy_animation_graph
in your current cargo workspace (or you are in the bevy_animation_graph directory), you can
replace show_graph
with cargo run -p bevy_animation_graph --bin show_graph
in the above commands.
Examples
Blend running and walking animation based on movement speed
Consider the following simple scenario:
- Inputs:
- We have running and walking animations.
- We have a target movement speed for the character.
- We know the movement speeds corresponding to the unmodified walk and run
animations, which we call
walk_base_speed
andrun_base_speed
. - We decide on a range of target speeds where the blend between walk and run
should happen. We call this
blend_start
andblend_end
.
- Desired output:
- A animation that blends between the running and walking animation if the target speed is
between
blend_start
andblend_end
, and scales the playback speed to match the target speed based onwalk_base_speed
andrun_base_speed
.
- A animation that blends between the running and walking animation if the target speed is
between
A solution to this problem is as follows:
-
The blend factor between the two animations can be computed as
blend_fac = clamp((target_speed - blend_start) / (blend_end - blend_start), 0, 1)
The playback speed factor applied to both animations is then
speed_fac = target_speed / (walk_base_speed * (1 - blend_fac) + run_base_speed * blend_fac)
-
Blend the two animations together using
blend_fac
. Loop the result and apply the speed factorspeed_fac
.
The resulting graphs can be seen in the assets directory of the source repository, under
assets/animation_graphs/velocity_to_params.animgraph.ron (for computing speed_fac
and blend_fac
) and
assets/animation_graphs/fox.animgraph.ron
(for the animation tasks).
How does this library work?
There are two types of values processed by the graph: parameters and poses.
Each node AnimationNode
in an animation graph has an arbitrary number of parameter inputs
and outputs, each with a particular type (defined in ParamValue
). Each edge
connects one output from one node to an input from another node, that is, the mapping of
parameter inputs to parameter outputs is 1-many. Parameters are used for things like
the speed factor of an animation or the weight of a blend.
Additionally, each node can have any number of pose inputs and a single pose output. Pose edges connect each pose output to a single pose input, that is, the mapping of pose outputs to pose inputs is 1-1. Nodes also must output the duration of the animation if they have a pose output.
Conceptually, pose outputs are sampled at a specific time, so when querying an input pose nodes must provide a time update. This time update can be a time increment (delta) or an absolute time.
Nodes query their inputs lazily using a provided graph context (rather than all inputs being
provided eagerly by the caller). The context will cache node outputs every frame to prevent repeated
computations. The API is described by the NodeLike
trait, which every graph node type must implement.
The PassContext
contains the API that a node has access to when called.
Dependencies
~17–46MB
~738K SLoC