Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/gizmos/3d_gizmos.rs
6592 views
1
//! This example demonstrates Bevy's immediate mode drawing API intended for visual debugging.
2
3
#[path = "../helpers/camera_controller.rs"]
4
mod camera_controller;
5
6
use bevy::{color::palettes::css::*, prelude::*};
7
use camera_controller::{CameraController, CameraControllerPlugin};
8
use std::f32::consts::PI;
9
10
fn main() {
11
App::new()
12
.add_plugins((DefaultPlugins, CameraControllerPlugin))
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
CameraController::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
shadows_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",
88
),
89
Node {
90
position_type: PositionType::Absolute,
91
top: px(12),
92
left: px(12),
93
..default()
94
},
95
));
96
}
97
98
fn draw_example_collection(
99
mut gizmos: Gizmos,
100
mut my_gizmos: Gizmos<MyRoundGizmos>,
101
time: Res<Time>,
102
) {
103
gizmos.grid(
104
Quat::from_rotation_x(PI / 2.),
105
UVec2::splat(20),
106
Vec2::new(2., 2.),
107
// Light gray
108
LinearRgba::gray(0.65),
109
);
110
gizmos.grid(
111
Isometry3d::new(Vec3::splat(10.0), Quat::from_rotation_x(PI / 3. * 2.)),
112
UVec2::splat(20),
113
Vec2::new(2., 2.),
114
PURPLE,
115
);
116
gizmos.sphere(Vec3::splat(10.0), 1.0, PURPLE);
117
118
gizmos
119
.primitive_3d(
120
&Plane3d {
121
normal: Dir3::Y,
122
half_size: Vec2::splat(1.0),
123
},
124
Isometry3d::new(
125
Vec3::splat(4.0) + Vec2::from(ops::sin_cos(time.elapsed_secs())).extend(0.0),
126
Quat::from_rotation_x(PI / 2. + time.elapsed_secs()),
127
),
128
GREEN,
129
)
130
.cell_count(UVec2::new(5, 10))
131
.spacing(Vec2::new(0.2, 0.1));
132
133
gizmos.cuboid(
134
Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)),
135
BLACK,
136
);
137
gizmos.rect(
138
Isometry3d::new(
139
Vec3::new(ops::cos(time.elapsed_secs()) * 2.5, 1., 0.),
140
Quat::from_rotation_y(PI / 2.),
141
),
142
Vec2::splat(2.),
143
LIME,
144
);
145
146
gizmos.cross(Vec3::new(-1., 1., 1.), 0.5, FUCHSIA);
147
148
let domain = Interval::EVERYWHERE;
149
let curve = FunctionCurve::new(domain, |t| {
150
(Vec2::from(ops::sin_cos(t * 10.0))).extend(t - 6.0)
151
});
152
let resolution = ((ops::sin(time.elapsed_secs()) + 1.0) * 100.0) as usize;
153
let times_and_colors = (0..=resolution)
154
.map(|n| n as f32 / resolution as f32)
155
.map(|t| t * 5.0)
156
.map(|t| (t, TEAL.mix(&HOT_PINK, t / 5.0)));
157
gizmos.curve_gradient_3d(curve, times_and_colors);
158
159
my_gizmos.sphere(Vec3::new(1., 0.5, 0.), 0.5, RED);
160
161
my_gizmos
162
.rounded_cuboid(Vec3::new(-2.0, 0.75, -0.75), Vec3::splat(0.9), TURQUOISE)
163
.edge_radius(0.1)
164
.arc_resolution(4);
165
166
for y in [0., 0.5, 1.] {
167
gizmos.ray(
168
Vec3::new(1., y, 0.),
169
Vec3::new(-3., ops::sin(time.elapsed_secs() * 3.), 0.),
170
BLUE,
171
);
172
}
173
174
my_gizmos
175
.arc_3d(
176
180.0_f32.to_radians(),
177
0.2,
178
Isometry3d::new(
179
Vec3::ONE,
180
Quat::from_rotation_arc(Vec3::Y, Vec3::ONE.normalize()),
181
),
182
ORANGE,
183
)
184
.resolution(10);
185
186
// Circles have 32 line-segments by default.
187
my_gizmos.circle(Quat::from_rotation_arc(Vec3::Z, Vec3::Y), 3., BLACK);
188
189
// You may want to increase this for larger circles or spheres.
190
my_gizmos
191
.circle(Quat::from_rotation_arc(Vec3::Z, Vec3::Y), 3.1, NAVY)
192
.resolution(64);
193
my_gizmos
194
.sphere(Isometry3d::IDENTITY, 3.2, BLACK)
195
.resolution(64);
196
197
gizmos.arrow(Vec3::ZERO, Vec3::splat(1.5), YELLOW);
198
199
// You can create more complex arrows using the arrow builder.
200
gizmos
201
.arrow(Vec3::new(2., 0., 2.), Vec3::new(2., 2., 2.), ORANGE_RED)
202
.with_double_end()
203
.with_tip_length(0.5);
204
}
205
206
fn update_config(
207
mut config_store: ResMut<GizmoConfigStore>,
208
keyboard: Res<ButtonInput<KeyCode>>,
209
time: Res<Time>,
210
) {
211
if keyboard.just_pressed(KeyCode::KeyT) {
212
for (_, config, _) in config_store.iter_mut() {
213
config.depth_bias = if config.depth_bias == 0. { -1. } else { 0. };
214
}
215
}
216
if keyboard.just_pressed(KeyCode::KeyP) {
217
for (_, config, _) in config_store.iter_mut() {
218
// Toggle line perspective
219
config.line.perspective ^= true;
220
// Increase the line width when line perspective is on
221
config.line.width *= if config.line.perspective { 5. } else { 1. / 5. };
222
}
223
}
224
225
let (config, _) = config_store.config_mut::<DefaultGizmoConfigGroup>();
226
if keyboard.pressed(KeyCode::ArrowRight) {
227
config.line.width += 5. * time.delta_secs();
228
config.line.width = config.line.width.clamp(0., 50.);
229
}
230
if keyboard.pressed(KeyCode::ArrowLeft) {
231
config.line.width -= 5. * time.delta_secs();
232
config.line.width = config.line.width.clamp(0., 50.);
233
}
234
if keyboard.just_pressed(KeyCode::Digit1) {
235
config.enabled ^= true;
236
}
237
if keyboard.just_pressed(KeyCode::KeyU) {
238
config.line.style = match config.line.style {
239
GizmoLineStyle::Solid => GizmoLineStyle::Dotted,
240
GizmoLineStyle::Dotted => GizmoLineStyle::Dashed {
241
gap_scale: 3.0,
242
line_scale: 5.0,
243
},
244
_ => GizmoLineStyle::Solid,
245
};
246
}
247
if keyboard.just_pressed(KeyCode::KeyJ) {
248
config.line.joints = match config.line.joints {
249
GizmoLineJoint::Bevel => GizmoLineJoint::Miter,
250
GizmoLineJoint::Miter => GizmoLineJoint::Round(4),
251
GizmoLineJoint::Round(_) => GizmoLineJoint::None,
252
GizmoLineJoint::None => GizmoLineJoint::Bevel,
253
};
254
}
255
256
let (my_config, _) = config_store.config_mut::<MyRoundGizmos>();
257
if keyboard.pressed(KeyCode::ArrowUp) {
258
my_config.line.width += 5. * time.delta_secs();
259
my_config.line.width = my_config.line.width.clamp(0., 50.);
260
}
261
if keyboard.pressed(KeyCode::ArrowDown) {
262
my_config.line.width -= 5. * time.delta_secs();
263
my_config.line.width = my_config.line.width.clamp(0., 50.);
264
}
265
if keyboard.just_pressed(KeyCode::Digit2) {
266
my_config.enabled ^= true;
267
}
268
if keyboard.just_pressed(KeyCode::KeyI) {
269
my_config.line.style = match my_config.line.style {
270
GizmoLineStyle::Solid => GizmoLineStyle::Dotted,
271
GizmoLineStyle::Dotted => GizmoLineStyle::Dashed {
272
gap_scale: 3.0,
273
line_scale: 5.0,
274
},
275
_ => GizmoLineStyle::Solid,
276
};
277
}
278
if keyboard.just_pressed(KeyCode::KeyK) {
279
my_config.line.joints = match my_config.line.joints {
280
GizmoLineJoint::Bevel => GizmoLineJoint::Miter,
281
GizmoLineJoint::Miter => GizmoLineJoint::Round(4),
282
GizmoLineJoint::Round(_) => GizmoLineJoint::None,
283
GizmoLineJoint::None => GizmoLineJoint::Bevel,
284
};
285
}
286
287
if keyboard.just_pressed(KeyCode::KeyB) {
288
// AABB gizmos are normally only drawn on entities with a ShowAabbGizmo component
289
// We can change this behavior in the configuration of AabbGizmoGroup
290
config_store.config_mut::<AabbGizmoConfigGroup>().1.draw_all ^= true;
291
}
292
}
293
294