Skip to content

Commit

Permalink
Rework animation to be done in two phases. (#11707)
Browse files Browse the repository at this point in the history
# Objective

Bevy's animation system currently does tree traversals based on `Name`
that aren't necessary. Not only do they require in unsafe code because
tree traversals are awkward with parallelism, but they are also somewhat
slow, brittle, and complex, which manifested itself as way too many
queries in #11670.

# Solution

Divide animation into two phases: animation *advancement* and animation
*evaluation*, which run after one another. *Advancement* operates on the
`AnimationPlayer` and sets the current animation time to match the game
time. *Evaluation* operates on all animation bones in the scene in
parallel and sets the transforms and/or morph weights based on the time
and the clip.

To do this, we introduce a new component, `AnimationTarget`, which the
asset loader places on every bone. It contains the ID of the entity
containing the `AnimationPlayer`, as well as a UUID that identifies
which bone in the animation the target corresponds to. In the case of
glTF, the UUID is derived from the full path name to the bone. The rule
that `AnimationTarget`s are descendants of the entity containing
`AnimationPlayer` is now just a convention, not a requirement; this
allows us to eliminate the unsafe code.

# Migration guide

* `AnimationClip` now uses UUIDs instead of hierarchical paths based on
the `Name` component to refer to bones. This has several consequences:
- A new component, `AnimationTarget`, should be placed on each bone that
you wish to animate, in order to specify its UUID and the associated
`AnimationPlayer`. The glTF loader automatically creates these
components as necessary, so most uses of glTF rigs shouldn't need to
change.
- Moving a bone around the tree, or renaming it, no longer prevents an
`AnimationPlayer` from affecting it.
- Dynamically changing the `AnimationPlayer` component will likely
require manual updating of the `AnimationTarget` components.
* Entities with `AnimationPlayer` components may now possess descendants
that also have `AnimationPlayer` components. They may not, however,
animate the same bones.
* As they aren't specific to `TypeId`s,
`bevy_reflect::utility::NoOpTypeIdHash` and
`bevy_reflect::utility::NoOpTypeIdHasher` have been renamed to
`bevy_reflect::utility::NoOpHash` and
`bevy_reflect::utility::NoOpHasher` respectively.
  • Loading branch information
pcwalton committed Feb 19, 2024
1 parent f1fcf69 commit 5f1dd39
Show file tree
Hide file tree
Showing 9 changed files with 753 additions and 494 deletions.
5 changes: 5 additions & 0 deletions crates/bevy_animation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ keywords = ["bevy"]
bevy_app = { path = "../bevy_app", version = "0.13.0" }
bevy_asset = { path = "../bevy_asset", version = "0.13.0" }
bevy_core = { path = "../bevy_core", version = "0.13.0" }
bevy_log = { path = "../bevy_log", version = "0.13.0" }
bevy_math = { path = "../bevy_math", version = "0.13.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.13.0", features = [
"bevy",
Expand All @@ -24,5 +25,9 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.13.0" }
bevy_transform = { path = "../bevy_transform", version = "0.13.0" }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.13.0" }

# other
sha1_smol = { version = "1.0" }
uuid = { version = "1.7", features = ["v5"] }

[lints]
workspace = true
Loading

0 comments on commit 5f1dd39

Please sign in to comment.