Struct bevy::asset::Assets

pub struct Assets<A>
where A: Asset,
{ /* private fields */ }
Expand description

Stores Asset values identified by their AssetId.

Assets identified by AssetId::Index will be stored in a “dense” vec-like storage. This is more efficient, but it means that the assets can only be identified at runtime. This is the default behavior.

Assets identified by AssetId::Uuid will be stored in a hashmap. This is less efficient, but it means that the assets can be referenced at compile time.

This tracks (and queues) AssetEvent events whenever changes to the collection occur.

Implementations§

§

impl<A> Assets<A>
where A: Asset,

pub fn get_handle_provider(&self) -> AssetHandleProvider

Retrieves an AssetHandleProvider capable of reserving new Handle values for assets that will be stored in this collection.

pub fn reserve_handle(&self) -> Handle<A>

Reserves a new Handle for an asset that will be stored in this collection.

pub fn insert(&mut self, id: impl Into<AssetId<A>>, asset: A)

Inserts the given asset, identified by the given id. If an asset already exists for id, it will be replaced.

Examples found in repository?
examples/2d/mesh2d_manual.rs (lines 284-287)
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    fn build(&self, app: &mut App) {
        // Load our custom shader
        let mut shaders = app.world_mut().resource_mut::<Assets<Shader>>();
        shaders.insert(
            &COLORED_MESH2D_SHADER_HANDLE,
            Shader::from_wgsl(COLORED_MESH2D_SHADER, file!()),
        );

        // Register our custom draw function, and add our render systems
        app.get_sub_app_mut(RenderApp)
            .unwrap()
            .add_render_command::<Transparent2d, DrawColoredMesh2d>()
            .init_resource::<SpecializedRenderPipelines<ColoredMesh2dPipeline>>()
            .init_resource::<RenderColoredMesh2dInstances>()
            .add_systems(
                ExtractSchedule,
                extract_colored_mesh2d.after(extract_mesh2d),
            )
            .add_systems(Render, queue_colored_mesh2d.in_set(RenderSet::QueueMeshes));
    }
More examples
Hide additional examples
examples/3d/tonemapping.rs (line 276)
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
fn resize_image(
    image_mesh: Query<(&Handle<StandardMaterial>, &Handle<Mesh>), With<HDRViewer>>,
    materials: Res<Assets<StandardMaterial>>,
    mut meshes: ResMut<Assets<Mesh>>,
    images: Res<Assets<Image>>,
    mut image_events: EventReader<AssetEvent<Image>>,
) {
    for event in image_events.read() {
        let (AssetEvent::Added { id } | AssetEvent::Modified { id }) = event else {
            continue;
        };

        for (mat_h, mesh_h) in &image_mesh {
            let Some(mat) = materials.get(mat_h) else {
                continue;
            };

            let Some(ref base_color_texture) = mat.base_color_texture else {
                continue;
            };

            if *id != base_color_texture.id() {
                continue;
            };

            let Some(image_changed) = images.get(*id) else {
                continue;
            };

            let size = image_changed.size_f32().normalize_or_zero() * 1.4;
            // Resize Mesh
            let quad = Mesh::from(Rectangle::from_size(size));
            meshes.insert(mesh_h, quad);
        }
    }
}

pub fn get_or_insert_with( &mut self, id: impl Into<AssetId<A>>, insert_fn: impl FnOnce() -> A ) -> &mut A

Retrieves an Asset stored for the given id if it exists. If it does not exist, it will be inserted using insert_fn.

pub fn contains(&self, id: impl Into<AssetId<A>>) -> bool

Returns true if the id exists in this collection. Otherwise it returns false.

pub fn add(&mut self, asset: impl Into<A>) -> Handle<A>

Adds the given asset and allocates a new strong Handle for it.

Examples found in repository?
examples/audio/decodable.rs (lines 97-99)
95
96
97
98
99
100
101
102
103
104
fn setup(mut assets: ResMut<Assets<SineAudio>>, mut commands: Commands) {
    // add a `SineAudio` to the asset server so that it can be played
    let audio_handle = assets.add(SineAudio {
        frequency: 440., //this is the frequency of A4
    });
    commands.spawn(AudioSourceBundle {
        source: audio_handle,
        ..default()
    });
}
More examples
Hide additional examples
examples/3d/clearcoat.rs (line 89)
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
fn create_sphere_mesh(meshes: &mut Assets<Mesh>) -> Handle<Mesh> {
    // We're going to use normal maps, so make sure we've generated tangents, or
    // else the normal maps won't show up.

    let mut sphere_mesh = Sphere::new(1.0).mesh().build();
    sphere_mesh
        .generate_tangents()
        .expect("Failed to generate tangents");
    meshes.add(sphere_mesh)
}

