//! Plays animations from a skinned glTF. use std::{f32::consts::PI, time::Duration}; use bevy::{pbr::CascadeShadowConfigBuilder, prelude::*}; const FOX_PATH: &str = "models/animated/Fox.glb"; fn main() { App::new() .insert_resource(AmbientLight { color: Color::WHITE, brightness: 2000., ..default() }) .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, setup_scene_once_loaded) .run(); } #[derive(Resource)] struct Animations { graph_handle: Handle, index: AnimationNodeIndex, } fn setup( mut commands: Commands, asset_server: Res, mut meshes: ResMut>, mut materials: ResMut>, mut graphs: ResMut>, ) { // Build the animation graph let (graph, index) = AnimationGraph::from_clip( // We specifically want the "walk" animation, which is the first one. asset_server.load(GltfAssetLabel::Animation(0).from_asset(FOX_PATH)), ); // Keep our animation graph in a Resource so that it can be inserted onto // the correct entity once the scene actually loads. let graph_handle = graphs.add(graph); commands.insert_resource(Animations { graph_handle: graph_handle.clone(), index, }); // Camera commands.spawn(( Camera3d::default(), Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y), )); // Plane commands.spawn(( Mesh3d(meshes.add(Plane3d::default().mesh().size(500000.0, 500000.0))), MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), )); // Light commands.spawn(( Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)), DirectionalLight { shadows_enabled: true, ..default() }, CascadeShadowConfigBuilder { first_cascade_far_bound: 200.0, maximum_distance: 400.0, ..default() } .build(), )); // Fox commands.spawn(( SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(FOX_PATH))), AnimationGraphHandle(graph_handle), )); } // Once the scene is loaded, start the animation fn setup_scene_once_loaded( mut commands: Commands, animations: Res, mut players: Query<(Entity, &mut AnimationPlayer), Added>, ) { for (entity, mut player) in &mut players { let mut transitions = AnimationTransitions::new(); // Make sure to start the animation via the `AnimationTransitions` // component. The `AnimationTransitions` component wants to manage all // the animations and will get confused if the animations are started // directly via the `AnimationPlayer`. transitions .play(&mut player, animations.index, Duration::ZERO) .repeat(); commands .entity(entity) .insert(transitions) .insert(AnimationGraphHandle(animations.graph_handle.clone())); } }