docs/bevy/examples/gizmos/light_gizmos.rs 6.2 K · 188 lines · raw · history

1 //! This example demonstrates how to visualize lights properties through the gizmo API.
2
3 use std::f32::consts::{FRAC_PI_2, PI};
4
5 use bevy::{
6 color::palettes::css::{DARK_CYAN, GOLD, GRAY, ORANGE, PURPLE},
7 prelude::*,
8 };
9
10 fn main() {
11 App::new()
12 .add_plugins(DefaultPlugins)
13 .add_systems(Startup, setup)
14 .add_systems(Update, rotate_camera)
15 .add_systems(Update, update_config)
16 .run();
17 }
18
19 #[derive(Component)]
20 struct GizmoColorText;
21
22 fn gizmo_color_text(config: &LightGizmoConfigGroup) -> String {
23 match config.color {
24 LightGizmoColor::Manual(color) => format!("Manual {}", Srgba::from(color).to_hex()),
25 LightGizmoColor::Varied => "Random from entity".to_owned(),
26 LightGizmoColor::MatchLightColor => "Match light color".to_owned(),
27 LightGizmoColor::ByLightType => {
28 format!(
29 "Point {}, Spot {}, Directional {}, Rect {}",
30 Srgba::from(config.point_light_color).to_hex(),
31 Srgba::from(config.spot_light_color).to_hex(),
32 Srgba::from(config.directional_light_color).to_hex(),
33 Srgba::from(config.rect_light_color).to_hex()
34 )
35 }
36 }
37 }
38
39 fn setup(
40 mut commands: Commands,
41 mut meshes: ResMut<Assets<Mesh>>,
42 mut materials: ResMut<Assets<StandardMaterial>>,
43 mut config_store: ResMut<GizmoConfigStore>,
44 ) {
45 // Circular base.
46 commands.spawn((
47 Mesh3d(meshes.add(Circle::new(4.0))),
48 MeshMaterial3d(materials.add(Color::WHITE)),
49 Transform::from_rotation(Quat::from_rotation_x(-FRAC_PI_2)),
50 ));
51
52 // Cubes.
53 {
54 let mesh = meshes.add(Cuboid::new(1.0, 1.0, 1.0));
55 let material = materials.add(Color::srgb_u8(124, 144, 255));
56 for x in [-2.0, 0.0, 2.0] {
57 commands.spawn((
58 Mesh3d(mesh.clone()),
59 MeshMaterial3d(material.clone()),
60 Transform::from_xyz(x, 0.5, 0.0),
61 ));
62 }
63 }
64
65 // Lights.
66 {
67 commands.spawn((
68 PointLight {
69 shadow_maps_enabled: true,
70 range: 2.0,
71 color: DARK_CYAN.into(),
72 ..default()
73 },
74 Transform::from_xyz(0.0, 1.5, 0.0),
75 ));
76 commands.spawn((
77 SpotLight {
78 shadow_maps_enabled: true,
79 range: 3.5,
80 color: PURPLE.into(),
81 outer_angle: PI / 4.0,
82 inner_angle: PI / 4.0 * 0.8,
83 ..default()
84 },
85 Transform::from_xyz(4.0, 2.0, 0.0).looking_at(Vec3::X * 1.5, Vec3::Y),
86 ));
87 commands.spawn((
88 DirectionalLight {
89 color: GOLD.into(),
90 illuminance: DirectionalLight::default().illuminance * 0.05,
91 shadow_maps_enabled: true,
92 ..default()
93 },
94 Transform::from_xyz(-4.0, 2.0, 0.0).looking_at(Vec3::NEG_X * 1.5, Vec3::Y),
95 ));
96 commands.spawn((
97 RectLight {
98 color: ORANGE.into(),
99 intensity: 200_000.0,
100 width: 1.5,
101 height: 0.8,
102 range: 20.0,
103 },
104 Transform::from_xyz(0.0, 3.0, -3.0).looking_at(Vec3::ZERO, Vec3::Y),
105 ));
106 }
107
108 // Camera.
109 commands.spawn((
110 Camera3d::default(),
111 Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
112 ));
113
114 // Example instructions and gizmo config.
115 {
116 commands.spawn((
117 Text::new(
118 "Press 'D' to toggle drawing gizmos on top of everything else in the scene\n\
119 Hold 'Left' or 'Right' to change the line width of the gizmos\n\
120 Press 'A' to toggle drawing of the light gizmos\n\
121 Press 'C' to cycle between the light gizmos coloring modes",
122 ),
123 Node {
124 position_type: PositionType::Absolute,
125 top: px(12),
126 left: px(12),
127 ..default()
128 },
129 ));
130
131 let (_, light_config) = config_store.config_mut::<LightGizmoConfigGroup>();
132 light_config.draw_all = true;
133 light_config.color = LightGizmoColor::MatchLightColor;
134
135 commands
136 .spawn((
137 Text::new("Gizmo color mode: "),
138 GizmoColorText,
139 Node {
140 position_type: PositionType::Absolute,
141 bottom: px(12),
142 left: px(12),
143 ..default()
144 },
145 ))
146 .with_child(TextSpan(gizmo_color_text(light_config)));
147 }
148 }
149
150 fn rotate_camera(mut transform: Single<&mut Transform, With<Camera>>, time: Res<Time>) {
151 transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_secs() / 2.));
152 }
153
154 fn update_config(
155 mut config_store: ResMut<GizmoConfigStore>,
156 keyboard: Res<ButtonInput<KeyCode>>,
157 time: Res<Time>,
158 color_text_query: Single<Entity, With<GizmoColorText>>,
159 mut writer: TextUiWriter,
160 ) {
161 if keyboard.just_pressed(KeyCode::KeyD) {
162 for (_, config, _) in config_store.iter_mut() {
163 config.depth_bias = if config.depth_bias == 0. { -1. } else { 0. };
164 }
165 }
166
167 let (config, light_config) = config_store.config_mut::<LightGizmoConfigGroup>();
168 if keyboard.pressed(KeyCode::ArrowRight) {
169 config.line.width += 5. * time.delta_secs();
170 config.line.width = config.line.width.clamp(0., 50.);
171 }
172 if keyboard.pressed(KeyCode::ArrowLeft) {
173 config.line.width -= 5. * time.delta_secs();
174 config.line.width = config.line.width.clamp(0., 50.);
175 }
176 if keyboard.just_pressed(KeyCode::KeyA) {
177 config.enabled ^= true;
178 }
179 if keyboard.just_pressed(KeyCode::KeyC) {
180 light_config.color = match light_config.color {
181 LightGizmoColor::Manual(_) => LightGizmoColor::Varied,
182 LightGizmoColor::Varied => LightGizmoColor::MatchLightColor,
183 LightGizmoColor::MatchLightColor => LightGizmoColor::ByLightType,
184 LightGizmoColor::ByLightType => LightGizmoColor::Manual(GRAY.into()),
185 };
186 *writer.text(*color_text_query, 1) = gizmo_color_text(light_config);
187 }
188 }