//! Illustrates bloom post-processing using HDR and emissive materials. use bevy::{ core_pipeline::{ bloom::{Bloom, BloomCompositeMode}, tonemapping::Tonemapping, }, math::ops, prelude::*, }; use std::{ collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, }; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup_scene) .add_systems(Update, (update_bloom_settings, bounce_spheres)) .run(); } fn setup_scene( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { commands.spawn(( Camera3d::default(), Camera { hdr: true, // 1. HDR is required for bloom clear_color: ClearColorConfig::Custom(Color::BLACK), ..default() }, Tonemapping::TonyMcMapface, // 2. Using a tonemapper that desaturates to white is recommended Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), Bloom::NATURAL, // 3. Enable bloom for the camera )); let material_emissive1 = materials.add(StandardMaterial { emissive: LinearRgba::rgb(0.0, 0.0, 150.0), // 4. Put something bright in a dark environment to see the effect ..default() }); let material_emissive2 = materials.add(StandardMaterial { emissive: LinearRgba::rgb(1000.0, 1000.0, 1000.0), ..default() }); let material_emissive3 = materials.add(StandardMaterial { emissive: LinearRgba::rgb(50.0, 0.0, 0.0), ..default() }); let material_non_emissive = materials.add(StandardMaterial { base_color: Color::BLACK, ..default() }); let mesh = meshes.add(Sphere::new(0.4).mesh().ico(5).unwrap()); for x in -5..5 { for z in -5..5 { // This generates a pseudo-random integer between `[0, 6)`, but deterministically so // the same spheres are always the same colors. let mut hasher = DefaultHasher::new(); (x, z).hash(&mut hasher); let rand = (hasher.finish() + 3) % 6; let (material, scale) = match rand { 0 => (material_emissive1.clone(), 0.5), 1 => (material_emissive2.clone(), 0.1), 2 => (material_emissive3.clone(), 1.0), 3..=5 => (material_non_emissive.clone(), 1.5), _ => unreachable!(), }; commands.spawn(( Mesh3d(mesh.clone()), MeshMaterial3d(material), Transform::from_xyz(x as f32 * 2.0, 0.0, z as f32 * 2.0) .with_scale(Vec3::splat(scale)), Bouncing, )); } } // example instructions commands.spawn(( Text::default(), Node { position_type: PositionType::Absolute, bottom: Val::Px(12.0), left: Val::Px(12.0), ..default() }, )); } // ------------------------------------------------------------------------------------------------ fn update_bloom_settings( camera: Single<(Entity, Option<&mut Bloom>), With>, mut text: Single<&mut Text>, mut commands: Commands, keycode: Res>, time: Res