Include AnimationTarget directly in the animation query rather than reading it through the EntityMut (#15413)

# Objective

Improve the performance of animation.  

`animate_targets` only does work for entities with a `AnimationTarget`
component, but the query it uses has no filters and matches all
archetypes, resulting in extra work checking and ignoring every other
entity in the world.

In addition, it uses `EntityMutExcept::get`, which has to look up the
`ComponentId` for `AnimationTarget` each time it's used.

Fixes #15412

## Solution

Instead of `entity_mut.get::<AnimationTarget>()`, add `&AnimationTarget`
to the query and read it directly. This requires adding
`AnimationTarget` to the list of exceptions in the `EntityMutExcept`.
Since the resulting type is getting long, add an alias for it.

This does mean that `AnimationTarget` is no longer available through
`entity`, which means it's not possible to animate the `AnimationTarget`
component itself.

## Testing

I ran performance traces of many_foxes comparing this branch to main.
Red is main, yellow is these changes:


![image](https://github.com/user-attachments/assets/93ef7d70-5103-4952-86b9-312aafc53e5f)
This commit is contained in:
Chris Russell 2024-09-27 14:18:03 -04:00 committed by GitHub
parent b04947d44f
commit 2486343e87
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 29 deletions

View file

@ -5,12 +5,8 @@ use core::{
fmt::{self, Debug, Formatter},
};
use bevy_asset::Handle;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
component::Component,
world::{EntityMutExcept, Mut},
};
use bevy_ecs::{component::Component, world::Mut};
use bevy_math::{Quat, Vec3};
use bevy_reflect::{FromReflect, GetTypeRegistration, Reflect, TypePath, Typed};
use bevy_render::mesh::morph::MorphWeights;
@ -18,9 +14,8 @@ use bevy_transform::prelude::Transform;
use crate::{
animatable,
graph::AnimationGraph,
prelude::{Animatable, GetKeyframe},
AnimationEvaluationError, AnimationPlayer, Interpolation,
AnimationEntityMut, AnimationEvaluationError, Interpolation,
};
/// A value on a component that Bevy can animate.
@ -154,7 +149,7 @@ pub trait Keyframes: Reflect + Debug + Send + Sync {
fn apply_single_keyframe<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
entity: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
entity: AnimationEntityMut<'a>,
weight: f32,
) -> Result<(), AnimationEvaluationError>;
@ -185,7 +180,7 @@ pub trait Keyframes: Reflect + Debug + Send + Sync {
fn apply_tweened_keyframes<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
entity: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
entity: AnimationEntityMut<'a>,
interpolation: Interpolation,
step_start: usize,
time: f32,
@ -285,7 +280,7 @@ impl Keyframes for TranslationKeyframes {
fn apply_single_keyframe<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
_: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
_: AnimationEntityMut<'a>,
weight: f32,
) -> Result<(), AnimationEvaluationError> {
let mut component = transform.ok_or_else(|| {
@ -301,7 +296,7 @@ impl Keyframes for TranslationKeyframes {
fn apply_tweened_keyframes<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
_: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
_: AnimationEntityMut<'a>,
interpolation: Interpolation,
step_start: usize,
time: f32,
@ -340,7 +335,7 @@ impl Keyframes for ScaleKeyframes {
fn apply_single_keyframe<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
_: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
_: AnimationEntityMut<'a>,
weight: f32,
) -> Result<(), AnimationEvaluationError> {
let mut component = transform.ok_or_else(|| {
@ -356,7 +351,7 @@ impl Keyframes for ScaleKeyframes {
fn apply_tweened_keyframes<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
_: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
_: AnimationEntityMut<'a>,
interpolation: Interpolation,
step_start: usize,
time: f32,
@ -395,7 +390,7 @@ impl Keyframes for RotationKeyframes {
fn apply_single_keyframe<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
_: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
_: AnimationEntityMut<'a>,
weight: f32,
) -> Result<(), AnimationEvaluationError> {
let mut component = transform.ok_or_else(|| {
@ -411,7 +406,7 @@ impl Keyframes for RotationKeyframes {
fn apply_tweened_keyframes<'a>(
&self,
transform: Option<Mut<'a, Transform>>,
_: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
_: AnimationEntityMut<'a>,
interpolation: Interpolation,
step_start: usize,
time: f32,
@ -454,7 +449,7 @@ where
fn apply_single_keyframe<'a>(
&self,
_: Option<Mut<'a, Transform>>,
mut entity: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
mut entity: AnimationEntityMut<'a>,
weight: f32,
) -> Result<(), AnimationEvaluationError> {
let mut component = entity.get_mut::<P::Component>().ok_or_else(|| {
@ -472,7 +467,7 @@ where
fn apply_tweened_keyframes<'a>(
&self,
_: Option<Mut<'a, Transform>>,
mut entity: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
mut entity: AnimationEntityMut<'a>,
interpolation: Interpolation,
step_start: usize,
time: f32,
@ -536,7 +531,7 @@ impl Keyframes for MorphWeightsKeyframes {
fn apply_single_keyframe<'a>(
&self,
_: Option<Mut<'a, Transform>>,
mut entity: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
mut entity: AnimationEntityMut<'a>,
weight: f32,
) -> Result<(), AnimationEvaluationError> {
let mut dest = entity.get_mut::<MorphWeights>().ok_or_else(|| {
@ -555,7 +550,7 @@ impl Keyframes for MorphWeightsKeyframes {
fn apply_tweened_keyframes<'a>(
&self,
_: Option<Mut<'a, Transform>>,
mut entity: EntityMutExcept<'a, (Transform, AnimationPlayer, Handle<AnimationGraph>)>,
mut entity: AnimationEntityMut<'a>,
interpolation: Interpolation,
step_start: usize,
time: f32,

View file

@ -1094,28 +1094,33 @@ pub fn advance_animations(
});
}
/// A type alias for [`EntityMutExcept`] as used in animation.
pub type AnimationEntityMut<'w> = EntityMutExcept<
'w,
(
AnimationTarget,
Transform,
AnimationPlayer,
Handle<AnimationGraph>,
),
>;
/// A system that modifies animation targets (e.g. bones in a skinned mesh)
/// according to the currently-playing animations.
pub fn animate_targets(
clips: Res<Assets<AnimationClip>>,
graphs: Res<Assets<AnimationGraph>>,
players: Query<(&AnimationPlayer, &Handle<AnimationGraph>)>,
mut targets: Query<(
Option<&mut Transform>,
EntityMutExcept<(Transform, AnimationPlayer, Handle<AnimationGraph>)>,
)>,
mut targets: Query<(&AnimationTarget, Option<&mut Transform>, AnimationEntityMut)>,
) {
// Evaluate all animation targets in parallel.
targets
.par_iter_mut()
.for_each(|(mut transform, mut entity_mut)| {
let Some(&AnimationTarget {
.for_each(|(target, mut transform, mut entity_mut)| {
let &AnimationTarget {
id: target_id,
player: player_id,
}) = entity_mut.get::<AnimationTarget>()
else {
return;
};
} = target;
let (animation_player, animation_graph_id) =
if let Ok((player, graph_handle)) = players.get(player_id) {