Skip to main content

rect_light/
rect_light.rs

1//! Illustrates rectangular area lights and how surface roughness affects their appearance.
2
3use bevy::camera_controller::free_camera::{FreeCamera, FreeCameraPlugin};
4use bevy::prelude::*;
5
6fn main() {
7    App::new()
8        .add_plugins((
9            DefaultPlugins.set(WindowPlugin {
10                primary_window: Some(Window {
11                    present_mode: bevy::window::PresentMode::Mailbox,
12                    ..default()
13                }),
14                ..default()
15            }),
16            FreeCameraPlugin,
17        ))
18        .add_systems(Startup, setup)
19        .add_systems(Update, (toggle_gizmos, adjust_roughness))
20        .run();
21}
22
23#[derive(Resource)]
24struct FloorMaterial(Handle<StandardMaterial>);
25
26#[derive(Component)]
27struct RoughnessDisplay;
28
29/// Simple scene with a sphere on a reflective floor, lit by two rectangular area lights
30fn setup(
31    mut commands: Commands,
32    mut meshes: ResMut<Assets<Mesh>>,
33    mut materials: ResMut<Assets<StandardMaterial>>,
34) {
35    let floor_material = materials.add(StandardMaterial {
36        base_color: Color::WHITE,
37        metallic: 1.0,
38        perceptual_roughness: 0.6,
39        ..default()
40    });
41    commands.insert_resource(FloorMaterial(floor_material.clone()));
42    commands.spawn((
43        Mesh3d(meshes.add(Plane3d::default().mesh().size(20.0, 20.0))),
44        MeshMaterial3d(floor_material),
45    ));
46
47    commands.spawn((
48        Mesh3d(meshes.add(Sphere::new(1.0))),
49        MeshMaterial3d(materials.add(Color::WHITE)),
50        Transform::from_xyz(0.0, 1.0, 0.0),
51    ));
52
53    // Lights
54    commands.spawn((
55        RectLight {
56            color: Color::srgb(1.0, 0.3, 0.2),
57            intensity: 100_000.0,
58            width: 2.0,
59            height: 1.0,
60            range: 20.0,
61        },
62        ShowLightGizmo::default(),
63        Transform::from_xyz(1.0, 3.0, 1.0).looking_at(Vec3::Y, Vec3::Y),
64    ));
65
66    commands.spawn((
67        RectLight {
68            color: Color::srgb(0.5, 0.7, 1.0),
69            intensity: 800_000.0,
70            width: 1.5,
71            height: 4.0,
72            range: 20.0,
73        },
74        ShowLightGizmo::default(),
75        Transform::from_xyz(-2.0, 1.5, -3.0)
76            .with_rotation(Quat::from_rotation_y(std::f32::consts::PI)),
77    ));
78
79    commands.spawn((
80        Camera3d::default(),
81        Transform::from_xyz(-8.0, 5.0, 8.0).looking_at(Vec3::Y, Vec3::Y),
82        FreeCamera::default(),
83    ));
84
85    commands.spawn((
86        Text::new("Controls\nArrow Up/Down: Adjust floor roughness\nG: Toggle light gizmos\n\nRoughness: 0.60"),
87        TextFont {
88            font_size: FontSize::Px(18.0),
89            ..default()
90        },
91        TextColor(Color::srgb(0.9, 0.9, 0.9)),
92        Node {
93            position_type: PositionType::Absolute,
94            top: px(12),
95            left: px(12),
96            ..default()
97        },
98        RoughnessDisplay,
99    ));
100}
101
102/// Update floor roughness
103fn adjust_roughness(
104    keys: Res<ButtonInput<KeyCode>>,
105    floor_material: Res<FloorMaterial>,
106    mut materials: ResMut<Assets<StandardMaterial>>,
107    mut text_query: Query<&mut Text, With<RoughnessDisplay>>,
108) {
109    let delta = if keys.pressed(KeyCode::ArrowUp) {
110        0.005
111    } else if keys.pressed(KeyCode::ArrowDown) {
112        -0.005
113    } else {
114        return;
115    };
116
117    if let Some(mut material) = materials.get_mut(&floor_material.0) {
118        material.perceptual_roughness = (material.perceptual_roughness + delta).clamp(0.0, 1.0);
119
120        if let Ok(mut text) = text_query.single_mut() {
121            **text = format!(
122                "Controls\nArrow Up/Down: Adjust floor roughness\nG: Toggle light gizmos\n\nRoughness: {:.2}",
123                material.perceptual_roughness
124            );
125        }
126    }
127}
128
129fn toggle_gizmos(keys: Res<ButtonInput<KeyCode>>, mut config_store: ResMut<GizmoConfigStore>) {
130    if keys.just_pressed(KeyCode::KeyG) {
131        let (config, light_config) = config_store.config_mut::<LightGizmoConfigGroup>();
132        light_config.draw_all = false;
133        config.enabled = !config.enabled;
134    }
135}