1
1
use anyhow:: Result ;
2
+ use bevy_animation:: AnimationPlayer ;
2
3
use bevy_asset:: {
3
4
AssetIoError , AssetLoader , AssetPath , BoxedFuture , Handle , LoadContext , LoadedAsset ,
4
5
} ;
@@ -136,100 +137,6 @@ async fn load_gltf<'a, 'b>(
136
137
}
137
138
}
138
139
139
- #[ cfg( feature = "bevy_animation" ) ]
140
- let paths = {
141
- let mut paths = HashMap :: < usize , ( usize , Vec < Name > ) > :: new ( ) ;
142
- for scene in gltf. scenes ( ) {
143
- for node in scene. nodes ( ) {
144
- let root_index = node. index ( ) ;
145
- paths_recur ( node, & [ ] , & mut paths, root_index) ;
146
- }
147
- }
148
- paths
149
- } ;
150
-
151
- #[ cfg( feature = "bevy_animation" ) ]
152
- let ( animations, named_animations, animation_roots) = {
153
- let mut animations = vec ! [ ] ;
154
- let mut named_animations = HashMap :: default ( ) ;
155
- let mut animation_roots = HashSet :: default ( ) ;
156
- for animation in gltf. animations ( ) {
157
- let mut animation_clip = bevy_animation:: AnimationClip :: default ( ) ;
158
- for channel in animation. channels ( ) {
159
- match channel. sampler ( ) . interpolation ( ) {
160
- gltf:: animation:: Interpolation :: Linear => ( ) ,
161
- other => warn ! (
162
- "Animation interpolation {:?} is not supported, will use linear" ,
163
- other
164
- ) ,
165
- } ;
166
- let node = channel. target ( ) . node ( ) ;
167
- let reader = channel. reader ( |buffer| Some ( & buffer_data[ buffer. index ( ) ] ) ) ;
168
- let keyframe_timestamps: Vec < f32 > = if let Some ( inputs) = reader. read_inputs ( ) {
169
- match inputs {
170
- gltf:: accessor:: Iter :: Standard ( times) => times. collect ( ) ,
171
- gltf:: accessor:: Iter :: Sparse ( _) => {
172
- warn ! ( "Sparse accessor not supported for animation sampler input" ) ;
173
- continue ;
174
- }
175
- }
176
- } else {
177
- warn ! ( "Animations without a sampler input are not supported" ) ;
178
- return Err ( GltfError :: MissingAnimationSampler ( animation. index ( ) ) ) ;
179
- } ;
180
-
181
- let keyframes = if let Some ( outputs) = reader. read_outputs ( ) {
182
- match outputs {
183
- gltf:: animation:: util:: ReadOutputs :: Translations ( tr) => {
184
- bevy_animation:: Keyframes :: Translation ( tr. map ( Vec3 :: from) . collect ( ) )
185
- }
186
- gltf:: animation:: util:: ReadOutputs :: Rotations ( rots) => {
187
- bevy_animation:: Keyframes :: Rotation (
188
- rots. into_f32 ( ) . map ( bevy_math:: Quat :: from_array) . collect ( ) ,
189
- )
190
- }
191
- gltf:: animation:: util:: ReadOutputs :: Scales ( scale) => {
192
- bevy_animation:: Keyframes :: Scale ( scale. map ( Vec3 :: from) . collect ( ) )
193
- }
194
- gltf:: animation:: util:: ReadOutputs :: MorphTargetWeights ( _) => {
195
- warn ! ( "Morph animation property not yet supported" ) ;
196
- continue ;
197
- }
198
- }
199
- } else {
200
- warn ! ( "Animations without a sampler output are not supported" ) ;
201
- return Err ( GltfError :: MissingAnimationSampler ( animation. index ( ) ) ) ;
202
- } ;
203
-
204
- if let Some ( ( root_index, path) ) = paths. get ( & node. index ( ) ) {
205
- animation_roots. insert ( root_index) ;
206
- animation_clip. add_curve_to_path (
207
- bevy_core:: EntityPath {
208
- parts : path. clone ( ) ,
209
- } ,
210
- bevy_animation:: VariableCurve {
211
- keyframe_timestamps,
212
- keyframes,
213
- } ,
214
- ) ;
215
- } else {
216
- warn ! (
217
- "Animation ignored for node {}: part of its hierarchy is missing a name" ,
218
- node. index( )
219
- ) ;
220
- }
221
- }
222
- let handle = load_context. set_labeled_asset (
223
- & format ! ( "Animation{}" , animation. index( ) ) ,
224
- LoadedAsset :: new ( animation_clip) ,
225
- ) ;
226
- if let Some ( name) = animation. name ( ) {
227
- named_animations. insert ( name. to_string ( ) , handle. clone ( ) ) ;
228
- }
229
- animations. push ( handle) ;
230
- }
231
- ( animations, named_animations, animation_roots)
232
- } ;
233
140
234
141
let mut meshes = vec ! [ ] ;
235
142
let mut named_meshes = HashMap :: default ( ) ;
@@ -458,49 +365,39 @@ async fn load_gltf<'a, 'b>(
458
365
let mut scenes = vec ! [ ] ;
459
366
let mut named_scenes = HashMap :: default ( ) ;
460
367
let mut active_camera_found = false ;
368
+ let mut node_index_to_entity_map = HashMap :: new ( ) ;
461
369
for scene in gltf. scenes ( ) {
462
370
let mut err = None ;
463
371
let mut world = World :: default ( ) ;
464
- let mut node_index_to_entity_map = HashMap :: new ( ) ;
465
372
let mut entity_to_skin_index_map = HashMap :: new ( ) ;
466
373
467
374
world
468
375
. spawn ( )
469
376
. insert_bundle ( SpatialBundle :: VISIBLE_IDENTITY )
470
377
. with_children ( |parent| {
471
378
for node in scene. nodes ( ) {
472
- let result = load_node (
379
+ match load_node (
473
380
& node,
474
381
parent,
475
382
load_context,
476
383
& buffer_data,
477
384
& mut node_index_to_entity_map,
478
385
& mut entity_to_skin_index_map,
479
386
& mut active_camera_found,
480
- ) ;
481
- if result. is_err ( ) {
482
- err = Some ( result) ;
483
- return ;
387
+ Some ( & gltf) ,
388
+ ) {
389
+ Err ( e) => {
390
+ err = Some ( Err ( e) as Result < ( ) , _ > ) ;
391
+ return ;
392
+ }
393
+ Ok ( e) => ( ) ,
484
394
}
485
395
}
486
396
} ) ;
487
397
if let Some ( Err ( err) ) = err {
488
398
return Err ( err) ;
489
399
}
490
400
491
- #[ cfg( feature = "bevy_animation" ) ]
492
- {
493
- // for each node root in a scene, check if it's the root of an animation
494
- // if it is, add the AnimationPlayer component
495
- for node in scene. nodes ( ) {
496
- if animation_roots. contains ( & node. index ( ) ) {
497
- world
498
- . entity_mut ( * node_index_to_entity_map. get ( & node. index ( ) ) . unwrap ( ) )
499
- . insert ( bevy_animation:: AnimationPlayer :: default ( ) ) ;
500
- }
501
- }
502
- }
503
-
504
401
for ( & entity, & skin_index) in & entity_to_skin_index_map {
505
402
let mut entity = world. entity_mut ( entity) ;
506
403
let skin = gltf. skins ( ) . nth ( skin_index) . unwrap ( ) ;
@@ -524,6 +421,106 @@ async fn load_gltf<'a, 'b>(
524
421
scenes. push ( scene_handle) ;
525
422
}
526
423
424
+ // #[cfg(feature = "bevy_animation")]
425
+ // let paths = {
426
+ // let mut paths = HashMap::<usize, (usize, Vec<Name>)>::new();
427
+ // for scene in gltf.scenes() {
428
+ // for node in scene.nodes() {
429
+ // let root_index = node.index();
430
+ // paths_recur(node, &[], &mut paths, root_index);
431
+ // }
432
+ // }
433
+ // paths
434
+ // };
435
+
436
+ #[ cfg( feature = "bevy_animation" ) ]
437
+ let ( animations, named_animations, animation_roots) = {
438
+ let mut animations = vec ! [ ] ;
439
+ let mut named_animations = HashMap :: default ( ) ;
440
+ for animation in gltf. animations ( ) {
441
+ let mut animation_clip = bevy_animation:: AnimationClip :: default ( ) ;
442
+ for channel in animation. channels ( ) {
443
+ match channel. sampler ( ) . interpolation ( ) {
444
+ gltf:: animation:: Interpolation :: Linear => ( ) ,
445
+ other => warn ! (
446
+ "Animation interpolation {:?} is not supported, will use linear" ,
447
+ other
448
+ ) ,
449
+ } ;
450
+ let node = channel. target ( ) . node ( ) ;
451
+ let reader = channel. reader ( |buffer| Some ( & buffer_data[ buffer. index ( ) ] ) ) ;
452
+ let keyframe_timestamps: Vec < f32 > = if let Some ( inputs) = reader. read_inputs ( ) {
453
+ match inputs {
454
+ gltf:: accessor:: Iter :: Standard ( times) => times. collect ( ) ,
455
+ gltf:: accessor:: Iter :: Sparse ( _) => {
456
+ warn ! ( "Sparse accessor not supported for animation sampler input" ) ;
457
+ continue ;
458
+ }
459
+ }
460
+ } else {
461
+ warn ! ( "Animations without a sampler input are not supported" ) ;
462
+ return Err ( GltfError :: MissingAnimationSampler ( animation. index ( ) ) ) ;
463
+ } ;
464
+
465
+ let keyframes = if let Some ( outputs) = reader. read_outputs ( ) {
466
+ match outputs {
467
+ gltf:: animation:: util:: ReadOutputs :: Translations ( tr) => {
468
+ bevy_animation:: Keyframes :: Translation ( tr. map ( Vec3 :: from) . collect ( ) )
469
+ }
470
+ gltf:: animation:: util:: ReadOutputs :: Rotations ( rots) => {
471
+ bevy_animation:: Keyframes :: Rotation (
472
+ rots. into_f32 ( ) . map ( bevy_math:: Quat :: from_array) . collect ( ) ,
473
+ )
474
+ }
475
+ gltf:: animation:: util:: ReadOutputs :: Scales ( scale) => {
476
+ bevy_animation:: Keyframes :: Scale ( scale. map ( Vec3 :: from) . collect ( ) )
477
+ }
478
+ gltf:: animation:: util:: ReadOutputs :: MorphTargetWeights ( _) => {
479
+ warn ! ( "Morph animation property not yet supported" ) ;
480
+ continue ;
481
+ }
482
+ }
483
+ } else {
484
+ warn ! ( "Animations without a sampler output are not supported" ) ;
485
+ return Err ( GltfError :: MissingAnimationSampler ( animation. index ( ) ) ) ;
486
+ } ;
487
+
488
+ let node_entity = * node_index_to_entity_map. get ( & node. index ( ) ) . unwrap ( ) ;
489
+ // animation_nodes.insert(node.index());
490
+ // TODO: find root & attach AnimationPlayer?
491
+ animation_clip. add_curve_to_path (
492
+ node_entity,
493
+ bevy_animation:: VariableCurve {
494
+ keyframe_timestamps,
495
+ keyframes,
496
+ } ,
497
+ ) ;
498
+ }
499
+ let handle = load_context. set_labeled_asset (
500
+ & format ! ( "Animation{}" , animation. index( ) ) ,
501
+ LoadedAsset :: new ( animation_clip) ,
502
+ ) ;
503
+ if let Some ( name) = animation. name ( ) {
504
+ named_animations. insert ( name. to_string ( ) , handle. clone ( ) ) ;
505
+ }
506
+ animations. push ( handle) ;
507
+ }
508
+ ( animations, named_animations, ( ) )
509
+ } ;
510
+
511
+ // #[cfg(feature = "bevy_animation")]
512
+ // {
513
+ // // for each node root in a scene, check if it's the root of an animation
514
+ // // if it is, add the AnimationPlayer component
515
+ // for node in gltf.scenes().flat_map(|s| s.nodes()) {
516
+ // if animation_roots.contains(&node.index()) {
517
+ // world
518
+ // .entity_mut(*node_index_to_entity_map.get(&node.index()).unwrap())
519
+ // .insert(bevy_animation::AnimationPlayer::default());
520
+ // }
521
+ // }
522
+ // }
523
+
527
524
load_context. set_default_asset ( LoadedAsset :: new ( Gltf {
528
525
default_scene : gltf
529
526
. default_scene ( )
@@ -546,6 +543,10 @@ async fn load_gltf<'a, 'b>(
546
543
Ok ( ( ) )
547
544
}
548
545
546
+ fn is_animation_root ( gltf : & gltf:: Gltf , node : & gltf:: Node ) -> bool {
547
+ gltf. animations ( ) . flat_map ( |a| a. channels ( ) ) . any ( |c| node. children ( ) . any ( |n| c. target ( ) . node ( ) . index ( ) == n. index ( ) ) )
548
+ }
549
+
549
550
fn node_name ( node : & Node ) -> Name {
550
551
let name = node
551
552
. name ( )
@@ -694,6 +695,7 @@ fn load_material(material: &Material, load_context: &mut LoadContext) -> Handle<
694
695
}
695
696
696
697
/// Loads a glTF node.
698
+ #[ allow( clippy:: too_many_arguments) ]
697
699
fn load_node (
698
700
gltf_node : & gltf:: Node ,
699
701
world_builder : & mut WorldChildBuilder ,
@@ -702,7 +704,8 @@ fn load_node(
702
704
node_index_to_entity_map : & mut HashMap < usize , Entity > ,
703
705
entity_to_skin_index_map : & mut HashMap < Entity , usize > ,
704
706
active_camera_found : & mut bool ,
705
- ) -> Result < ( ) , GltfError > {
707
+ gltf : Option < & gltf:: Gltf > ,
708
+ ) -> Result < Entity , GltfError > {
706
709
let transform = gltf_node. transform ( ) ;
707
710
let mut gltf_error = None ;
708
711
let mut node = world_builder. spawn_bundle ( SpatialBundle :: from ( Transform :: from_matrix (
@@ -763,6 +766,16 @@ fn load_node(
763
766
* active_camera_found = true ;
764
767
}
765
768
769
+ #[ cfg( feature = "bevy_animation" ) ]
770
+ if let Some ( gltf) = gltf {
771
+ if is_animation_root ( gltf, gltf_node) {
772
+ node. insert ( bevy_animation:: AnimationPlayer :: default ( ) ) ;
773
+ } else {
774
+ println ! ( "Root, but not animation" ) ;
775
+ println ! ( "{:?}" , gltf_node) ;
776
+ }
777
+ }
778
+
766
779
// Map node index to entity
767
780
node_index_to_entity_map. insert ( gltf_node. index ( ) , node. id ( ) ) ;
768
781
@@ -898,6 +911,7 @@ fn load_node(
898
911
node_index_to_entity_map,
899
912
entity_to_skin_index_map,
900
913
active_camera_found,
914
+ None ,
901
915
) {
902
916
gltf_error = Some ( err) ;
903
917
return ;
@@ -907,7 +921,7 @@ fn load_node(
907
921
if let Some ( err) = gltf_error {
908
922
Err ( err)
909
923
} else {
910
- Ok ( ( ) )
924
+ Ok ( node . id ( ) )
911
925
}
912
926
}
913
927
0 commit comments