@@ -5,7 +5,7 @@ use bevy_asset::{
5
5
use bevy_core:: Name ;
6
6
use bevy_ecs:: world:: World ;
7
7
use bevy_log:: warn;
8
- use bevy_math:: { Mat4 , Vec3 } ;
8
+ use bevy_math:: { Mat4 , Vec3 , Vec4 } ;
9
9
use bevy_pbr:: {
10
10
AlphaMode , DirectionalLight , DirectionalLightBundle , PbrBundle , PointLight , PointLightBundle ,
11
11
StandardMaterial ,
@@ -37,7 +37,10 @@ use gltf::{
37
37
use std:: { collections:: VecDeque , path:: Path } ;
38
38
use thiserror:: Error ;
39
39
40
- use crate :: { Gltf , GltfNode } ;
40
+ use crate :: {
41
+ Gltf , GltfAnimatedNode , GltfAnimation , GltfAnimationInterpolation , GltfNode , GltfNodeAnimation ,
42
+ GltfNodeAnimationKeyframes ,
43
+ } ;
41
44
42
45
/// An error that occurs when loading a glTF file.
43
46
#[ derive( Error , Debug ) ]
@@ -109,6 +112,76 @@ async fn load_gltf<'a, 'b>(
109
112
}
110
113
}
111
114
115
+ let mut animations = vec ! [ ] ;
116
+ let mut named_animations = HashMap :: default ( ) ;
117
+ let mut animated_nodes = HashSet :: default ( ) ;
118
+ for animation in gltf. animations ( ) {
119
+ let mut gltf_animation = GltfAnimation :: default ( ) ;
120
+ for channel in animation. channels ( ) {
121
+ let interpolation = match channel. sampler ( ) . interpolation ( ) {
122
+ gltf:: animation:: Interpolation :: Linear => GltfAnimationInterpolation :: Linear ,
123
+ gltf:: animation:: Interpolation :: Step => GltfAnimationInterpolation :: Step ,
124
+ gltf:: animation:: Interpolation :: CubicSpline => {
125
+ GltfAnimationInterpolation :: CubicSpline
126
+ }
127
+ } ;
128
+ let node = channel. target ( ) . node ( ) ;
129
+ let reader = channel. reader ( |buffer| Some ( & buffer_data[ buffer. index ( ) ] ) ) ;
130
+ let keyframe_timestamps: Vec < f32 > = if let Some ( inputs) = reader. read_inputs ( ) {
131
+ match inputs {
132
+ gltf:: accessor:: Iter :: Standard ( times) => times. collect ( ) ,
133
+ gltf:: accessor:: Iter :: Sparse ( _) => {
134
+ warn ! ( "sparse accessor not supported for animation sampler input" ) ;
135
+ continue ;
136
+ }
137
+ }
138
+ } else {
139
+ panic ! ( "animations without a sampler input are not supported" ) ;
140
+ } ;
141
+
142
+ let keyframes = if let Some ( outputs) = reader. read_outputs ( ) {
143
+ match outputs {
144
+ gltf:: animation:: util:: ReadOutputs :: Translations ( tr) => {
145
+ GltfNodeAnimationKeyframes :: Translation ( tr. map ( Vec3 :: from) . collect ( ) )
146
+ }
147
+ gltf:: animation:: util:: ReadOutputs :: Rotations ( rots) => {
148
+ GltfNodeAnimationKeyframes :: Rotation (
149
+ rots. into_f32 ( ) . map ( Vec4 :: from) . collect ( ) ,
150
+ )
151
+ }
152
+ gltf:: animation:: util:: ReadOutputs :: Scales ( scale) => {
153
+ GltfNodeAnimationKeyframes :: Scale ( scale. map ( Vec3 :: from) . collect ( ) )
154
+ }
155
+ gltf:: animation:: util:: ReadOutputs :: MorphTargetWeights ( _) => {
156
+ warn ! ( "Morph animation property not yet supported" ) ;
157
+ continue ;
158
+ }
159
+ }
160
+ } else {
161
+ panic ! ( "animations without a sampler output are not supported" ) ;
162
+ } ;
163
+
164
+ gltf_animation
165
+ . node_animations
166
+ . entry ( node. index ( ) )
167
+ . or_default ( )
168
+ . push ( GltfNodeAnimation {
169
+ keyframe_timestamps,
170
+ keyframes,
171
+ interpolation,
172
+ } ) ;
173
+ animated_nodes. insert ( node. index ( ) ) ;
174
+ }
175
+ let handle = load_context. set_labeled_asset (
176
+ & format ! ( "Animation{}" , animation. index( ) ) ,
177
+ LoadedAsset :: new ( gltf_animation) ,
178
+ ) ;
179
+ if let Some ( name) = animation. name ( ) {
180
+ named_animations. insert ( name. to_string ( ) , handle. clone ( ) ) ;
181
+ }
182
+ animations. push ( handle) ;
183
+ }
184
+
112
185
let mut meshes = vec ! [ ] ;
113
186
let mut named_meshes = HashMap :: default ( ) ;
114
187
for mesh in gltf. meshes ( ) {
@@ -292,7 +365,8 @@ async fn load_gltf<'a, 'b>(
292
365
. insert_bundle ( ( Transform :: identity ( ) , GlobalTransform :: identity ( ) ) )
293
366
. with_children ( |parent| {
294
367
for node in scene. nodes ( ) {
295
- let result = load_node ( & node, parent, load_context, & buffer_data) ;
368
+ let result =
369
+ load_node ( & node, parent, load_context, & buffer_data, & animated_nodes) ;
296
370
if result. is_err ( ) {
297
371
err = Some ( result) ;
298
372
return ;
@@ -324,6 +398,8 @@ async fn load_gltf<'a, 'b>(
324
398
named_materials,
325
399
nodes,
326
400
named_nodes,
401
+ animations,
402
+ named_animations,
327
403
} ) ) ;
328
404
329
405
Ok ( ( ) )
@@ -459,6 +535,7 @@ fn load_node(
459
535
world_builder : & mut WorldChildBuilder ,
460
536
load_context : & mut LoadContext ,
461
537
buffer_data : & [ Vec < u8 > ] ,
538
+ animated_nodes : & HashSet < usize > ,
462
539
) -> Result < ( ) , GltfError > {
463
540
let transform = gltf_node. transform ( ) ;
464
541
let mut gltf_error = None ;
@@ -467,6 +544,12 @@ fn load_node(
467
544
GlobalTransform :: identity ( ) ,
468
545
) ) ;
469
546
547
+ if animated_nodes. contains ( & gltf_node. index ( ) ) {
548
+ node. insert ( GltfAnimatedNode {
549
+ index : gltf_node. index ( ) ,
550
+ } ) ;
551
+ }
552
+
470
553
if let Some ( name) = gltf_node. name ( ) {
471
554
node. insert ( Name :: new ( name. to_string ( ) ) ) ;
472
555
}
@@ -601,7 +684,7 @@ fn load_node(
601
684
602
685
// append other nodes
603
686
for child in gltf_node. children ( ) {
604
- if let Err ( err) = load_node ( & child, parent, load_context, buffer_data) {
687
+ if let Err ( err) = load_node ( & child, parent, load_context, buffer_data, animated_nodes ) {
605
688
gltf_error = Some ( err) ;
606
689
return ;
607
690
}
0 commit comments