-
First I uploaded a glTF file and set scene with this.
Now I changed the colors of all materials like this.
Now I want to make a function applying CustomMaterial with glsl codes(like this example shader_material_glsl) to SceneBundle. (I found this bevy shader example, but this showed applying CustomMaterial to MaterialMeshBundle not SceneBundle..) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 6 replies
-
This question came up a few times recently in the bevy discord. This is finally the opportunity to write it down on a search-engine-enabled web page. You need to:
We will create a system that does all those steps and call it We create a new marker component #[derive(AsBindGroup, TypeUuid, Debug, Clone)]
#[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"]
pub struct MyCustomMaterial {
// …
}
impl<'a> From<&'a StandardMaterial> for MyCustomMaterial {
fn from(value: &'a StandardMaterial) -> Self {
todo!()
}
}
#[derive(Component)]
struct CustomizeMaterial;
pub fn customize_scene_materials(
unloaded_instances: Query<(Entity, &SceneInstance), With<CustomizeMaterial>>,
handles: Query<(Entity, &Handle<StandardMaterial>)>,
pbr_materials: Res<Assets<StandardMaterial>>,
scene_manager: Res<SceneSpawner>,
mut custom_materials: ResMut<Assets<MyCustomMaterial>>,
mut cmds: Commands,
) {
for (entity, instance, hooked) in unloaded_instances.iter() {
if scene_manager.instance_is_ready(**instance) {
cmds.entity(entity).remove::<CustomizeMaterial>();
}
// Iterate over all entities in scene (once it's loaded)
let handles = handles.iter_many(scene_manager.iter_instance_entities(**instance));
for (entity, material_handle) in handles {
let Some(material) = pbr_materials.get(material_handle) else { continue; };
let custom = custom_materials.add(material.into());
cmds.entity(entity).insert(custom).remove::<Handle<StandardMaterial>>();
}
}
} A disadvantage of this is that the conversion occurs every time the scene is loaded. This should change in the future with asset pre-processing. You might benefit to adding app.add_system(customize_scene_materials.run_if(any_with_component::<CustomizeMaterial>())) Edit: Just modifying existing materialIf you don't want to add a custom material, but just edit an existing one, it's a bit easier: #[derive(Component)]
struct CustomizeMaterial;
pub fn customize_scene_materials(
unloaded_instances: Query<(Entity, &SceneInstance), With<CustomizeMaterial>>,
handles: Query<(Entity, &Handle<StandardMaterial>)>,
mut pbr_materials: ResMut<Assets<StandardMaterial>>,
scene_manager: Res<SceneSpawner>,
) {
for (entity, instance, hooked) in unloaded_instances.iter() {
if scene_manager.instance_is_ready(**instance) {
cmds.entity(entity).remove::<CustomizeMaterial>();
}
// Iterate over all entities in scene (once it's loaded)
let handles = handles.iter_many(scene_manager.iter_instance_entities(**instance));
for (entity, material_handle) in handles {
let Some(material) = pbr_materials.get_mut(material_handle) else { continue; };
material.color = Color::RED;
}
}
} Modify individual scene materialsSeveral instances of the same scene share the same materials, if you want to only modify materials in one scene and not the other, you need to replace the // Access mutably the handle, change the system parameter
mut handles: Query<(Entity, &mut Handle<StandardMaterial>)>,
// Replace the inner `for` loop by this. It clones the material,
// creates a new one and replaces the handle
// Iterate over all entities in scene (once it's loaded)
let mut handles = handles.iter_many_mut(scene_manager.iter_instance_entities(**instance));
while let Some((entity, mut material_handle)) = handles.fetch_next() {
let Some(material) = pbr_materials.get(material_handle) else { continue; };
let mut new_material = material.clone();
new_material.color = Color::RED;
*material_handle = pbr_materials.add(new_material);
} |
Beta Was this translation helpful? Give feedback.
This question came up a few times recently in the bevy discord. This is finally the opportunity to write it down on a search-engine-enabled web page.
You need to:
SceneSpawner::iter_instance_entities
)Handle<StandardMaterial>
componentStandardMaterial
for that handleHandle<StandardMaterial>
We will create a system that does all those steps and call it
customize_scene_materials
.We create a new mar…