# 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));
 | 
						|
}
 |