Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/gizmos/3d_gizmos.rs
9423 views
1
//! This example demonstrates Bevy's immediate mode drawing API intended for visual debugging.
2
3
use bevy::{
4
camera_controller::free_camera::{FreeCamera, FreeCameraPlugin},
5
color::palettes::css::*,
6
prelude::*,
7
};
8
use std::f32::consts::PI;
9
10
fn 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
// We can create our own gizmo config group!
20
#[derive(Default, Reflect, GizmoConfigGroup)]
21
struct MyRoundGizmos;
22
23
fn 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
// When drawing a lot of static lines a Gizmo component can have
32
// far better performance than the Gizmos system parameter,
33
// but the system parameter will perform better for smaller lines that update often.
34
35
// A sphere made out of 30_000 lines!
36
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
// plane
58
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
// cube
63
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
// light
69
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
// example instructions
78
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
99
fn 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
// Light gray
109
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
// Circles have 32 line-segments by default.
188
my_gizmos.circle(Quat::from_rotation_arc(Vec3::Z, Vec3::Y), 3., BLACK);
189
190
// You may want to increase this for larger circles or spheres.
191
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
// You can create more complex arrows using the arrow builder.
201
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
207
fn 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
// Toggle line perspective
221
config.line.perspective ^= true;
222
// Increase the line width when line perspective is on
223
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
// AABB gizmos are normally only drawn on entities with a ShowAabbGizmo component
291
// We can change this behavior in the configuration of AabbGizmoGroup
292
config_store.config_mut::<AabbGizmoConfigGroup>().1.draw_all ^= true;
293
}
294
if keyboard.just_pressed(KeyCode::Space) {
295
virtual_time.toggle();
296
}
297
}
298
299