 dcc03724a5
			
		
	
	
		dcc03724a5
		
	
	
	
	
		
			
			# Objective NOTE: This depends on #7267 and should not be merged until #7267 is merged. If you are reviewing this before that is merged, I highly recommend viewing the Base Sets commit instead of trying to find my changes amongst those from #7267. "Default sets" as described by the [Stageless RFC](https://github.com/bevyengine/rfcs/pull/45) have some [unfortunate consequences](https://github.com/bevyengine/bevy/discussions/7365). ## Solution This adds "base sets" as a variant of `SystemSet`: A set is a "base set" if `SystemSet::is_base` returns `true`. Typically this will be opted-in to using the `SystemSet` derive: ```rust #[derive(SystemSet, Clone, Hash, Debug, PartialEq, Eq)] #[system_set(base)] enum MyBaseSet { A, B, } ``` **Base sets are exclusive**: a system can belong to at most one "base set". Adding a system to more than one will result in an error. When possible we fail immediately during system-config-time with a nice file + line number. For the more nested graph-ey cases, this will fail at the final schedule build. **Base sets cannot belong to other sets**: this is where the word "base" comes from Systems and Sets can only be added to base sets using `in_base_set`. Calling `in_set` with a base set will fail. As will calling `in_base_set` with a normal set. ```rust app.add_system(foo.in_base_set(MyBaseSet::A)) // X must be a normal set ... base sets cannot be added to base sets .configure_set(X.in_base_set(MyBaseSet::A)) ``` Base sets can still be configured like normal sets: ```rust app.add_system(MyBaseSet::B.after(MyBaseSet::Ap)) ``` The primary use case for base sets is enabling a "default base set": ```rust schedule.set_default_base_set(CoreSet::Update) // this will belong to CoreSet::Update by default .add_system(foo) // this will override the default base set with PostUpdate .add_system(bar.in_base_set(CoreSet::PostUpdate)) ``` This allows us to build apis that work by default in the standard Bevy style. This is a rough analog to the "default stage" model, but it use the new "stageless sets" model instead, with all of the ordering flexibility (including exclusive systems) that it provides. --- ## Changelog - Added "base sets" and ported CoreSet to use them. ## Migration Guide TODO
		
			
				
	
	
		
			167 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Illustrates bloom configuration using HDR and emissive materials.
 | |
| 
 | |
| use bevy::{core_pipeline::bloom::BloomSettings, prelude::*};
 | |
| use std::{
 | |
|     collections::hash_map::DefaultHasher,
 | |
|     hash::{Hash, Hasher},
 | |
| };
 | |
| 
 | |
| fn main() {
 | |
|     App::new()
 | |
|         .add_plugins(DefaultPlugins)
 | |
|         .add_startup_system(setup_scene)
 | |
|         .add_system(update_bloom_settings)
 | |
|         .add_system(bounce_spheres)
 | |
|         .run();
 | |
| }
 | |
| 
 | |
