
# Objective - Simplify `Camera` initialization - allow effects to require HDR ## Solution - Split out `Camera.hdr` into a marker `Hdr` component ## Testing - ran `bloom_3d` example --- ## Showcase ```rs // before commands.spawn(( Camera3d Camera { hdr: true ..Default::default() } )) // after commands.spawn((Camera3d, Hdr)); // other rendering components can require that the camera enables hdr! // currently implemented for Bloom, AutoExposure, and Atmosphere. #[require(Hdr)] pub struct Bloom; ```
121 lines
4.0 KiB
Rust
121 lines
4.0 KiB
Rust
//! This example showcases pbr atmospheric scattering
|
|
|
|
use std::f32::consts::PI;
|
|
|
|
use bevy::{
|
|
core_pipeline::{bloom::Bloom, tonemapping::Tonemapping},
|
|
pbr::{light_consts::lux, Atmosphere, AtmosphereSettings, CascadeShadowConfigBuilder},
|
|
prelude::*,
|
|
render::camera::Exposure,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_systems(Startup, (setup_camera_fog, setup_terrain_scene))
|
|
.add_systems(Update, dynamic_scene)
|
|
.run();
|
|
}
|
|
|
|
fn setup_camera_fog(mut commands: Commands) {
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Transform::from_xyz(-1.2, 0.15, 0.0).looking_at(Vec3::Y * 0.1, Vec3::Y),
|
|
// This is the component that enables atmospheric scattering for a camera
|
|
Atmosphere::EARTH,
|
|
// The scene is in units of 10km, so we need to scale up the
|
|
// aerial view lut distance and set the scene scale accordingly.
|
|
// Most usages of this feature will not need to adjust this.
|
|
AtmosphereSettings {
|
|
aerial_view_lut_max_distance: 3.2e5,
|
|
scene_units_to_m: 1e+4,
|
|
..Default::default()
|
|
},
|
|
// The directional light illuminance used in this scene
|
|
// (the one recommended for use with this feature) is
|
|
// quite bright, so raising the exposure compensation helps
|
|
// bring the scene to a nicer brightness range.
|
|
Exposure::SUNLIGHT,
|
|
// Tonemapper chosen just because it looked good with the scene, any
|
|
// tonemapper would be fine :)
|
|
Tonemapping::AcesFitted,
|
|
// Bloom gives the sun a much more natural look.
|
|
Bloom::NATURAL,
|
|
));
|
|
}
|
|
|
|
#[derive(Component)]
|
|
struct Terrain;
|
|
|
|
fn setup_terrain_scene(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
asset_server: Res<AssetServer>,
|
|
) {
|
|
// Configure a properly scaled cascade shadow map for this scene (defaults are too large, mesh units are in km)
|
|
let cascade_shadow_config = CascadeShadowConfigBuilder {
|
|
first_cascade_far_bound: 0.3,
|
|
maximum_distance: 3.0,
|
|
..default()
|
|
}
|
|
.build();
|
|
|
|
// Sun
|
|
commands.spawn((
|
|
DirectionalLight {
|
|
shadows_enabled: true,
|
|
// lux::RAW_SUNLIGHT is recommended for use with this feature, since
|
|
// other values approximate sunlight *post-scattering* in various
|
|
// conditions. RAW_SUNLIGHT in comparison is the illuminance of the
|
|
// sun unfiltered by the atmosphere, so it is the proper input for
|
|
// sunlight to be filtered by the atmosphere.
|
|
illuminance: lux::RAW_SUNLIGHT,
|
|
..default()
|
|
},
|
|
Transform::from_xyz(1.0, -0.4, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
cascade_shadow_config,
|
|
));
|
|
|
|
let sphere_mesh = meshes.add(Mesh::from(Sphere { radius: 1.0 }));
|
|
|
|
// light probe spheres
|
|
commands.spawn((
|
|
Mesh3d(sphere_mesh.clone()),
|
|
MeshMaterial3d(materials.add(StandardMaterial {
|
|
base_color: Color::WHITE,
|
|
metallic: 1.0,
|
|
perceptual_roughness: 0.0,
|
|
..default()
|
|
})),
|
|
Transform::from_xyz(-0.3, 0.1, -0.1).with_scale(Vec3::splat(0.05)),
|
|
));
|
|
|
|
commands.spawn((
|
|
Mesh3d(sphere_mesh.clone()),
|
|
MeshMaterial3d(materials.add(StandardMaterial {
|
|
base_color: Color::WHITE,
|
|
metallic: 0.0,
|
|
perceptual_roughness: 1.0,
|
|
..default()
|
|
})),
|
|
Transform::from_xyz(-0.3, 0.1, 0.1).with_scale(Vec3::splat(0.05)),
|
|
));
|
|
|
|
// Terrain
|
|
commands.spawn((
|
|
Terrain,
|
|
SceneRoot(
|
|
asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/terrain/terrain.glb")),
|
|
),
|
|
Transform::from_xyz(-1.0, 0.0, -0.5)
|
|
.with_scale(Vec3::splat(0.5))
|
|
.with_rotation(Quat::from_rotation_y(PI / 2.0)),
|
|
));
|
|
}
|
|
|
|
fn dynamic_scene(mut suns: Query<&mut Transform, With<DirectionalLight>>, time: Res<Time>) {
|
|
suns.iter_mut()
|
|
.for_each(|mut tf| tf.rotate_x(-time.delta_secs() * PI / 10.0));
|
|
}
|