1use bevy::{
4 camera_controller::free_camera::{FreeCamera, FreeCameraPlugin},
5 color::palettes::css::*,
6 prelude::*,
7};
8use std::f32::consts::PI;
9
10fn main() {
11 App::new()
12 .add_plugins((DefaultPlugins, FreeCameraPlugin))
13 .init_gizmo_group::<MyRoundGizmos>()
14 .add_systems(Startup, setup)
15 .add_systems(Update, (draw_example_collection, update_config))
16 .run();
17}
18
19#[derive(Default, Reflect, GizmoConfigGroup)]
21struct MyRoundGizmos;
22
23fn setup(
24 mut commands: Commands,
25 mut gizmo_assets: ResMut<Assets<GizmoAsset>>,
26 mut meshes: ResMut<Assets<Mesh>>,
27 mut materials: ResMut<Assets<StandardMaterial>>,
28) {
29 let mut gizmo = GizmoAsset::new();
30
31 gizmo
37 .sphere(Isometry3d::IDENTITY, 0.5, CRIMSON)
38 .resolution(30_000 / 3);
39
40 commands.spawn((
41 Gizmo {
42 handle: gizmo_assets.add(gizmo),
43 line_config: GizmoLineConfig {
44 width: 5.,
45 ..default()
46 },
47 ..default()
48 },
49 Transform::from_xyz(4., 1., 0.),
50 ));
51
52 commands.spawn((
53 Camera3d::default(),
54 Transform::from_xyz(0., 1.5, 6.).looking_at(Vec3::ZERO, Vec3::Y),
55 FreeCamera::default(),
56 ));
57 commands.spawn((
59 Mesh3d(meshes.add(Plane3d::default().mesh().size(5.0, 5.0))),
60 MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))),
61 ));
62 commands.spawn((
64 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
65 MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))),
66 Transform::from_xyz(0.0, 0.5, 0.0),
67 ));
68 commands.spawn((
70 PointLight {
71 shadow_maps_enabled: true,
72 ..default()
73 },
74 Transform::from_xyz(4.0, 8.0, 4.0),
75 ));
76
77 commands.spawn((
79 Text::new(
80 "Press 'T' to toggle drawing gizmos on top of everything else in the scene\n\
81 Press 'P' to toggle perspective for line gizmos\n\
82 Hold 'Left' or 'Right' to change the line width of straight gizmos\n\
83 Hold 'Up' or 'Down' to change the line width of round gizmos\n\
84 Press '1' or '2' to toggle the visibility of straight gizmos or round gizmos\n\
85 Press 'B' to show all AABB boxes\n\
86 Press 'U' or 'I' to cycle through line styles for straight or round gizmos\n\
87 Press 'J' or 'K' to cycle through line joins for straight or round gizmos\n\
88 Press 'Spacebar' to toggle pause",
89 ),
90 Node {
91 position_type: PositionType::Absolute,
92 top: px(12),
93 left: px(12),
94 ..default()
95 },
96 ));
97}
98
99fn draw_example_collection(
100 mut gizmos: Gizmos,
101 mut my_gizmos: Gizmos<MyRoundGizmos>,
102 time: Res<Time>,
103) {
104 gizmos.grid(
105 Quat::from_rotation_x(PI / 2.),
106 UVec2::splat(20),
107 Vec2::new(2., 2.),
108 LinearRgba::gray(0.65),
110 );
111 gizmos.grid(
112 Isometry3d::new(Vec3::splat(10.0), Quat::from_rotation_x(PI / 3. * 2.)),
113 UVec2::splat(20),
114 Vec2::new(2., 2.),
115 PURPLE,
116 );
117 gizmos.sphere(Vec3::splat(10.0), 1.0, PURPLE);
118
119 gizmos
120 .primitive_3d(
121 &Plane3d {
122 normal: Dir3::Y,
123 half_size: Vec2::splat(1.0),
124 },
125 Isometry3d::new(
126 Vec3::splat(4.0) + Vec2::from(ops::sin_cos(time.elapsed_secs())).extend(0.0),
127 Quat::from_rotation_x(PI / 2. + time.elapsed_secs()),
128 ),
129 GREEN,
130 )
131 .cell_count(UVec2::new(5, 10))
132 .spacing(Vec2::new(0.2, 0.1));
133
134 gizmos.cube(
135 Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)),
136 BLACK,
137 );
138 gizmos.rect(
139 Isometry3d::new(
140 Vec3::new(ops::cos(time.elapsed_secs()) * 2.5, 1., 0.),
141 Quat::from_rotation_y(PI / 2.),
142 ),
143 Vec2::splat(2.),
144 LIME,
145 );
146
147 gizmos.cross(Vec3::new(-1., 1., 1.), 0.5, FUCHSIA);
148
149 let domain = Interval::EVERYWHERE;
150 let curve = FunctionCurve::new(domain, |t| {
151 (Vec2::from(ops::sin_cos(t * 10.0))).extend(t - 6.0)
152 });
153 let resolution = ((ops::sin(time.elapsed_secs()) + 1.0) * 100.0) as usize;
154 let times_and_colors = (0..=resolution)
155 .map(|n| n as f32 / resolution as f32)
156 .map(|t| t * 5.0)
157 .map(|t| (t, TEAL.mix(&HOT_PINK, t / 5.0)));
158 gizmos.curve_gradient_3d(curve, times_and_colors);
159
160 my_gizmos.sphere(Vec3::new(1., 0.5, 0.), 0.5, RED);
161
162 my_gizmos
163 .rounded_cuboid(Vec3::new(-2.0, 0.75, -0.75), Vec3::splat(0.9), TURQUOISE)
164 .edge_radius(0.1)
165 .arc_resolution(4);
166
167 for y in [0., 0.5, 1.] {
168 gizmos.ray(
169 Vec3::new(1., y, 0.),
170 Vec3::new(-3., ops::sin(time.elapsed_secs() * 3.), 0.),
171 BLUE,
172 );
173 }
174
175 my_gizmos
176 .arc_3d(
177 180.0_f32.to_radians(),
178 0.2,
179 Isometry3d::new(
180 Vec3::ONE,
181 Quat::from_rotation_arc(Vec3::Y, Vec3::ONE.normalize()),
182 ),
183 ORANGE,
184 )
185 .resolution(10);
186
187 my_gizmos.circle(Quat::from_rotation_arc(Vec3::Z, Vec3::Y), 3., BLACK);
189
190 my_gizmos
192 .circle(Quat::from_rotation_arc(Vec3::Z, Vec3::Y), 3.1, NAVY)
193 .resolution(64);
194 my_gizmos
195 .sphere(Isometry3d::IDENTITY, 3.2, BLACK)
196 .resolution(64);
197
198 gizmos.arrow(Vec3::ZERO, Vec3::splat(1.5), YELLOW);
199
200 gizmos
202 .arrow(Vec3::new(2., 0., 2.), Vec3::new(2., 2., 2.), ORANGE_RED)
203 .with_double_end()
204 .with_tip_length(0.5);
205}
206
207fn update_config(
208 mut config_store: ResMut<GizmoConfigStore>,
209 keyboard: Res<ButtonInput<KeyCode>>,
210 real_time: Res<Time<Real>>,
211 mut virtual_time: ResMut<Time<Virtual>>,
212) {
213 if keyboard.just_pressed(KeyCode::KeyT) {
214 for (_, config, _) in config_store.iter_mut() {
215 config.depth_bias = if config.depth_bias == 0. { -1. } else { 0. };
216 }
217 }
218 if keyboard.just_pressed(KeyCode::KeyP) {
219 for (_, config, _) in config_store.iter_mut() {
220 config.line.perspective ^= true;
222 config.line.width *= if config.line.perspective { 5. } else { 1. / 5. };
224 }
225 }
226
227 let (config, _) = config_store.config_mut::<DefaultGizmoConfigGroup>();
228 if keyboard.pressed(KeyCode::ArrowRight) {
229 config.line.width += 5. * real_time.delta_secs();
230 config.line.width = config.line.width.clamp(0., 50.);
231 }
232 if keyboard.pressed(KeyCode::ArrowLeft) {
233 config.line.width -= 5. * real_time.delta_secs();
234 config.line.width = config.line.width.clamp(0., 50.);
235 }
236 if keyboard.just_pressed(KeyCode::Digit1) {
237 config.enabled ^= true;
238 }
239 if keyboard.just_pressed(KeyCode::KeyU) {
240 config.line.style = match config.line.style {
241 GizmoLineStyle::Solid => GizmoLineStyle::Dotted,
242 GizmoLineStyle::Dotted => GizmoLineStyle::Dashed {
243 gap_scale: 3.0,
244 line_scale: 5.0,
245 },
246 _ => GizmoLineStyle::Solid,
247 };
248 }
249 if keyboard.just_pressed(KeyCode::KeyJ) {
250 config.line.joints = match config.line.joints {
251 GizmoLineJoint::Bevel => GizmoLineJoint::Miter,
252 GizmoLineJoint::Miter => GizmoLineJoint::Round(4),
253 GizmoLineJoint::Round(_) => GizmoLineJoint::None,
254 GizmoLineJoint::None => GizmoLineJoint::Bevel,
255 };
256 }
257
258 let (my_config, _) = config_store.config_mut::<MyRoundGizmos>();
259 if keyboard.pressed(KeyCode::ArrowUp) {
260 my_config.line.width += 5. * real_time.delta_secs();
261 my_config.line.width = my_config.line.width.clamp(0., 50.);
262 }
263 if keyboard.pressed(KeyCode::ArrowDown) {
264 my_config.line.width -= 5. * real_time.delta_secs();
265 my_config.line.width = my_config.line.width.clamp(0., 50.);
266 }
267 if keyboard.just_pressed(KeyCode::Digit2) {
268 my_config.enabled ^= true;
269 }
270 if keyboard.just_pressed(KeyCode::KeyI) {
271 my_config.line.style = match my_config.line.style {
272 GizmoLineStyle::Solid => GizmoLineStyle::Dotted,
273 GizmoLineStyle::Dotted => GizmoLineStyle::Dashed {
274 gap_scale: 3.0,
275 line_scale: 5.0,
276 },
277 _ => GizmoLineStyle::Solid,
278 };
279 }
280 if keyboard.just_pressed(KeyCode::KeyK) {
281 my_config.line.joints = match my_config.line.joints {
282 GizmoLineJoint::Bevel => GizmoLineJoint::Miter,
283 GizmoLineJoint::Miter => GizmoLineJoint::Round(4),
284 GizmoLineJoint::Round(_) => GizmoLineJoint::None,
285 GizmoLineJoint::None => GizmoLineJoint::Bevel,
286 };
287 }
288
289 if keyboard.just_pressed(KeyCode::KeyB) {
290 config_store.config_mut::<AabbGizmoConfigGroup>().1.draw_all ^= true;
293 }
294 if keyboard.just_pressed(KeyCode::Space) {
295 virtual_time.toggle();
296 }
297}