Allow setting RenderAssetUsages for gLTF meshes & materials during load (#12302)

# Objective

- Closes #11954

## Solution

Change the load_meshes field in `GltfLoaderSettings` from a bool to
`RenderAssetUsages` flag, and add a new load_materials flag.

Use these to determine where the gLTF mesh and material assets are
retained in memory (if the provided flags are empty, then the assets are
skipped during load).

---

## Migration Guide
When loading gLTF assets with `asset_server.load_with_settings`, use
`RenderAssetUsages` instead of `bool` when setting load_meshes e.g.
```rust
let _ = asset_server.load_with_settings("...", |s: &mut GltfLoaderSettings| {
    s.load_meshes = RenderAssetUsages::RENDER_WORLD;
});
``` 

Use the new load_materials field for controlling material load &
retention behaviour instead of load_meshes.

gLTF .meta files need similar updates e.g
```
load_meshes: true,
```
to
```
load_meshes: ("MAIN_WORLD | RENDER_WORLD"),
```

---------

Co-authored-by: 66OJ66 <hi0obxud@anonaddy.me>
This commit is contained in:
66OJ66 2024-03-12 00:11:01 +00:00 committed by GitHub
parent 686d354d28
commit c7298599ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -130,8 +130,14 @@ pub struct GltfLoader {
/// ```
#[derive(Serialize, Deserialize)]
pub struct GltfLoaderSettings {
/// If true, the loader will load mesh nodes and the associated materials.
pub load_meshes: bool,
/// If empty, the gltf mesh nodes will be skipped.
///
/// Otherwise, nodes will be loaded and retained in RAM/VRAM according to the active flags.
pub load_meshes: RenderAssetUsages,
/// If empty, the gltf materials will be skipped.
///
/// Otherwise, materials will be loaded and retained in RAM/VRAM according to the active flags.
pub load_materials: RenderAssetUsages,
/// 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.
@ -143,7 +149,8 @@ pub struct GltfLoaderSettings {
impl Default for GltfLoaderSettings {
fn default() -> Self {
Self {
load_meshes: true,
load_meshes: RenderAssetUsages::default(),
load_materials: RenderAssetUsages::default(),
load_cameras: true,
load_lights: true,
include_source: false,
@ -340,6 +347,7 @@ async fn load_gltf<'a, 'b, 'c>(
&linear_textures,
parent_path,
loader.supported_compressed_formats,
settings.load_materials,
)
.await?;
process_loaded_texture(load_context, &mut _texture_handles, image);
@ -359,6 +367,7 @@ async fn load_gltf<'a, 'b, 'c>(
linear_textures,
parent_path,
loader.supported_compressed_formats,
settings.load_materials,
)
.await
});
@ -377,13 +386,16 @@ async fn load_gltf<'a, 'b, 'c>(
let mut materials = vec![];
let mut named_materials = HashMap::default();
// NOTE: materials must be loaded after textures because image load() calls will happen before load_with_settings, preventing is_srgb from being set properly
for material in gltf.materials() {
let handle = load_material(&material, load_context, false);
if let Some(name) = material.name() {
named_materials.insert(name.into(), handle.clone());
// Only include materials in the output if they're set to be retained in the MAIN_WORLD and/or RENDER_WORLD by the load_materials flag
if !settings.load_materials.is_empty() {
// NOTE: materials must be loaded after textures because image load() calls will happen before load_with_settings, preventing is_srgb from being set properly
for material in gltf.materials() {
let handle = load_material(&material, load_context, false);
if let Some(name) = material.name() {
named_materials.insert(name.into(), handle.clone());
}
materials.push(handle);
}
materials.push(handle);
}
let mut meshes = vec![];
let mut named_meshes = HashMap::default();
@ -404,7 +416,7 @@ async fn load_gltf<'a, 'b, 'c>(
let primitive_label = primitive_label(&gltf_mesh, &primitive);
let primitive_topology = get_primitive_topology(primitive.mode())?;
let mut mesh = Mesh::new(primitive_topology, RenderAssetUsages::default());
let mut mesh = Mesh::new(primitive_topology, settings.load_meshes);
// Read vertex attributes
for (semantic, accessor) in primitive.attributes() {
@ -744,6 +756,7 @@ async fn load_image<'a, 'b>(
linear_textures: &HashSet<usize>,
parent_path: &'b Path,
supported_compressed_formats: CompressedImageFormats,
render_asset_usages: RenderAssetUsages,
) -> Result<ImageOrPath, GltfError> {
let is_srgb = !linear_textures.contains(&gltf_texture.index());
let sampler_descriptor = texture_sampler(&gltf_texture);
@ -764,7 +777,7 @@ async fn load_image<'a, 'b>(
supported_compressed_formats,
is_srgb,
ImageSampler::Descriptor(sampler_descriptor),
RenderAssetUsages::default(),
render_asset_usages,
)?;
Ok(ImageOrPath::Image {
image,
@ -788,7 +801,7 @@ async fn load_image<'a, 'b>(
supported_compressed_formats,
is_srgb,
ImageSampler::Descriptor(sampler_descriptor),
RenderAssetUsages::default(),
render_asset_usages,
)?,
label: texture_label(&gltf_texture),
})
@ -1100,7 +1113,8 @@ fn load_node(
let mut morph_weights = None;
node.with_children(|parent| {
if settings.load_meshes {
// Only include meshes in the output if they're set to be retained in the MAIN_WORLD and/or RENDER_WORLD by the load_meshes flag
if !settings.load_meshes.is_empty() {
if let Some(mesh) = gltf_node.mesh() {
// append primitives
for primitive in mesh.primitives() {
@ -1264,7 +1278,8 @@ fn load_node(
}
});
if settings.load_meshes {
// Only include meshes in the output if they're set to be retained in the MAIN_WORLD and/or RENDER_WORLD by the load_meshes flag
if !settings.load_meshes.is_empty() {
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));