Animation / Morph Targets

Back to examples View in GitHub

Play an animation with morph targets.

Also illustrates how to read morph target names in name_morphs.

use bevy::{prelude::*, scene::SceneInstanceReady}; use std::f32::consts::PI;  const GLTF_PATH: &str = "models/animated/MorphStressTest.gltf";  fn main() {     App::new()         .add_plugins(DefaultPlugins)         .insert_resource(AmbientLight {             brightness: 150.0,             ..default()         })         .add_systems(Startup, setup)         .add_systems(Update, name_morphs)         .run(); }  #[derive(Component)] struct AnimationToPlay {     graph_handle: Handle<AnimationGraph>,     index: AnimationNodeIndex, }  fn setup(     mut commands: Commands,     asset_server: Res<AssetServer>,     mut graphs: ResMut<Assets<AnimationGraph>>, ) {     let (graph, index) = AnimationGraph::from_clip(         asset_server.load(GltfAssetLabel::Animation(2).from_asset(GLTF_PATH)),     );      commands         .spawn((             AnimationToPlay {                 graph_handle: graphs.add(graph),                 index,             },             SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(GLTF_PATH))),         ))         .observe(play_animation_when_ready);      commands.spawn((         DirectionalLight::default(),         Transform::from_rotation(Quat::from_rotation_z(PI / 2.0)),     ));      commands.spawn((         Camera3d::default(),         Transform::from_xyz(3.0, 2.1, 10.2).looking_at(Vec3::ZERO, Vec3::Y),     )); }  fn play_animation_when_ready(     scene_ready: On<SceneInstanceReady>,     mut commands: Commands,     children: Query<&Children>,     animations_to_play: Query<&AnimationToPlay>,     mut players: Query<&mut AnimationPlayer>, ) {     if let Ok(animation_to_play) = animations_to_play.get(scene_ready.entity) {         for child in children.iter_descendants(scene_ready.entity) {             if let Ok(mut player) = players.get_mut(child) {                 player.play(animation_to_play.index).repeat();                  commands                     .entity(child)                     .insert(AnimationGraphHandle(animation_to_play.graph_handle.clone()));             }         }     } }  /// Whenever a mesh asset is loaded, print the name of the asset and the names /// of its morph targets. fn name_morphs(     asset_server: Res<AssetServer>,     mut events: MessageReader<AssetEvent<Mesh>>,     meshes: Res<Assets<Mesh>>, ) {     for event in events.read() {         if let AssetEvent::<Mesh>::Added { id } = event             && let Some(path) = asset_server.get_path(*id)             && let Some(mesh) = meshes.get(*id)             && let Some(names) = mesh.morph_target_names()         {             info!("Morph target names for {path:?}:");              for name in names {                 info!("  {name}");             }         }     } }