//! Play an animation with morph targets. //! //! Also illustrates how to read morph target names in `name_morphs`. use bevy::{prelude::*, world_serialization::WorldInstanceReady}; use std::f32::consts::PI; const GLTF_PATH: &str = "models/animated/MorphStressTest.gltf"; fn main() { App::new() .add_plugins(DefaultPlugins) .insert_resource(GlobalAmbientLight { brightness: 150.0, ..default() }) .add_systems(Startup, setup) .add_systems(Update, name_morphs) .run(); } #[derive(Component)] struct AnimationToPlay { graph_handle: Handle, index: AnimationNodeIndex, } fn setup( mut commands: Commands, asset_server: Res, mut graphs: ResMut>, ) { 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, }, WorldAssetRoot(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, 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, mut events: MessageReader>, meshes: Res>, ) { for event in events.read() { if let AssetEvent::::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}"); } } } }