Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animation: Layered Blend Per Bone / Additive Blending #14395

Closed
ethereumdegen opened this issue Jul 19, 2024 · 4 comments · Fixed by #15631
Closed

Animation: Layered Blend Per Bone / Additive Blending #14395

ethereumdegen opened this issue Jul 19, 2024 · 4 comments · Fixed by #15631
Labels
A-Animation Make things move and change over time C-Feature A new feature, making something new possible

Comments

@ethereumdegen
Copy link
Contributor

ethereumdegen commented Jul 19, 2024

What problem does this solve or what need does it fill?

I want to be able to have apply a normal 'running' animation to my characters whole body, but then also be able to apply a bone-layer-masked animation to just the torso of the character on TOP of that running animation at will.

What solution would you like?

I would like for the bevy animation system to be able to support 'Layered Blend Per Bone' , the ability to apply an animation to a particular set of bones ( by bone [node] name ). Ideally, I also want the blend to apply in such a way that my layered animation is FULLY expressed, not averaged down by a division of the total weights of all animations. This is because I want the sword slash on the torso to look complete and not weird like it does when trying to blend it in 0.14 .

To be honest, an example with a humanoid who is running and sometimes doing a sword slash would be preferable to the fox example because i dont think the fox example is powerful enough to full express and capture what is needed.

What alternative(s) have you considered?

Additional context

@ethereumdegen ethereumdegen added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Jul 19, 2024
@ethereumdegen
Copy link
Contributor Author

One way we could do this simply is by allowing for the animation system to define a 'BoneSet' which is a group of bones, and then you can have weights PER bone set as opposed to weights per the entire AnimGraph .

@alice-i-cecile alice-i-cecile added A-Animation Make things move and change over time and removed S-Needs-Triage This issue needs to be labelled labels Jul 19, 2024
@CptPotato
Copy link
Contributor

Looks somewhat related to #14230 (the additive blending part)

@pcwalton
Copy link
Contributor

pcwalton commented Sep 1, 2024

#15013 implements most of this, but not the additive blending part.

