Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/testbed/3d.rs
6592 views
1
//! 3d testbed
2
//!
3
//! You can switch scene by pressing the spacebar
4
5
mod helpers;
6
7
use bevy::prelude::*;
8
use helpers::Next;
9
10
fn main() {
11
let mut app = App::new();
12
app.add_plugins((DefaultPlugins,))
13
.init_state::<Scene>()
14
.add_systems(OnEnter(Scene::Light), light::setup)
15
.add_systems(OnEnter(Scene::Bloom), bloom::setup)
16
.add_systems(OnEnter(Scene::Gltf), gltf::setup)
17
.add_systems(OnEnter(Scene::Animation), animation::setup)
18
.add_systems(OnEnter(Scene::Gizmos), gizmos::setup)
19
.add_systems(
20
OnEnter(Scene::GltfCoordinateConversion),
21
gltf_coordinate_conversion::setup,
22
)
23
.add_systems(Update, switch_scene)
24
.add_systems(Update, gizmos::draw_gizmos.run_if(in_state(Scene::Gizmos)))
25
.add_systems(
26
Update,
27
gltf_coordinate_conversion::draw_gizmos
28
.run_if(in_state(Scene::GltfCoordinateConversion)),
29
);
30
31
#[cfg(feature = "bevy_ci_testing")]
32
app.add_systems(Update, helpers::switch_scene_in_ci::<Scene>);
33
34
app.run();
35
}
36
37
#[derive(Debug, Clone, Eq, PartialEq, Hash, States, Default)]
38
enum Scene {
39
#[default]
40
Light,
41
Bloom,
42
Gltf,
43
Animation,
44
Gizmos,
45
GltfCoordinateConversion,
46
}
47
48
impl Next for Scene {
49
fn next(&self) -> Self {
50
match self {
51
Scene::Light => Scene::Bloom,
52
Scene::Bloom => Scene::Gltf,
53
Scene::Gltf => Scene::Animation,
54
Scene::Animation => Scene::Gizmos,
55
Scene::Gizmos => Scene::GltfCoordinateConversion,
56
Scene::GltfCoordinateConversion => Scene::Light,
57
}
58
}
59
}
60
61
fn switch_scene(
62
keyboard: Res<ButtonInput<KeyCode>>,
63
scene: Res<State<Scene>>,
64
mut next_scene: ResMut<NextState<Scene>>,
65
) {
66
if keyboard.just_pressed(KeyCode::Space) {
67
info!("Switching scene");
68
next_scene.set(scene.get().next());
69
}
70
}
71
72
mod light {
73
use std::f32::consts::PI;
74
75
use bevy::{
76
color::palettes::css::{DEEP_PINK, LIME, RED},
77
prelude::*,
78
};
79
80
const CURRENT_SCENE: super::Scene = super::Scene::Light;
81
82
pub fn setup(
83
mut commands: Commands,
84
mut meshes: ResMut<Assets<Mesh>>,
85
mut materials: ResMut<Assets<StandardMaterial>>,
86
) {
87
commands.spawn((
88
Mesh3d(meshes.add(Plane3d::default().mesh().size(10.0, 10.0))),
89
MeshMaterial3d(materials.add(StandardMaterial {
90
base_color: Color::WHITE,
91
perceptual_roughness: 1.0,
92
..default()
93
})),
94
DespawnOnExit(CURRENT_SCENE),
95
));
96
97
commands.spawn((
98
Mesh3d(meshes.add(Cuboid::default())),
99
MeshMaterial3d(materials.add(StandardMaterial {
100
base_color: DEEP_PINK.into(),
101
..default()
102
})),
103
Transform::from_xyz(0.0, 1.0, 0.0),
104
DespawnOnExit(CURRENT_SCENE),
105
));
106
107
commands.spawn((
108
PointLight {
109
intensity: 100_000.0,
110
color: RED.into(),
111
shadows_enabled: true,
112
..default()
113
},
114
Transform::from_xyz(1.0, 2.0, 0.0),
115
DespawnOnExit(CURRENT_SCENE),
116
));
117
118
commands.spawn((
119
SpotLight {
120
intensity: 100_000.0,
121
color: LIME.into(),
122
shadows_enabled: true,
123
inner_angle: 0.6,
124
outer_angle: 0.8,
125
..default()
126
},
127
Transform::from_xyz(-1.0, 2.0, 0.0).looking_at(Vec3::new(-1.0, 0.0, 0.0), Vec3::Z),
128
DespawnOnExit(CURRENT_SCENE),
129
));
130
131
commands.spawn((
132
DirectionalLight {
133
illuminance: light_consts::lux::OVERCAST_DAY,
134
shadows_enabled: true,
135
..default()
136
},
137
Transform {
138
translation: Vec3::new(0.0, 2.0, 0.0),
139
rotation: Quat::from_rotation_x(-PI / 4.),
140
..default()
141
},
142
DespawnOnExit(CURRENT_SCENE),
143
));
144
145
commands.spawn((
146
Camera3d::default(),
147
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
148
DespawnOnExit(CURRENT_SCENE),
149
));
150
}
151
}
152
153
mod bloom {
154
use bevy::{core_pipeline::tonemapping::Tonemapping, post_process::bloom::Bloom, prelude::*};
155
156
const CURRENT_SCENE: super::Scene = super::Scene::Bloom;
157
158
pub fn setup(
159
mut commands: Commands,
160
mut meshes: ResMut<Assets<Mesh>>,
161
mut materials: ResMut<Assets<StandardMaterial>>,
162
) {
163
commands.spawn((
164
Camera3d::default(),
165
Tonemapping::TonyMcMapface,
166
Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
167
Bloom::NATURAL,
168
DespawnOnExit(CURRENT_SCENE),
169
));
170
171
let material_emissive1 = materials.add(StandardMaterial {
172
emissive: LinearRgba::rgb(13.99, 5.32, 2.0),
173
..default()
174
});
175
let material_emissive2 = materials.add(StandardMaterial {
176
emissive: LinearRgba::rgb(2.0, 13.99, 5.32),
177
..default()
178
});
179
180
let mesh = meshes.add(Sphere::new(0.5).mesh().ico(5).unwrap());
181
182
for z in -2..3_i32 {
183
let material = match (z % 2).abs() {
184
0 => material_emissive1.clone(),
185
1 => material_emissive2.clone(),
186
_ => unreachable!(),
187
};
188
189
commands.spawn((
190
Mesh3d(mesh.clone()),
191
MeshMaterial3d(material),
192
Transform::from_xyz(z as f32 * 2.0, 0.0, 0.0),
193
DespawnOnExit(CURRENT_SCENE),
194
));
195
}
196
}
197
}
198
199
mod gltf {
200
use bevy::prelude::*;
201
202
const CURRENT_SCENE: super::Scene = super::Scene::Gltf;
203
204
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
205
commands.spawn((
206
Camera3d::default(),
207
Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
208
EnvironmentMapLight {
209
diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
210
specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
211
intensity: 250.0,
212
..default()
213
},
214
DespawnOnExit(CURRENT_SCENE),
215
));
216
217
commands.spawn((
218
DirectionalLight {
219
shadows_enabled: true,
220
..default()
221
},
222
DespawnOnExit(CURRENT_SCENE),
223
));
224
commands.spawn((
225
SceneRoot(asset_server.load(
226
GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"),
227
)),
228
DespawnOnExit(CURRENT_SCENE),
229
));
230
}
231
}
232
233
mod animation {
234
use std::{f32::consts::PI, time::Duration};
235
236
use bevy::{prelude::*, scene::SceneInstanceReady};
237
238
const CURRENT_SCENE: super::Scene = super::Scene::Animation;
239
const FOX_PATH: &str = "models/animated/Fox.glb";
240
241
#[derive(Resource)]
242
struct Animation {
243
animation: AnimationNodeIndex,
244
graph: Handle<AnimationGraph>,
245
}
246
247
pub fn setup(
248
mut commands: Commands,
249
asset_server: Res<AssetServer>,
250
mut graphs: ResMut<Assets<AnimationGraph>>,
251
) {
252
let (graph, node) = AnimationGraph::from_clip(
253
asset_server.load(GltfAssetLabel::Animation(2).from_asset(FOX_PATH)),
254
);
255
256
let graph_handle = graphs.add(graph);
257
commands.insert_resource(Animation {
258
animation: node,
259
graph: graph_handle,
260
});
261
262
commands.spawn((
263
Camera3d::default(),
264
Transform::from_xyz(100.0, 100.0, 150.0).looking_at(Vec3::new(0.0, 20.0, 0.0), Vec3::Y),
265
DespawnOnExit(CURRENT_SCENE),
266
));
267
268
commands.spawn((
269
Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)),
270
DirectionalLight {
271
shadows_enabled: true,
272
..default()
273
},
274
DespawnOnExit(CURRENT_SCENE),
275
));
276
277
commands
278
.spawn((
279
SceneRoot(asset_server.load(GltfAssetLabel::Scene(0).from_asset(FOX_PATH))),
280
DespawnOnExit(CURRENT_SCENE),
281
))
282
.observe(pause_animation_frame);
283
}
284
285
fn pause_animation_frame(
286
event: On<SceneInstanceReady>,
287
children: Query<&Children>,
288
mut commands: Commands,
289
animation: Res<Animation>,
290
mut players: Query<(Entity, &mut AnimationPlayer)>,
291
) {
292
for child in children.iter_descendants(event.entity()) {
293
if let Ok((entity, mut player)) = players.get_mut(child) {
294
let mut transitions = AnimationTransitions::new();
295
transitions
296
.play(&mut player, animation.animation, Duration::ZERO)
297
.seek_to(0.5)
298
.pause();
299
300
commands
301
.entity(entity)
302
.insert(AnimationGraphHandle(animation.graph.clone()))
303
.insert(transitions);
304
}
305
}
306
}
307
}
308
309
mod gizmos {
310
use bevy::{color::palettes::css::*, prelude::*};
311
312
pub fn setup(mut commands: Commands) {
313
commands.spawn((
314
Camera3d::default(),
315
Transform::from_xyz(-1.0, 2.5, 6.5).looking_at(Vec3::ZERO, Vec3::Y),
316
DespawnOnExit(super::Scene::Gizmos),
317
));
318
}
319
320
pub fn draw_gizmos(mut gizmos: Gizmos) {
321
gizmos.cuboid(
322
Transform::from_translation(Vec3::X * -1.75).with_scale(Vec3::splat(1.25)),
323
RED,
324
);
325
gizmos
326
.sphere(Isometry3d::from_translation(Vec3::X * -3.5), 0.75, GREEN)
327
.resolution(30_000 / 3);
328
329
// 3d grids with all variations of outer edges on or off
330
for i in 0..8 {
331
let x = 1.5 * (i % 4) as f32;
332
let y = 1.0 * (0.5 - (i / 4) as f32);
333
let mut grid = gizmos.grid_3d(
334
Isometry3d::from_translation(Vec3::new(x, y, 0.0)),
335
UVec3::new(5, 4, 3),
336
Vec3::splat(0.175),
337
Color::WHITE,
338
);
339
if i & 1 > 0 {
340
grid = grid.outer_edges_x();
341
}
342
if i & 2 > 0 {
343
grid = grid.outer_edges_y();
344
}
345
if i & 4 > 0 {
346
grid.outer_edges_z();
347
}
348
}
349
}
350
}
351
352
mod gltf_coordinate_conversion {
353
use bevy::{
354
color::palettes::basic::*, gltf::GltfLoaderSettings, prelude::*, scene::SceneInstanceReady,
355
};
356
357
const CURRENT_SCENE: super::Scene = super::Scene::GltfCoordinateConversion;
358
359
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
360
commands.spawn((
361
Camera3d::default(),
362
Transform::from_xyz(-4.0, 4.0, -5.0).looking_at(Vec3::ZERO, Vec3::Y),
363
DespawnOnExit(CURRENT_SCENE),
364
));
365
366
commands.spawn((
367
DirectionalLight {
368
color: BLUE.into(),
369
..default()
370
},
371
Transform::IDENTITY.looking_to(Dir3::Z, Dir3::Y),
372
DespawnOnExit(CURRENT_SCENE),
373
));
374
375
commands.spawn((
376
DirectionalLight {
377
color: RED.into(),
378
..default()
379
},
380
Transform::IDENTITY.looking_to(Dir3::X, Dir3::Y),
381
DespawnOnExit(CURRENT_SCENE),
382
));
383
384
commands.spawn((
385
DirectionalLight {
386
color: GREEN.into(),
387
..default()
388
},
389
Transform::IDENTITY.looking_to(Dir3::NEG_Y, Dir3::X),
390
DespawnOnExit(CURRENT_SCENE),
391
));
392
393
commands
394
.spawn((
395
SceneRoot(asset_server.load_with_settings(
396
GltfAssetLabel::Scene(0).from_asset("models/Faces/faces.glb"),
397
|s: &mut GltfLoaderSettings| {
398
s.use_model_forward_direction = Some(true);
399
},
400
)),
401
DespawnOnExit(CURRENT_SCENE),
402
))
403
.observe(show_aabbs);
404
}
405
406
pub fn show_aabbs(
407
event: On<SceneInstanceReady>,
408
mut commands: Commands,
409
children: Query<&Children>,
410
meshes: Query<(), With<Mesh3d>>,
411
) {
412
for child in children
413
.iter_descendants(event.entity())
414
.filter(|&e| meshes.contains(e))
415
{
416
commands.entity(child).insert(ShowAabbGizmo {
417
color: Some(BLACK.into()),
418
});
419
}
420
}
421
422
pub fn draw_gizmos(mut gizmos: Gizmos) {
423
gizmos.axes(Transform::IDENTITY, 1.0);
424
}
425
}
426
427