Skip to content

Commit 9ea9c5d

Browse files
authored
Add edit_material_on_gltf example (#17677)
# Objective Create a minimal example of how to modify the material from a `Gltf`. This is frequently asked about on the help channel of the discord. ## Solution Create the example. ## Showcase ![image](https://github.com/user-attachments/assets/efeab96d-056d-4597-953b-80ee5162749c)
1 parent 989f547 commit 9ea9c5d

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,17 @@ description = "Showcases different blend modes"
920920
category = "3D Rendering"
921921
wasm = true
922922

923+
[[example]]
924+
name = "edit_material_on_gltf"
925+
path = "examples/3d/edit_material_on_gltf.rs"
926+
doc-scrape-examples = true
927+
928+
[package.metadata.example.edit_material_on_gltf]
929+
name = "Edit Gltf Material"
930+
description = "Showcases changing materials of a Gltf after Scene spawn"
931+
category = "3D Rendering"
932+
wasm = true
933+
923934
[[example]]
924935
name = "lighting"
925936
path = "examples/3d/lighting.rs"

examples/3d/edit_material_on_gltf.rs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! Showcases how to change the material of a `Scene` spawned from a Gltf
2+
3+
use bevy::{
4+
app::{App, PluginGroup, Startup},
5+
asset::{AssetServer, Assets},
6+
audio::AudioPlugin,
7+
color::{palettes, Color},
8+
gltf::GltfAssetLabel,
9+
math::{Dir3, Vec3},
10+
pbr::{DirectionalLight, MeshMaterial3d, StandardMaterial},
11+
prelude::{Camera3d, Children, Commands, Component, Query, Res, ResMut, Transform, Trigger},
12+
scene::{SceneInstanceReady, SceneRoot},
13+
DefaultPlugins,
14+
};
15+
16+
fn main() {
17+
App::new()
18+
.add_plugins(DefaultPlugins.build().disable::<AudioPlugin>())
19+
.add_systems(Startup, setup_scene)
20+
.add_observer(change_material)
21+
.run();
22+
}
23+
24+
/// This is added to a [`SceneRoot`] and will cause the [`StandardMaterial::base_color`]
25+
/// of all materials to be overwritten
26+
#[derive(Component)]
27+
struct ColorOverride(Color);
28+
29+
fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
30+
commands.spawn((
31+
Camera3d::default(),
32+
Transform::from_xyz(0., 1., 2.5).looking_at(Vec3::new(0., 0.25, 0.), Dir3::Y),
33+
));
34+
35+
commands.spawn((
36+
DirectionalLight::default(),
37+
Transform::from_xyz(0., 1., 0.25).looking_at(Vec3::ZERO, Dir3::Y),
38+
));
39+
40+
// FlightHelmet handle
41+
let flight_helmet = asset_server
42+
.load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"));
43+
// This model will keep its original materials
44+
commands.spawn(SceneRoot(flight_helmet.clone()));
45+
// This model will be tinted red
46+
commands.spawn((
47+
SceneRoot(flight_helmet.clone()),
48+
Transform::from_xyz(-1.25, 0., 0.),
49+
ColorOverride(palettes::tailwind::RED_300.into()),
50+
));
51+
// This model will be tinted green
52+
commands.spawn((
53+
SceneRoot(flight_helmet),
54+
Transform::from_xyz(1.25, 0., 0.),
55+
ColorOverride(palettes::tailwind::GREEN_300.into()),
56+
));
57+
}
58+
59+
fn change_material(
60+
trigger: Trigger<SceneInstanceReady>,
61+
mut commands: Commands,
62+
children: Query<&Children>,
63+
color_override: Query<&ColorOverride>,
64+
mesh_materials: Query<&MeshMaterial3d<StandardMaterial>>,
65+
mut asset_materials: ResMut<Assets<StandardMaterial>>,
66+
) {
67+
// Get the `ColorOverride` of the entity, if it does not have a color override, skip
68+
let Ok(color_override) = color_override.get(trigger.target()) else {
69+
return;
70+
};
71+
72+
// Iterate over all children recursively
73+
for descendants in children.iter_descendants(trigger.target()) {
74+
// Get the material of the descendant
75+
if let Some(material) = mesh_materials
76+
.get(descendants)
77+
.ok()
78+
.and_then(|id| asset_materials.get_mut(id.id()))
79+
{
80+
// Create a copy of the material and override base color
81+
// If you intend on creating multiple models with the same tint, it
82+
// is best to cache the handle somewhere, as having multiple materials
83+
// that are identical is expensive
84+
let mut new_material = material.clone();
85+
new_material.base_color = color_override.0;
86+
87+
// Override `MeshMaterial3d` with new material
88+
commands
89+
.entity(descendants)
90+
.insert(MeshMaterial3d(asset_materials.add(new_material)));
91+
}
92+
}
93+
}

examples/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ Example | Description
150150
[Decal](../examples/3d/decal.rs) | Decal rendering
151151
[Deferred Rendering](../examples/3d/deferred_rendering.rs) | Renders meshes with both forward and deferred pipelines
152152
[Depth of field](../examples/3d/depth_of_field.rs) | Demonstrates depth of field
153+
[Edit Gltf Material](../examples/3d/edit_material_on_gltf.rs) | Showcases changing materials of a Gltf after Scene spawn
153154
[Fog](../examples/3d/fog.rs) | A scene showcasing the distance fog effect
154155
[Fog volumes](../examples/3d/fog_volumes.rs) | Demonstrates fog volumes
155156
[Generate Custom Mesh](../examples/3d/generate_custom_mesh.rs) | Simple showcase of how to generate a custom mesh with a custom texture

0 commit comments

Comments
 (0)