mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
Make RenderStage::Extract
run on the render world (#4402)
# Objective - Currently, the `Extract` `RenderStage` is executed on the main world, with the render world available as a resource. - However, when needing access to resources in the render world (e.g. to mutate them), the only way to do so was to get exclusive access to the whole `RenderWorld` resource. - This meant that effectively only one extract which wrote to resources could run at a time. - We didn't previously make `Extract`ing writing to the world a non-happy path, even though we want to discourage that. ## Solution - Move the extract stage to run on the render world. - Add the main world as a `MainWorld` resource. - Add an `Extract` `SystemParam` as a convenience to access a (read only) `SystemParam` in the main world during `Extract`. ## Future work It should be possible to avoid needing to use `get_or_spawn` for the render commands, since now the `Commands`' `Entities` matches up with the world being executed on. We need to determine how this interacts with https://github.com/bevyengine/bevy/pull/3519 It's theoretically possible to remove the need for the `value` method on `Extract`. However, that requires slightly changing the `SystemParam` interface, which would make it more complicated. That would probably mess up the `SystemState` api too. ## Todo I still need to add doc comments to `Extract`. --- ## Changelog ### Changed - The `Extract` `RenderStage` now runs on the render world (instead of the main world as before). You must use the `Extract` `SystemParam` to access the main world during the extract phase. Resources on the render world can now be accessed using `ResMut` during extract. ### Removed - `Commands::spawn_and_forget`. Use `Commands::get_or_spawn(e).insert_bundle(bundle)` instead ## Migration Guide The `Extract` `RenderStage` now runs on the render world (instead of the main world as before). You must use the `Extract` `SystemParam` to access the main world during the extract phase. `Extract` takes a single type parameter, which is any system parameter (such as `Res`, `Query` etc.). It will extract this from the main world, and returns the result of this extraction when `value` is called on it. For example, if previously your extract system looked like: ```rust fn extract_clouds(mut commands: Commands, clouds: Query<Entity, With<Cloud>>) { for cloud in clouds.iter() { commands.get_or_spawn(cloud).insert(Cloud); } } ``` the new version would be: ```rust fn extract_clouds(mut commands: Commands, mut clouds: Extract<Query<Entity, With<Cloud>>>) { for cloud in clouds.value().iter() { commands.get_or_spawn(cloud).insert(Cloud); } } ``` The diff is: ```diff --- a/src/clouds.rs +++ b/src/clouds.rs @@ -1,5 +1,5 @@ -fn extract_clouds(mut commands: Commands, clouds: Query<Entity, With<Cloud>>) { - for cloud in clouds.iter() { +fn extract_clouds(mut commands: Commands, mut clouds: Extract<Query<Entity, With<Cloud>>>) { + for cloud in clouds.value().iter() { commands.get_or_spawn(cloud).insert(Cloud); } } ``` You can now also access resources from the render world using the normal system parameters during `Extract`: ```rust fn extract_assets(mut render_assets: ResMut<MyAssets>, source_assets: Extract<Res<MyAssets>>) { *render_assets = source_assets.clone(); } ``` Please note that all existing extract systems need to be updated to match this new style; even if they currently compile they will not run as expected. A warning will be emitted on a best-effort basis if this is not met. Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
e6faf993b0
commit
7b2cf98896
22 changed files with 375 additions and 192 deletions
|
@ -25,7 +25,7 @@ use bevy_render::{
|
||||||
DrawFunctionId, DrawFunctions, EntityPhaseItem, PhaseItem, RenderPhase,
|
DrawFunctionId, DrawFunctions, EntityPhaseItem, PhaseItem, RenderPhase,
|
||||||
},
|
},
|
||||||
render_resource::CachedRenderPipelineId,
|
render_resource::CachedRenderPipelineId,
|
||||||
RenderApp, RenderStage,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_utils::FloatOrd;
|
use bevy_utils::FloatOrd;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -123,7 +123,7 @@ impl BatchedPhaseItem for Transparent2d {
|
||||||
|
|
||||||
pub fn extract_core_2d_camera_phases(
|
pub fn extract_core_2d_camera_phases(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
cameras_2d: Query<(Entity, &Camera), With<Camera2d>>,
|
cameras_2d: Extract<Query<(Entity, &Camera), With<Camera2d>>>,
|
||||||
) {
|
) {
|
||||||
for (entity, camera) in cameras_2d.iter() {
|
for (entity, camera) in cameras_2d.iter() {
|
||||||
if camera.is_active {
|
if camera.is_active {
|
||||||
|
|
|
@ -34,7 +34,7 @@ use bevy_render::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::TextureCache,
|
texture::TextureCache,
|
||||||
view::ViewDepthTexture,
|
view::ViewDepthTexture,
|
||||||
RenderApp, RenderStage,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_utils::{FloatOrd, HashMap};
|
use bevy_utils::{FloatOrd, HashMap};
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ impl CachedRenderPipelinePhaseItem for Transparent3d {
|
||||||
|
|
||||||
pub fn extract_core_3d_camera_phases(
|
pub fn extract_core_3d_camera_phases(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
cameras_3d: Query<(Entity, &Camera), With<Camera3d>>,
|
cameras_3d: Extract<Query<(Entity, &Camera), With<Camera3d>>>,
|
||||||
) {
|
) {
|
||||||
for (entity, camera) in cameras_3d.iter() {
|
for (entity, camera) in cameras_3d.iter() {
|
||||||
if camera.is_active {
|
if camera.is_active {
|
||||||
|
|
|
@ -12,7 +12,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
world::{World, WorldId},
|
world::{World, WorldId},
|
||||||
};
|
};
|
||||||
use bevy_utils::{tracing::info, HashMap, HashSet};
|
use bevy_utils::{
|
||||||
|
tracing::{info, warn},
|
||||||
|
HashMap, HashSet,
|
||||||
|
};
|
||||||
use downcast_rs::{impl_downcast, Downcast};
|
use downcast_rs::{impl_downcast, Downcast};
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -88,6 +91,7 @@ pub struct SystemStage {
|
||||||
last_tick_check: u32,
|
last_tick_check: u32,
|
||||||
/// If true, buffers will be automatically applied at the end of the stage. If false, buffers must be manually applied.
|
/// If true, buffers will be automatically applied at the end of the stage. If false, buffers must be manually applied.
|
||||||
apply_buffers: bool,
|
apply_buffers: bool,
|
||||||
|
must_read_resource: Option<ComponentId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemStage {
|
impl SystemStage {
|
||||||
|
@ -110,6 +114,7 @@ impl SystemStage {
|
||||||
uninitialized_at_end: vec![],
|
uninitialized_at_end: vec![],
|
||||||
last_tick_check: Default::default(),
|
last_tick_check: Default::default(),
|
||||||
apply_buffers: true,
|
apply_buffers: true,
|
||||||
|
must_read_resource: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +144,10 @@ impl SystemStage {
|
||||||
self.executor = executor;
|
self.executor = executor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_must_read_resource(&mut self, resource_id: ComponentId) {
|
||||||
|
self.must_read_resource = Some(resource_id);
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_system<Params>(mut self, system: impl IntoSystemDescriptor<Params>) -> Self {
|
pub fn with_system<Params>(mut self, system: impl IntoSystemDescriptor<Params>) -> Self {
|
||||||
self.add_system(system);
|
self.add_system(system);
|
||||||
|
@ -563,6 +572,20 @@ impl SystemStage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_uses_resource(&self, resource_id: ComponentId, world: &World) {
|
||||||
|
debug_assert!(!self.systems_modified);
|
||||||
|
for system in &self.parallel {
|
||||||
|
let access = system.component_access().unwrap();
|
||||||
|
if !access.has_read(resource_id) {
|
||||||
|
let component_name = world.components().get_info(resource_id).unwrap().name();
|
||||||
|
warn!(
|
||||||
|
"System {} doesn't access resource {component_name}, despite being required to",
|
||||||
|
system.name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// All system and component change ticks are scanned once the world counter has incremented
|
/// All system and component change ticks are scanned once the world counter has incremented
|
||||||
/// at least [`CHECK_TICK_THRESHOLD`](crate::change_detection::CHECK_TICK_THRESHOLD)
|
/// at least [`CHECK_TICK_THRESHOLD`](crate::change_detection::CHECK_TICK_THRESHOLD)
|
||||||
/// times since the previous `check_tick` scan.
|
/// times since the previous `check_tick` scan.
|
||||||
|
@ -782,6 +805,9 @@ impl Stage for SystemStage {
|
||||||
if world.contains_resource::<ReportExecutionOrderAmbiguities>() {
|
if world.contains_resource::<ReportExecutionOrderAmbiguities>() {
|
||||||
self.report_ambiguities(world);
|
self.report_ambiguities(world);
|
||||||
}
|
}
|
||||||
|
if let Some(resource_id) = self.must_read_resource {
|
||||||
|
self.check_uses_resource(resource_id, world);
|
||||||
|
}
|
||||||
} else if self.executor_modified {
|
} else if self.executor_modified {
|
||||||
self.executor.rebuild_cached_data(&self.parallel);
|
self.executor.rebuild_cached_data(&self.parallel);
|
||||||
self.executor_modified = false;
|
self.executor_modified = false;
|
||||||
|
|
|
@ -145,12 +145,6 @@ impl<'w, 's> Commands<'w, 's> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns a [`Bundle`] without pre-allocating an [`Entity`]. The [`Entity`] will be allocated
|
|
||||||
/// when this [`Command`] is applied.
|
|
||||||
pub fn spawn_and_forget(&mut self, bundle: impl Bundle) {
|
|
||||||
self.queue.push(Spawn { bundle });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new entity with the components contained in `bundle`.
|
/// Creates a new entity with the components contained in `bundle`.
|
||||||
///
|
///
|
||||||
/// This returns an [`EntityCommands`] builder, which enables inserting more components and
|
/// This returns an [`EntityCommands`] builder, which enables inserting more components and
|
||||||
|
|
|
@ -34,7 +34,7 @@ use bevy_render::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::FallbackImage,
|
texture::FallbackImage,
|
||||||
view::{ExtractedView, Msaa, VisibleEntities},
|
view::{ExtractedView, Msaa, VisibleEntities},
|
||||||
RenderApp, RenderStage,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_utils::{tracing::error, HashMap, HashSet};
|
use bevy_utils::{tracing::error, HashMap, HashSet};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
@ -455,15 +455,15 @@ pub type RenderMaterials<T> = HashMap<Handle<T>, PreparedMaterial<T>>;
|
||||||
/// into the "render world".
|
/// into the "render world".
|
||||||
fn extract_materials<M: Material>(
|
fn extract_materials<M: Material>(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut events: EventReader<AssetEvent<M>>,
|
mut events: Extract<EventReader<AssetEvent<M>>>,
|
||||||
assets: Res<Assets<M>>,
|
assets: Extract<Res<Assets<M>>>,
|
||||||
) {
|
) {
|
||||||
let mut changed_assets = HashSet::default();
|
let mut changed_assets = HashSet::default();
|
||||||
let mut removed = Vec::new();
|
let mut removed = Vec::new();
|
||||||
for event in events.iter() {
|
for event in events.iter() {
|
||||||
match event {
|
match event {
|
||||||
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
||||||
changed_assets.insert(handle);
|
changed_assets.insert(handle.clone_weak());
|
||||||
}
|
}
|
||||||
AssetEvent::Removed { handle } => {
|
AssetEvent::Removed { handle } => {
|
||||||
changed_assets.remove(handle);
|
changed_assets.remove(handle);
|
||||||
|
@ -474,8 +474,8 @@ fn extract_materials<M: Material>(
|
||||||
|
|
||||||
let mut extracted_assets = Vec::new();
|
let mut extracted_assets = Vec::new();
|
||||||
for handle in changed_assets.drain() {
|
for handle in changed_assets.drain() {
|
||||||
if let Some(asset) = assets.get(handle) {
|
if let Some(asset) = assets.get(&handle) {
|
||||||
extracted_assets.push((handle.clone_weak(), asset.clone()));
|
extracted_assets.push((handle, asset.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ use bevy_render::{
|
||||||
view::{
|
view::{
|
||||||
ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility, VisibleEntities,
|
ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility, VisibleEntities,
|
||||||
},
|
},
|
||||||
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::FloatOrd;
|
use bevy_utils::FloatOrd;
|
||||||
|
@ -386,7 +387,10 @@ pub struct ExtractedClustersPointLights {
|
||||||
data: Vec<VisiblePointLights>,
|
data: Vec<VisiblePointLights>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_clusters(mut commands: Commands, views: Query<(Entity, &Clusters), With<Camera>>) {
|
pub fn extract_clusters(
|
||||||
|
mut commands: Commands,
|
||||||
|
views: Extract<Query<(Entity, &Clusters), With<Camera>>>,
|
||||||
|
) {
|
||||||
for (entity, clusters) in views.iter() {
|
for (entity, clusters) in views.iter() {
|
||||||
commands.get_or_spawn(entity).insert_bundle((
|
commands.get_or_spawn(entity).insert_bundle((
|
||||||
ExtractedClustersPointLights {
|
ExtractedClustersPointLights {
|
||||||
|
@ -404,20 +408,22 @@ pub fn extract_clusters(mut commands: Commands, views: Query<(Entity, &Clusters)
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn extract_lights(
|
pub fn extract_lights(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
point_light_shadow_map: Res<PointLightShadowMap>,
|
point_light_shadow_map: Extract<Res<PointLightShadowMap>>,
|
||||||
directional_light_shadow_map: Res<DirectionalLightShadowMap>,
|
directional_light_shadow_map: Extract<Res<DirectionalLightShadowMap>>,
|
||||||
global_point_lights: Res<GlobalVisiblePointLights>,
|
global_point_lights: Extract<Res<GlobalVisiblePointLights>>,
|
||||||
mut point_lights: Query<(&PointLight, &mut CubemapVisibleEntities, &GlobalTransform)>,
|
point_lights: Extract<Query<(&PointLight, &CubemapVisibleEntities, &GlobalTransform)>>,
|
||||||
mut spot_lights: Query<(&SpotLight, &mut VisibleEntities, &GlobalTransform)>,
|
spot_lights: Extract<Query<(&SpotLight, &VisibleEntities, &GlobalTransform)>>,
|
||||||
mut directional_lights: Query<
|
directional_lights: Extract<
|
||||||
(
|
Query<
|
||||||
Entity,
|
(
|
||||||
&DirectionalLight,
|
Entity,
|
||||||
&mut VisibleEntities,
|
&DirectionalLight,
|
||||||
&GlobalTransform,
|
&VisibleEntities,
|
||||||
&Visibility,
|
&GlobalTransform,
|
||||||
),
|
&Visibility,
|
||||||
Without<SpotLight>,
|
),
|
||||||
|
Without<SpotLight>,
|
||||||
|
>,
|
||||||
>,
|
>,
|
||||||
mut previous_point_lights_len: Local<usize>,
|
mut previous_point_lights_len: Local<usize>,
|
||||||
mut previous_spot_lights_len: Local<usize>,
|
mut previous_spot_lights_len: Local<usize>,
|
||||||
|
@ -441,10 +447,10 @@ pub fn extract_lights(
|
||||||
|
|
||||||
let mut point_lights_values = Vec::with_capacity(*previous_point_lights_len);
|
let mut point_lights_values = Vec::with_capacity(*previous_point_lights_len);
|
||||||
for entity in global_point_lights.iter().copied() {
|
for entity in global_point_lights.iter().copied() {
|
||||||
if let Ok((point_light, cubemap_visible_entities, transform)) = point_lights.get_mut(entity)
|
if let Ok((point_light, cubemap_visible_entities, transform)) = point_lights.get(entity) {
|
||||||
{
|
// TODO: This is very much not ideal. We should be able to re-use the vector memory.
|
||||||
let render_cubemap_visible_entities =
|
// However, since exclusive access to the main world in extract is ill-advised, we just clone here.
|
||||||
std::mem::take(cubemap_visible_entities.into_inner());
|
let render_cubemap_visible_entities = cubemap_visible_entities.clone();
|
||||||
point_lights_values.push((
|
point_lights_values.push((
|
||||||
entity,
|
entity,
|
||||||
(
|
(
|
||||||
|
@ -475,8 +481,10 @@ pub fn extract_lights(
|
||||||
|
|
||||||
let mut spot_lights_values = Vec::with_capacity(*previous_spot_lights_len);
|
let mut spot_lights_values = Vec::with_capacity(*previous_spot_lights_len);
|
||||||
for entity in global_point_lights.iter().copied() {
|
for entity in global_point_lights.iter().copied() {
|
||||||
if let Ok((spot_light, visible_entities, transform)) = spot_lights.get_mut(entity) {
|
if let Ok((spot_light, visible_entities, transform)) = spot_lights.get(entity) {
|
||||||
let render_visible_entities = std::mem::take(visible_entities.into_inner());
|
// TODO: This is very much not ideal. We should be able to re-use the vector memory.
|
||||||
|
// However, since exclusive access to the main world in extract is ill-advised, we just clone here.
|
||||||
|
let render_visible_entities = visible_entities.clone();
|
||||||
let texel_size =
|
let texel_size =
|
||||||
2.0 * spot_light.outer_angle.tan() / directional_light_shadow_map.size as f32;
|
2.0 * spot_light.outer_angle.tan() / directional_light_shadow_map.size as f32;
|
||||||
|
|
||||||
|
@ -512,7 +520,7 @@ pub fn extract_lights(
|
||||||
commands.insert_or_spawn_batch(spot_lights_values);
|
commands.insert_or_spawn_batch(spot_lights_values);
|
||||||
|
|
||||||
for (entity, directional_light, visible_entities, transform, visibility) in
|
for (entity, directional_light, visible_entities, transform, visibility) in
|
||||||
directional_lights.iter_mut()
|
directional_lights.iter()
|
||||||
{
|
{
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
continue;
|
continue;
|
||||||
|
@ -530,7 +538,8 @@ pub fn extract_lights(
|
||||||
);
|
);
|
||||||
let directional_light_texel_size =
|
let directional_light_texel_size =
|
||||||
largest_dimension / directional_light_shadow_map.size as f32;
|
largest_dimension / directional_light_shadow_map.size as f32;
|
||||||
let render_visible_entities = std::mem::take(visible_entities.into_inner());
|
// TODO: As above
|
||||||
|
let render_visible_entities = visible_entities.clone();
|
||||||
commands.get_or_spawn(entity).insert_bundle((
|
commands.get_or_spawn(entity).insert_bundle((
|
||||||
ExtractedDirectionalLight {
|
ExtractedDirectionalLight {
|
||||||
color: directional_light.color,
|
color: directional_light.color,
|
||||||
|
|
|
@ -25,7 +25,7 @@ use bevy_render::{
|
||||||
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
||||||
},
|
},
|
||||||
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms},
|
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms},
|
||||||
RenderApp, RenderStage,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
|
@ -118,14 +118,16 @@ pub fn extract_meshes(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut prev_caster_commands_len: Local<usize>,
|
mut prev_caster_commands_len: Local<usize>,
|
||||||
mut prev_not_caster_commands_len: Local<usize>,
|
mut prev_not_caster_commands_len: Local<usize>,
|
||||||
meshes_query: Query<(
|
meshes_query: Extract<
|
||||||
Entity,
|
Query<(
|
||||||
&ComputedVisibility,
|
Entity,
|
||||||
&GlobalTransform,
|
&ComputedVisibility,
|
||||||
&Handle<Mesh>,
|
&GlobalTransform,
|
||||||
Option<With<NotShadowReceiver>>,
|
&Handle<Mesh>,
|
||||||
Option<With<NotShadowCaster>>,
|
Option<With<NotShadowReceiver>>,
|
||||||
)>,
|
Option<With<NotShadowCaster>>,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
let mut caster_commands = Vec::with_capacity(*prev_caster_commands_len);
|
let mut caster_commands = Vec::with_capacity(*prev_caster_commands_len);
|
||||||
let mut not_caster_commands = Vec::with_capacity(*prev_not_caster_commands_len);
|
let mut not_caster_commands = Vec::with_capacity(*prev_not_caster_commands_len);
|
||||||
|
@ -202,12 +204,12 @@ impl SkinnedMeshJoints {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_skinned_meshes(
|
pub fn extract_skinned_meshes(
|
||||||
query: Query<(Entity, &ComputedVisibility, &SkinnedMesh)>,
|
|
||||||
inverse_bindposes: Res<Assets<SkinnedMeshInverseBindposes>>,
|
|
||||||
joint_query: Query<&GlobalTransform>,
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut previous_len: Local<usize>,
|
mut previous_len: Local<usize>,
|
||||||
mut previous_joint_len: Local<usize>,
|
mut previous_joint_len: Local<usize>,
|
||||||
|
query: Extract<Query<(Entity, &ComputedVisibility, &SkinnedMesh)>>,
|
||||||
|
inverse_bindposes: Extract<Res<Assets<SkinnedMeshInverseBindposes>>>,
|
||||||
|
joint_query: Extract<Query<&GlobalTransform>>,
|
||||||
) {
|
) {
|
||||||
let mut values = Vec::with_capacity(*previous_len);
|
let mut values = Vec::with_capacity(*previous_len);
|
||||||
let mut joints = Vec::with_capacity(*previous_joint_len);
|
let mut joints = Vec::with_capacity(*previous_joint_len);
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_resource::TextureView,
|
render_resource::TextureView,
|
||||||
view::{ExtractedView, ExtractedWindows, VisibleEntities},
|
view::{ExtractedView, ExtractedWindows, VisibleEntities},
|
||||||
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
|
@ -393,13 +394,15 @@ pub struct ExtractedCamera {
|
||||||
|
|
||||||
pub fn extract_cameras(
|
pub fn extract_cameras(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query: Query<(
|
query: Extract<
|
||||||
Entity,
|
Query<(
|
||||||
&Camera,
|
Entity,
|
||||||
&CameraRenderGraph,
|
&Camera,
|
||||||
&GlobalTransform,
|
&CameraRenderGraph,
|
||||||
&VisibleEntities,
|
&GlobalTransform,
|
||||||
)>,
|
&VisibleEntities,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
for (entity, camera, camera_render_graph, transform, visible_entities) in query.iter() {
|
for (entity, camera, camera_render_graph, transform, visible_entities) in query.iter() {
|
||||||
if !camera.is_active {
|
if !camera.is_active {
|
||||||
|
|
|
@ -2,15 +2,15 @@ use crate::{
|
||||||
render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType},
|
render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
view::ComputedVisibility,
|
view::ComputedVisibility,
|
||||||
RenderApp, RenderStage,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{Asset, Handle};
|
use bevy_asset::{Asset, Handle};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
query::{QueryItem, WorldQuery},
|
query::{QueryItem, ReadOnlyWorldQuery, WorldQuery},
|
||||||
system::{lifetimeless::Read, StaticSystemParam},
|
system::lifetimeless::Read,
|
||||||
};
|
};
|
||||||
use std::{marker::PhantomData, ops::Deref};
|
use std::{marker::PhantomData, ops::Deref};
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ impl<C: Component> DynamicUniformIndex<C> {
|
||||||
/// in the [`RenderStage::Extract`](crate::RenderStage::Extract) step.
|
/// in the [`RenderStage::Extract`](crate::RenderStage::Extract) step.
|
||||||
pub trait ExtractComponent: Component {
|
pub trait ExtractComponent: Component {
|
||||||
/// ECS [`WorldQuery`] to fetch the components to extract.
|
/// ECS [`WorldQuery`] to fetch the components to extract.
|
||||||
type Query: WorldQuery;
|
type Query: WorldQuery + ReadOnlyWorldQuery;
|
||||||
/// Filters the entities with additional constraints.
|
/// Filters the entities with additional constraints.
|
||||||
type Filter: WorldQuery;
|
type Filter: WorldQuery + ReadOnlyWorldQuery;
|
||||||
/// Defines how the component is transferred into the "render world".
|
/// Defines how the component is transferred into the "render world".
|
||||||
fn extract_component(item: QueryItem<Self::Query>) -> Self;
|
fn extract_component(item: QueryItem<Self::Query>) -> Self;
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ impl<T: Asset> ExtractComponent for Handle<T> {
|
||||||
fn extract_components<C: ExtractComponent>(
|
fn extract_components<C: ExtractComponent>(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut previous_len: Local<usize>,
|
mut previous_len: Local<usize>,
|
||||||
mut query: StaticSystemParam<Query<(Entity, C::Query), C::Filter>>,
|
mut query: Extract<Query<(Entity, C::Query), C::Filter>>,
|
||||||
) {
|
) {
|
||||||
let mut values = Vec::with_capacity(*previous_len);
|
let mut values = Vec::with_capacity(*previous_len);
|
||||||
for (entity, query_item) in query.iter_mut() {
|
for (entity, query_item) in query.iter_mut() {
|
||||||
|
@ -196,7 +196,7 @@ fn extract_components<C: ExtractComponent>(
|
||||||
fn extract_visible_components<C: ExtractComponent>(
|
fn extract_visible_components<C: ExtractComponent>(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut previous_len: Local<usize>,
|
mut previous_len: Local<usize>,
|
||||||
mut query: StaticSystemParam<Query<(Entity, Read<ComputedVisibility>, C::Query), C::Filter>>,
|
mut query: Extract<Query<(Entity, &ComputedVisibility, C::Query), C::Filter>>,
|
||||||
) {
|
) {
|
||||||
let mut values = Vec::with_capacity(*previous_len);
|
let mut values = Vec::with_capacity(*previous_len);
|
||||||
for (entity, computed_visibility, query_item) in query.iter_mut() {
|
for (entity, computed_visibility, query_item) in query.iter_mut() {
|
||||||
|
|
120
crates/bevy_render/src/extract_param.rs
Normal file
120
crates/bevy_render/src/extract_param.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
use crate::MainWorld;
|
||||||
|
use bevy_ecs::{
|
||||||
|
prelude::*,
|
||||||
|
system::{
|
||||||
|
ReadOnlySystemParamFetch, ResState, SystemMeta, SystemParam, SystemParamFetch,
|
||||||
|
SystemParamState, SystemState,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
/// A helper for accessing [`MainWorld`] content using a system parameter.
|
||||||
|
///
|
||||||
|
/// A [`SystemParam`] adapter which applies the contained `SystemParam` to the [`World`]
|
||||||
|
/// contained in [`MainWorld`]. This parameter only works for systems run
|
||||||
|
/// during [`RenderStage::Extract`].
|
||||||
|
///
|
||||||
|
/// This requires that the contained [`SystemParam`] does not mutate the world, as it
|
||||||
|
/// uses a read-only reference to [`MainWorld`] internally.
|
||||||
|
///
|
||||||
|
/// ## Context
|
||||||
|
///
|
||||||
|
/// [`RenderStage::Extract`] is used to extract (move) data from the simulation world ([`MainWorld`]) to the
|
||||||
|
/// render world. The render world drives rendering each frame (generally to a [Window]).
|
||||||
|
/// This design is used to allow performing calculations related to rendering a prior frame at the same
|
||||||
|
/// time as the next frame is simulated, which increases throughput (FPS).
|
||||||
|
///
|
||||||
|
/// [`Extract`] is used to get data from the main world during [`RenderStage::Extract`].
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use bevy_ecs::prelude::*;
|
||||||
|
/// use bevy_render::Extract;
|
||||||
|
/// # #[derive(Component)]
|
||||||
|
/// # struct Cloud;
|
||||||
|
/// fn extract_clouds(mut commands: Commands, clouds: Extract<Query<Entity, With<Cloud>>>) {
|
||||||
|
/// for cloud in clouds.iter() {
|
||||||
|
/// commands.get_or_spawn(cloud).insert(Cloud);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`RenderStage::Extract`]: crate::RenderStage::Extract
|
||||||
|
/// [Window]: bevy_window::Window
|
||||||
|
pub struct Extract<'w, 's, P: SystemParam + 'static>
|
||||||
|
where
|
||||||
|
P::Fetch: ReadOnlySystemParamFetch,
|
||||||
|
{
|
||||||
|
item: <P::Fetch as SystemParamFetch<'w, 's>>::Item,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'w, 's, P: SystemParam> SystemParam for Extract<'w, 's, P>
|
||||||
|
where
|
||||||
|
P::Fetch: ReadOnlySystemParamFetch,
|
||||||
|
{
|
||||||
|
type Fetch = ExtractState<P>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct ExtractState<P: SystemParam> {
|
||||||
|
state: SystemState<P>,
|
||||||
|
main_world_state: ResState<MainWorld>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: only accesses MainWorld resource with read only system params using ResState,
|
||||||
|
// which is initialized in init()
|
||||||
|
unsafe impl<P: SystemParam + 'static> SystemParamState for ExtractState<P> {
|
||||||
|
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
|
||||||
|
let mut main_world = world.resource_mut::<MainWorld>();
|
||||||
|
Self {
|
||||||
|
state: SystemState::new(&mut main_world),
|
||||||
|
main_world_state: ResState::init(world, system_meta),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'w, 's, P: SystemParam + 'static> SystemParamFetch<'w, 's> for ExtractState<P>
|
||||||
|
where
|
||||||
|
P::Fetch: ReadOnlySystemParamFetch,
|
||||||
|
{
|
||||||
|
type Item = Extract<'w, 's, P>;
|
||||||
|
|
||||||
|
unsafe fn get_param(
|
||||||
|
state: &'s mut Self,
|
||||||
|
system_meta: &SystemMeta,
|
||||||
|
world: &'w World,
|
||||||
|
change_tick: u32,
|
||||||
|
) -> Self::Item {
|
||||||
|
let main_world = ResState::<MainWorld>::get_param(
|
||||||
|
&mut state.main_world_state,
|
||||||
|
system_meta,
|
||||||
|
world,
|
||||||
|
change_tick,
|
||||||
|
);
|
||||||
|
let item = state.state.get(main_world.into_inner());
|
||||||
|
Extract { item }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'w, 's, P: SystemParam> Deref for Extract<'w, 's, P>
|
||||||
|
where
|
||||||
|
P::Fetch: ReadOnlySystemParamFetch,
|
||||||
|
{
|
||||||
|
type Target = <P::Fetch as SystemParamFetch<'w, 's>>::Item;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'w, 's, P: SystemParam> DerefMut for Extract<'w, 's, P>
|
||||||
|
where
|
||||||
|
P::Fetch: ReadOnlySystemParamFetch,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.item
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::system::{Commands, Res, Resource};
|
use bevy_ecs::system::{Commands, Res, Resource};
|
||||||
pub use bevy_render_macros::ExtractResource;
|
pub use bevy_render_macros::ExtractResource;
|
||||||
|
|
||||||
use crate::{RenderApp, RenderStage};
|
use crate::{Extract, RenderApp, RenderStage};
|
||||||
|
|
||||||
/// Describes how a resource gets extracted for rendering.
|
/// Describes how a resource gets extracted for rendering.
|
||||||
///
|
///
|
||||||
|
@ -39,8 +39,11 @@ impl<R: ExtractResource> Plugin for ExtractResourcePlugin<R> {
|
||||||
|
|
||||||
/// This system extracts the resource of the corresponding [`Resource`] type
|
/// This system extracts the resource of the corresponding [`Resource`] type
|
||||||
/// by cloning it.
|
/// by cloning it.
|
||||||
pub fn extract_resource<R: ExtractResource>(mut commands: Commands, resource: Res<R::Source>) {
|
pub fn extract_resource<R: ExtractResource>(
|
||||||
|
mut commands: Commands,
|
||||||
|
resource: Extract<Res<R::Source>>,
|
||||||
|
) {
|
||||||
if resource.is_changed() {
|
if resource.is_changed() {
|
||||||
commands.insert_resource(R::extract_resource(resource.into_inner()));
|
commands.insert_resource(R::extract_resource(&*resource));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ extern crate core;
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod extract_component;
|
pub mod extract_component;
|
||||||
|
mod extract_param;
|
||||||
pub mod extract_resource;
|
pub mod extract_resource;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
|
@ -16,6 +17,8 @@ pub mod settings;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
pub mod view;
|
pub mod view;
|
||||||
|
|
||||||
|
pub use extract_param::Extract;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
|
@ -45,7 +48,10 @@ use bevy_app::{App, AppLabel, Plugin};
|
||||||
use bevy_asset::{AddAsset, AssetServer};
|
use bevy_asset::{AddAsset, AssetServer};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_utils::tracing::debug;
|
use bevy_utils::tracing::debug;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
/// Contains the default Bevy rendering backend based on wgpu.
|
/// Contains the default Bevy rendering backend based on wgpu.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -79,11 +85,14 @@ pub enum RenderStage {
|
||||||
Cleanup,
|
Cleanup,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Render App World. This is only available as a resource during the Extract step.
|
/// The simulation [`World`] of the application, stored as a resource.
|
||||||
|
/// This resource is only available during [`RenderStage::Extract`] and not
|
||||||
|
/// during command application of that stage.
|
||||||
|
/// See [`Extract`] for more details.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RenderWorld(World);
|
pub struct MainWorld(World);
|
||||||
|
|
||||||
impl Deref for RenderWorld {
|
impl Deref for MainWorld {
|
||||||
type Target = World;
|
type Target = World;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
@ -91,7 +100,7 @@ impl Deref for RenderWorld {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for RenderWorld {
|
impl DerefMut for MainWorld {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
|
@ -107,11 +116,6 @@ pub mod main_graph {
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)]
|
||||||
pub struct RenderApp;
|
pub struct RenderApp;
|
||||||
|
|
||||||
/// A "scratch" world used to avoid allocating new worlds every frame when
|
|
||||||
/// swapping out the [`RenderWorld`].
|
|
||||||
#[derive(Default)]
|
|
||||||
struct ScratchRenderWorld(World);
|
|
||||||
|
|
||||||
impl Plugin for RenderPlugin {
|
impl Plugin for RenderPlugin {
|
||||||
/// Initializes the renderer, sets up the [`RenderStage`](RenderStage) and creates the rendering sub-app.
|
/// Initializes the renderer, sets up the [`RenderStage`](RenderStage) and creates the rendering sub-app.
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
|
@ -150,7 +154,7 @@ impl Plugin for RenderPlugin {
|
||||||
app.insert_resource(device.clone())
|
app.insert_resource(device.clone())
|
||||||
.insert_resource(queue.clone())
|
.insert_resource(queue.clone())
|
||||||
.insert_resource(adapter_info.clone())
|
.insert_resource(adapter_info.clone())
|
||||||
.init_resource::<ScratchRenderWorld>()
|
.init_resource::<ScratchMainWorld>()
|
||||||
.register_type::<Frustum>()
|
.register_type::<Frustum>()
|
||||||
.register_type::<CubemapFrusta>();
|
.register_type::<CubemapFrusta>();
|
||||||
|
|
||||||
|
@ -160,8 +164,20 @@ impl Plugin for RenderPlugin {
|
||||||
let mut render_app = App::empty();
|
let mut render_app = App::empty();
|
||||||
let mut extract_stage =
|
let mut extract_stage =
|
||||||
SystemStage::parallel().with_system(PipelineCache::extract_shaders);
|
SystemStage::parallel().with_system(PipelineCache::extract_shaders);
|
||||||
|
// Get the ComponentId for MainWorld. This does technically 'waste' a `WorldId`, but that's probably fine
|
||||||
|
render_app.init_resource::<MainWorld>();
|
||||||
|
render_app.world.remove_resource::<MainWorld>();
|
||||||
|
let main_world_in_render = render_app
|
||||||
|
.world
|
||||||
|
.components()
|
||||||
|
.get_resource_id(TypeId::of::<MainWorld>());
|
||||||
|
// `Extract` systems must read from the main world. We want to emit an error when that doesn't occur
|
||||||
|
// Safe to unwrap: Ensured it existed just above
|
||||||
|
extract_stage.set_must_read_resource(main_world_in_render.unwrap());
|
||||||
// don't apply buffers when the stage finishes running
|
// don't apply buffers when the stage finishes running
|
||||||
// extract stage runs on the app world, but the buffers are applied to the render world
|
// extract stage runs on the render world, but buffers are applied
|
||||||
|
// after access to the main world is removed
|
||||||
|
// See also https://github.com/bevyengine/bevy/issues/5082
|
||||||
extract_stage.set_apply_buffers(false);
|
extract_stage.set_apply_buffers(false);
|
||||||
render_app
|
render_app
|
||||||
.add_stage(RenderStage::Extract, extract_stage)
|
.add_stage(RenderStage::Extract, extract_stage)
|
||||||
|
@ -300,6 +316,11 @@ impl Plugin for RenderPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A "scratch" world used to avoid allocating new worlds every frame when
|
||||||
|
/// swapping out the [`MainWorld`] for [`RenderStage::Extract`].
|
||||||
|
#[derive(Default)]
|
||||||
|
struct ScratchMainWorld(World);
|
||||||
|
|
||||||
/// Executes the [`Extract`](RenderStage::Extract) stage of the renderer.
|
/// Executes the [`Extract`](RenderStage::Extract) stage of the renderer.
|
||||||
/// This updates the render world with the extracted ECS data of the current frame.
|
/// This updates the render world with the extracted ECS data of the current frame.
|
||||||
fn extract(app_world: &mut World, render_app: &mut App) {
|
fn extract(app_world: &mut World, render_app: &mut App) {
|
||||||
|
@ -308,17 +329,20 @@ fn extract(app_world: &mut World, render_app: &mut App) {
|
||||||
.get_stage_mut::<SystemStage>(&RenderStage::Extract)
|
.get_stage_mut::<SystemStage>(&RenderStage::Extract)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// temporarily add the render world to the app world as a resource
|
// temporarily add the app world to the render world as a resource
|
||||||
let scratch_world = app_world.remove_resource::<ScratchRenderWorld>().unwrap();
|
let scratch_world = app_world.remove_resource::<ScratchMainWorld>().unwrap();
|
||||||
let render_world = std::mem::replace(&mut render_app.world, scratch_world.0);
|
let inserted_world = std::mem::replace(app_world, scratch_world.0);
|
||||||
app_world.insert_resource(RenderWorld(render_world));
|
let running_world = &mut render_app.world;
|
||||||
|
running_world.insert_resource(MainWorld(inserted_world));
|
||||||
|
|
||||||
extract.run(app_world);
|
extract.run(running_world);
|
||||||
|
// move the app world back, as if nothing happened.
|
||||||
|
let inserted_world = running_world.remove_resource::<MainWorld>().unwrap();
|
||||||
|
let scratch_world = std::mem::replace(app_world, inserted_world.0);
|
||||||
|
app_world.insert_resource(ScratchMainWorld(scratch_world));
|
||||||
|
|
||||||
// add the render world back to the render app
|
// Note: We apply buffers (read, Commands) after the `MainWorld` has been removed from the render app's world
|
||||||
let render_world = app_world.remove_resource::<RenderWorld>().unwrap();
|
// so that in future, pipelining will be able to do this too without any code relying on it.
|
||||||
let scratch_world = std::mem::replace(&mut render_app.world, render_world.0);
|
// see <https://github.com/bevyengine/bevy/issues/5082>
|
||||||
app_world.insert_resource(ScratchRenderWorld(scratch_world));
|
extract.apply_buffers(running_world);
|
||||||
|
|
||||||
extract.apply_buffers(&mut render_app.world);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{RenderApp, RenderStage};
|
use crate::{Extract, RenderApp, RenderStage};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
|
@ -123,15 +123,15 @@ pub type RenderAssets<A> = HashMap<Handle<A>, <A as RenderAsset>::PreparedAsset>
|
||||||
/// into the "render world".
|
/// into the "render world".
|
||||||
fn extract_render_asset<A: RenderAsset>(
|
fn extract_render_asset<A: RenderAsset>(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut events: EventReader<AssetEvent<A>>,
|
mut events: Extract<EventReader<AssetEvent<A>>>,
|
||||||
assets: Res<Assets<A>>,
|
assets: Extract<Res<Assets<A>>>,
|
||||||
) {
|
) {
|
||||||
let mut changed_assets = HashSet::default();
|
let mut changed_assets = HashSet::default();
|
||||||
let mut removed = Vec::new();
|
let mut removed = Vec::new();
|
||||||
for event in events.iter() {
|
for event in events.iter() {
|
||||||
match event {
|
match event {
|
||||||
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
||||||
changed_assets.insert(handle);
|
changed_assets.insert(handle.clone_weak());
|
||||||
}
|
}
|
||||||
AssetEvent::Removed { handle } => {
|
AssetEvent::Removed { handle } => {
|
||||||
changed_assets.remove(handle);
|
changed_assets.remove(handle);
|
||||||
|
@ -142,8 +142,8 @@ fn extract_render_asset<A: RenderAsset>(
|
||||||
|
|
||||||
let mut extracted_assets = Vec::new();
|
let mut extracted_assets = Vec::new();
|
||||||
for handle in changed_assets.drain() {
|
for handle in changed_assets.drain() {
|
||||||
if let Some(asset) = assets.get(handle) {
|
if let Some(asset) = assets.get(&handle) {
|
||||||
extracted_assets.push((handle.clone_weak(), asset.extract_asset()));
|
extracted_assets.push((handle, asset.extract_asset()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
ShaderProcessor, ShaderReflectError,
|
ShaderProcessor, ShaderReflectError,
|
||||||
},
|
},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
RenderWorld,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||||
use bevy_ecs::event::EventReader;
|
use bevy_ecs::event::EventReader;
|
||||||
|
@ -546,11 +546,10 @@ impl PipelineCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn extract_shaders(
|
pub(crate) fn extract_shaders(
|
||||||
mut world: ResMut<RenderWorld>,
|
mut cache: ResMut<Self>,
|
||||||
shaders: Res<Assets<Shader>>,
|
shaders: Extract<Res<Assets<Shader>>>,
|
||||||
mut events: EventReader<AssetEvent<Shader>>,
|
mut events: Extract<EventReader<AssetEvent<Shader>>>,
|
||||||
) {
|
) {
|
||||||
let mut cache = world.resource_mut::<Self>();
|
|
||||||
for event in events.iter() {
|
for event in events.iter() {
|
||||||
match event {
|
match event {
|
||||||
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
render_resource::TextureView,
|
render_resource::TextureView,
|
||||||
renderer::{RenderDevice, RenderInstance},
|
renderer::{RenderDevice, RenderInstance},
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
RenderApp, RenderStage, RenderWorld,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -68,11 +68,10 @@ impl DerefMut for ExtractedWindows {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_windows(
|
fn extract_windows(
|
||||||
mut render_world: ResMut<RenderWorld>,
|
mut extracted_windows: ResMut<ExtractedWindows>,
|
||||||
mut closed: EventReader<WindowClosed>,
|
mut closed: Extract<EventReader<WindowClosed>>,
|
||||||
windows: Res<Windows>,
|
windows: Extract<Res<Windows>>,
|
||||||
) {
|
) {
|
||||||
let mut extracted_windows = render_world.get_resource_mut::<ExtractedWindows>().unwrap();
|
|
||||||
for window in windows.iter() {
|
for window in windows.iter() {
|
||||||
let (new_width, new_height) = (
|
let (new_width, new_height) = (
|
||||||
window.physical_width().max(1),
|
window.physical_width().max(1),
|
||||||
|
|
|
@ -17,7 +17,7 @@ use bevy_render::{
|
||||||
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
BevyDefault, DefaultImageSampler, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
||||||
},
|
},
|
||||||
view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms},
|
view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms},
|
||||||
RenderApp, RenderStage,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ bitflags::bitflags! {
|
||||||
pub fn extract_mesh2d(
|
pub fn extract_mesh2d(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut previous_len: Local<usize>,
|
mut previous_len: Local<usize>,
|
||||||
query: Query<(Entity, &ComputedVisibility, &GlobalTransform, &Mesh2dHandle)>,
|
query: Extract<Query<(Entity, &ComputedVisibility, &GlobalTransform, &Mesh2dHandle)>>,
|
||||||
) {
|
) {
|
||||||
let mut values = Vec::with_capacity(*previous_len);
|
let mut values = Vec::with_capacity(*previous_len);
|
||||||
for (entity, computed_visibility, transform, handle) in query.iter() {
|
for (entity, computed_visibility, transform, handle) in query.iter() {
|
||||||
|
|
|
@ -23,7 +23,7 @@ use bevy_render::{
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
texture::{BevyDefault, Image},
|
texture::{BevyDefault, Image},
|
||||||
view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility},
|
view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility},
|
||||||
RenderWorld,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::FloatOrd;
|
use bevy_utils::FloatOrd;
|
||||||
|
@ -197,10 +197,9 @@ pub struct SpriteAssetEvents {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_sprite_events(
|
pub fn extract_sprite_events(
|
||||||
mut render_world: ResMut<RenderWorld>,
|
mut events: ResMut<SpriteAssetEvents>,
|
||||||
mut image_events: EventReader<AssetEvent<Image>>,
|
mut image_events: Extract<EventReader<AssetEvent<Image>>>,
|
||||||
) {
|
) {
|
||||||
let mut events = render_world.resource_mut::<SpriteAssetEvents>();
|
|
||||||
let SpriteAssetEvents { ref mut images } = *events;
|
let SpriteAssetEvents { ref mut images } = *events;
|
||||||
images.clear();
|
images.clear();
|
||||||
|
|
||||||
|
@ -221,17 +220,18 @@ pub fn extract_sprite_events(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_sprites(
|
pub fn extract_sprites(
|
||||||
mut render_world: ResMut<RenderWorld>,
|
mut extracted_sprites: ResMut<ExtractedSprites>,
|
||||||
texture_atlases: Res<Assets<TextureAtlas>>,
|
texture_atlases: Extract<Res<Assets<TextureAtlas>>>,
|
||||||
sprite_query: Query<(&Visibility, &Sprite, &GlobalTransform, &Handle<Image>)>,
|
sprite_query: Extract<Query<(&Visibility, &Sprite, &GlobalTransform, &Handle<Image>)>>,
|
||||||
atlas_query: Query<(
|
atlas_query: Extract<
|
||||||
&Visibility,
|
Query<(
|
||||||
&TextureAtlasSprite,
|
&Visibility,
|
||||||
&GlobalTransform,
|
&TextureAtlasSprite,
|
||||||
&Handle<TextureAtlas>,
|
&GlobalTransform,
|
||||||
)>,
|
&Handle<TextureAtlas>,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
let mut extracted_sprites = render_world.resource_mut::<ExtractedSprites>();
|
|
||||||
extracted_sprites.sprites.clear();
|
extracted_sprites.sprites.clear();
|
||||||
for (visibility, sprite, transform, handle) in sprite_query.iter() {
|
for (visibility, sprite, transform, handle) in sprite_query.iter() {
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use bevy_ecs::{
|
||||||
};
|
};
|
||||||
use bevy_math::{Vec2, Vec3};
|
use bevy_math::{Vec2, Vec3};
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_render::{texture::Image, view::Visibility, RenderWorld};
|
use bevy_render::{texture::Image, view::Visibility, Extract};
|
||||||
use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas};
|
use bevy_sprite::{Anchor, ExtractedSprite, ExtractedSprites, TextureAtlas};
|
||||||
use bevy_transform::prelude::{GlobalTransform, Transform};
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
use bevy_utils::HashSet;
|
use bevy_utils::HashSet;
|
||||||
|
@ -61,16 +61,13 @@ pub struct Text2dBundle {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_text2d_sprite(
|
pub fn extract_text2d_sprite(
|
||||||
mut render_world: ResMut<RenderWorld>,
|
mut extracted_sprites: ResMut<ExtractedSprites>,
|
||||||
texture_atlases: Res<Assets<TextureAtlas>>,
|
texture_atlases: Extract<Res<Assets<TextureAtlas>>>,
|
||||||
text_pipeline: Res<DefaultTextPipeline>,
|
text_pipeline: Extract<Res<DefaultTextPipeline>>,
|
||||||
windows: Res<Windows>,
|
windows: Extract<Res<Windows>>,
|
||||||
text2d_query: Query<(Entity, &Visibility, &Text, &GlobalTransform, &Text2dSize)>,
|
text2d_query: Extract<Query<(Entity, &Visibility, &Text, &GlobalTransform, &Text2dSize)>>,
|
||||||
) {
|
) {
|
||||||
let mut extracted_sprites = render_world.resource_mut::<ExtractedSprites>();
|
|
||||||
|
|
||||||
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
||||||
|
|
||||||
for (entity, visibility, text, transform, calculated_size) in text2d_query.iter() {
|
for (entity, visibility, text, transform, calculated_size) in text2d_query.iter() {
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -21,7 +21,7 @@ use bevy_render::{
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
texture::Image,
|
texture::Image,
|
||||||
view::{ExtractedView, ViewUniforms, Visibility},
|
view::{ExtractedView, ViewUniforms, Visibility},
|
||||||
RenderApp, RenderStage, RenderWorld,
|
Extract, RenderApp, RenderStage,
|
||||||
};
|
};
|
||||||
use bevy_sprite::{Rect, SpriteAssetEvents, TextureAtlas};
|
use bevy_sprite::{Rect, SpriteAssetEvents, TextureAtlas};
|
||||||
use bevy_text::{DefaultTextPipeline, Text};
|
use bevy_text::{DefaultTextPipeline, Text};
|
||||||
|
@ -174,18 +174,19 @@ pub struct ExtractedUiNodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_uinodes(
|
pub fn extract_uinodes(
|
||||||
mut render_world: ResMut<RenderWorld>,
|
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
|
||||||
images: Res<Assets<Image>>,
|
images: Extract<Res<Assets<Image>>>,
|
||||||
uinode_query: Query<(
|
uinode_query: Extract<
|
||||||
&Node,
|
Query<(
|
||||||
&GlobalTransform,
|
&Node,
|
||||||
&UiColor,
|
&GlobalTransform,
|
||||||
&UiImage,
|
&UiColor,
|
||||||
&Visibility,
|
&UiImage,
|
||||||
Option<&CalculatedClip>,
|
&Visibility,
|
||||||
)>,
|
Option<&CalculatedClip>,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
let mut extracted_uinodes = render_world.resource_mut::<ExtractedUiNodes>();
|
|
||||||
extracted_uinodes.uinodes.clear();
|
extracted_uinodes.uinodes.clear();
|
||||||
for (uinode, transform, color, image, visibility, clip) in uinode_query.iter() {
|
for (uinode, transform, color, image, visibility, clip) in uinode_query.iter() {
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
|
@ -226,8 +227,7 @@ pub struct DefaultCameraView(pub Entity);
|
||||||
|
|
||||||
pub fn extract_default_ui_camera_view<T: Component>(
|
pub fn extract_default_ui_camera_view<T: Component>(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
render_world: Res<RenderWorld>,
|
query: Extract<Query<(Entity, &Camera, Option<&UiCameraConfig>), With<T>>>,
|
||||||
query: Query<(Entity, &Camera, Option<&UiCameraConfig>), With<T>>,
|
|
||||||
) {
|
) {
|
||||||
for (entity, camera, camera_ui) in query.iter() {
|
for (entity, camera, camera_ui) in query.iter() {
|
||||||
// ignore cameras with disabled ui
|
// ignore cameras with disabled ui
|
||||||
|
@ -245,10 +245,8 @@ pub fn extract_default_ui_camera_view<T: Component>(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
projection.update(logical_size.x, logical_size.y);
|
projection.update(logical_size.x, logical_size.y);
|
||||||
// This roundabout approach is required because spawn().id() won't work in this context
|
let default_camera_view = commands
|
||||||
let default_camera_view = render_world.entities().reserve_entity();
|
.spawn()
|
||||||
commands
|
|
||||||
.get_or_spawn(default_camera_view)
|
|
||||||
.insert(ExtractedView {
|
.insert(ExtractedView {
|
||||||
projection: projection.get_projection_matrix(),
|
projection: projection.get_projection_matrix(),
|
||||||
transform: GlobalTransform::from_xyz(
|
transform: GlobalTransform::from_xyz(
|
||||||
|
@ -258,7 +256,8 @@ pub fn extract_default_ui_camera_view<T: Component>(
|
||||||
),
|
),
|
||||||
width: physical_size.x,
|
width: physical_size.x,
|
||||||
height: physical_size.y,
|
height: physical_size.y,
|
||||||
});
|
})
|
||||||
|
.id();
|
||||||
commands.get_or_spawn(entity).insert_bundle((
|
commands.get_or_spawn(entity).insert_bundle((
|
||||||
DefaultCameraView(default_camera_view),
|
DefaultCameraView(default_camera_view),
|
||||||
RenderPhase::<TransparentUi>::default(),
|
RenderPhase::<TransparentUi>::default(),
|
||||||
|
@ -268,23 +267,22 @@ pub fn extract_default_ui_camera_view<T: Component>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_text_uinodes(
|
pub fn extract_text_uinodes(
|
||||||
mut render_world: ResMut<RenderWorld>,
|
mut extracted_uinodes: ResMut<ExtractedUiNodes>,
|
||||||
texture_atlases: Res<Assets<TextureAtlas>>,
|
texture_atlases: Extract<Res<Assets<TextureAtlas>>>,
|
||||||
text_pipeline: Res<DefaultTextPipeline>,
|
text_pipeline: Extract<Res<DefaultTextPipeline>>,
|
||||||
windows: Res<Windows>,
|
windows: Extract<Res<Windows>>,
|
||||||
uinode_query: Query<(
|
uinode_query: Extract<
|
||||||
Entity,
|
Query<(
|
||||||
&Node,
|
Entity,
|
||||||
&GlobalTransform,
|
&Node,
|
||||||
&Text,
|
&GlobalTransform,
|
||||||
&Visibility,
|
&Text,
|
||||||
Option<&CalculatedClip>,
|
&Visibility,
|
||||||
)>,
|
Option<&CalculatedClip>,
|
||||||
|
)>,
|
||||||
|
>,
|
||||||
) {
|
) {
|
||||||
let mut extracted_uinodes = render_world.resource_mut::<ExtractedUiNodes>();
|
|
||||||
|
|
||||||
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
||||||
|
|
||||||
for (entity, uinode, transform, text, visibility, clip) in uinode_query.iter() {
|
for (entity, uinode, transform, text, visibility, clip) in uinode_query.iter() {
|
||||||
if !visibility.is_visible {
|
if !visibility.is_visible {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -19,7 +19,7 @@ use bevy::{
|
||||||
},
|
},
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
view::VisibleEntities,
|
view::VisibleEntities,
|
||||||
RenderApp, RenderStage,
|
Extract, RenderApp, RenderStage,
|
||||||
},
|
},
|
||||||
sprite::{
|
sprite::{
|
||||||
DrawMesh2d, Mesh2dHandle, Mesh2dPipeline, Mesh2dPipelineKey, Mesh2dUniform,
|
DrawMesh2d, Mesh2dHandle, Mesh2dPipeline, Mesh2dPipelineKey, Mesh2dUniform,
|
||||||
|
@ -286,7 +286,9 @@ impl Plugin for ColoredMesh2dPlugin {
|
||||||
pub fn extract_colored_mesh2d(
|
pub fn extract_colored_mesh2d(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut previous_len: Local<usize>,
|
mut previous_len: Local<usize>,
|
||||||
query: Query<(Entity, &ComputedVisibility), With<ColoredMesh2d>>,
|
// When extracting, you must use `Extract` to mark the `SystemParam`s
|
||||||
|
// which should be taken from the main world.
|
||||||
|
query: Extract<Query<(Entity, &ComputedVisibility), With<ColoredMesh2d>>>,
|
||||||
) {
|
) {
|
||||||
let mut values = Vec::with_capacity(*previous_len);
|
let mut values = Vec::with_capacity(*previous_len);
|
||||||
for (entity, computed_visibility) in query.iter() {
|
for (entity, computed_visibility) in query.iter() {
|
||||||
|
|
|
@ -4,13 +4,18 @@
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
core_pipeline::core_3d::Transparent3d,
|
core_pipeline::core_3d::Transparent3d,
|
||||||
ecs::system::{lifetimeless::SRes, SystemParamItem},
|
ecs::system::{
|
||||||
|
lifetimeless::{Read, SRes},
|
||||||
|
SystemParamItem,
|
||||||
|
},
|
||||||
pbr::{
|
pbr::{
|
||||||
DrawMesh, MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup,
|
DrawMesh, MeshPipeline, MeshPipelineKey, MeshUniform, SetMeshBindGroup,
|
||||||
SetMeshViewBindGroup,
|
SetMeshViewBindGroup,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
|
extract_component::{ExtractComponent, ExtractComponentPlugin},
|
||||||
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
mesh::MeshVertexBufferLayout,
|
mesh::MeshVertexBufferLayout,
|
||||||
render_asset::RenderAssets,
|
render_asset::RenderAssets,
|
||||||
render_phase::{
|
render_phase::{
|
||||||
|
@ -64,6 +69,8 @@ impl Plugin for CustomMaterialPlugin {
|
||||||
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
app.add_plugin(ExtractComponentPlugin::<CustomMaterial>::default())
|
||||||
|
.add_plugin(ExtractResourcePlugin::<ExtractedTime>::default());
|
||||||
|
|
||||||
app.sub_app_mut(RenderApp)
|
app.sub_app_mut(RenderApp)
|
||||||
.add_render_command::<Transparent3d, DrawCustom>()
|
.add_render_command::<Transparent3d, DrawCustom>()
|
||||||
|
@ -73,26 +80,20 @@ impl Plugin for CustomMaterialPlugin {
|
||||||
})
|
})
|
||||||
.init_resource::<CustomPipeline>()
|
.init_resource::<CustomPipeline>()
|
||||||
.init_resource::<SpecializedMeshPipelines<CustomPipeline>>()
|
.init_resource::<SpecializedMeshPipelines<CustomPipeline>>()
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_time)
|
|
||||||
.add_system_to_stage(RenderStage::Extract, extract_custom_material)
|
|
||||||
.add_system_to_stage(RenderStage::Prepare, prepare_time)
|
.add_system_to_stage(RenderStage::Prepare, prepare_time)
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_custom)
|
.add_system_to_stage(RenderStage::Queue, queue_custom)
|
||||||
.add_system_to_stage(RenderStage::Queue, queue_time_bind_group);
|
.add_system_to_stage(RenderStage::Queue, queue_time_bind_group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the `CustomMaterial` component into the render world
|
impl ExtractComponent for CustomMaterial {
|
||||||
fn extract_custom_material(
|
type Query = Read<CustomMaterial>;
|
||||||
mut commands: Commands,
|
|
||||||
mut previous_len: Local<usize>,
|
type Filter = ();
|
||||||
mut query: Query<Entity, With<CustomMaterial>>,
|
|
||||||
) {
|
fn extract_component(_: bevy::ecs::query::QueryItem<Self::Query>) -> Self {
|
||||||
let mut values = Vec::with_capacity(*previous_len);
|
CustomMaterial
|
||||||
for entity in query.iter_mut() {
|
|
||||||
values.push((entity, (CustomMaterial,)));
|
|
||||||
}
|
}
|
||||||
*previous_len = values.len();
|
|
||||||
commands.insert_or_spawn_batch(values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add each entity with a mesh and a `CustomMaterial` to every view's `Transparent3d` render phase using the `CustomPipeline`
|
// add each entity with a mesh and a `CustomMaterial` to every view's `Transparent3d` render phase using the `CustomPipeline`
|
||||||
|
@ -138,11 +139,14 @@ struct ExtractedTime {
|
||||||
seconds_since_startup: f32,
|
seconds_since_startup: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the passed time into a resource in the render world
|
impl ExtractResource for ExtractedTime {
|
||||||
fn extract_time(mut commands: Commands, time: Res<Time>) {
|
type Source = Time;
|
||||||
commands.insert_resource(ExtractedTime {
|
|
||||||
seconds_since_startup: time.seconds_since_startup() as f32,
|
fn extract_resource(time: &Self::Source) -> Self {
|
||||||
});
|
ExtractedTime {
|
||||||
|
seconds_since_startup: time.seconds_since_startup() as f32,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TimeMeta {
|
struct TimeMeta {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use bevy::{
|
||||||
math::{DVec2, DVec3},
|
math::{DVec2, DVec3},
|
||||||
pbr::{ExtractedPointLight, GlobalLightMeta},
|
pbr::{ExtractedPointLight, GlobalLightMeta},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{camera::ScalingMode, RenderApp, RenderStage},
|
render::{camera::ScalingMode, Extract, RenderApp, RenderStage},
|
||||||
window::PresentMode,
|
window::PresentMode,
|
||||||
};
|
};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
@ -156,7 +156,7 @@ impl Plugin for LogVisibleLights {
|
||||||
|
|
||||||
// System for printing the number of meshes on every tick of the timer
|
// System for printing the number of meshes on every tick of the timer
|
||||||
fn print_visible_light_count(
|
fn print_visible_light_count(
|
||||||
time: Res<Time>,
|
time: Res<ExtractedTime>,
|
||||||
mut timer: Local<PrintingTimer>,
|
mut timer: Local<PrintingTimer>,
|
||||||
visible: Query<&ExtractedPointLight>,
|
visible: Query<&ExtractedPointLight>,
|
||||||
global_light_meta: Res<GlobalLightMeta>,
|
global_light_meta: Res<GlobalLightMeta>,
|
||||||
|
@ -172,8 +172,11 @@ fn print_visible_light_count(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_time(mut commands: Commands, time: Res<Time>) {
|
#[derive(Deref, DerefMut)]
|
||||||
commands.insert_resource(time.into_inner().clone());
|
pub struct ExtractedTime(Time);
|
||||||
|
|
||||||
|
fn extract_time(mut commands: Commands, time: Extract<Res<Time>>) {
|
||||||
|
commands.insert_resource(ExtractedTime(time.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PrintingTimer(Timer);
|
struct PrintingTimer(Timer);
|
||||||
|
|
Loading…
Reference in a new issue