Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/gltf/edit_material_on_gltf.rs
9356 views
1
//! Showcases how to change the material of a `Scene` spawned from a Gltf
2
3
use bevy::{
4
audio::AudioPlugin, color::palettes, gltf::GltfMaterialName, prelude::*,
5
scene::SceneInstanceReady,
6
};
7
8
fn main() {
9
App::new()
10
.add_plugins(DefaultPlugins.build().disable::<AudioPlugin>())
11
.add_systems(Startup, setup_scene)
12
.add_observer(change_material)
13
.run();
14
}
15
16
/// This is added to a [`SceneRoot`] and will cause the [`StandardMaterial::base_color`]
17
/// of materials with [`GltfMaterialName`] equal to `LeatherPartsMat`.
18
#[derive(Component)]
19
struct ColorOverride(Color);
20
21
fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
22
commands.spawn((
23
Camera3d::default(),
24
Transform::from_xyz(0., 1., 2.5).looking_at(Vec3::new(0., 0.25, 0.), Dir3::Y),
25
));
26
27
commands.spawn((
28
DirectionalLight::default(),
29
Transform::from_xyz(0., 1., 0.25).looking_at(Vec3::ZERO, Dir3::Y),
30
));
31
32
// FlightHelmet handle
33
let flight_helmet = asset_server
34
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"));
35
// This model will keep its original materials
36
commands.spawn(SceneRoot(flight_helmet.clone()));
37
// This model will be tinted red
38
commands.spawn((
39
SceneRoot(flight_helmet.clone()),
40
Transform::from_xyz(-1.25, 0., 0.),
41
ColorOverride(palettes::tailwind::RED_300.into()),
42
));
43
// This model will be tinted green
44
commands.spawn((
45
SceneRoot(flight_helmet),
46
Transform::from_xyz(1.25, 0., 0.),
47
ColorOverride(palettes::tailwind::GREEN_300.into()),
48
));
49
}
50
51
/// On [`SceneInstanceReady`], iterates over all descendants of the scene
52
/// and modifies the tint of the material for the materials named `LeatherPartsMat`.
53
///
54
/// If the [`SceneRoot`] does not have a [`ColorOverride`], it is skipped.
55
fn change_material(
56
scene_ready: On<SceneInstanceReady>,
57
mut commands: Commands,
58
children: Query<&Children>,
59
color_override: Query<&ColorOverride>,
60
mesh_materials: Query<(&MeshMaterial3d<StandardMaterial>, &GltfMaterialName)>,
61
mut asset_materials: ResMut<Assets<StandardMaterial>>,
62
) {
63
info!("processing Scene Entity: {}", scene_ready.entity);
64
65
// Get the `ColorOverride` of the entity, if it does not have a color override, return
66
let Ok(color_override) = color_override.get(scene_ready.entity) else {
67
info!("{} does not have a color override", scene_ready.entity);
68
return;
69
};
70
71
// Iterate over all children recursively
72
for descendant in children.iter_descendants(scene_ready.entity) {
73
// Get the material id and name which were created from the glTF file information
74
let Ok((id, material_name)) = mesh_materials.get(descendant) else {
75
continue;
76
};
77
// Get the material of the descendant
78
let Some(material) = asset_materials.get_mut(id.id()) else {
79
continue;
80
};
81
82
// match on the material name, modifying the materials as necessary
83
match material_name.0.as_str() {
84
"LeatherPartsMat" => {
85
info!("editing LeatherPartsMat to use ColorOverride tint");
86
// Create a copy of the material and override base color
87
// If you intend on creating multiple models with the same tint, it
88
// is best to cache the handle somewhere, as having multiple materials
89
// that are identical is expensive
90
let mut new_material = material.clone();
91
new_material.base_color = color_override.0;
92
93
// Override `MeshMaterial3d` with new material
94
commands
95
.entity(descendant)
96
.insert(MeshMaterial3d(asset_materials.add(new_material)));
97
}
98
name => {
99
info!("not replacing: {name}");
100
}
101
}
102
}
103
}
104
105