pbr/
pbr.rs

1//! This example shows how to configure Physically Based Rendering (PBR) parameters.
2
3use bevy::camera::ScalingMode;
4use bevy::prelude::*;
5
6fn main() {
7    App::new()
8        .add_plugins(DefaultPlugins)
9        .add_systems(Startup, setup)
10        .add_systems(Update, environment_map_load_finish)
11        .run();
12}
13
14/// set up a simple 3D scene
15fn setup(
16    mut commands: Commands,
17    mut meshes: ResMut<Assets<Mesh>>,
18    mut materials: ResMut<Assets<StandardMaterial>>,
19    asset_server: Res<AssetServer>,
20) {
21    let sphere_mesh = meshes.add(Sphere::new(0.45));
22    // add entities to the world
23    for y in -2..=2 {
24        for x in -5..=5 {
25            let x01 = (x + 5) as f32 / 10.0;
26            let y01 = (y + 2) as f32 / 4.0;
27            // sphere
28            commands.spawn((
29                Mesh3d(sphere_mesh.clone()),
30                MeshMaterial3d(materials.add(StandardMaterial {
31                    base_color: Srgba::hex("#ffd891").unwrap().into(),
32                    // vary key PBR parameters on a grid of spheres to show the effect
33                    metallic: y01,
34                    perceptual_roughness: x01,
35                    ..default()
36                })),
37                Transform::from_xyz(x as f32, y as f32 + 0.5, 0.0),
38            ));
39        }
40    }
41    // unlit sphere
42    commands.spawn((
43        Mesh3d(sphere_mesh),
44        MeshMaterial3d(materials.add(StandardMaterial {
45            base_color: Srgba::hex("#ffd891").unwrap().into(),
46            // vary key PBR parameters on a grid of spheres to show the effect
47            unlit: true,
48            ..default()
49        })),
50        Transform::from_xyz(-5.0, -2.5, 0.0),
51    ));
52
53    commands.spawn((
54        DirectionalLight {
55            illuminance: 1_500.,
56            ..default()
57        },
58        Transform::from_xyz(50.0, 50.0, 50.0).looking_at(Vec3::ZERO, Vec3::Y),
59    ));
60
61    // labels
62    commands.spawn((
63        Text::new("Perceptual Roughness"),
64        TextFont {
65            font_size: 30.0,
66            ..default()
67        },
68        Node {
69            position_type: PositionType::Absolute,
70            top: px(20),
71            left: px(100),
72            ..default()
73        },
74    ));
75
76    commands.spawn((
77        Text::new("Metallic"),
78        TextFont {
79            font_size: 30.0,
80            ..default()
81        },
82        Node {
83            position_type: PositionType::Absolute,
84            top: px(130),
85            right: Val::ZERO,
86            ..default()
87        },
88        UiTransform {
89            rotation: Rot2::degrees(90.),
90            ..default()
91        },
92    ));
93
94    commands.spawn((
95        Text::new("Loading Environment Map..."),
96        TextFont {
97            font_size: 30.0,
98            ..default()
99        },
100        Node {
101            position_type: PositionType::Absolute,
102            bottom: px(20),
103            right: px(20),
104            ..default()
105        },
106        EnvironmentMapLabel,
107    ));
108
109    // camera
110    commands.spawn((
111        Camera3d::default(),
112        Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::default(), Vec3::Y),
113        Projection::from(OrthographicProjection {
114            scale: 0.01,
115            scaling_mode: ScalingMode::WindowSize,
116            ..OrthographicProjection::default_3d()
117        }),
118        EnvironmentMapLight {
119            diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
120            specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
121            intensity: 900.0,
122            ..default()
123        },
124    ));
125}
126
127fn environment_map_load_finish(
128    mut commands: Commands,
129    asset_server: Res<AssetServer>,
130    environment_map: Single<&EnvironmentMapLight>,
131    label_entity: Option<Single<Entity, With<EnvironmentMapLabel>>>,
132) {
133    if asset_server
134        .load_state(&environment_map.diffuse_map)
135        .is_loaded()
136        && asset_server
137            .load_state(&environment_map.specular_map)
138            .is_loaded()
139    {
140        // Do not attempt to remove `label_entity` if it has already been removed.
141        if let Some(label_entity) = label_entity {
142            commands.entity(*label_entity).despawn();
143        }
144    }
145}
146
147#[derive(Component)]
148struct EnvironmentMapLabel;