render_layers/
render_layers.rs

1// Demonstrates shapes respecting render layers
2// Adapted directly from https://github.com/bevyengine/bevy/blob/main/examples/3d/render_to_texture.rs
3
4use std::f32::consts::PI;
5
6use bevy::{
7    color::palettes::css::*,
8    image::ImageSampler,
9    prelude::*,
10    render::{camera::RenderTarget, view::RenderLayers},
11};
12use bevy_vector_shapes::prelude::*;
13
14fn main() {
15    App::new()
16        .add_plugins(DefaultPlugins)
17        .add_plugins(ShapePlugin::default())
18        .insert_resource(ClearColor(DIM_GRAY.into()))
19        .add_systems(Startup, setup)
20        .add_systems(Update, (rotate_cube, draw_shapes))
21        .run();
22}
23
24// Marks the main pass cube, to which the texture is applied.
25#[derive(Component)]
26struct MainPassCube;
27
28fn setup(
29    mut commands: Commands,
30    mut meshes: ResMut<Assets<Mesh>>,
31    mut materials: ResMut<Assets<StandardMaterial>>,
32    mut images: ResMut<Assets<Image>>,
33) {
34    let image_handle =
35        Canvas::create_image(images.as_mut(), 512, 512, ImageSampler::Default, false);
36
37    // This specifies the layer used for the first pass, which will be attached to the first pass camera and cube.
38    let first_pass_layer = RenderLayers::layer(1);
39
40    // Light
41    // NOTE: Currently lights are shared between passes - see https://github.com/bevyengine/bevy/issues/3462
42    commands.spawn((
43        PointLight::default(),
44        Transform::from_translation(Vec3::new(0.0, 0.0, 10.0)),
45    ));
46
47    commands.spawn((
48        Camera3d::default(),
49        Camera {
50            clear_color: ClearColorConfig::Custom(Color::WHITE),
51            // render before the "main pass" camera
52            order: -1,
53            target: RenderTarget::Image(image_handle.clone().into()),
54            ..default()
55        },
56        Transform::from_translation(Vec3::new(0.0, 0.0, 15.0)).looking_at(Vec3::ZERO, Vec3::Y),
57        Msaa::Off,
58        first_pass_layer,
59    ));
60
61    let cube_size = 4.0;
62    let cube_handle = meshes.add(Mesh::from(Cuboid::new(cube_size, cube_size, cube_size)));
63
64    // This material has the texture that has been rendered.
65    let material_handle = materials.add(StandardMaterial {
66        base_color_texture: Some(image_handle),
67        reflectance: 0.02,
68        unlit: false,
69        ..default()
70    });
71
72    // Main pass cube, with material containing the rendered first pass texture.
73    commands.spawn((
74        Mesh3d(cube_handle),
75        MeshMaterial3d(material_handle),
76        Transform::from_xyz(0.0, 0.0, 1.5).with_rotation(Quat::from_rotation_x(-PI / 5.0)),
77        MainPassCube,
78    ));
79
80    // The main pass camera.
81    commands.spawn((
82        Camera3d::default(),
83        Transform::from_xyz(0.0, 0.0, 15.0).looking_at(Vec3::ZERO, Vec3::Y),
84        Msaa::Off,
85    ));
86}
87
88fn draw_shapes(time: Res<Time>, mut painter: ShapePainter) {
89    painter.reset();
90    painter.render_layers = Some(RenderLayers::layer(1));
91    painter.hollow = true;
92    painter.transform.scale = Vec3::ONE * 3.0;
93
94    let meter_fill = (time.elapsed_secs().sin() + 1.0) / 2.0;
95    let meter_size = PI * 1.5;
96
97    let start_angle = -meter_size / 2.0;
98    let end_angle = -meter_size / 2.0 + meter_fill * meter_size;
99
100    painter.cap = Cap::Round;
101    painter.thickness = 0.4;
102    painter.set_color(CRIMSON * (1.0 / (0.5 + meter_fill)));
103    painter.arc(1.3, start_angle, end_angle);
104
105    painter.cap = Cap::None;
106    painter.thickness = 0.2;
107    painter.set_color(DARK_GRAY);
108    painter.arc(1.6, start_angle, -start_angle);
109    painter.arc(0.8, start_angle, -start_angle);
110
111    let offset = Quat::from_rotation_z(start_angle) * Vec3::Y * 1.1;
112    painter.translate(offset);
113    painter.arc(0.5, start_angle + PI * 1.5, start_angle + 2.5 * PI);
114    painter.translate(-offset);
115
116    painter.translate(Quat::from_rotation_z(-start_angle) * Vec3::Y * 1.1);
117    painter.arc(0.5, start_angle + PI, start_angle + 2.0 * PI);
118}
119
120fn rotate_cube(time: Res<Time>, mut query: Query<&mut Transform, With<MainPassCube>>) {
121    for mut transform in &mut query {
122        transform.rotation = Quat::from_rotation_x(time.elapsed_secs())
123            * Quat::from_rotation_y(time.elapsed_secs() / 2.0);
124    }
125}