/// Spawn a regular object with a clearcoat layer. This looks like car paint.
fn spawn_car_paint_sphere(
    commands: &mut Commands,
    materials: &mut Assets<StandardMaterial>,
    asset_server: &AssetServer,
    sphere: &Handle<Mesh>,
) {
    commands
        .spawn(PbrBundle {
            mesh: sphere.clone(),
            material: materials.add(StandardMaterial {
                clearcoat: 1.0,
                clearcoat_perceptual_roughness: 0.1,
                normal_map_texture: Some(asset_server.load_with_settings(
                    "textures/BlueNoise-Normal.png",
                    |settings: &mut ImageLoaderSettings| settings.is_srgb = false,
                )),
                metallic: 0.9,
                perceptual_roughness: 0.5,
                base_color: BLUE.into(),
                ..default()
            }),
            transform: Transform::from_xyz(-1.0, 1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
            ..default()
        })
        .insert(ExampleSphere);
}

/// Spawn a semitransparent object with a clearcoat layer.
fn spawn_coated_glass_bubble_sphere(
    commands: &mut Commands,
    materials: &mut Assets<StandardMaterial>,
    sphere: &Handle<Mesh>,
) {
    commands
        .spawn(PbrBundle {
            mesh: sphere.clone(),
            material: materials.add(StandardMaterial {
                clearcoat: 1.0,
                clearcoat_perceptual_roughness: 0.1,
                metallic: 0.5,
                perceptual_roughness: 0.1,
                base_color: Color::srgba(0.9, 0.9, 0.9, 0.3),
                alpha_mode: AlphaMode::Blend,
                ..default()
            }),
            transform: Transform::from_xyz(-1.0, -1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
            ..default()
        })
        .insert(ExampleSphere);
}

/// Spawns an object with both a clearcoat normal map (a scratched varnish) and
/// a main layer normal map (the golf ball pattern).
///
/// This object is in glTF format, using the `KHR_materials_clearcoat`
/// extension.
fn spawn_golf_ball(commands: &mut Commands, asset_server: &AssetServer) {
    commands
        .spawn(SceneBundle {
            scene: asset_server.load("models/GolfBall/GolfBall.glb#Scene0"),
            transform: Transform::from_xyz(1.0, 1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
            ..default()
        })
        .insert(ExampleSphere);
}

/// Spawns an object with only a clearcoat normal map (a scratch pattern) and no
/// main layer normal map.
fn spawn_scratched_gold_ball(
    commands: &mut Commands,
    materials: &mut Assets<StandardMaterial>,
    asset_server: &AssetServer,
    sphere: &Handle<Mesh>,
) {
    commands
        .spawn(PbrBundle {
            mesh: sphere.clone(),
            material: materials.add(StandardMaterial {
                clearcoat: 1.0,
                clearcoat_perceptual_roughness: 0.3,
                clearcoat_normal_texture: Some(asset_server.load_with_settings(
                    "textures/ScratchedGold-Normal.png",
                    |settings: &mut ImageLoaderSettings| settings.is_srgb = false,
                )),
                metallic: 0.9,
                perceptual_roughness: 0.1,
                base_color: GOLD.into(),
                ..default()
            }),
            transform: Transform::from_xyz(1.0, -1.0, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
            ..default()
        })
        .insert(ExampleSphere);
}
examples/async_tasks/async_compute.rs (line 39)
34
35
36
37
38
39
40
41
42
43
44
fn add_assets(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    let box_mesh_handle = meshes.add(Cuboid::new(0.25, 0.25, 0.25));
    commands.insert_resource(BoxMeshHandle(box_mesh_handle));

    let box_material_handle = materials.add(Color::srgb(1.0, 0.2, 0.3));
    commands.insert_resource(BoxMaterialHandle(box_material_handle));
}
examples/2d/mesh2d.rs (line 19)
12
13
14
15
16
17
18
19
20
21
22
23
24
fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    commands.spawn(Camera2dBundle::default());
    commands.spawn(MaterialMesh2dBundle {
        mesh: meshes.add(Rectangle::default()).into(),
        transform: Transform::default().with_scale(Vec3::splat(128.)),
        material: materials.add(Color::from(PURPLE)),
        ..default()
    });
}
examples/2d/pixel_grid_snap.rs (line 86)
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
fn setup_mesh(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    commands.spawn((
        MaterialMesh2dBundle {
            mesh: meshes.add(Capsule2d::default()).into(),
            transform: Transform::from_xyz(40., 0., 2.).with_scale(Vec3::splat(32.)),
            material: materials.add(Color::BLACK),
            ..default()
        },
        Rotate,
        PIXEL_PERFECT_LAYERS,
    ));
}

fn setup_camera(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
    let canvas_size = Extent3d {
        width: RES_WIDTH,
        height: RES_HEIGHT,
        ..default()
    };

    // this Image serves as a canvas representing the low-resolution game screen
    let mut canvas = Image {
        texture_descriptor: TextureDescriptor {
            label: None,
            size: canvas_size,
            dimension: TextureDimension::D2,
            format: TextureFormat::Bgra8UnormSrgb,
            mip_level_count: 1,
            sample_count: 1,
            usage: TextureUsages::TEXTURE_BINDING
                | TextureUsages::COPY_DST
                | TextureUsages::RENDER_ATTACHMENT,
            view_formats: &[],
        },
        ..default()
    };

    // fill image.data with zeroes
    canvas.resize(canvas_size);

    let image_handle = images.add(canvas);

    // this camera renders whatever is on `PIXEL_PERFECT_LAYERS` to the canvas
    commands.spawn((
        Camera2dBundle {
            camera: Camera {
                // render before the "main pass" camera
                order: -1,
                target: RenderTarget::Image(image_handle.clone()),
                ..default()
            },
            ..default()
        },
        InGameCamera,
        PIXEL_PERFECT_LAYERS,
    ));

    // spawn the canvas
    commands.spawn((
        SpriteBundle {
            texture: image_handle,
            ..default()
        },
        Canvas,
        HIGH_RES_LAYERS,
    ));

    // the "outer" camera renders whatever is on `HIGH_RES_LAYERS` to the screen.
    // here, the canvas and one of the sample sprites will be rendered by this camera
    commands.spawn((Camera2dBundle::default(), OuterCamera, HIGH_RES_LAYERS));
}
examples/audio/pitch.rs (line 34)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fn play_pitch(
    mut pitch_assets: ResMut<Assets<Pitch>>,
    frequency: Res<PitchFrequency>,
    mut events: EventReader<PlayPitch>,
    mut commands: Commands,
) {
    for _ in events.read() {
        info!("playing pitch with frequency: {}", frequency.0);
        commands.spawn(PitchBundle {
            source: pitch_assets.add(Pitch::new(frequency.0, Duration::new(1, 0))),
            settings: PlaybackSettings::DESPAWN,
        });
        info!("number of pitch assets: {}", pitch_assets.len());
    }
}

pub fn get_strong_handle(&mut self, id: AssetId<A>) -> Option<Handle<A>>

Upgrade an AssetId into a strong Handle that will prevent asset drop.

Returns None if the provided id is not part of this Assets collection. For example, it may have been dropped earlier.

pub fn get(&self, id: impl Into<AssetId<A>>) -> Option<&A>

Retrieves a reference to the Asset with the given id, if it exists. Note that this supports anything that implements Into<AssetId<A>>, which includes Handle and AssetId.

Examples found in repository?
examples/animation/morph_targets.rs (line 92)
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
fn name_morphs(
    mut has_printed: Local<bool>,
    morph_data: Res<MorphData>,
    meshes: Res<Assets<Mesh>>,
) {
    if *has_printed {
        return;
    }

    let Some(mesh) = meshes.get(&morph_data.mesh) else {
        return;
    };
    let Some(names) = mesh.morph_target_names() else {
        return;
    };
    for name in names {
        println!("  {name}");
    }
    *has_printed = true;
}
More examples
Hide additional examples
examples/stress_tests/many_animated_sprites.rs (line 124)
116
117
118
119
120
121
122
123
124
125
126
127
128
fn animate_sprite(
    time: Res<Time>,
    texture_atlases: Res<Assets<TextureAtlasLayout>>,
    mut query: Query<(&mut AnimationTimer, &mut TextureAtlas)>,
) {
    for (mut timer, mut sheet) in query.iter_mut() {
        timer.tick(time.delta());
        if timer.just_finished() {
            let texture_atlas = texture_atlases.get(&sheet.layout).unwrap();
            sheet.index = (sheet.index + 1) % texture_atlas.textures.len();
        }
    }
}
examples/asset/processing/asset_processing.rs (line 240)
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
fn print_text(
    handles: Res<TextAssets>,
    texts: Res<Assets<Text>>,
    mut asset_events: EventReader<AssetEvent<Text>>,
) {
    if !asset_events.is_empty() {
        // This prints the current values of the assets
        // Hot-reloading is supported, so try modifying the source assets (and their meta files)!
        println!("Current Values:");
        println!("  a: {:?}", texts.get(&handles.a));
        println!("  b: {:?}", texts.get(&handles.b));
        println!("  c: {:?}", texts.get(&handles.c));
        println!("  d: {:?}", texts.get(&handles.d));
        println!("  e: {:?}", texts.get(&handles.e));
        println!("(You can modify source assets and their .meta files to hot-reload changes!)");
        println!();
        asset_events.clear();
    }
}
examples/asset/custom_asset.rs (line 126)
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
fn print_on_load(
    mut state: ResMut<State>,
    custom_assets: Res<Assets<CustomAsset>>,
    blob_assets: Res<Assets<Blob>>,
) {
    let custom_asset = custom_assets.get(&state.handle);
    let other_custom_asset = custom_assets.get(&state.other_handle);
    let blob = blob_assets.get(&state.blob);

    // Can't print results if the assets aren't ready
    if state.printed {
        return;
    }

    if custom_asset.is_none() {
        info!("Custom Asset Not Ready");
        return;
    }

    if other_custom_asset.is_none() {
        info!("Other Custom Asset Not Ready");
        return;
    }

    if blob.is_none() {
        info!("Blob Not Ready");
        return;
    }

    info!("Custom asset loaded: {:?}", custom_asset.unwrap());
    info!("Custom asset loaded: {:?}", other_custom_asset.unwrap());
    info!("Blob Size: {:?} Bytes", blob.unwrap().bytes.len());

    // Once printed, we won't print again
    state.printed = true;
}
examples/3d/tonemapping.rs (line 257)
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
fn resize_image(
    image_mesh: Query<(&Handle<StandardMaterial>, &Handle<Mesh>), With<HDRViewer>>,
    materials: Res<Assets<StandardMaterial>>,
    mut meshes: ResMut<Assets<Mesh>>,
    images: Res<Assets<Image>>,
    mut image_events: EventReader<AssetEvent<Image>>,
) {
    for event in image_events.read() {
        let (AssetEvent::Added { id } | AssetEvent::Modified { id }) = event else {
            continue;
        };

        for (mat_h, mesh_h) in &image_mesh {
            let Some(mat) = materials.get(mat_h) else {
                continue;
            };

            let Some(ref base_color_texture) = mat.base_color_texture else {
                continue;
            };

            if *id != base_color_texture.id() {
                continue;
            };

            let Some(image_changed) = images.get(*id) else {
                continue;
            };

            let size = image_changed.size_f32().normalize_or_zero() * 1.4;
            // Resize Mesh
            let quad = Mesh::from(Rectangle::from_size(size));
            meshes.insert(mesh_h, quad);
        }
    }
}
examples/tools/scene_viewer/morph_viewer_plugin.rs (line 251)
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
fn detect_morphs(
    mut commands: Commands,
    morphs: Query<(Entity, &MorphWeights, Option<&Name>)>,
    meshes: Res<Assets<Mesh>>,
    scene_handle: Res<SceneHandle>,
    mut setup: Local<bool>,
    asset_server: Res<AssetServer>,
) {
    let no_morphing = morphs.iter().len() == 0;
    if no_morphing {
        return;
    }
    if scene_handle.is_loaded && !*setup {
        *setup = true;
    } else {
        return;
    }
    let mut detected = Vec::new();

    for (entity, weights, name) in &morphs {
        let target_names = weights
            .first_mesh()
            .and_then(|h| meshes.get(h))
            .and_then(|m| m.morph_target_names());
        let targets = Target::new(name, weights.weights(), target_names, entity);
        detected.extend(targets);
    }
    detected.truncate(AVAILABLE_KEYS.len());
    let style = TextStyle {
        font: asset_server.load("assets/fonts/FiraMono-Medium.ttf"),
        font_size: 13.0,
        ..default()
    };
    let mut sections = vec![
        TextSection::new("Morph Target Controls\n", style.clone()),
        TextSection::new("---------------\n", style.clone()),
    ];
    let target_to_text =
        |(i, target): (usize, &Target)| target.text_section(AVAILABLE_KEYS[i].name, style.clone());
    sections.extend(detected.iter().enumerate().map(target_to_text));
    commands.insert_resource(WeightsControl { weights: detected });
    commands.spawn(TextBundle::from_sections(sections).with_style(Style {
        position_type: PositionType::Absolute,
        top: Val::Px(10.0),
        left: Val::Px(10.0),
        ..default()
    }));
}

pub fn get_mut(&mut self, id: impl Into<AssetId<A>>) -> Option<&mut A>

Retrieves a mutable reference to the Asset with the given id, if it exists. Note that this supports anything that implements Into<AssetId<A>>, which includes Handle and AssetId.

Examples found in repository?
examples/3d/deferred_rendering.rs (line 299)
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
fn update_normal(
    mut already_ran: Local<bool>,
    mut images: ResMut<Assets<Image>>,
    normal: Res<Normal>,
) {
    if *already_ran {
        return;
    }
    if let Some(normal) = normal.0.as_ref() {
        if let Some(image) = images.get_mut(normal) {
            image.texture_descriptor.format = TextureFormat::Rgba8Unorm;
            *already_ran = true;
        }
    }
}
More examples
Hide additional examples
examples/3d/parallax_mapping.rs (line 367)
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
fn update_normal(
    mut already_ran: Local<bool>,
    mut images: ResMut<Assets<Image>>,
    normal: Res<Normal>,
) {
    if *already_ran {
        return;
    }
    if let Some(normal) = normal.0.as_ref() {
        if let Some(image) = images.get_mut(normal) {
            image.texture_descriptor.format = TextureFormat::Rgba8Unorm;
            *already_ran = true;
        }
    }
}
examples/3d/animated_material.rs (line 56)
50
51
52
53
54
55
56
57
58
59
60
61
62
fn animate_materials(
    material_handles: Query<&Handle<StandardMaterial>>,
    time: Res<Time>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    for material_handle in material_handles.iter() {
        if let Some(material) = materials.get_mut(material_handle) {
            if let Color::Hsla(ref mut hsla) = material.base_color {
                *hsla = hsla.rotate_hue(time.delta_seconds() * 100.0);
            }
        }
    }
}
examples/3d/tonemapping.rs (line 233)
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
fn drag_drop_image(
    image_mat: Query<&Handle<StandardMaterial>, With<HDRViewer>>,
    text: Query<Entity, (With<Text>, With<SceneNumber>)>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    mut drop_events: EventReader<FileDragAndDrop>,
    asset_server: Res<AssetServer>,
    mut commands: Commands,
) {
    let Some(new_image) = drop_events.read().find_map(|e| match e {
        FileDragAndDrop::DroppedFile { path_buf, .. } => {
            Some(asset_server.load(path_buf.to_string_lossy().to_string()))
        }
        _ => None,
    }) else {
        return;
    };

    for mat_h in &image_mat {
        if let Some(mat) = materials.get_mut(mat_h) {
            mat.base_color_texture = Some(new_image.clone());

            // Despawn the image viewer instructions
            if let Ok(text_entity) = text.get_single() {
                commands.entity(text_entity).despawn();
            }
        }
    }
}
examples/shader/shader_prepass.rs (line 248)
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
fn toggle_prepass_view(
    mut prepass_view: Local<u32>,
    keycode: Res<ButtonInput<KeyCode>>,
    material_handle: Query<&Handle<PrepassOutputMaterial>>,
    mut materials: ResMut<Assets<PrepassOutputMaterial>>,
    mut text: Query<&mut Text>,
) {
    if keycode.just_pressed(KeyCode::Space) {
        *prepass_view = (*prepass_view + 1) % 4;

        let label = match *prepass_view {
            0 => "transparent",
            1 => "depth",
            2 => "normals",
            3 => "motion vectors",
            _ => unreachable!(),
        };
        let mut text = text.single_mut();
        text.sections[0].value = format!("Prepass Output: {label}\n");
        for section in &mut text.sections {
            section.style.color = Color::WHITE;
        }

        let handle = material_handle.single();
        let mat = materials.get_mut(handle).unwrap();
        mat.settings.show_depth = (*prepass_view == 1) as u32;
        mat.settings.show_normals = (*prepass_view == 2) as u32;
        mat.settings.show_motion_vectors = (*prepass_view == 3) as u32;
    }
}
examples/2d/texture_atlas.rs (line 229)
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
fn create_texture_atlas(
    folder: &LoadedFolder,
    padding: Option<UVec2>,
    sampling: Option<ImageSampler>,
    textures: &mut ResMut<Assets<Image>>,
) -> (TextureAtlasLayout, Handle<Image>) {
    // Build a texture atlas using the individual sprites
    let mut texture_atlas_builder =
        TextureAtlasBuilder::default().padding(padding.unwrap_or_default());
    for handle in folder.handles.iter() {
        let id = handle.id().typed_unchecked::<Image>();
        let Some(texture) = textures.get(id) else {
            warn!(
                "{:?} did not resolve to an `Image` asset.",
                handle.path().unwrap()
            );
            continue;
        };

        texture_atlas_builder.add_texture(Some(id), texture);
    }

    let (texture_atlas_layout, texture) = texture_atlas_builder.finish().unwrap();
    let texture = textures.add(texture);

    // Update the sampling settings of the texture atlas
    let image = textures.get_mut(&texture).unwrap();
    image.sampler = sampling.unwrap_or_default();

    (texture_atlas_layout, texture)
}

pub fn remove(&mut self, id: impl Into<AssetId<A>>) -> Option<A>

Removes (and returns) the Asset with the given id, if it exists. Note that this supports anything that implements Into<AssetId<A>>, which includes Handle and AssetId.

Examples found in repository?
examples/asset/asset_decompression.rs (line 123)
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
fn decompress<A: Asset>(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut compressed_assets: ResMut<Assets<GzAsset>>,
    query: Query<(Entity, &Compressed<A>)>,
) {
    for (entity, Compressed { compressed, .. }) in query.iter() {
        let Some(GzAsset { uncompressed }) = compressed_assets.remove(compressed) else {
            continue;
        };

        let uncompressed = uncompressed.take::<A>().unwrap();

        commands
            .entity(entity)
            .remove::<Compressed<A>>()
            .insert(asset_server.add(uncompressed));
    }
}

pub fn remove_untracked(&mut self, id: impl Into<AssetId<A>>) -> Option<A>

Removes (and returns) the Asset with the given id, if it exists. This skips emitting AssetEvent::Removed. Note that this supports anything that implements Into<AssetId<A>>, which includes Handle and AssetId.

pub fn is_empty(&self) -> bool

Returns true if there are no assets in this collection.

pub fn len(&self) -> usize

Returns the number of assets currently stored in the collection.

Examples found in repository?
examples/audio/pitch.rs (line 37)
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fn play_pitch(
    mut pitch_assets: ResMut<Assets<Pitch>>,
    frequency: Res<PitchFrequency>,
    mut events: EventReader<PlayPitch>,
    mut commands: Commands,
) {
    for _ in events.read() {
        info!("playing pitch with frequency: {}", frequency.0);
        commands.spawn(PitchBundle {
            source: pitch_assets.add(Pitch::new(frequency.0, Duration::new(1, 0))),
            settings: PlaybackSettings::DESPAWN,
        });
        info!("number of pitch assets: {}", pitch_assets.len());
    }
}

pub fn ids(&self) -> impl Iterator<Item = AssetId<A>>

Returns an iterator over the AssetId of every Asset stored in this collection.

pub fn iter(&self) -> impl Iterator<Item = (AssetId<A>, &A)>

Returns an iterator over the AssetId and Asset ref of every asset in this collection.

Examples found in repository?
examples/tools/scene_viewer/animation_plugin.rs (line 79)
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
fn assign_clips(
    mut players: Query<&mut AnimationPlayer>,
    targets: Query<(Entity, &AnimationTarget)>,
    parents: Query<&Parent>,
    scene_handle: Res<SceneHandle>,
    clips: Res<Assets<AnimationClip>>,
    gltf_assets: Res<Assets<Gltf>>,
    assets: Res<AssetServer>,
    mut graphs: ResMut<Assets<AnimationGraph>>,
    mut commands: Commands,
    mut setup: Local<bool>,
) {
    if scene_handle.is_loaded && !*setup {
        *setup = true;
    } else {
        return;
    }

    let gltf = gltf_assets.get(&scene_handle.gltf_handle).unwrap();
    let animations = &gltf.animations;
    if animations.is_empty() {
        return;
    }

    let count = animations.len();
    let plural = if count == 1 { "" } else { "s" };
    info!("Found {} animation{plural}", animations.len());
    let names: Vec<_> = gltf.named_animations.keys().collect();
    info!("Animation names: {names:?}");

    // Map animation target IDs to entities.
    let animation_target_id_to_entity: HashMap<_, _> = targets
        .iter()
        .map(|(entity, target)| (target.id, entity))
        .collect();

    // Build up a list of all animation clips that belong to each player. A clip
    // is considered to belong to an animation player if all targets of the clip
    // refer to entities whose nearest ancestor player is that animation player.

    let mut player_to_graph: EntityHashMap<(AnimationGraph, Vec<AnimationNodeIndex>)> =
        EntityHashMap::default();

    for (clip_id, clip) in clips.iter() {
        let mut ancestor_player = None;
        for target_id in clip.curves().keys() {
            // If the animation clip refers to entities that aren't present in
            // the scene, bail.
            let Some(&target) = animation_target_id_to_entity.get(target_id) else {
                continue;
            };

            // Find the nearest ancestor animation player.
            let mut current = Some(target);
            while let Some(entity) = current {
                if players.contains(entity) {
                    match ancestor_player {
                        None => {
                            // If we haven't found a player yet, record the one
                            // we found.
                            ancestor_player = Some(entity);
                        }
                        Some(ancestor) => {
                            // If we have found a player, then make sure it's
                            // the same player we located before.
                            if ancestor != entity {
                                // It's a different player. Bail.
                                ancestor_player = None;
                                break;
                            }
                        }
                    }
                }

                // Go to the next parent.
                current = parents.get(entity).ok().map(|parent| parent.get());
            }
        }

        let Some(ancestor_player) = ancestor_player else {
            warn!(
                "Unexpected animation hierarchy for animation clip {:?}; ignoring.",
                clip_id
            );
            continue;
        };

        let Some(clip_handle) = assets.get_id_handle(clip_id) else {
            warn!("Clip {:?} wasn't loaded.", clip_id);
            continue;
        };

        let &mut (ref mut graph, ref mut clip_indices) =
            player_to_graph.entry(ancestor_player).or_default();
        let node_index = graph.add_clip(clip_handle, 1.0, graph.root);
        clip_indices.push(node_index);
    }

    // Now that we've built up a list of all clips that belong to each player,
    // package them up into a `Clips` component, play the first such animation,
    // and add that component to the player.
    for (player_entity, (graph, clips)) in player_to_graph {
        let Ok(mut player) = players.get_mut(player_entity) else {
            warn!("Animation targets referenced a nonexistent player. This shouldn't happen.");
            continue;
        };
        let graph = graphs.add(graph);
        let animations = Clips::new(clips);
        player.play(animations.current()).repeat();
        commands
            .entity(player_entity)
            .insert(animations)
            .insert(graph);
    }
}

pub fn iter_mut(&mut self) -> AssetsMutIterator<'_, A>

Returns an iterator over the AssetId and mutable Asset ref of every asset in this collection.

Examples found in repository?
examples/3d/transparency_3d.rs (line 120)
118
119
120
121
122
123
pub fn fade_transparency(time: Res<Time>, mut materials: ResMut<Assets<StandardMaterial>>) {
    let alpha = (time.elapsed_seconds().sin() / 2.0) + 0.5;
    for (_, material) in materials.iter_mut() {
        material.base_color.set_alpha(alpha);
    }
}
More examples
Hide additional examples
examples/ui/ui_material.rs (line 17)
16
17
18
19
20
21
22
fn update(time: Res<Time>, mut ui_materials: ResMut<Assets<CustomUiMaterial>>) {
    for (_, material) in ui_materials.iter_mut() {
        // rainbow color effect
        let new_color = Color::hsl((time.elapsed_seconds() * 60.0) % 360.0, 1., 0.5);
        material.color = LinearRgba::from(new_color).to_f32_array().into();
    }
}
examples/3d/parallax_mapping.rs (line 99)
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
fn update_parallax_depth_scale(
    input: Res<ButtonInput<KeyCode>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    mut target_depth: Local<TargetDepth>,
    mut depth_update: Local<bool>,
    mut text: Query<&mut Text>,
) {
    if input.just_pressed(KeyCode::Digit1) {
        target_depth.0 -= DEPTH_UPDATE_STEP;
        target_depth.0 = target_depth.0.max(0.0);
        *depth_update = true;
    }
    if input.just_pressed(KeyCode::Digit2) {
        target_depth.0 += DEPTH_UPDATE_STEP;
        target_depth.0 = target_depth.0.min(MAX_DEPTH);
        *depth_update = true;
    }
    if *depth_update {
        let mut text = text.single_mut();
        for (_, mat) in materials.iter_mut() {
            let current_depth = mat.parallax_depth_scale;
            let new_depth = current_depth.lerp(target_depth.0, DEPTH_CHANGE_RATE);
            mat.parallax_depth_scale = new_depth;
            text.sections[0].value = format!("Parallax depth scale: {new_depth:.5}\n");
            if (new_depth - current_depth).abs() <= 0.000000001 {
                *depth_update = false;
            }
        }
    }
}

fn switch_method(
    input: Res<ButtonInput<KeyCode>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    mut text: Query<&mut Text>,
    mut current: Local<CurrentMethod>,
) {
    if input.just_pressed(KeyCode::Space) {
        current.next_method();
    } else {
        return;
    }
    let mut text = text.single_mut();
    text.sections[2].value = format!("Method: {}\n", *current);

    for (_, mat) in materials.iter_mut() {
        mat.parallax_mapping_method = current.0;
    }
}

fn update_parallax_layers(
    input: Res<ButtonInput<KeyCode>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    mut target_layers: Local<TargetLayers>,
    mut text: Query<&mut Text>,
) {
    if input.just_pressed(KeyCode::Digit3) {
        target_layers.0 -= 1.0;
        target_layers.0 = target_layers.0.max(0.0);
    } else if input.just_pressed(KeyCode::Digit4) {
        target_layers.0 += 1.0;
    } else {
        return;
    }
    let layer_count = target_layers.0.exp2();
    let mut text = text.single_mut();
    text.sections[1].value = format!("Layers: {layer_count:.0}\n");

    for (_, mat) in materials.iter_mut() {
        mat.max_parallax_layer_count = layer_count;
    }
}
examples/3d/deferred_rendering.rs (line 355)
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
fn switch_mode(
    mut text: Query<&mut Text>,
    mut commands: Commands,
    keys: Res<ButtonInput<KeyCode>>,
    mut default_opaque_renderer_method: ResMut<DefaultOpaqueRendererMethod>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    cameras: Query<Entity, With<Camera>>,
    mut pause: ResMut<Pause>,
    mut hide_ui: Local<bool>,
    mut mode: Local<DefaultRenderMode>,
) {
    let mut text = text.single_mut();
    let text = &mut text.sections[0].value;

    text.clear();

    if keys.just_pressed(KeyCode::Space) {
        pause.0 = !pause.0;
    }

    if keys.just_pressed(KeyCode::Digit1) {
        *mode = DefaultRenderMode::Deferred;
        default_opaque_renderer_method.set_to_deferred();
        println!("DefaultOpaqueRendererMethod: Deferred");
        for _ in materials.iter_mut() {}
        for camera in &cameras {
            commands.entity(camera).remove::<NormalPrepass>();
            commands.entity(camera).insert(DepthPrepass);
            commands.entity(camera).insert(MotionVectorPrepass);
            commands.entity(camera).insert(DeferredPrepass);
        }
    }
    if keys.just_pressed(KeyCode::Digit2) {
        *mode = DefaultRenderMode::Forward;
        default_opaque_renderer_method.set_to_forward();
        println!("DefaultOpaqueRendererMethod: Forward");
        for _ in materials.iter_mut() {}
        for camera in &cameras {
            commands.entity(camera).remove::<NormalPrepass>();
            commands.entity(camera).remove::<DepthPrepass>();
            commands.entity(camera).remove::<MotionVectorPrepass>();
            commands.entity(camera).remove::<DeferredPrepass>();
        }
    }
    if keys.just_pressed(KeyCode::Digit3) {
        *mode = DefaultRenderMode::ForwardPrepass;
        default_opaque_renderer_method.set_to_forward();
        println!("DefaultOpaqueRendererMethod: Forward + Prepass");
        for _ in materials.iter_mut() {}
        for camera in &cameras {
            commands.entity(camera).insert(NormalPrepass);
            commands.entity(camera).insert(DepthPrepass);
            commands.entity(camera).insert(MotionVectorPrepass);
            commands.entity(camera).remove::<DeferredPrepass>();
        }
    }

    if keys.just_pressed(KeyCode::KeyH) {
        *hide_ui = !*hide_ui;
    }

    if !*hide_ui {
        text.push_str("(H) Hide UI\n");
        text.push_str("(Space) Play/Pause\n\n");
        text.push_str("Rendering Method:\n");

        text.push_str(&format!(
            "(1) {} Deferred\n",
            if let DefaultRenderMode::Deferred = *mode {
                ">"
            } else {
                ""
            }
        ));
        text.push_str(&format!(
            "(2) {} Forward\n",
            if let DefaultRenderMode::Forward = *mode {
                ">"
            } else {
                ""
            }
        ));
        text.push_str(&format!(
            "(3) {} Forward + Prepass\n",
            if let DefaultRenderMode::ForwardPrepass = *mode {
                ">"
            } else {
                ""
            }
        ));
    }
}

pub fn track_assets( assets: ResMut<'_, Assets<A>>, asset_server: Res<'_, AssetServer> )

A system that synchronizes the state of assets in this collection with the AssetServer. This manages Handle drop events.

pub fn asset_events( assets: ResMut<'_, Assets<A>>, events: EventWriter<'_, AssetEvent<A>> )

A system that applies accumulated asset change events to the Events resource.

Trait Implementations§

§

impl<A> Default for Assets<A>
where A: Asset,

§

fn default() -> Assets<A>

Returns the “default value” for a type. Read more
§

impl<A> Resource for Assets<A>
where A: Asset, Assets<A>: Send + Sync + 'static,

Auto Trait Implementations§

§

impl<A> Freeze for Assets<A>

§

impl<A> RefUnwindSafe for Assets<A>
where A: RefUnwindSafe,

§

impl<A> Send for Assets<A>

§

impl<A> Sync for Assets<A>

§

impl<A> Unpin for Assets<A>
where A: Unpin,

§

impl<A> UnwindSafe for Assets<A>
where A: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

§

impl<T> FromWorld for T
where T: Default,

§

fn from_world(_world: &mut World) -> T

Creates Self using data from the given World.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

§

fn into_sample(self) -> T

§

impl<T> NoneValue for T
where T: Default,

§

type NoneType = T

§

fn null_value() -> T

The none-equivalent value.
§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

§

fn to_sample_(self) -> U

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
§

impl<T> ConditionalSend for T
where T: Send,

§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

§

impl<T> Settings for T
where T: 'static + Send + Sync,

§

impl<T> WasmNotSend for T
where T: Send,

§

impl<T> WasmNotSendSync for T
where T: WasmNotSend + WasmNotSync,

§

impl<T> WasmNotSync for T
where T: Sync,