fullscreen_material/
fullscreen_material.rs1use bevy::{
9 core_pipeline::fullscreen_material::{FullscreenMaterial, FullscreenMaterialPlugin},
10 prelude::*,
11 render::{extract_component::ExtractComponent, render_resource::ShaderType},
12 shader::ShaderRef,
13};
14
15fn main() {
16 App::new()
17 .add_plugins((
18 DefaultPlugins,
19 FullscreenMaterialPlugin::<FullscreenEffect>::default(),
20 ))
21 .add_systems(Startup, setup)
22 .add_systems(Update, (update_intensity, toggle_effect))
23 .run();
24}
25
26fn setup(
27 mut commands: Commands,
28 mut meshes: ResMut<Assets<Mesh>>,
29 mut materials: ResMut<Assets<StandardMaterial>>,
30) {
31 commands.spawn((
32 Camera3d::default(),
33 Transform::from_translation(Vec3::new(0.0, 0.0, 5.0)).looking_at(Vec3::default(), Vec3::Y),
34 FullscreenEffect::new(0.0),
35 ));
36
37 commands.spawn((
38 Mesh3d(meshes.add(Cuboid::default())),
39 MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))),
40 Transform::default(),
41 ));
42
43 commands.spawn(DirectionalLight {
44 illuminance: 1_000.,
45 ..default()
46 });
47
48 commands.spawn((
49 Text::new("(T) FullscreenEffect: On"),
50 Node {
51 position_type: PositionType::Absolute,
52 top: px(12),
53 left: px(12),
54 ..default()
55 },
56 ));
57}
58
59fn update_intensity(
60 mut effects: Query<&mut FullscreenEffect>,
61 time: Res<Time>,
62 mut last_intensity: Local<f32>,
63 mut phase_offset: Local<f32>,
64) {
65 let t = time.elapsed_secs();
66 let freq = FullscreenEffect::FREQUENCY;
67 let max = FullscreenEffect::MAX_INTENSITY;
68
69 for mut effect in &mut effects {
70 if effect.intensity != *last_intensity {
74 let target_sine = (effect.intensity / max) * 2.0 - 1.0;
76 *phase_offset = ops::asin(target_sine) - t * freq;
78 }
79
80 let phase = t * freq + *phase_offset;
82 let mut intensity = ops::sin(phase);
84
85 intensity = (intensity + 1.0) / 2.0;
87 *last_intensity = intensity * max;
88
89 effect.intensity = *last_intensity;
90 }
91}
92
93fn toggle_effect(
94 mut text: Single<&mut Text>,
95 keys: Res<ButtonInput<KeyCode>>,
96 camera: Single<(Entity, Option<&FullscreenEffect>), With<Camera3d>>,
97 mut commands: Commands,
98) {
99 if keys.just_pressed(KeyCode::KeyT) {
100 let (entity, effect) = *camera;
101
102 if effect.is_some() {
103 commands.entity(entity).remove::<FullscreenEffect>();
104 text.clear();
105 text.push_str("(T) FullscreenEffect: Off");
106 } else {
107 commands.entity(entity).insert(FullscreenEffect::new(0.0));
108 text.clear();
109 text.push_str("(T) FullscreenEffect: On");
110 }
111 }
112}
113
114#[derive(Component, ExtractComponent, Clone, Copy, ShaderType, Default)]
115struct FullscreenEffect {
116 intensity: f32,
117 #[cfg(feature = "webgl2")]
120 _webgl2_padding: Vec3,
121}
122
123impl FullscreenEffect {
124 const FREQUENCY: f32 = 2.0;
125 const MAX_INTENSITY: f32 = 0.015;
126
127 fn new(intensity: f32) -> Self {
128 Self {
129 intensity,
130 ..Default::default()
131 }
132 }
133}
134
135impl FullscreenMaterial for FullscreenEffect {
136 fn fragment_shader() -> ShaderRef {
137 "shaders/fullscreen_effect.wgsl".into()
138 }
139
140 }