github-merge-queue bot pushed a commit that referenced this issue Sep 2, 2024
…animations affect. (#15013)

This commit adds support for *masks* to the animation graph. A mask is a
set of animation targets (bones) that neither a node nor its descendants
are allowed to animate. Animation targets can be assigned one or more
*mask group*s, which are specific to a single graph. If a node masks out
any mask group that an animation target belongs to, animation curves for
that target will be ignored during evaluation.

The canonical use case for masks is to support characters holding
objects. Typically, character animations will contain hand animations in
the case that the character's hand is empty. (For example, running
animations may close a character's fingers into a fist.) However, when
the character is holding an object, the animation must be altered so
that the hand grips the object.

Bevy currently has no convenient way to handle this. The only workaround
that I can see is to have entirely separate animation clips for
characters' hands and bodies and keep them in sync, which is burdensome
and doesn't match artists' expectations from other engines, which all
effectively have support for masks. However, with mask group support,
this task is simple. We assign each hand to a mask group and parent all
character animations to a node. When a character grasps an object in
hand, we position the fingers as appropriate and then enable the mask
group for that hand in that node. This allows the character's animations
to run normally, while the object remains correctly attached to the
hand.

Note that even with this PR, we won't have support for running separate
animations for a character's hand and the rest of the character. This is
because we're missing additive blending: there's no way to combine the
two masked animations together properly. I intend that to be a follow-up
PR.

The major engines all have support for masks, though the workflow varies
from engine to engine:

* Unity has support for masks [essentially as implemented here], though
with layers instead of a tree. However, when using the Mecanim
("Humanoid") feature, precise control over bones is lost in favor of
predefined muscle groups.

* Unreal has a feature named [*layered blend per bone*]. This allows for
separate blend weights for different bones, effectively achieving masks.
I believe that the combination of blend nodes and masks make Bevy's
animation graph as expressible as that of Unreal, once we have support
for additive blending, though you may have to use more nodes than you
would in Unreal. Moreover, separating out the concepts of "blend weight"
and "which bones this node applies to" seems like a cleaner design than
what Unreal has.

* Godot's `AnimationTree` has the notion of [*blend filters*], which are
essentially the same as masks as implemented in this PR.

Additionally, this patch fixes a bug with weight evaluation whereby
weights weren't properly propagated down to grandchildren, because the
weight evaluation for a node only checked its parent's weight, not its
evaluated weight. I considered submitting this as a separate PR, but
given that this PR refactors that code entirely to support masks and
weights under a unified "evaluated node" concept, I simply included the
fix here.

A new example, `animation_masks`, has been added. It demonstrates how to
toggle masks on and off for specific portions of a skin.

This is part of #14395, but I'm going to defer closing that issue until
we have additive blending.

[essentially as implemented here]:
https://docs.unity3d.com/560/Documentation/Manual/class-AvatarMask.html

[*layered blend per bone*]:
https://dev.epicgames.com/documentation/en-us/unreal-engine/using-layered-animations-in-unreal-engine

[*blend filters*]:
https://docs.godotengine.org/en/stable/tutorials/animation/animation_tree.html

## Migration Guide

* The serialized format of animation graphs has changed with the
addition of animation masks. To upgrade animation graph RON files, add
`mask` and `mask_groups` fields as appropriate. (They can be safely set
to zero.)
@alice-i-cecile alice-i-cecile changed the title Animation: Layered Blend Per Bone Animation: Layered Blend Per Bone / Additive Blending Sep 11, 2024
pcwalton added a commit to pcwalton/bevy that referenced this issue Oct 3, 2024
*Additive blending* is an ubiquitous feature in game engines that allows
animations to be concatenated instead of blended. The canonical use case
is to allow a character to hold a weapon while performing arbitrary
poses. For example, if you had a character that needed to be able to
walk or run while attacking with a weapon, the typical workflow is to
have an additive blend node that combines walking and running animation
clips with an animation clip of one of the limbs performing a weapon
attack animation.

This commit adds support for additive blending to Bevy. It builds on top
of the flexible infrastructure in bevyengine#15589 and introduces a new type of
node, the *add node*. Like blend nodes, add nodes combine the animations
of their children according to their weights. Unlike blend nodes,
however, add nodes don't normalize the weights to 1.0.

The `animation_masks` example has been overhauled to demonstrate the use
of additive blending in combination with masks. There are now controls
to choose an animation clip for every limb of the fox individually.

This patch also fixes a bug whereby masks were incorrectly accumulated
with `insert()` during the graph threading phase, which could cause
corruption of computed masks in some cases.

Note that the `clip` field has been replaced with an `AnimationNodeType`
enum, which breaks `animgraph.ron` files. The `Fox.animgraph.ron` asset
has been updated to the new format.

Closes bevyengine#14395.
@pcwalton
Copy link
Contributor

pcwalton commented Oct 3, 2024

#15631 implements this.

github-merge-queue bot pushed a commit that referenced this issue Oct 4, 2024
*Additive blending* is an ubiquitous feature in game engines that allows
animations to be concatenated instead of blended. The canonical use case
is to allow a character to hold a weapon while performing arbitrary
poses. For example, if you had a character that needed to be able to
walk or run while attacking with a weapon, the typical workflow is to
have an additive blend node that combines walking and running animation
clips with an animation clip of one of the limbs performing a weapon
attack animation.

This commit adds support for additive blending to Bevy. It builds on top
of the flexible infrastructure in #15589 and introduces a new type of
node, the *add node*. Like blend nodes, add nodes combine the animations
of their children according to their weights. Unlike blend nodes,
however, add nodes don't normalize the weights to 1.0.

The `animation_masks` example has been overhauled to demonstrate the use
of additive blending in combination with masks. There are now controls
to choose an animation clip for every limb of the fox individually.

This patch also fixes a bug whereby masks were incorrectly accumulated
with `insert()` during the graph threading phase, which could cause
corruption of computed masks in some cases.

Note that the `clip` field has been replaced with an `AnimationNodeType`
enum, which breaks `animgraph.ron` files. The `Fox.animgraph.ron` asset
has been updated to the new format.

Closes #14395.

## Showcase


https://github.com/user-attachments/assets/52dfe05f-fdb3-477a-9462-ec150f93df33

## Migration Guide

* The `animgraph.ron` format has changed to accommodate the new
*additive blending* feature. You'll need to change `clip` fields to
instances of the new `AnimationNodeType` enum.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Animation Make things move and change over time C-Feature A new feature, making something new possible
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants