1+ mod morph;
2+
13use anyhow:: Result ;
24use bevy_asset:: {
35 AssetIoError , AssetLoader , AssetPath , BoxedFuture , Handle , LoadContext , LoadedAsset ,
@@ -16,6 +18,7 @@ use bevy_render::{
1618 camera:: { Camera , OrthographicProjection , PerspectiveProjection , Projection , ScalingMode } ,
1719 color:: Color ,
1820 mesh:: {
21+ morph:: MorphWeights ,
1922 skinning:: { SkinnedMesh , SkinnedMeshInverseBindposes } ,
2023 Indices , Mesh , VertexAttributeValues ,
2124 } ,
@@ -64,6 +67,8 @@ pub enum GltfError {
6467 MissingAnimationSampler ( usize ) ,
6568 #[ error( "failed to generate tangents: {0}" ) ]
6669 GenerateTangentsError ( #[ from] bevy_render:: mesh:: GenerateTangentsError ) ,
70+ #[ error( "failed to generate morph targets: {0}" ) ]
71+ MorphTarget ( #[ from] bevy_render:: mesh:: morph:: MorphTargetsGenerationError ) ,
6772}
6873
6974/// Loads glTF files with all of their data as their corresponding bevy representations.
@@ -146,6 +151,7 @@ async fn load_gltf<'a, 'b>(
146151
147152 #[ cfg( feature = "bevy_animation" ) ]
148153 let ( animations, named_animations, animation_roots) = {
154+ use gltf:: animation:: util:: ReadOutputs ;
149155 let mut animations = vec ! [ ] ;
150156 let mut named_animations = HashMap :: default ( ) ;
151157 let mut animation_roots = HashSet :: default ( ) ;
@@ -176,20 +182,17 @@ async fn load_gltf<'a, 'b>(
176182
177183 let keyframes = if let Some ( outputs) = reader. read_outputs ( ) {
178184 match outputs {
179- gltf :: animation :: util :: ReadOutputs :: Translations ( tr) => {
185+ ReadOutputs :: Translations ( tr) => {
180186 bevy_animation:: Keyframes :: Translation ( tr. map ( Vec3 :: from) . collect ( ) )
181187 }
182- gltf:: animation:: util:: ReadOutputs :: Rotations ( rots) => {
183- bevy_animation:: Keyframes :: Rotation (
184- rots. into_f32 ( ) . map ( bevy_math:: Quat :: from_array) . collect ( ) ,
185- )
186- }
187- gltf:: animation:: util:: ReadOutputs :: Scales ( scale) => {
188+ ReadOutputs :: Rotations ( rots) => bevy_animation:: Keyframes :: Rotation (
189+ rots. into_f32 ( ) . map ( bevy_math:: Quat :: from_array) . collect ( ) ,
190+ ) ,
191+ ReadOutputs :: Scales ( scale) => {
188192 bevy_animation:: Keyframes :: Scale ( scale. map ( Vec3 :: from) . collect ( ) )
189193 }
190- gltf:: animation:: util:: ReadOutputs :: MorphTargetWeights ( _) => {
191- warn ! ( "Morph animation property not yet supported" ) ;
192- continue ;
194+ ReadOutputs :: MorphTargetWeights ( weights) => {
195+ bevy_animation:: Keyframes :: Weights ( weights. into_f32 ( ) . collect ( ) )
193196 }
194197 }
195198 } else {
@@ -233,6 +236,7 @@ async fn load_gltf<'a, 'b>(
233236 let mut primitives = vec ! [ ] ;
234237 for primitive in mesh. primitives ( ) {
235238 let primitive_label = primitive_label ( & mesh, & primitive) ;
239+ let morph_targets_label = morph_targets_label ( & mesh, & primitive) ;
236240 let reader = primitive. reader ( |buffer| Some ( & buffer_data[ buffer. index ( ) ] ) ) ;
237241 let primitive_topology = get_primitive_topology ( primitive. mode ( ) ) ?;
238242
@@ -282,6 +286,15 @@ async fn load_gltf<'a, 'b>(
282286 mesh. set_indices ( Some ( Indices :: U32 ( indices. into_u32 ( ) . collect ( ) ) ) ) ;
283287 } ;
284288
289+ let target_count = reader. read_morph_targets ( ) . len ( ) ;
290+ if target_count != 0 {
291+ let walker = morph:: PrimitiveMorphTargets :: new ( & reader) ;
292+ let store = |image| {
293+ load_context. set_labeled_asset ( & morph_targets_label, LoadedAsset :: new ( image) )
294+ } ;
295+ mesh. set_morph_targets ( walker, store) ?;
296+ }
297+
285298 if mesh. attribute ( Mesh :: ATTRIBUTE_NORMAL ) . is_none ( )
286299 && matches ! ( mesh. primitive_topology( ) , PrimitiveTopology :: TriangleList )
287300 {
@@ -767,6 +780,16 @@ fn load_node(
767780 // Map node index to entity
768781 node_index_to_entity_map. insert ( gltf_node. index ( ) , node. id ( ) ) ;
769782
783+ if let Some ( mesh) = gltf_node. mesh ( ) {
784+ if let Some ( extras) = mesh. extras ( ) . as_ref ( ) {
785+ node. insert ( super :: GltfMeshExtras {
786+ value : extras. get ( ) . to_string ( ) ,
787+ } ) ;
788+ }
789+ if let Some ( weights) = mesh. weights ( ) {
790+ node. insert ( MorphWeights :: new ( weights. to_vec ( ) ) ) ;
791+ }
792+ } ;
770793 node. with_children ( |parent| {
771794 if let Some ( mesh) = gltf_node. mesh ( ) {
772795 // append primitives
@@ -788,27 +811,35 @@ fn load_node(
788811 let material_asset_path =
789812 AssetPath :: new_ref ( load_context. path ( ) , Some ( & material_label) ) ;
790813
791- let mut mesh_entity = parent. spawn ( PbrBundle {
814+ let mut primitive_entity = parent. spawn ( PbrBundle {
792815 mesh : load_context. get_handle ( mesh_asset_path) ,
793816 material : load_context. get_handle ( material_asset_path) ,
794817 ..Default :: default ( )
795818 } ) ;
796- mesh_entity. insert ( Aabb :: from_min_max (
819+ let target_count = primitive. morph_targets ( ) . len ( ) ;
820+ if target_count != 0 {
821+ let weights = match mesh. weights ( ) {
822+ Some ( weights) => weights. to_vec ( ) ,
823+ None => vec ! [ 0.0 ; target_count] ,
824+ } ;
825+ primitive_entity. insert ( MorphWeights :: new ( weights) ) ;
826+ }
827+ primitive_entity. insert ( Aabb :: from_min_max (
797828 Vec3 :: from_slice ( & bounds. min ) ,
798829 Vec3 :: from_slice ( & bounds. max ) ,
799830 ) ) ;
800831
801832 if let Some ( extras) = primitive. extras ( ) {
802- mesh_entity . insert ( super :: GltfExtras {
833+ primitive_entity . insert ( super :: GltfExtras {
803834 value : extras. get ( ) . to_string ( ) ,
804835 } ) ;
805836 }
806837 if let Some ( name) = mesh. name ( ) {
807- mesh_entity . insert ( Name :: new ( name. to_string ( ) ) ) ;
838+ primitive_entity . insert ( Name :: new ( name. to_string ( ) ) ) ;
808839 }
809840 // Mark for adding skinned mesh
810841 if let Some ( skin) = gltf_node. skin ( ) {
811- entity_to_skin_index_map. insert ( mesh_entity . id ( ) , skin. index ( ) ) ;
842+ entity_to_skin_index_map. insert ( primitive_entity . id ( ) , skin. index ( ) ) ;
812843 }
813844 }
814845 }
@@ -921,6 +952,15 @@ fn primitive_label(mesh: &gltf::Mesh, primitive: &Primitive) -> String {
921952 format ! ( "Mesh{}/Primitive{}" , mesh. index( ) , primitive. index( ) )
922953}
923954
955+ /// Returns the label for the `mesh` and `primitive`.
956+ fn morph_targets_label ( mesh : & gltf:: Mesh , primitive : & Primitive ) -> String {
957+ format ! (
958+ "Mesh{}/Primitive{}/MorphTargets" ,
959+ mesh. index( ) ,
960+ primitive. index( )
961+ )
962+ }
963+
924964/// Returns the label for the `material`.
925965fn material_label ( material : & gltf:: Material ) -> String {
926966 if let Some ( index) = material. index ( ) {
0 commit comments