Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/ui/ui_material.rs
6595 views
1
//! Demonstrates the use of [`UiMaterials`](UiMaterial) and how to change material values
2
3
use bevy::{
4
color::palettes::css::DARK_BLUE, prelude::*, reflect::TypePath, render::render_resource::*,
5
shader::ShaderRef,
6
};
7
8
/// This example uses a shader source file from the assets subdirectory
9
const SHADER_ASSET_PATH: &str = "shaders/custom_ui_material.wgsl";
10
11
fn main() {
12
App::new()
13
.add_plugins(DefaultPlugins)
14
.add_plugins(UiMaterialPlugin::<CustomUiMaterial>::default())
15
.add_systems(Startup, setup)
16
.add_systems(Update, animate)
17
.run();
18
}
19
20
fn setup(
21
mut commands: Commands,
22
mut ui_materials: ResMut<Assets<CustomUiMaterial>>,
23
asset_server: Res<AssetServer>,
24
) {
25
// Camera so we can see UI
26
commands.spawn(Camera2d);
27
28
commands
29
.spawn(Node {
30
width: percent(100),
31
height: percent(100),
32
align_items: AlignItems::Center,
33
justify_content: JustifyContent::Center,
34
..default()
35
})
36
.with_children(|parent| {
37
let banner_scale_factor = 0.5;
38
parent.spawn((
39
Node {
40
position_type: PositionType::Absolute,
41
width: px(905.0 * banner_scale_factor),
42
height: px(363.0 * banner_scale_factor),
43
border: UiRect::all(px(20)),
44
..default()
45
},
46
MaterialNode(ui_materials.add(CustomUiMaterial {
47
color: LinearRgba::WHITE.to_f32_array().into(),
48
slider: Vec4::splat(0.5),
49
color_texture: asset_server.load("branding/banner.png"),
50
border_color: LinearRgba::WHITE.to_f32_array().into(),
51
})),
52
BorderRadius::all(px(20)),
53
// UI material nodes can have outlines and shadows like any other UI node
54
Outline {
55
width: px(2),
56
offset: px(100),
57
color: DARK_BLUE.into(),
58
},
59
));
60
});
61
}
62
63
#[derive(AsBindGroup, Asset, TypePath, Debug, Clone)]
64
struct CustomUiMaterial {
65
/// Color multiplied with the image
66
#[uniform(0)]
67
color: Vec4,
68
/// Represents how much of the image is visible
69
/// Goes from 0 to 1
70
/// A `Vec4` is used here because Bevy with webgl2 requires that uniforms are 16-byte aligned but only the first component is read.
71
#[uniform(1)]
72
slider: Vec4,
73
/// Image used to represent the slider
74
#[texture(2)]
75
#[sampler(3)]
76
color_texture: Handle<Image>,
77
/// Color of the image's border
78
#[uniform(4)]
79
border_color: Vec4,
80
}
81
82
impl UiMaterial for CustomUiMaterial {
83
fn fragment_shader() -> ShaderRef {
84
SHADER_ASSET_PATH.into()
85
}
86
}
87
88
// Fills the slider slowly over 2 seconds and resets it
89
// Also updates the color of the image to a rainbow color
90
fn animate(
91
mut materials: ResMut<Assets<CustomUiMaterial>>,
92
q: Query<&MaterialNode<CustomUiMaterial>>,
93
time: Res<Time>,
94
) {
95
let duration = 2.0;
96
for handle in &q {
97
if let Some(material) = materials.get_mut(handle) {
98
// rainbow color effect
99
let new_color = Color::hsl((time.elapsed_secs() * 60.0) % 360.0, 1., 0.5);
100
let border_color = Color::hsl((time.elapsed_secs() * 60.0) % 360.0, 0.75, 0.75);
101
material.color = new_color.to_linear().to_vec4();
102
material.slider.x =
103
((time.elapsed_secs() % (duration * 2.0)) - duration).abs() / duration;
104
material.border_color = border_color.to_linear().to_vec4();
105
}
106
}
107
}
108
109