Skip to content

Commit 7477c97

Browse files
rparrettexjam
authored andcommitted
Add 3d shapes example (bevyengine#4613)
# Objective - As requested here: bevyengine#4520 (comment) - Make it easier to spot issues with built-in shapes ## Solution https://user-images.githubusercontent.com/200550/165624709-c40dfe7e-0e1e-4bd3-ae52-8ae66888c171.mp4 - Add an example showcasing the built-in 3d shapes with lighting/shadows - Rotate objects in such a way that all faces are seen by the camera - Add a UV debug texture ## Discussion I'm not sure if this is what @alice-i-cecile had in mind, but I adapted the little "torus playground" from the issue linked above to include all built-in shapes. This exact arrangement might not be particularly scalable if many more shapes are added. Maybe a slow camera pan, or cycling with the keyboard or on a timer, or a sidebar with buttons would work better. If one of the latter options is used, options for showing wireframes or computed flat normals might add some additional utility. Ideally, I think we'd have a better way of visualizing normals. Happy to rework this or close it if there's not a consensus around it being useful.
1 parent 7eb3ba2 commit 7477c97

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ path = "examples/3d/pbr.rs"
200200
name = "shadow_biases"
201201
path = "examples/3d/shadow_biases.rs"
202202

203+
[[example]]
204+
name = "3d_shapes"
205+
path = "examples/3d/shapes.rs"
206+
203207
[[example]]
204208
name = "shadow_caster_receiver"
205209
path = "examples/3d/shadow_caster_receiver.rs"

examples/3d/shapes.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! This example demonstrates the built-in 3d shapes in Bevy.
2+
//! The scene includes a patterned texture and a rotation for visualizing the normals and UVs.
3+
4+
use bevy::{
5+
prelude::*,
6+
render::render_resource::{Extent3d, TextureDimension, TextureFormat},
7+
};
8+
9+
fn main() {
10+
App::new()
11+
.insert_resource(Msaa { samples: 4 })
12+
.add_plugins(DefaultPlugins)
13+
.add_startup_system(setup)
14+
.add_system(rotate)
15+
.run();
16+
}
17+
18+
/// A marker component for our shapes so we can query them separately from the ground plane
19+
#[derive(Component)]
20+
struct Shape;
21+
22+
const X_EXTENT: f32 = 14.;
23+
24+
fn setup(
25+
mut commands: Commands,
26+
mut meshes: ResMut<Assets<Mesh>>,
27+
mut images: ResMut<Assets<Image>>,
28+
mut materials: ResMut<Assets<StandardMaterial>>,
29+
) {
30+
let debug_material = materials.add(StandardMaterial {
31+
base_color_texture: Some(images.add(uv_debug_texture())),
32+
..default()
33+
});
34+
35+
let shapes = [
36+
meshes.add(shape::Cube::default().into()),
37+
meshes.add(shape::Box::default().into()),
38+
meshes.add(shape::Capsule::default().into()),
39+
meshes.add(shape::Torus::default().into()),
40+
meshes.add(shape::Icosphere::default().into()),
41+
meshes.add(shape::UVSphere::default().into()),
42+
];
43+
44+
let num_shapes = shapes.len();
45+
46+
for (i, shape) in shapes.into_iter().enumerate() {
47+
commands
48+
.spawn_bundle(PbrBundle {
49+
mesh: shape,
50+
material: debug_material.clone(),
51+
transform: Transform {
52+
translation: Vec3::new(
53+
-X_EXTENT / 2. + i as f32 / (num_shapes - 1) as f32 * X_EXTENT,
54+
2.0,
55+
0.0,
56+
),
57+
..default()
58+
},
59+
..Default::default()
60+
})
61+
.insert(Shape);
62+
}
63+
64+
commands.spawn_bundle(PointLightBundle {
65+
point_light: PointLight {
66+
intensity: 9000.0,
67+
range: 100.,
68+
shadows_enabled: true,
69+
..Default::default()
70+
},
71+
transform: Transform::from_xyz(8.0, 16.0, 8.0),
72+
..Default::default()
73+
});
74+
75+
// ground plane
76+
commands.spawn_bundle(PbrBundle {
77+
mesh: meshes.add(shape::Plane { size: 50. }.into()),
78+
material: materials.add(Color::SILVER.into()),
79+
..Default::default()
80+
});
81+
82+
commands.spawn_bundle(PerspectiveCameraBundle {
83+
transform: Transform::from_xyz(0.0, 6., 12.0).looking_at(Vec3::new(0., 1., 0.), Vec3::Y),
84+
..Default::default()
85+
});
86+
}
87+
88+
fn rotate(mut query: Query<&mut Transform, With<Shape>>, time: Res<Time>) {
89+
for mut transform in query.iter_mut() {
90+
transform.rotation = Quat::from_rotation_y(time.seconds_since_startup() as f32 / 2.)
91+
* Quat::from_rotation_x(-std::f32::consts::PI / 4.)
92+
}
93+
}
94+
95+
/// Creates a colorful test pattern
96+
fn uv_debug_texture() -> Image {
97+
const TEXTURE_SIZE: usize = 8;
98+
99+
let mut palette: [u8; 32] = [
100+
255, 102, 159, 255, 255, 159, 102, 255, 236, 255, 102, 255, 121, 255, 102, 255, 102, 255,
101+
198, 255, 102, 198, 255, 255, 121, 102, 255, 255, 236, 102, 255, 255,
102+
];
103+
104+
let mut texture_data = [0; TEXTURE_SIZE * TEXTURE_SIZE * 4];
105+
for y in 0..TEXTURE_SIZE {
106+
let offset = TEXTURE_SIZE * y * 4;
107+
texture_data[offset..(offset + TEXTURE_SIZE * 4)].copy_from_slice(&palette);
108+
palette.rotate_right(4);
109+
}
110+
111+
Image::new_fill(
112+
Extent3d {
113+
width: TEXTURE_SIZE as u32,
114+
height: TEXTURE_SIZE as u32,
115+
depth_or_array_layers: 1,
116+
},
117+
TextureDimension::D2,
118+
&texture_data,
119+
TextureFormat::Rgba8UnormSrgb,
120+
)
121+
}

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ Example | File | Description
116116
`texture` | [`3d/texture.rs`](./3d/texture.rs) | Shows configuration of texture materials
117117
`update_gltf_scene` | [`3d/update_gltf_scene.rs`](./3d/update_gltf_scene.rs) | Update a scene from a gltf file, either by spawning the scene as a child of another entity, or by accessing the entities of the scene
118118
`wireframe` | [`3d/wireframe.rs`](./3d/wireframe.rs) | Showcases wireframe rendering
119+
`3d_shapes` | [`3d/shapes.rs`](./3d/shapes.rs) | A scene showcasing the built-in 3D shapes
119120

120121
## Animation
121122

0 commit comments

Comments
 (0)