Add GltfLoaderSettings (#10804)
# Objective
when loading gltfs we may want to filter the results. in particular, i
need to be able to exclude cameras.
i can do this already by modifying the gltf after load and before
spawning, but it seems like a useful general option.
## Solution
add `GltfLoaderSettings` struct with bool members:
- `load_cameras` : checked before processing camera nodes.
- `load_lights` : checked before processing light nodes
- `load_meshes` : checked before loading meshes, materials and morph
weights
Existing code will work as before. Now you also have the option to
restrict what parts of the gltf are loaded. For example, to load a gltf
but exclude the cameras, replace a call to
`asset_server.load("my.gltf")` with:
```rust
asset_server.load_with_settings(
    "my.gltf",
    |s: &mut GltfLoaderSettings| {
        s.load_cameras = false;
    }
);
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									0a588dbfd9
								
							
						
					
					
						commit
						74ead1eb80
					
				| @ -39,7 +39,7 @@ use gltf::{ | ||||
|     texture::{MagFilter, MinFilter, WrappingMode}, | ||||
|     Material, Node, Primitive, Semantic, | ||||
| }; | ||||
| use serde::Deserialize; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::{ | ||||
|     collections::VecDeque, | ||||
|     path::{Path, PathBuf}, | ||||
| @ -105,20 +105,57 @@ pub struct GltfLoader { | ||||
|     pub custom_vertex_attributes: HashMap<String, MeshVertexAttribute>, | ||||
| } | ||||
| 
 | ||||
| /// Specifies optional settings for processing gltfs at load time. By default, all recognized contents of
 | ||||
| /// the gltf will be loaded.
 | ||||
| ///
 | ||||
| /// # Example
 | ||||
| ///
 | ||||
| /// To load a gltf but exclude the cameras, replace a call to `asset_server.load("my.gltf")` with
 | ||||
| /// ```no_run
 | ||||
| /// # use bevy_asset::{AssetServer, Handle};
 | ||||
| /// # use bevy_gltf::*;
 | ||||
| /// # let asset_server: AssetServer = panic!();
 | ||||
| /// let gltf_handle: Handle<Gltf> = asset_server.load_with_settings(
 | ||||
| ///     "my.gltf",
 | ||||
| ///     |s: &mut GltfLoaderSettings| {
 | ||||
| ///         s.load_cameras = false;
 | ||||
| ///     }
 | ||||
| /// );    
 | ||||
| /// ```
 | ||||
| #[derive(Serialize, Deserialize)] | ||||
| pub struct GltfLoaderSettings { | ||||
|     /// If true, the loader will load mesh nodes and the associated materials.
 | ||||
|     pub load_meshes: bool, | ||||
|     /// If true, the loader will spawn cameras for gltf camera nodes.
 | ||||
|     pub load_cameras: bool, | ||||
|     /// If true, the loader will spawn lights for gltf light nodes.
 | ||||
|     pub load_lights: bool, | ||||
| } | ||||
| 
 | ||||
| impl Default for GltfLoaderSettings { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             load_meshes: true, | ||||
|             load_cameras: true, | ||||
|             load_lights: true, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl AssetLoader for GltfLoader { | ||||
|     type Asset = Gltf; | ||||
|     type Settings = (); | ||||
|     type Settings = GltfLoaderSettings; | ||||
|     type Error = GltfError; | ||||
|     fn load<'a>( | ||||
|         &'a self, | ||||
|         reader: &'a mut Reader, | ||||
|         _settings: &'a (), | ||||
|         settings: &'a GltfLoaderSettings, | ||||
|         load_context: &'a mut LoadContext, | ||||
|     ) -> bevy_utils::BoxedFuture<'a, Result<Gltf, Self::Error>> { | ||||
|         Box::pin(async move { | ||||
|             let mut bytes = Vec::new(); | ||||
|             reader.read_to_end(&mut bytes).await?; | ||||
|             load_gltf(self, &bytes, load_context).await | ||||
|             load_gltf(self, &bytes, load_context, settings).await | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
| @ -132,6 +169,7 @@ async fn load_gltf<'a, 'b, 'c>( | ||||
|     loader: &GltfLoader, | ||||
|     bytes: &'a [u8], | ||||
|     load_context: &'b mut LoadContext<'c>, | ||||
|     settings: &'b GltfLoaderSettings, | ||||
| ) -> Result<Gltf, GltfError> { | ||||
|     let gltf = gltf::Gltf::from_slice(bytes)?; | ||||
|     let buffer_data = load_buffers(&gltf, load_context).await?; | ||||
| @ -555,6 +593,7 @@ async fn load_gltf<'a, 'b, 'c>( | ||||
|                         parent, | ||||
|                         load_context, | ||||
|                         &mut scene_load_context, | ||||
|                         settings, | ||||
|                         &mut node_index_to_entity_map, | ||||
|                         &mut entity_to_skin_index_map, | ||||
|                         &mut active_camera_found, | ||||
| @ -860,6 +899,7 @@ fn load_node( | ||||
|     world_builder: &mut WorldChildBuilder, | ||||
|     root_load_context: &LoadContext, | ||||
|     load_context: &mut LoadContext, | ||||
|     settings: &GltfLoaderSettings, | ||||
|     node_index_to_entity_map: &mut HashMap<usize, Entity>, | ||||
|     entity_to_skin_index_map: &mut HashMap<Entity, usize>, | ||||
|     active_camera_found: &mut bool, | ||||
| @ -887,6 +927,7 @@ fn load_node( | ||||
|     } | ||||
| 
 | ||||
|     // create camera node
 | ||||
|     if settings.load_cameras { | ||||
|         if let Some(camera) = gltf_node.camera() { | ||||
|             let projection = match camera.projection() { | ||||
|                 gltf::camera::Projection::Orthographic(orthographic) => { | ||||
| @ -928,6 +969,7 @@ fn load_node( | ||||
| 
 | ||||
|             *active_camera_found = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Map node index to entity
 | ||||
|     node_index_to_entity_map.insert(gltf_node.index(), node.id()); | ||||
| @ -935,6 +977,7 @@ fn load_node( | ||||
|     let mut morph_weights = None; | ||||
| 
 | ||||
|     node.with_children(|parent| { | ||||
|         if settings.load_meshes { | ||||
|             if let Some(mesh) = gltf_node.mesh() { | ||||
|                 // append primitives
 | ||||
|                 for primitive in mesh.primitives() { | ||||
| @ -997,7 +1040,9 @@ fn load_node( | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if settings.load_lights { | ||||
|             if let Some(light) = gltf_node.light() { | ||||
|                 match light.kind() { | ||||
|                     gltf::khr_lights_punctual::Kind::Directional => { | ||||
| @ -1073,6 +1118,7 @@ fn load_node( | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // append other nodes
 | ||||
|         for child in gltf_node.children() { | ||||
| @ -1081,6 +1127,7 @@ fn load_node( | ||||
|                 parent, | ||||
|                 root_load_context, | ||||
|                 load_context, | ||||
|                 settings, | ||||
|                 node_index_to_entity_map, | ||||
|                 entity_to_skin_index_map, | ||||
|                 active_camera_found, | ||||
| @ -1092,11 +1139,13 @@ fn load_node( | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     if settings.load_meshes { | ||||
|         if let (Some(mesh), Some(weights)) = (gltf_node.mesh(), morph_weights) { | ||||
|             let primitive_label = mesh.primitives().next().map(|p| primitive_label(&mesh, &p)); | ||||
|             let first_mesh = primitive_label.map(|label| load_context.get_label_handle(label)); | ||||
|             node.insert(MorphWeights::new(weights, first_mesh)?); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if let Some(err) = gltf_error { | ||||
|         Err(err) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 robtfm
						robtfm