Changing a Material
When you load a scene from a glTF and spawn it multiple times, the material handles in each instance of the scene point to the same material asset.
If you want to modify the material properties of only one of these instances, you can clone it, modify it, and add it to the asset server.
Bevy 0.14
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_resource::<RedMaterial>()
.add_systems(Startup, (setup_scene, setup))
.add_systems(PostUpdate, decorate_red_fox)
.run();
}
#[derive(Component)]
struct RedFox;
#[derive(Resource)]
struct RedMaterial(Handle<StandardMaterial>);
impl FromWorld for RedMaterial {
fn from_world(world: &mut World) -> Self {
let mut materials = world.resource_mut::<Assets<StandardMaterial>>();
let red: Color = basic::RED.into();
Self(materials.add(StandardMaterial::from(red)))
}
}
fn decorate_red_fox(
mut events: EventReader<SceneInstanceReady>,
instances: Query<&SceneInstance, With<RedFox>>,
spawner: Res<SceneSpawner>,
mut material_query: Query<&mut Handle<StandardMaterial>>,
red_material: Res<RedMaterial>,
) {
for event in events.read() {
let Ok(instance) = instances.get(event.parent) else {
continue;
};
for instance_entity in spawner.iter_instance_entities(**instance) {
let Ok(mut original_material) =
material_query.get_mut(instance_entity)
else {
continue;
};
*original_material = red_material.0.clone();
}
}
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((
SceneBundle {
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
transform: Transform::from_scale(Vec3::splat(0.02))
.with_translation(Vec3::NEG_X),
..default()
},
RedFox,
));
commands.spawn(SceneBundle {
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
transform: Transform::from_scale(Vec3::splat(0.02))
.with_translation(Vec3::X),
..default()
});
}