| fn setup_scene(
 | |
|     mut commands: Commands,
 | |
|     mut meshes: ResMut<Assets<Mesh>>,
 | |
|     mut materials: ResMut<Assets<StandardMaterial>>,
 | |
|     asset_server: Res<AssetServer>,
 | |
| ) {
 | |
|     commands.spawn((
 | |
|         Camera3dBundle {
 | |
|             camera: Camera {
 | |
|                 hdr: true, // 1. HDR must be enabled on the camera
 | |
|                 ..default()
 | |
|             },
 | |
|             transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
 | |
|             ..default()
 | |
|         },
 | |
|         BloomSettings::default(), // 2. Enable bloom for the camera
 | |
|     ));
 | |
| 
 | |
|     let material_emissive = materials.add(StandardMaterial {
 | |
|         emissive: Color::rgb_linear(5.2, 1.2, 0.8), // 3. Set StandardMaterial::emissive using Color::rgb_linear, for entities we want to apply bloom to
 | |
|         ..default()
 | |
|     });
 | |
|     let material_non_emissive = materials.add(StandardMaterial {
 | |
|         base_color: Color::GRAY,
 | |
|         ..default()
 | |
|     });
 | |
| 
 | |
|     let mesh = meshes.add(
 | |
|         shape::Icosphere {
 | |
|             radius: 0.5,
 | |
|             subdivisions: 5,
 | |
|         }
 | |
|         .try_into()
 | |
|         .unwrap(),
 | |
|     );
 | |
| 
 | |
|     for x in -10..10 {
 | |
|         for z in -10..10 {
 | |
|             let mut hasher = DefaultHasher::new();
 | |
|             (x, z).hash(&mut hasher);
 | |
|             let rand = hasher.finish() % 2 == 0;
 | |
| 
 | |
|             let material = if rand {
 | |
|                 material_emissive.clone()
 | |
|             } else {
 | |
|                 material_non_emissive.clone()
 | |
|             };
 | |
| 
 | |
|             commands.spawn((
 | |
|                 PbrBundle {
 | |
|                     mesh: mesh.clone(),
 | |
|                     material,
 | |
|                     transform: Transform::from_xyz(x as f32 * 2.0, 0.0, z as f32 * 2.0),
 | |
|                     ..default()
 | |
|                 },
 | |
|                 Bouncing,
 | |
|             ));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     commands.spawn(
 | |
|         TextBundle::from_section(
 | |
|             "",
 | |
|             TextStyle {
 | |
|                 font: asset_server.load("fonts/FiraMono-Medium.ttf"),
 | |
|                 font_size: 18.0,
 | |
|                 color: Color::BLACK,
 | |
|             },
 | |
|         )
 | |
|         .with_style(Style {
 | |
|             position_type: PositionType::Absolute,
 | |
|             position: UiRect {
 | |
|                 top: Val::Px(10.0),
 | |
|                 left: Val::Px(10.0),
 | |
|                 ..default()
 | |
|             },
 | |
|             ..default()
 | |
|         }),
 | |
|     );
 | |
| }
 | |
| 
 | |
| // ------------------------------------------------------------------------------------------------
 | |
| 
 | |
| fn update_bloom_settings(
 | |
|     mut camera: Query<&mut BloomSettings>,
 | |
|     mut text: Query<&mut Text>,
 | |
|     keycode: Res<Input<KeyCode>>,
 | |
|     time: Res<Time>,
 | |
| ) {
 | |
|     let mut bloom_settings = camera.single_mut();
 | |
|     let mut text = text.single_mut();
 | |
|     let text = &mut text.sections[0].value;
 | |
| 
 | |
|     *text = "BloomSettings\n".to_string();
 | |
|     text.push_str("-------------\n");
 | |
|     text.push_str(&format!("Threshold: {}\n", bloom_settings.threshold));
 | |
|     text.push_str(&format!("Knee: {}\n", bloom_settings.knee));
 | |
|     text.push_str(&format!("Scale: {}\n", bloom_settings.scale));
 | |
|     text.push_str(&format!("Intensity: {}\n", bloom_settings.intensity));
 | |
| 
 | |
|     text.push_str("\n\n");
 | |
| 
 | |
|     text.push_str("Controls (-/+)\n");
 | |
|     text.push_str("---------------\n");
 | |
|     text.push_str("Q/W - Threshold\n");
 | |
|     text.push_str("E/R - Knee\n");
 | |
|     text.push_str("A/S - Scale\n");
 | |
|     text.push_str("D/F - Intensity\n");
 | |
| 
 | |
|     let dt = time.delta_seconds();
 | |
| 
 | |
|     if keycode.pressed(KeyCode::Q) {
 | |
|         bloom_settings.threshold -= dt;
 | |
|     }
 | |
|     if keycode.pressed(KeyCode::W) {
 | |
|         bloom_settings.threshold += dt;
 | |
|     }
 | |
| 
 | |
|     if keycode.pressed(KeyCode::E) {
 | |
|         bloom_settings.knee -= dt;
 | |
|     }
 | |
|     if keycode.pressed(KeyCode::R) {
 | |
|         bloom_settings.knee += dt;
 | |
|     }
 | |
| 
 | |
|     if keycode.pressed(KeyCode::A) {
 | |
|         bloom_settings.scale -= dt;
 | |
|     }
 | |
|     if keycode.pressed(KeyCode::S) {
 | |
|         bloom_settings.scale += dt;
 | |
|     }
 | |
| 
 | |
|     if keycode.pressed(KeyCode::D) {
 | |
|         bloom_settings.intensity -= dt;
 | |
|     }
 | |
|     if keycode.pressed(KeyCode::F) {
 | |
|         bloom_settings.intensity += dt;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[derive(Component)]
 | |
| struct Bouncing;
 | |
| 
 | |
| fn bounce_spheres(time: Res<Time>, mut query: Query<&mut Transform, With<Bouncing>>) {
 | |
|     for mut transform in query.iter_mut() {
 | |
|         transform.translation.y =
 | |
|             (transform.translation.x + transform.translation.z + time.elapsed_seconds()).sin();
 | |
|     }
 | |
| }
 |