Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/animation/animated_mesh.rs
6592 views
1
//! Plays an animation on a skinned glTF model of a fox.
2
3
use std::f32::consts::PI;
4
5
use bevy::{light::CascadeShadowConfigBuilder, prelude::*, scene::SceneInstanceReady};
6
7
// An example asset that contains a mesh and animation.
8
const GLTF_PATH: &str = "models/animated/Fox.glb";
9
10
fn main() {
11
App::new()
12
.insert_resource(AmbientLight {
13
color: Color::WHITE,
14
brightness: 2000.,
15
..default()
16
})
17
.add_plugins(DefaultPlugins)
18
.add_systems(Startup, setup_mesh_and_animation)
19
.add_systems(Startup, setup_camera_and_environment)
20
.run();
21
}
22
23
// A component that stores a reference to an animation we want to play. This is
24
// created when we start loading the mesh (see `setup_mesh_and_animation`) and
25
// read when the mesh has spawned (see `play_animation_once_loaded`).
26
#[derive(Component)]
27
struct AnimationToPlay {
28
graph_handle: Handle<AnimationGraph>,
29
index: AnimationNodeIndex,
30
}
31
32
fn setup_mesh_and_animation(
33
mut commands: Commands,
34
asset_server: Res<AssetServer>,
35
mut graphs: ResMut<Assets<AnimationGraph>>,
36
) {
37
// Create an animation graph containing a single animation. We want the "run"
38
// animation from our example asset, which has an index of two.
39
let (graph, index) = AnimationGraph::from_clip(
40
asset_server.load(GltfAssetLabel::Animation(2).from_asset(GLTF_PATH)),
41
);
42
43
// Store the animation graph as an asset.
44
let graph_handle = graphs.add(graph);
45
46
// Create a component that stores a reference to our animation.
47
let animation_to_play = AnimationToPlay {
48
graph_handle,
49
index,
50
};
51
52
// Start loading the asset as a scene and store a reference to it in a
53
// SceneRoot component. This component will automatically spawn a scene
54
// containing our mesh once it has loaded.
55
let mesh_scene = SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(GLTF_PATH)));
56
57
// Spawn an entity with our components, and connect it to an observer that
58
// will trigger when the scene is loaded and spawned.
59
commands
60
.spawn((animation_to_play, mesh_scene))
61
.observe(play_animation_when_ready);
62
}
63
64
fn play_animation_when_ready(
65
event: On<SceneInstanceReady>,
66
mut commands: Commands,
67
children: Query<&Children>,
68
animations_to_play: Query<&AnimationToPlay>,
69
mut players: Query<&mut AnimationPlayer>,
70
) {
71
// The entity we spawned in `setup_mesh_and_animation` is the trigger's target.
72
// Start by finding the AnimationToPlay component we added to that entity.
73
if let Ok(animation_to_play) = animations_to_play.get(event.entity()) {
74
// The SceneRoot component will have spawned the scene as a hierarchy
75
// of entities parented to our entity. Since the asset contained a skinned
76
// mesh and animations, it will also have spawned an animation player
77
// component. Search our entity's descendants to find the animation player.
78
for child in children.iter_descendants(event.entity()) {
79
if let Ok(mut player) = players.get_mut(child) {
80
// Tell the animation player to start the animation and keep
81
// repeating it.
82
//
83
// If you want to try stopping and switching animations, see the
84
// `animated_mesh_control.rs` example.
85
player.play(animation_to_play.index).repeat();
86
87
// Add the animation graph. This only needs to be done once to
88
// connect the animation player to the mesh.
89
commands
90
.entity(child)
91
.insert(AnimationGraphHandle(animation_to_play.graph_handle.clone()));
92
}
93
}
94
}
95
}
96
97
// Spawn a camera and a simple environment with a ground plane and light.
98
fn setup_camera_and_environment(
99
mut commands: Commands,
100
mut meshes: ResMut<Assets<Mesh>>,
101
mut materials: ResMut<Assets<StandardMaterial>>,
102
) {
103
// Camera
104
commands.spawn((
105
Camera3d::default(),
106
Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y),
107
));
108
109
// Plane
110
commands.spawn((
111
Mesh3d(meshes.add(Plane3d::default().mesh().size(500000.0, 500000.0))),
112
MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))),
113
));
114
115
// Light
116
commands.spawn((
117
Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)),
118
DirectionalLight {
119
shadows_enabled: true,
120
..default()
121
},
122
CascadeShadowConfigBuilder {
123
first_cascade_far_bound: 200.0,
124
maximum_distance: 400.0,
125
..default()
126
}
127
.build(),
128
));
129
}
130
131