From 95b7f0bf731efc4339292ca79ed53f3bd20dd90e Mon Sep 17 00:00:00 2001 From: re0312 Date: Sun, 7 Jul 2024 05:54:08 +0800 Subject: [PATCH 01/55] init --- .../src/auto_exposure/buffers.rs | 15 ++- crates/bevy_core_pipeline/src/core_2d/mod.rs | 15 ++- .../src/core_3d/camera_3d.rs | 3 + crates/bevy_core_pipeline/src/core_3d/mod.rs | 96 ++++++++++--------- crates/bevy_core_pipeline/src/dof/mod.rs | 51 +++++----- crates/bevy_core_pipeline/src/taa/mod.rs | 30 +++--- crates/bevy_pbr/src/cluster/mod.rs | 21 ++-- crates/bevy_pbr/src/light_probe/mod.rs | 33 +++++-- crates/bevy_pbr/src/material.rs | 1 + crates/bevy_pbr/src/prepass/mod.rs | 13 ++- crates/bevy_pbr/src/ssao/mod.rs | 14 ++- crates/bevy_pbr/src/volumetric_fog/mod.rs | 15 ++- crates/bevy_render/src/camera/camera.rs | 69 +++++++------ crates/bevy_render/src/extract_component.rs | 17 ++-- crates/bevy_render/src/lib.rs | 71 +++++++++----- crates/bevy_render/src/view/visibility/mod.rs | 43 +++++---- crates/bevy_render/src/world_sync.rs | 79 +++++++++++++++ crates/bevy_sprite/src/mesh2d/mesh.rs | 8 +- crates/bevy_ui/src/render/mod.rs | 80 +++++++++------- 19 files changed, 439 insertions(+), 235 deletions(-) create mode 100644 crates/bevy_render/src/world_sync.rs diff --git a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs index 5a6d4330f2b4c..c7ee0f2d3a6ef 100644 --- a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs +++ b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs @@ -1,7 +1,10 @@ +use std::ops::Deref; + use bevy_ecs::prelude::*; use bevy_render::{ render_resource::{StorageBuffer, UniformBuffer}, renderer::{RenderDevice, RenderQueue}, + world_sync::RenderWorldSyncEntity, Extract, }; use bevy_utils::{Entry, HashMap}; @@ -27,13 +30,21 @@ pub(super) struct ExtractedStateBuffers { pub(super) fn extract_buffers( mut commands: Commands, - changed: Extract>>, + changed: Extract< + Query<(&RenderWorldSyncEntity, &AutoExposureSettings), Changed>, + >, mut removed: Extract>, ) { commands.insert_resource(ExtractedStateBuffers { changed: changed .iter() - .map(|(entity, settings)| (entity, settings.clone())) + .filter_map(|(entity, settings)| { + if let Some(entity) = entity.entity() { + return Some((entity, settings.clone())); + } else { + None + } + }) .collect(), removed: removed.read().collect(), }); diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index 869356c502315..624fab2f11333 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -27,7 +27,7 @@ pub mod graph { } } -use std::ops::Range; +use std::ops::{Deref, Range}; pub use camera_2d::*; pub use main_transparent_pass_2d_node::*; @@ -44,6 +44,7 @@ use bevy_render::{ PhaseItemExtraIndex, SortedPhaseItem, ViewSortedRenderPhases, }, render_resource::CachedRenderPipelineId, + world_sync::RenderWorldSyncEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -159,9 +160,8 @@ impl CachedRenderPipelinePhaseItem for Transparent2d { } pub fn extract_core_2d_camera_phases( - mut commands: Commands, mut transparent_2d_phases: ResMut>, - cameras_2d: Extract>>, + cameras_2d: Extract>>, mut live_entities: Local, ) { live_entities.clear(); @@ -170,11 +170,10 @@ pub fn extract_core_2d_camera_phases( if !camera.is_active { continue; } - - commands.get_or_spawn(entity); - transparent_2d_phases.insert_or_clear(entity); - - live_entities.insert(entity); + if let Some(entity) = entity.entity() { + transparent_2d_phases.insert_or_clear(entity); + live_entities.insert(entity); + } } // Clear out all dead views. diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index cf062d340ff79..f6c6779fba019 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -10,6 +10,7 @@ use bevy_render::{ primitives::Frustum, render_resource::{LoadOp, TextureUsages}, view::{ColorGrading, VisibleEntities}, + world_sync::RenderWorldSyncEntity, }; use bevy_transform::prelude::{GlobalTransform, Transform}; use serde::{Deserialize, Serialize}; @@ -152,6 +153,7 @@ pub struct Camera3dBundle { pub color_grading: ColorGrading, pub exposure: Exposure, pub main_texture_usages: CameraMainTextureUsages, + pub render_entity: RenderWorldSyncEntity, } // NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference @@ -171,6 +173,7 @@ impl Default for Camera3dBundle { exposure: Default::default(), main_texture_usages: Default::default(), deband_dither: DebandDither::Enabled, + render_entity: RenderWorldSyncEntity::default(), } } } diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index d2ddc76982668..5ec16bf1fa20f 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -62,7 +62,7 @@ pub const DEPTH_TEXTURE_SAMPLING_SUPPORTED: bool = false; #[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))] pub const DEPTH_TEXTURE_SAMPLING_SUPPORTED: bool = true; -use std::ops::Range; +use std::ops::{Deref, Range}; use bevy_asset::{AssetId, UntypedAssetId}; use bevy_color::LinearRgba; @@ -71,7 +71,10 @@ pub use main_opaque_pass_3d_node::*; pub use main_transparent_pass_3d_node::*; use bevy_app::{App, Plugin, PostUpdate}; -use bevy_ecs::{entity::EntityHashSet, prelude::*}; +use bevy_ecs::{ + entity::{self, EntityHashSet}, + prelude::*, +}; use bevy_math::FloatOrd; use bevy_render::{ camera::{Camera, ExtractedCamera}, @@ -90,6 +93,7 @@ use bevy_render::{ renderer::RenderDevice, texture::{BevyDefault, ColorAttachment, Image, TextureCache}, view::{ExtractedView, ViewDepthTexture, ViewTarget}, + world_sync::RenderWorldSyncEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::{tracing::warn, HashMap}; @@ -503,29 +507,28 @@ impl CachedRenderPipelinePhaseItem for Transparent3d { } pub fn extract_core_3d_camera_phases( - mut commands: Commands, mut opaque_3d_phases: ResMut>, mut alpha_mask_3d_phases: ResMut>, mut transmissive_3d_phases: ResMut>, mut transparent_3d_phases: ResMut>, - cameras_3d: Extract>>, + cameras_3d: Extract>>, mut live_entities: Local, ) { live_entities.clear(); - for (entity, camera) in &cameras_3d { + for (render_entity, camera) in &cameras_3d { if !camera.is_active { continue; } - commands.get_or_spawn(entity); - - opaque_3d_phases.insert_or_clear(entity); - alpha_mask_3d_phases.insert_or_clear(entity); - transmissive_3d_phases.insert_or_clear(entity); - transparent_3d_phases.insert_or_clear(entity); + if let Some(entity) = render_entity.entity() { + opaque_3d_phases.insert_or_clear(entity); + alpha_mask_3d_phases.insert_or_clear(entity); + transmissive_3d_phases.insert_or_clear(entity); + transparent_3d_phases.insert_or_clear(entity); - live_entities.insert(entity); + live_entities.insert(entity); + }; } opaque_3d_phases.retain(|entity, _| live_entities.contains(entity)); @@ -544,7 +547,7 @@ pub fn extract_camera_prepass_phase( cameras_3d: Extract< Query< ( - Entity, + &RenderWorldSyncEntity, &Camera, Has, Has, @@ -558,44 +561,51 @@ pub fn extract_camera_prepass_phase( ) { live_entities.clear(); - for (entity, camera, depth_prepass, normal_prepass, motion_vector_prepass, deferred_prepass) in - cameras_3d.iter() + for ( + render_entity, + camera, + depth_prepass, + normal_prepass, + motion_vector_prepass, + deferred_prepass, + ) in cameras_3d.iter() { if !camera.is_active { continue; } - if depth_prepass || normal_prepass || motion_vector_prepass { - opaque_3d_prepass_phases.insert_or_clear(entity); - alpha_mask_3d_prepass_phases.insert_or_clear(entity); - } else { - opaque_3d_prepass_phases.remove(&entity); - alpha_mask_3d_prepass_phases.remove(&entity); - } - - if deferred_prepass { - opaque_3d_deferred_phases.insert_or_clear(entity); - alpha_mask_3d_deferred_phases.insert_or_clear(entity); - } else { - opaque_3d_deferred_phases.remove(&entity); - alpha_mask_3d_deferred_phases.remove(&entity); - } + if let Some(entity) = render_entity.entity() { + if depth_prepass || normal_prepass || motion_vector_prepass { + opaque_3d_prepass_phases.insert_or_clear(entity); + alpha_mask_3d_prepass_phases.insert_or_clear(entity); + } else { + opaque_3d_prepass_phases.remove(&entity); + alpha_mask_3d_prepass_phases.remove(&entity); + } - live_entities.insert(entity); + if deferred_prepass { + opaque_3d_deferred_phases.insert_or_clear(entity); + alpha_mask_3d_deferred_phases.insert_or_clear(entity); + } else { + opaque_3d_deferred_phases.remove(&entity); + alpha_mask_3d_deferred_phases.remove(&entity); + } + live_entities.insert(entity); - let mut entity = commands.get_or_spawn(entity); + let mut entity = commands.get_or_spawn(entity); - if depth_prepass { - entity.insert(DepthPrepass); - } - if normal_prepass { - entity.insert(NormalPrepass); - } - if motion_vector_prepass { - entity.insert(MotionVectorPrepass); - } - if deferred_prepass { - entity.insert(DeferredPrepass); + if depth_prepass { + entity.insert(DepthPrepass); + } + if normal_prepass { + entity.insert(NormalPrepass); + } + if motion_vector_prepass { + entity.insert(MotionVectorPrepass); + } + if deferred_prepass { + entity.insert(DeferredPrepass); + } } } diff --git a/crates/bevy_core_pipeline/src/dof/mod.rs b/crates/bevy_core_pipeline/src/dof/mod.rs index 032e9f63d703c..b07f20f9f6474 100644 --- a/crates/bevy_core_pipeline/src/dof/mod.rs +++ b/crates/bevy_core_pipeline/src/dof/mod.rs @@ -14,6 +14,8 @@ //! //! [Depth of field]: https://en.wikipedia.org/wiki/Depth_of_field +use std::ops::Deref; + use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, Handle}; use bevy_derive::{Deref, DerefMut}; @@ -48,6 +50,7 @@ use bevy_render::{ prepare_view_targets, ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, }, + world_sync::RenderWorldSyncEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::{info_once, prelude::default, warn_once}; @@ -793,7 +796,7 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline { /// Extracts all [`DepthOfFieldSettings`] components into the render world. fn extract_depth_of_field_settings( mut commands: Commands, - mut query: Extract>, + mut query: Extract>, ) { if !DEPTH_TEXTURE_SAMPLING_SUPPORTED { info_once!( @@ -803,29 +806,31 @@ fn extract_depth_of_field_settings( } for (entity, dof_settings, projection) in query.iter_mut() { - // Depth of field is nonsensical without a perspective projection. - let Projection::Perspective(ref perspective_projection) = *projection else { - continue; - }; + if let Some(entity) = entity.entity() { + // Depth of field is nonsensical without a perspective projection. + let Projection::Perspective(ref perspective_projection) = *projection else { + continue; + }; - let focal_length = - calculate_focal_length(dof_settings.sensor_height, perspective_projection.fov); - - // Convert `DepthOfFieldSettings` to `DepthOfFieldUniform`. - commands.get_or_spawn(entity).insert(( - *dof_settings, - DepthOfFieldUniform { - focal_distance: dof_settings.focal_distance, - focal_length, - coc_scale_factor: focal_length * focal_length - / (dof_settings.sensor_height * dof_settings.aperture_f_stops), - max_circle_of_confusion_diameter: dof_settings.max_circle_of_confusion_diameter, - max_depth: dof_settings.max_depth, - pad_a: 0, - pad_b: 0, - pad_c: 0, - }, - )); + let focal_length = + calculate_focal_length(dof_settings.sensor_height, perspective_projection.fov); + + // Convert `DepthOfFieldSettings` to `DepthOfFieldUniform`. + commands.get_or_spawn(entity).insert(( + *dof_settings, + DepthOfFieldUniform { + focal_distance: dof_settings.focal_distance, + focal_length, + coc_scale_factor: focal_length * focal_length + / (dof_settings.sensor_height * dof_settings.aperture_f_stops), + max_circle_of_confusion_diameter: dof_settings.max_circle_of_confusion_diameter, + max_depth: dof_settings.max_depth, + pad_a: 0, + pad_b: 0, + pad_c: 0, + }, + )); + } } } diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index 04d67f451d43e..3b6d1f3448c24 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -32,6 +32,7 @@ use bevy_render::{ renderer::{RenderContext, RenderDevice}, texture::{BevyDefault, CachedTexture, TextureCache}, view::{ExtractedView, Msaa, ViewTarget}, + world_sync::RenderWorldSyncEntity, ExtractSchedule, MainWorld, Render, RenderApp, RenderSet, }; @@ -338,21 +339,28 @@ impl SpecializedRenderPipeline for TaaPipeline { } fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut) { - let mut cameras_3d = main_world - .query_filtered::<(Entity, &Camera, &Projection, &mut TemporalAntiAliasSettings), ( - With, - With, - With, - With, - )>(); + let mut cameras_3d = main_world.query_filtered::<( + &RenderWorldSyncEntity, + &Camera, + &Projection, + &mut TemporalAntiAliasSettings, + ), ( + With, + With, + With, + With, + )>(); for (entity, camera, camera_projection, mut taa_settings) in cameras_3d.iter_mut(&mut main_world) { - let has_perspective_projection = matches!(camera_projection, Projection::Perspective(_)); - if camera.is_active && has_perspective_projection { - commands.get_or_spawn(entity).insert(taa_settings.clone()); - taa_settings.reset = false; + if let Some(entity) = entity.entity() { + let has_perspective_projection = + matches!(camera_projection, Projection::Perspective(_)); + if camera.is_active && has_perspective_projection { + commands.get_or_spawn(entity).insert(taa_settings.clone()); + taa_settings.reset = false; + } } } } diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index a0d628474db8e..b7904932dbd70 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -19,6 +19,7 @@ use bevy_render::{ UniformBuffer, }, renderer::{RenderDevice, RenderQueue}, + world_sync::RenderWorldSyncEntity, Extract, }; use bevy_utils::{hashbrown::HashSet, tracing::warn}; @@ -511,7 +512,7 @@ pub(crate) fn clusterable_object_order( /// Extracts clusters from the main world from the render world. pub fn extract_clusters( mut commands: Commands, - views: Extract>, + views: Extract>, ) { for (entity, clusters, camera) in &views { if !camera.is_active { @@ -536,14 +537,16 @@ pub fn extract_clusters( } } - commands.get_or_spawn(entity).insert(( - ExtractedClusterableObjects { data }, - ExtractedClusterConfig { - near: clusters.near, - far: clusters.far, - dimensions: clusters.dimensions, - }, - )); + if let Some(entity) = entity.entity() { + commands.get_or_spawn(entity).insert(( + ExtractedClusterableObjects { data }, + ExtractedClusterConfig { + near: clusters.near, + far: clusters.far, + dimensions: clusters.dimensions, + }, + )); + } } } diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index 8c41f28280f7b..a0a768413e68a 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -23,6 +23,7 @@ use bevy_render::{ settings::WgpuFeatures, texture::{FallbackImage, GpuImage, Image}, view::ExtractedView, + world_sync::RenderWorldSyncEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::prelude::GlobalTransform; @@ -344,7 +345,17 @@ impl Plugin for LightProbePlugin { fn gather_light_probes( image_assets: Res>, light_probe_query: Extract>>, - view_query: Extract), With>>, + view_query: Extract< + Query< + ( + &RenderWorldSyncEntity, + &GlobalTransform, + &Frustum, + Option<&C>, + ), + With, + >, + >, mut reflection_probes: Local>>, mut view_reflection_probes: Local>>, mut commands: Commands, @@ -382,15 +393,17 @@ fn gather_light_probes( // Gather up the light probes in the list. render_view_light_probes.maybe_gather_light_probes(&view_reflection_probes); - // Record the per-view light probes. - if render_view_light_probes.is_empty() { - commands - .get_or_spawn(view_entity) - .remove::>(); - } else { - commands - .get_or_spawn(view_entity) - .insert(render_view_light_probes); + if let Some(entity) = view_entity.entity() { + // Record the per-view light probes. + if render_view_light_probes.is_empty() { + commands + .get_or_spawn(entity) + .remove::>(); + } else { + commands + .get_or_spawn(entity) + .insert(render_view_light_probes); + } } } } diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index a1c07e7413501..272b60d81e1be 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -572,6 +572,7 @@ pub fn queue_material_meshes( ) where M::Data: PartialEq + Eq + Hash + Clone, { + println!("queue view :{}",views.iter().count()); for ( view_entity, view, diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 5330e055ee3c3..8fa50a0f128a8 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -3,6 +3,7 @@ mod prepass_bindings; use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef}; use bevy_render::render_resource::binding_types::uniform_buffer; use bevy_render::view::WithMesh; +use bevy_render::world_sync::RenderWorldSyncEntity; pub use prepass_bindings::*; use bevy_asset::{load_internal_asset, AssetServer}; @@ -577,14 +578,18 @@ where // Extract the render phases for the prepass pub fn extract_camera_previous_view_data( mut commands: Commands, - cameras_3d: Extract), With>>, + cameras_3d: Extract< + Query<(&RenderWorldSyncEntity, &Camera, Option<&PreviousViewData>), With>, + >, ) { for (entity, camera, maybe_previous_view_data) in cameras_3d.iter() { if camera.is_active { - let mut entity = commands.get_or_spawn(entity); + if let Some(entity) = entity.entity() { + let mut entity = commands.get_or_spawn(entity); - if let Some(previous_view_data) = maybe_previous_view_data { - entity.insert(previous_view_data.clone()); + if let Some(previous_view_data) = maybe_previous_view_data { + entity.insert(previous_view_data.clone()); + } } } } diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 9c43854b94810..cc6b2a78dd2bb 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -30,6 +30,7 @@ use bevy_render::{ renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue}, texture::{CachedTexture, TextureCache}, view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms}, + world_sync::RenderWorldSyncEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::{ @@ -484,7 +485,11 @@ fn extract_ssao_settings( mut commands: Commands, cameras: Extract< Query< - (Entity, &Camera, &ScreenSpaceAmbientOcclusionSettings), + ( + &RenderWorldSyncEntity, + &Camera, + &ScreenSpaceAmbientOcclusionSettings, + ), (With, With, With), >, >, @@ -498,9 +503,10 @@ fn extract_ssao_settings( ); return; } - - if camera.is_active { - commands.get_or_spawn(entity).insert(ssao_settings.clone()); + if let Some(entity) = entity.entity() { + if camera.is_active { + commands.get_or_spawn(entity).insert(ssao_settings.clone()); + } } } } diff --git a/crates/bevy_pbr/src/volumetric_fog/mod.rs b/crates/bevy_pbr/src/volumetric_fog/mod.rs index 170d38cb21f23..7b0c8c5f64ba9 100644 --- a/crates/bevy_pbr/src/volumetric_fog/mod.rs +++ b/crates/bevy_pbr/src/volumetric_fog/mod.rs @@ -44,7 +44,7 @@ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ component::Component, entity::Entity, - query::{Has, QueryItem, With}, + query::{Changed, Has, QueryItem, With}, reflect::ReflectComponent, schedule::IntoSystemConfigs as _, system::{lifetimeless::Read, Commands, Query, Res, ResMut, Resource}, @@ -68,6 +68,7 @@ use bevy_render::{ renderer::{RenderContext, RenderDevice, RenderQueue}, texture::BevyDefault, view::{ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniformOffset}, + world_sync::RenderWorldSyncEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::prelude::default; @@ -376,7 +377,9 @@ impl FromWorld for VolumetricFogPipeline { /// world to the render world. pub fn extract_volumetric_fog( mut commands: Commands, - view_targets: Extract>, + view_targets: Extract< + Query<(&RenderWorldSyncEntity, &VolumetricFogSettings), Changed>, + >, volumetric_lights: Extract>, ) { if volumetric_lights.is_empty() { @@ -384,9 +387,11 @@ pub fn extract_volumetric_fog( } for (view_target, volumetric_fog_settings) in view_targets.iter() { - commands - .get_or_spawn(view_target) - .insert(*volumetric_fog_settings); + if let Some(entity) = view_target.entity() { + commands + .get_or_spawn(entity) + .insert(*volumetric_fog_settings); + } } for (entity, volumetric_light) in volumetric_lights.iter() { diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index b950b2a6b9382..2a4b2a528f34b 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -10,6 +10,7 @@ use crate::{ view::{ ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, RenderLayers, VisibleEntities, }, + world_sync::RenderWorldSyncEntity, Extract, }; use bevy_asset::{AssetEvent, AssetId, Assets, Handle}; @@ -830,12 +831,12 @@ pub fn extract_cameras( mut commands: Commands, query: Extract< Query<( - Entity, &Camera, &CameraRenderGraph, &GlobalTransform, &VisibleEntities, &Frustum, + &RenderWorldSyncEntity, Option<&ColorGrading>, Option<&Exposure>, Option<&TemporalJitter>, @@ -846,15 +847,22 @@ pub fn extract_cameras( >, primary_window: Extract>>, gpu_preprocessing_support: Res, + mut render_query: Query<( + Entity, + &mut ExtractedCamera, + &mut ExtractedView, + &mut VisibleEntities, + &mut Frustum, + )>, ) { let primary_window = primary_window.iter().next(); for ( - entity, camera, camera_render_graph, transform, visible_entities, frustum, + rw_entity, color_grading, exposure, temporal_jitter, @@ -863,11 +871,10 @@ pub fn extract_cameras( gpu_culling, ) in query.iter() { - let color_grading = color_grading.unwrap_or(&ColorGrading::default()).clone(); - if !camera.is_active { continue; } + let color_grading = color_grading.unwrap_or(&ColorGrading::default()).clone(); if let ( Some(URect { @@ -885,10 +892,10 @@ pub fn extract_cameras( continue; } - let mut commands = commands.get_or_spawn(entity); - - commands.insert(( - ExtractedCamera { + if let Ok((e, mut extract_camera, mut extracted_view, mut entities, mut fru)) = + render_query.get_mut(rw_entity.unwrap()) + { + *extract_camera = ExtractedCamera { target: camera.target.normalize(primary_window), viewport: camera.viewport.clone(), physical_viewport_size: Some(viewport_size), @@ -904,8 +911,8 @@ pub fn extract_cameras( .map(Exposure::exposure) .unwrap_or_else(|| Exposure::default().exposure()), hdr: camera.hdr, - }, - ExtractedView { + }; + *extracted_view = ExtractedView { clip_from_view: camera.clip_from_view(), world_from_view: *transform, clip_from_world: None, @@ -917,30 +924,30 @@ pub fn extract_cameras( viewport_size.y, ), color_grading, - }, - visible_entities.clone(), - *frustum, - )); - - if let Some(temporal_jitter) = temporal_jitter { - commands.insert(temporal_jitter.clone()); - } + }; + *entities = visible_entities.clone(); + *fru = *frustum; - if let Some(render_layers) = render_layers { - commands.insert(render_layers.clone()); - } + let mut commands = commands.entity(e); + if let Some(temporal_jitter) = temporal_jitter { + commands.insert(temporal_jitter.clone()); + } - if let Some(perspective) = projection { - commands.insert(perspective.clone()); - } + if let Some(render_layers) = render_layers { + commands.insert(render_layers.clone()); + } - if gpu_culling { - if *gpu_preprocessing_support == GpuPreprocessingSupport::Culling { - commands.insert(GpuCulling); - } else { - warn_once!( - "GPU culling isn't supported on this platform; ignoring `GpuCulling`." - ); + if let Some(perspective) = projection { + commands.insert(perspective.clone()); + } + if gpu_culling { + if *gpu_preprocessing_support == GpuPreprocessingSupport::Culling { + commands.insert(GpuCulling); + } else { + warn_once!( + "GPU culling isn't supported on this platform; ignoring `GpuCulling`." + ); + } } } } diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 4b327cf6af3e8..169a9c19626ad 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -2,6 +2,7 @@ use crate::{ render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ViewVisibility, + world_sync::RenderWorldSyncEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_app::{App, Plugin}; @@ -209,12 +210,14 @@ impl ExtractComponent for Handle { fn extract_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in &query { - if let Some(component) = C::extract_component(query_item) { - values.push((entity, component)); + if let Some(entity) = entity.entity() { + if let Some(component) = C::extract_component(query_item) { + values.push((entity, component)); + } } } *previous_len = values.len(); @@ -225,13 +228,15 @@ fn extract_components( fn extract_visible_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, view_visibility, query_item) in &query { if view_visibility.get() { - if let Some(component) = C::extract_component(query_item) { - values.push((entity, component)); + if let Some(entity) = entity.entity() { + if let Some(component) = C::extract_component(query_item) { + values.push((entity, component)); + } } } } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 49f25530b1323..92b52f8568ba4 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -35,6 +35,7 @@ pub mod settings; mod spatial_bundle; pub mod texture; pub mod view; +pub mod world_sync; pub mod prelude { #[doc(hidden)] pub use crate::{ @@ -53,6 +54,7 @@ pub mod prelude { } use batching::gpu_preprocessing::BatchingPlugin; +use bevy_ecs::component::ComponentInfo; use bevy_ecs::schedule::ScheduleBuildSettings; use bevy_utils::prelude::default; pub use extract_param::Extract; @@ -63,6 +65,7 @@ use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; +use world_sync::{entity_sync_system, WorldSyncPlugin}; use crate::mesh::GpuMesh; use crate::renderer::WgpuWrapper; @@ -346,6 +349,7 @@ impl Plugin for RenderPlugin { GlobalsPlugin, MorphPlugin, BatchingPlugin, + WorldSyncPlugin, )); app.init_resource::() @@ -463,35 +467,56 @@ unsafe fn initialize_render_app(app: &mut App) { render_system, ) .in_set(RenderSet::Render), - World::clear_entities.in_set(RenderSet::Cleanup), + // World::clear_entities.in_set(RenderSet::Cleanup), ), ); render_app.set_extract(|main_world, render_world| { - #[cfg(feature = "trace")] - let _render_span = bevy_utils::tracing::info_span!("extract main app to render subapp").entered(); + // #[cfg(feature = "trace")] + // let _render_span = bevy_utils::tracing::info_span!("extract main app to render subapp").entered(); + // { + // #[cfg(feature = "trace")] + // let _stage_span = + // bevy_utils::tracing::info_span!("reserve_and_flush") + // .entered(); + + // // reserve all existing main world entities for use in render_app + // // they can only be spawned using `get_or_spawn()` + // let total_count = main_world.entities().total_count(); + + // assert_eq!( + // render_world.entities().len(), + // 0, + // "An entity was spawned after the entity list was cleared last frame and before the extract schedule began. This is not supported", + // ); + + // // SAFETY: This is safe given the clear_entities call in the past frame and the assert above + // unsafe { + // render_world + // .entities_mut() + // .flush_and_reserve_invalid_assuming_no_entities(total_count); + // } + // } + println!("render World Entity:{}", render_world.entities().len()); + let mut vec = vec![]; + for e in render_world.iter_entities() { + vec.push(e.id()); + } + for e in vec { + fn log_components(entity: Entity, world: &mut World) { + let debug_infos: Vec<_> = world + .inspect_entity(entity) + .map(ComponentInfo::name) + .collect(); + println!("Entity {:?}: {:?}", entity, debug_infos); + } + log_components(e, render_world); + } + { #[cfg(feature = "trace")] - let _stage_span = - bevy_utils::tracing::info_span!("reserve_and_flush") - .entered(); - - // reserve all existing main world entities for use in render_app - // they can only be spawned using `get_or_spawn()` - let total_count = main_world.entities().total_count(); - - assert_eq!( - render_world.entities().len(), - 0, - "An entity was spawned after the entity list was cleared last frame and before the extract schedule began. This is not supported", - ); - - // SAFETY: This is safe given the clear_entities call in the past frame and the assert above - unsafe { - render_world - .entities_mut() - .flush_and_reserve_invalid_assuming_no_entities(total_count); - } + let _stage_span = bevy_utils::tracing::info_span!("entity_sync").entered(); + entity_sync_system(main_world, render_world); } // run extract schedule diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 341404d189fdb..1897f4194614e 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -1,7 +1,7 @@ mod range; mod render_layers; -use std::any::TypeId; +use std::{any::TypeId, ops::Deref}; pub use range::*; pub use render_layers::*; @@ -19,6 +19,7 @@ use crate::{ camera::{Camera, CameraProjection}, mesh::Mesh, primitives::{Aabb, Frustum, Sphere}, + world_sync::RenderWorldSyncEntity, }; use super::NoCpuCulling; @@ -411,6 +412,7 @@ pub fn check_visibility( Option<&RenderLayers>, Option<&Aabb>, &GlobalTransform, + &RenderWorldSyncEntity, Has, Has, ), @@ -441,6 +443,7 @@ pub fn check_visibility( maybe_entity_mask, maybe_model_aabb, transform, + render_entity, no_frustum_culling, has_visibility_range, ) = query_item; @@ -465,27 +468,29 @@ pub fn check_visibility( return; } - // If we have an aabb, do frustum culling - if !no_frustum_culling && !no_cpu_culling { - if let Some(model_aabb) = maybe_model_aabb { - let world_from_local = transform.affine(); - let model_sphere = Sphere { - center: world_from_local.transform_point3a(model_aabb.center), - radius: transform.radius_vec3a(model_aabb.half_extents), - }; - // Do quick sphere-based frustum culling - if !frustum.intersects_sphere(&model_sphere, false) { - return; - } - // Do aabb-based frustum culling - if !frustum.intersects_obb(model_aabb, &world_from_local, true, false) { - return; + if let Some(entity) = render_entity.deref() { + // If we have an aabb, do frustum culling + if !no_frustum_culling && !no_cpu_culling { + if let Some(model_aabb) = maybe_model_aabb { + let world_from_local = transform.affine(); + let model_sphere = Sphere { + center: world_from_local.transform_point3a(model_aabb.center), + radius: transform.radius_vec3a(model_aabb.half_extents), + }; + // Do quick sphere-based frustum culling + if !frustum.intersects_sphere(&model_sphere, false) { + return; + } + // Do aabb-based frustum culling + if !frustum.intersects_obb(model_aabb, &world_from_local, true, false) { + return; + } } } - } - view_visibility.set(); - queue.push(entity); + view_visibility.set(); + queue.push(*entity); + } }, ); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs new file mode 100644 index 0000000000000..a85a56e991211 --- /dev/null +++ b/crates/bevy_render/src/world_sync.rs @@ -0,0 +1,79 @@ +use std::marker::PhantomData; + +use bevy_app::Plugin; +use bevy_derive::{Deref, DerefMut}; +use bevy_ecs::{ + bundle::Bundle, + change_detection::DetectChanges, + component::{Component, ComponentHooks, StorageType}, + entity::{Entity, EntityHashSet}, + observer::Trigger, + query::Has, + system::{Commands, Query, ResMut, Resource}, + world::{self, Mut, OnAdd, OnRemove, World}, +}; +use bevy_hierarchy::DespawnRecursiveExt; + +#[derive(Component, Deref, Default, Clone)] +#[component(storage = "SparseSet")] +pub struct RenderWorldSyncEntity(Option); + +impl RenderWorldSyncEntity { + pub fn entity(&self) -> Option { + self.0 + } +} +enum EntityRecord { + Added(Entity), + Removed(Option), +} + +#[derive(Resource, Default, Deref, DerefMut)] +struct PendingSyncEntity { + records: Vec, +} + +pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut World) { + main_world.resource_scope(|world, mut pending: Mut| { + for record in pending.drain(..) { + match record { + EntityRecord::Added(e) => { + let id = render_world.spawn_empty().id(); + println!("sync added :main [{:?}],render:[{:?}]", e, id); + world.get_mut::(e).map(|mut e| { + e.0 = Some(id); + }); + } + EntityRecord::Removed(e) => { + if let Some(e) = e { + render_world + .get_entity_mut(e) + .map(|ec| ec.despawn_recursive()); + } + } + } + } + }); +} + +pub(crate) struct WorldSyncPlugin; + +impl Plugin for WorldSyncPlugin { + fn build(&self, app: &mut bevy_app::App) { + app.init_resource::(); + app.observe( + |trigger: Trigger, + mut pending: ResMut| { + pending.push(EntityRecord::Added(trigger.entity())); + }, + ); + app.observe( + |trigger: Trigger, + mut pending: ResMut, + query: Query<&RenderWorldSyncEntity>| { + let render_entity = query.get(trigger.entity()).unwrap().0; + pending.push(EntityRecord::Removed(render_entity)); + }, + ); + } +} diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 16aee3f52937b..88a4284b55929 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -223,7 +223,7 @@ pub fn extract_mesh2d( >, ) { render_mesh_instances.clear(); - let mut entities = Vec::with_capacity(*previous_len); + // let mut entities = Vec::with_capacity(*previous_len); for (entity, view_visibility, transform, handle, no_automatic_batching) in &query { if !view_visibility.get() { @@ -231,7 +231,7 @@ pub fn extract_mesh2d( } // FIXME: Remove this - it is just a workaround to enable rendering to work as // render commands require an entity to exist at the moment. - entities.push((entity, Mesh2d)); + // entities.push((entity, Mesh2d)); render_mesh_instances.insert( entity, RenderMesh2dInstance { @@ -245,8 +245,8 @@ pub fn extract_mesh2d( }, ); } - *previous_len = entities.len(); - commands.insert_or_spawn_batch(entities); + // *previous_len = entities.len(); + // commands.insert_or_spawn_batch(entities); } #[derive(Resource, Clone)] diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index c4cafa593ab1f..c988460c573dc 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -9,6 +9,7 @@ use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::texture::TRANSPARENT_IMAGE_HANDLE; +use bevy_render::world_sync::RenderWorldSyncEntity; use bevy_render::{ render_phase::{PhaseItem, PhaseItemExtraIndex}, texture::GpuImage, @@ -725,7 +726,14 @@ pub fn extract_default_ui_camera_view( mut commands: Commands, mut transparent_render_phases: ResMut>, ui_scale: Extract>, - query: Extract, With)>>>, + query: Extract< + Query< + (&RenderWorldSyncEntity, &Camera), + (Or<(With, With)>, Changed), + >, + >, + render_camera_view_query: Query<&DefaultCameraView>, + mut view_query: Query<&mut ExtractedView>, mut live_entities: Local, ) { live_entities.clear(); @@ -736,30 +744,29 @@ pub fn extract_default_ui_camera_view( if !camera.is_active { continue; } - - if let ( - Some(logical_size), - Some(URect { - min: physical_origin, - .. - }), - Some(physical_size), - ) = ( - camera.logical_viewport_size(), - camera.physical_viewport_rect(), - camera.physical_viewport_size(), - ) { - // use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection - let projection_matrix = Mat4::orthographic_rh( - 0.0, - logical_size.x * scale, - logical_size.y * scale, - 0.0, - 0.0, - UI_CAMERA_FAR, - ); - let default_camera_view = commands - .spawn(ExtractedView { + if let Some(entity) = entity.entity().clone() { + if let ( + Some(logical_size), + Some(URect { + min: physical_origin, + .. + }), + Some(physical_size), + ) = ( + camera.logical_viewport_size(), + camera.physical_viewport_rect(), + camera.physical_viewport_size(), + ) { + // use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection + let projection_matrix = Mat4::orthographic_rh( + 0.0, + logical_size.x * scale, + logical_size.y * scale, + 0.0, + 0.0, + UI_CAMERA_FAR, + ); + let extract_view = ExtractedView { clip_from_view: projection_matrix, world_from_view: GlobalTransform::from_xyz( 0.0, @@ -775,14 +782,21 @@ pub fn extract_default_ui_camera_view( physical_size.y, ), color_grading: Default::default(), - }) - .id(); - commands - .get_or_spawn(entity) - .insert(DefaultCameraView(default_camera_view)); - transparent_render_phases.insert_or_clear(entity); - - live_entities.insert(entity); + }; + if let Ok(default_ui_camera_view) = render_camera_view_query.get(entity) { + let mut extract_view_item = + view_query.get_mut(default_ui_camera_view.0).unwrap(); + *extract_view_item = extract_view + } else { + let default_camera_view = commands.spawn(extract_view).id(); + commands + .get_or_spawn(entity) + .insert(DefaultCameraView(default_camera_view)); + }; + transparent_render_phases.insert_or_clear(entity); + + live_entities.insert(entity); + } } } From 17f2bb0c4dcbd09fee165f1569bd70512728c23b Mon Sep 17 00:00:00 2001 From: re0312 Date: Sun, 7 Jul 2024 14:42:10 +0800 Subject: [PATCH 02/55] sync --- crates/bevy_pbr/src/bundle.rs | 2 + crates/bevy_pbr/src/material.rs | 5 +- crates/bevy_pbr/src/render/light.rs | 141 +++++++++++------- crates/bevy_render/src/camera/camera.rs | 87 +++++------ crates/bevy_render/src/view/visibility/mod.rs | 40 +++-- crates/bevy_render/src/world_sync.rs | 2 +- crates/bevy_sprite/src/mesh2d/mesh.rs | 6 - 7 files changed, 149 insertions(+), 134 deletions(-) diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index 3a6dec734fb72..bf57acb7cd2d9 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -6,6 +6,7 @@ use bevy_asset::Handle; use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent}; use bevy_reflect::Reflect; +use bevy_render::world_sync::RenderWorldSyncEntity; use bevy_render::{ mesh::Mesh, primitives::{CascadesFrusta, CubemapFrusta, Frustum}, @@ -92,6 +93,7 @@ pub struct PointLightBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, + pub render_entity: RenderWorldSyncEntity, } /// A component bundle for spot light entities diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 272b60d81e1be..1c288c96e3156 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -572,7 +572,6 @@ pub fn queue_material_meshes( ) where M::Data: PartialEq + Eq + Hash + Clone, { - println!("queue view :{}",views.iter().count()); for ( view_entity, view, @@ -677,6 +676,10 @@ pub fn queue_material_meshes( } let rangefinder = view.rangefinder3d(); + println!( + "visible_entities:{}", + visible_entities.iter::().count() + ); for visible_entity in visible_entities.iter::() { let Some(material_asset_id) = render_material_instances.get(visible_entity) else { continue; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 1356e94825ccc..3a3602de3084f 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -5,6 +5,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_render::world_sync::RenderWorldSyncEntity; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::GpuMesh, @@ -176,6 +177,7 @@ pub fn extract_lights( global_point_lights: Extract>, point_lights: Extract< Query<( + &RenderWorldSyncEntity, &PointLight, &CubemapVisibleEntities, &GlobalTransform, @@ -185,6 +187,7 @@ pub fn extract_lights( >, spot_lights: Extract< Query<( + &RenderWorldSyncEntity, &SpotLight, &VisibleEntities, &GlobalTransform, @@ -195,7 +198,7 @@ pub fn extract_lights( directional_lights: Extract< Query< ( - Entity, + &RenderWorldSyncEntity, &DirectionalLight, &CascadesVisibleEntities, &Cascades, @@ -231,8 +234,14 @@ pub fn extract_lights( let mut point_lights_values = Vec::with_capacity(*previous_point_lights_len); for entity in global_point_lights.iter().copied() { - let Ok((point_light, cubemap_visible_entities, transform, view_visibility, frusta)) = - point_lights.get(entity) + let Ok(( + render_entity, + point_light, + cubemap_visible_entities, + transform, + view_visibility, + frusta, + )) = point_lights.get(entity) else { continue; }; @@ -259,22 +268,30 @@ pub fn extract_lights( * std::f32::consts::SQRT_2, spot_light_angles: None, }; - point_lights_values.push(( - entity, - ( - extracted_point_light, - render_cubemap_visible_entities, - (*frusta).clone(), - ), - )); + if let Some(entity) = render_entity.entity() { + point_lights_values.push(( + entity, + ( + extracted_point_light, + render_cubemap_visible_entities, + (*frusta).clone(), + ), + )); + } } *previous_point_lights_len = point_lights_values.len(); commands.insert_or_spawn_batch(point_lights_values); let mut spot_lights_values = Vec::with_capacity(*previous_spot_lights_len); for entity in global_point_lights.iter().copied() { - if let Ok((spot_light, visible_entities, transform, view_visibility, frustum)) = - spot_lights.get(entity) + if let Ok(( + render_entity, + spot_light, + visible_entities, + transform, + view_visibility, + frustum, + )) = spot_lights.get(entity) { if !view_visibility.get() { continue; @@ -285,40 +302,45 @@ pub fn extract_lights( let texel_size = 2.0 * spot_light.outer_angle.tan() / directional_light_shadow_map.size as f32; - spot_lights_values.push(( - entity, - ( - ExtractedPointLight { - color: spot_light.color.into(), - // NOTE: Map from luminous power in lumens to luminous intensity in lumens per steradian - // for a point light. See https://google.github.io/filament/Filament.html#mjx-eqn-pointLightLuminousPower - // for details. - // Note: Filament uses a divisor of PI for spot lights. We choose to use the same 4*PI divisor - // in both cases so that toggling between point light and spot light keeps lit areas lit equally, - // which seems least surprising for users - intensity: spot_light.intensity / (4.0 * std::f32::consts::PI), - range: spot_light.range, - radius: spot_light.radius, - transform: *transform, - shadows_enabled: spot_light.shadows_enabled, - shadow_depth_bias: spot_light.shadow_depth_bias, - // The factor of SQRT_2 is for the worst-case diagonal offset - shadow_normal_bias: spot_light.shadow_normal_bias - * texel_size - * std::f32::consts::SQRT_2, - spot_light_angles: Some((spot_light.inner_angle, spot_light.outer_angle)), - }, - render_visible_entities, - *frustum, - ), - )); + if let Some(entity) = render_entity.entity() { + spot_lights_values.push(( + entity, + ( + ExtractedPointLight { + color: spot_light.color.into(), + // NOTE: Map from luminous power in lumens to luminous intensity in lumens per steradian + // for a point light. See https://google.github.io/filament/Filament.html#mjx-eqn-pointLightLuminousPower + // for details. + // Note: Filament uses a divisor of PI for spot lights. We choose to use the same 4*PI divisor + // in both cases so that toggling between point light and spot light keeps lit areas lit equally, + // which seems least surprising for users + intensity: spot_light.intensity / (4.0 * std::f32::consts::PI), + range: spot_light.range, + radius: spot_light.radius, + transform: *transform, + shadows_enabled: spot_light.shadows_enabled, + shadow_depth_bias: spot_light.shadow_depth_bias, + // The factor of SQRT_2 is for the worst-case diagonal offset + shadow_normal_bias: spot_light.shadow_normal_bias + * texel_size + * std::f32::consts::SQRT_2, + spot_light_angles: Some(( + spot_light.inner_angle, + spot_light.outer_angle, + )), + }, + render_visible_entities, + *frustum, + ), + )); + } } } *previous_spot_lights_len = spot_lights_values.len(); commands.insert_or_spawn_batch(spot_lights_values); for ( - entity, + render_entity, directional_light, visible_entities, cascades, @@ -336,23 +358,26 @@ pub fn extract_lights( // TODO: As above let render_visible_entities = visible_entities.clone(); - commands.get_or_spawn(entity).insert(( - ExtractedDirectionalLight { - color: directional_light.color.into(), - illuminance: directional_light.illuminance, - transform: *transform, - volumetric: volumetric_light.is_some(), - shadows_enabled: directional_light.shadows_enabled, - shadow_depth_bias: directional_light.shadow_depth_bias, - // The factor of SQRT_2 is for the worst-case diagonal offset - shadow_normal_bias: directional_light.shadow_normal_bias * std::f32::consts::SQRT_2, - cascade_shadow_config: cascade_config.clone(), - cascades: cascades.cascades.clone(), - frusta: frusta.frusta.clone(), - render_layers: maybe_layers.unwrap_or_default().clone(), - }, - render_visible_entities, - )); + if let Some(entity) = render_entity.entity() { + commands.get_or_spawn(entity).insert(( + ExtractedDirectionalLight { + color: directional_light.color.into(), + illuminance: directional_light.illuminance, + transform: *transform, + volumetric: volumetric_light.is_some(), + shadows_enabled: directional_light.shadows_enabled, + shadow_depth_bias: directional_light.shadow_depth_bias, + // The factor of SQRT_2 is for the worst-case diagonal offset + shadow_normal_bias: directional_light.shadow_normal_bias + * std::f32::consts::SQRT_2, + cascade_shadow_config: cascade_config.clone(), + cascades: cascades.cascades.clone(), + frusta: frusta.frusta.clone(), + render_layers: maybe_layers.unwrap_or_default().clone(), + }, + render_visible_entities, + )); + } } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 2a4b2a528f34b..68f62aea8d293 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -9,6 +9,7 @@ use crate::{ texture::GpuImage, view::{ ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, RenderLayers, VisibleEntities, + WithMesh, }, world_sync::RenderWorldSyncEntity, Extract, @@ -847,13 +848,6 @@ pub fn extract_cameras( >, primary_window: Extract>>, gpu_preprocessing_support: Res, - mut render_query: Query<( - Entity, - &mut ExtractedCamera, - &mut ExtractedView, - &mut VisibleEntities, - &mut Frustum, - )>, ) { let primary_window = primary_window.iter().next(); for ( @@ -862,7 +856,7 @@ pub fn extract_cameras( transform, visible_entities, frustum, - rw_entity, + render_entity, color_grading, exposure, temporal_jitter, @@ -892,43 +886,44 @@ pub fn extract_cameras( continue; } - if let Ok((e, mut extract_camera, mut extracted_view, mut entities, mut fru)) = - render_query.get_mut(rw_entity.unwrap()) - { - *extract_camera = ExtractedCamera { - target: camera.target.normalize(primary_window), - viewport: camera.viewport.clone(), - physical_viewport_size: Some(viewport_size), - physical_target_size: Some(target_size), - render_graph: camera_render_graph.0, - order: camera.order, - output_mode: camera.output_mode, - msaa_writeback: camera.msaa_writeback, - clear_color: camera.clear_color, - // this will be set in sort_cameras - sorted_camera_index_for_target: 0, - exposure: exposure - .map(Exposure::exposure) - .unwrap_or_else(|| Exposure::default().exposure()), - hdr: camera.hdr, - }; - *extracted_view = ExtractedView { - clip_from_view: camera.clip_from_view(), - world_from_view: *transform, - clip_from_world: None, - hdr: camera.hdr, - viewport: UVec4::new( - viewport_origin.x, - viewport_origin.y, - viewport_size.x, - viewport_size.y, - ), - color_grading, - }; - *entities = visible_entities.clone(); - *fru = *frustum; - - let mut commands = commands.entity(e); + if let Some(entity) = render_entity.entity() { + let mut commands = commands.entity(entity); + println!("camera:{}", visible_entities.get::().len()); + commands.insert(( + ExtractedCamera { + target: camera.target.normalize(primary_window), + viewport: camera.viewport.clone(), + physical_viewport_size: Some(viewport_size), + physical_target_size: Some(target_size), + render_graph: camera_render_graph.0, + order: camera.order, + output_mode: camera.output_mode, + msaa_writeback: camera.msaa_writeback, + clear_color: camera.clear_color, + // this will be set in sort_cameras + sorted_camera_index_for_target: 0, + exposure: exposure + .map(Exposure::exposure) + .unwrap_or_else(|| Exposure::default().exposure()), + hdr: camera.hdr, + }, + ExtractedView { + clip_from_view: camera.clip_from_view(), + world_from_view: *transform, + clip_from_world: None, + hdr: camera.hdr, + viewport: UVec4::new( + viewport_origin.x, + viewport_origin.y, + viewport_size.x, + viewport_size.y, + ), + color_grading, + }, + visible_entities.clone(), + *frustum, + )); + if let Some(temporal_jitter) = temporal_jitter { commands.insert(temporal_jitter.clone()); } @@ -949,7 +944,7 @@ pub fn extract_cameras( ); } } - } + }; } } } diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 1897f4194614e..62975cd28afcf 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -412,7 +412,6 @@ pub fn check_visibility( Option<&RenderLayers>, Option<&Aabb>, &GlobalTransform, - &RenderWorldSyncEntity, Has, Has, ), @@ -443,7 +442,6 @@ pub fn check_visibility( maybe_entity_mask, maybe_model_aabb, transform, - render_entity, no_frustum_culling, has_visibility_range, ) = query_item; @@ -468,29 +466,27 @@ pub fn check_visibility( return; } - if let Some(entity) = render_entity.deref() { - // If we have an aabb, do frustum culling - if !no_frustum_culling && !no_cpu_culling { - if let Some(model_aabb) = maybe_model_aabb { - let world_from_local = transform.affine(); - let model_sphere = Sphere { - center: world_from_local.transform_point3a(model_aabb.center), - radius: transform.radius_vec3a(model_aabb.half_extents), - }; - // Do quick sphere-based frustum culling - if !frustum.intersects_sphere(&model_sphere, false) { - return; - } - // Do aabb-based frustum culling - if !frustum.intersects_obb(model_aabb, &world_from_local, true, false) { - return; - } + // If we have an aabb, do frustum culling + if !no_frustum_culling && !no_cpu_culling { + if let Some(model_aabb) = maybe_model_aabb { + let world_from_local = transform.affine(); + let model_sphere = Sphere { + center: world_from_local.transform_point3a(model_aabb.center), + radius: transform.radius_vec3a(model_aabb.half_extents), + }; + // Do quick sphere-based frustum culling + if !frustum.intersects_sphere(&model_sphere, false) { + return; + } + // Do aabb-based frustum culling + if !frustum.intersects_obb(model_aabb, &world_from_local, true, false) { + return; } } - - view_visibility.set(); - queue.push(*entity); } + + view_visibility.set(); + queue.push(entity); }, ); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index a85a56e991211..94cbf69036f52 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -14,7 +14,7 @@ use bevy_ecs::{ }; use bevy_hierarchy::DespawnRecursiveExt; -#[derive(Component, Deref, Default, Clone)] +#[derive(Component, Deref, Default, Clone, Debug)] #[component(storage = "SparseSet")] pub struct RenderWorldSyncEntity(Option); diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 88a4284b55929..415f68ba7b83b 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -209,8 +209,6 @@ pub struct RenderMesh2dInstances(EntityHashMap); pub struct Mesh2d; pub fn extract_mesh2d( - mut commands: Commands, - mut previous_len: Local, mut render_mesh_instances: ResMut, query: Extract< Query<( @@ -223,7 +221,6 @@ pub fn extract_mesh2d( >, ) { render_mesh_instances.clear(); - // let mut entities = Vec::with_capacity(*previous_len); for (entity, view_visibility, transform, handle, no_automatic_batching) in &query { if !view_visibility.get() { @@ -231,7 +228,6 @@ pub fn extract_mesh2d( } // FIXME: Remove this - it is just a workaround to enable rendering to work as // render commands require an entity to exist at the moment. - // entities.push((entity, Mesh2d)); render_mesh_instances.insert( entity, RenderMesh2dInstance { @@ -245,8 +241,6 @@ pub fn extract_mesh2d( }, ); } - // *previous_len = entities.len(); - // commands.insert_or_spawn_batch(entities); } #[derive(Resource, Clone)] From 35fe01e56639febd46089e1442adc0caaeb4b228 Mon Sep 17 00:00:00 2001 From: re0312 Date: Mon, 22 Jul 2024 20:29:18 +0800 Subject: [PATCH 03/55] cleanup --- .../src/auto_exposure/buffers.rs | 14 +-- crates/bevy_core_pipeline/src/core_2d/mod.rs | 16 +-- .../src/core_3d/camera_3d.rs | 6 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 6 +- crates/bevy_core_pipeline/src/dof/mod.rs | 51 ++++---- crates/bevy_core_pipeline/src/taa/mod.rs | 16 ++- crates/bevy_pbr/src/bundle.rs | 4 +- crates/bevy_pbr/src/cluster/mod.rs | 25 ++-- crates/bevy_pbr/src/light_probe/mod.rs | 4 +- crates/bevy_pbr/src/prepass/mod.rs | 16 ++- crates/bevy_pbr/src/render/light.rs | 8 +- crates/bevy_pbr/src/ssao/mod.rs | 16 +-- crates/bevy_pbr/src/volumetric_fog/mod.rs | 4 +- crates/bevy_render/src/camera/camera.rs | 116 +++++++++--------- crates/bevy_render/src/extract_component.rs | 18 ++- crates/bevy_render/src/view/visibility/mod.rs | 1 - crates/bevy_render/src/world_sync.rs | 55 ++++----- crates/bevy_ui/src/render/mod.rs | 107 ++++++++-------- 18 files changed, 225 insertions(+), 258 deletions(-) diff --git a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs index c7ee0f2d3a6ef..3d273f275dce5 100644 --- a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs +++ b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs @@ -4,7 +4,7 @@ use bevy_ecs::prelude::*; use bevy_render::{ render_resource::{StorageBuffer, UniformBuffer}, renderer::{RenderDevice, RenderQueue}, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, }; use bevy_utils::{Entry, HashMap}; @@ -30,20 +30,14 @@ pub(super) struct ExtractedStateBuffers { pub(super) fn extract_buffers( mut commands: Commands, - changed: Extract< - Query<(&RenderWorldSyncEntity, &AutoExposureSettings), Changed>, - >, + changed: Extract>>, mut removed: Extract>, ) { commands.insert_resource(ExtractedStateBuffers { changed: changed .iter() - .filter_map(|(entity, settings)| { - if let Some(entity) = entity.entity() { - return Some((entity, settings.clone())); - } else { - None - } + .map(|(entity, settings)| { + (entity.entity(), settings.clone()); }) .collect(), removed: removed.read().collect(), diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index 624fab2f11333..4f9b8a8d88710 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -33,7 +33,10 @@ pub use camera_2d::*; pub use main_transparent_pass_2d_node::*; use bevy_app::{App, Plugin}; -use bevy_ecs::{entity::EntityHashSet, prelude::*}; +use bevy_ecs::{ + entity::{self, EntityHashSet}, + prelude::*, +}; use bevy_math::FloatOrd; use bevy_render::{ camera::Camera, @@ -44,7 +47,7 @@ use bevy_render::{ PhaseItemExtraIndex, SortedPhaseItem, ViewSortedRenderPhases, }, render_resource::CachedRenderPipelineId, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -161,7 +164,7 @@ impl CachedRenderPipelinePhaseItem for Transparent2d { pub fn extract_core_2d_camera_phases( mut transparent_2d_phases: ResMut>, - cameras_2d: Extract>>, + cameras_2d: Extract>>, mut live_entities: Local, ) { live_entities.clear(); @@ -170,10 +173,9 @@ pub fn extract_core_2d_camera_phases( if !camera.is_active { continue; } - if let Some(entity) = entity.entity() { - transparent_2d_phases.insert_or_clear(entity); - live_entities.insert(entity); - } + let entity = entity.entity(); + transparent_2d_phases.insert_or_clear(entity); + live_entities.insert(entity); } // Clear out all dead views. diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index f6c6779fba019..82fe502a7259f 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -10,7 +10,7 @@ use bevy_render::{ primitives::Frustum, render_resource::{LoadOp, TextureUsages}, view::{ColorGrading, VisibleEntities}, - world_sync::RenderWorldSyncEntity, + world_sync::{RenderEntity, ToRenderWorld}, }; use bevy_transform::prelude::{GlobalTransform, Transform}; use serde::{Deserialize, Serialize}; @@ -153,7 +153,7 @@ pub struct Camera3dBundle { pub color_grading: ColorGrading, pub exposure: Exposure, pub main_texture_usages: CameraMainTextureUsages, - pub render_entity: RenderWorldSyncEntity, + _marker: ToRenderWorld, } // NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference @@ -173,7 +173,7 @@ impl Default for Camera3dBundle { exposure: Default::default(), main_texture_usages: Default::default(), deband_dither: DebandDither::Enabled, - render_entity: RenderWorldSyncEntity::default(), + _marker: ToRenderWorld, } } } diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 5ec16bf1fa20f..bc40a7e410f15 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -93,7 +93,7 @@ use bevy_render::{ renderer::RenderDevice, texture::{BevyDefault, ColorAttachment, Image, TextureCache}, view::{ExtractedView, ViewDepthTexture, ViewTarget}, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::{tracing::warn, HashMap}; @@ -511,7 +511,7 @@ pub fn extract_core_3d_camera_phases( mut alpha_mask_3d_phases: ResMut>, mut transmissive_3d_phases: ResMut>, mut transparent_3d_phases: ResMut>, - cameras_3d: Extract>>, + cameras_3d: Extract>>, mut live_entities: Local, ) { live_entities.clear(); @@ -547,7 +547,7 @@ pub fn extract_camera_prepass_phase( cameras_3d: Extract< Query< ( - &RenderWorldSyncEntity, + &RenderEntity, &Camera, Has, Has, diff --git a/crates/bevy_core_pipeline/src/dof/mod.rs b/crates/bevy_core_pipeline/src/dof/mod.rs index b07f20f9f6474..ad08dd4306fb8 100644 --- a/crates/bevy_core_pipeline/src/dof/mod.rs +++ b/crates/bevy_core_pipeline/src/dof/mod.rs @@ -50,7 +50,7 @@ use bevy_render::{ prepare_view_targets, ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, }, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::{info_once, prelude::default, warn_once}; @@ -796,7 +796,7 @@ impl SpecializedRenderPipeline for DepthOfFieldPipeline { /// Extracts all [`DepthOfFieldSettings`] components into the render world. fn extract_depth_of_field_settings( mut commands: Commands, - mut query: Extract>, + mut query: Extract>, ) { if !DEPTH_TEXTURE_SAMPLING_SUPPORTED { info_once!( @@ -806,31 +806,30 @@ fn extract_depth_of_field_settings( } for (entity, dof_settings, projection) in query.iter_mut() { - if let Some(entity) = entity.entity() { - // Depth of field is nonsensical without a perspective projection. - let Projection::Perspective(ref perspective_projection) = *projection else { - continue; - }; + let entity = entity.entity(); + // Depth of field is nonsensical without a perspective projection. + let Projection::Perspective(ref perspective_projection) = *projection else { + continue; + }; - let focal_length = - calculate_focal_length(dof_settings.sensor_height, perspective_projection.fov); - - // Convert `DepthOfFieldSettings` to `DepthOfFieldUniform`. - commands.get_or_spawn(entity).insert(( - *dof_settings, - DepthOfFieldUniform { - focal_distance: dof_settings.focal_distance, - focal_length, - coc_scale_factor: focal_length * focal_length - / (dof_settings.sensor_height * dof_settings.aperture_f_stops), - max_circle_of_confusion_diameter: dof_settings.max_circle_of_confusion_diameter, - max_depth: dof_settings.max_depth, - pad_a: 0, - pad_b: 0, - pad_c: 0, - }, - )); - } + let focal_length = + calculate_focal_length(dof_settings.sensor_height, perspective_projection.fov); + + // Convert `DepthOfFieldSettings` to `DepthOfFieldUniform`. + commands.get_or_spawn(entity).insert(( + *dof_settings, + DepthOfFieldUniform { + focal_distance: dof_settings.focal_distance, + focal_length, + coc_scale_factor: focal_length * focal_length + / (dof_settings.sensor_height * dof_settings.aperture_f_stops), + max_circle_of_confusion_diameter: dof_settings.max_circle_of_confusion_diameter, + max_depth: dof_settings.max_depth, + pad_a: 0, + pad_b: 0, + pad_c: 0, + }, + )); } } diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index 3b6d1f3448c24..1f26e2fe6a71c 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -32,7 +32,7 @@ use bevy_render::{ renderer::{RenderContext, RenderDevice}, texture::{BevyDefault, CachedTexture, TextureCache}, view::{ExtractedView, Msaa, ViewTarget}, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, ExtractSchedule, MainWorld, Render, RenderApp, RenderSet, }; @@ -340,7 +340,7 @@ impl SpecializedRenderPipeline for TaaPipeline { fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut) { let mut cameras_3d = main_world.query_filtered::<( - &RenderWorldSyncEntity, + &RenderEntity, &Camera, &Projection, &mut TemporalAntiAliasSettings, @@ -354,13 +354,11 @@ fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut>, + views: Extract>, ) { for (entity, clusters, camera) in &views { if !camera.is_active { @@ -537,16 +537,15 @@ pub fn extract_clusters( } } - if let Some(entity) = entity.entity() { - commands.get_or_spawn(entity).insert(( - ExtractedClusterableObjects { data }, - ExtractedClusterConfig { - near: clusters.near, - far: clusters.far, - dimensions: clusters.dimensions, - }, - )); - } + let entity = entity.entity(); + commands.get_or_spawn(entity).insert(( + ExtractedClusterableObjects { data }, + ExtractedClusterConfig { + near: clusters.near, + far: clusters.far, + dimensions: clusters.dimensions, + }, + )); } } diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index a0a768413e68a..aa2fbe887e47b 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -23,7 +23,7 @@ use bevy_render::{ settings::WgpuFeatures, texture::{FallbackImage, GpuImage, Image}, view::ExtractedView, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::prelude::GlobalTransform; @@ -348,7 +348,7 @@ fn gather_light_probes( view_query: Extract< Query< ( - &RenderWorldSyncEntity, + &RenderEntity, &GlobalTransform, &Frustum, Option<&C>, diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 8fa50a0f128a8..37cba4d5401bc 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,9 +1,10 @@ mod prepass_bindings; +use bevy_ecs::entity; use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef}; use bevy_render::render_resource::binding_types::uniform_buffer; use bevy_render::view::WithMesh; -use bevy_render::world_sync::RenderWorldSyncEntity; +use bevy_render::world_sync::RenderEntity; pub use prepass_bindings::*; use bevy_asset::{load_internal_asset, AssetServer}; @@ -578,18 +579,15 @@ where // Extract the render phases for the prepass pub fn extract_camera_previous_view_data( mut commands: Commands, - cameras_3d: Extract< - Query<(&RenderWorldSyncEntity, &Camera, Option<&PreviousViewData>), With>, - >, + cameras_3d: Extract), With>>, ) { for (entity, camera, maybe_previous_view_data) in cameras_3d.iter() { if camera.is_active { - if let Some(entity) = entity.entity() { - let mut entity = commands.get_or_spawn(entity); + let entity = entity.entity(); + let mut entity = commands.get_or_spawn(entity); - if let Some(previous_view_data) = maybe_previous_view_data { - entity.insert(previous_view_data.clone()); - } + if let Some(previous_view_data) = maybe_previous_view_data { + entity.insert(previous_view_data.clone()); } } } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 3a3602de3084f..d5fa893b66554 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -5,7 +5,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_render::world_sync::RenderWorldSyncEntity; +use bevy_render::world_sync::RenderEntity; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::GpuMesh, @@ -177,7 +177,7 @@ pub fn extract_lights( global_point_lights: Extract>, point_lights: Extract< Query<( - &RenderWorldSyncEntity, + &RenderEntity, &PointLight, &CubemapVisibleEntities, &GlobalTransform, @@ -187,7 +187,7 @@ pub fn extract_lights( >, spot_lights: Extract< Query<( - &RenderWorldSyncEntity, + &RenderEntity, &SpotLight, &VisibleEntities, &GlobalTransform, @@ -198,7 +198,7 @@ pub fn extract_lights( directional_lights: Extract< Query< ( - &RenderWorldSyncEntity, + &RenderEntity, &DirectionalLight, &CascadesVisibleEntities, &Cascades, diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index cc6b2a78dd2bb..9f3b436c7d147 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -7,6 +7,7 @@ use bevy_core_pipeline::{ prepass::{DepthPrepass, NormalPrepass, ViewPrepassTextures}, }; use bevy_ecs::{ + entity, prelude::{Bundle, Component, Entity}, query::{Has, QueryItem, With}, reflect::ReflectComponent, @@ -30,7 +31,7 @@ use bevy_render::{ renderer::{RenderAdapter, RenderContext, RenderDevice, RenderQueue}, texture::{CachedTexture, TextureCache}, view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms}, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::{ @@ -485,11 +486,7 @@ fn extract_ssao_settings( mut commands: Commands, cameras: Extract< Query< - ( - &RenderWorldSyncEntity, - &Camera, - &ScreenSpaceAmbientOcclusionSettings, - ), + (&RenderEntity, &Camera, &ScreenSpaceAmbientOcclusionSettings), (With, With, With), >, >, @@ -503,10 +500,9 @@ fn extract_ssao_settings( ); return; } - if let Some(entity) = entity.entity() { - if camera.is_active { - commands.get_or_spawn(entity).insert(ssao_settings.clone()); - } + if camera.is_active { + let entity = entity.entity(); + commands.get_or_spawn(entity).insert(ssao_settings.clone()); } } } diff --git a/crates/bevy_pbr/src/volumetric_fog/mod.rs b/crates/bevy_pbr/src/volumetric_fog/mod.rs index 7b0c8c5f64ba9..f8e0cb90c6ea8 100644 --- a/crates/bevy_pbr/src/volumetric_fog/mod.rs +++ b/crates/bevy_pbr/src/volumetric_fog/mod.rs @@ -68,7 +68,7 @@ use bevy_render::{ renderer::{RenderContext, RenderDevice, RenderQueue}, texture::BevyDefault, view::{ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniformOffset}, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_utils::prelude::default; @@ -378,7 +378,7 @@ impl FromWorld for VolumetricFogPipeline { pub fn extract_volumetric_fog( mut commands: Commands, view_targets: Extract< - Query<(&RenderWorldSyncEntity, &VolumetricFogSettings), Changed>, + Query<(&RenderEntity, &VolumetricFogSettings), Changed>, >, volumetric_lights: Extract>, ) { diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 68f62aea8d293..bd035443a773e 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -11,7 +11,7 @@ use crate::{ ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, RenderLayers, VisibleEntities, WithMesh, }, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, }; use bevy_asset::{AssetEvent, AssetId, Assets, Handle}; @@ -837,7 +837,7 @@ pub fn extract_cameras( &GlobalTransform, &VisibleEntities, &Frustum, - &RenderWorldSyncEntity, + &RenderEntity, Option<&ColorGrading>, Option<&Exposure>, Option<&TemporalJitter>, @@ -886,66 +886,64 @@ pub fn extract_cameras( continue; } - if let Some(entity) = render_entity.entity() { - let mut commands = commands.entity(entity); - println!("camera:{}", visible_entities.get::().len()); - commands.insert(( - ExtractedCamera { - target: camera.target.normalize(primary_window), - viewport: camera.viewport.clone(), - physical_viewport_size: Some(viewport_size), - physical_target_size: Some(target_size), - render_graph: camera_render_graph.0, - order: camera.order, - output_mode: camera.output_mode, - msaa_writeback: camera.msaa_writeback, - clear_color: camera.clear_color, - // this will be set in sort_cameras - sorted_camera_index_for_target: 0, - exposure: exposure - .map(Exposure::exposure) - .unwrap_or_else(|| Exposure::default().exposure()), - hdr: camera.hdr, - }, - ExtractedView { - clip_from_view: camera.clip_from_view(), - world_from_view: *transform, - clip_from_world: None, - hdr: camera.hdr, - viewport: UVec4::new( - viewport_origin.x, - viewport_origin.y, - viewport_size.x, - viewport_size.y, - ), - color_grading, - }, - visible_entities.clone(), - *frustum, - )); - - if let Some(temporal_jitter) = temporal_jitter { - commands.insert(temporal_jitter.clone()); - } + let entity = render_entity.entity(); + let mut commands = commands.entity(entity); + commands.insert(( + ExtractedCamera { + target: camera.target.normalize(primary_window), + viewport: camera.viewport.clone(), + physical_viewport_size: Some(viewport_size), + physical_target_size: Some(target_size), + render_graph: camera_render_graph.0, + order: camera.order, + output_mode: camera.output_mode, + msaa_writeback: camera.msaa_writeback, + clear_color: camera.clear_color, + // this will be set in sort_cameras + sorted_camera_index_for_target: 0, + exposure: exposure + .map(Exposure::exposure) + .unwrap_or_else(|| Exposure::default().exposure()), + hdr: camera.hdr, + }, + ExtractedView { + clip_from_view: camera.clip_from_view(), + world_from_view: *transform, + clip_from_world: None, + hdr: camera.hdr, + viewport: UVec4::new( + viewport_origin.x, + viewport_origin.y, + viewport_size.x, + viewport_size.y, + ), + color_grading, + }, + visible_entities.clone(), + *frustum, + )); + + if let Some(temporal_jitter) = temporal_jitter { + commands.insert(temporal_jitter.clone()); + } - if let Some(render_layers) = render_layers { - commands.insert(render_layers.clone()); - } + if let Some(render_layers) = render_layers { + commands.insert(render_layers.clone()); + } - if let Some(perspective) = projection { - commands.insert(perspective.clone()); - } - if gpu_culling { - if *gpu_preprocessing_support == GpuPreprocessingSupport::Culling { - commands.insert(GpuCulling); - } else { - warn_once!( - "GPU culling isn't supported on this platform; ignoring `GpuCulling`." - ); - } + if let Some(perspective) = projection { + commands.insert(perspective.clone()); + } + if gpu_culling { + if *gpu_preprocessing_support == GpuPreprocessingSupport::Culling { + commands.insert(GpuCulling); + } else { + warn_once!( + "GPU culling isn't supported on this platform; ignoring `GpuCulling`." + ); } - }; - } + } + }; } } diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 169a9c19626ad..9289aecf9b266 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -2,7 +2,7 @@ use crate::{ render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ViewVisibility, - world_sync::RenderWorldSyncEntity, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_app::{App, Plugin}; @@ -210,14 +210,12 @@ impl ExtractComponent for Handle { fn extract_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in &query { - if let Some(entity) = entity.entity() { - if let Some(component) = C::extract_component(query_item) { - values.push((entity, component)); - } + if let Some(component) = C::extract_component(query_item) { + values.push((entity.entity(), component)); } } *previous_len = values.len(); @@ -228,15 +226,13 @@ fn extract_components( fn extract_visible_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, view_visibility, query_item) in &query { if view_visibility.get() { - if let Some(entity) = entity.entity() { - if let Some(component) = C::extract_component(query_item) { - values.push((entity, component)); - } + if let Some(component) = C::extract_component(query_item) { + values.push((entity.entity(), component)); } } } diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 62975cd28afcf..e077ee39cdfa7 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -19,7 +19,6 @@ use crate::{ camera::{Camera, CameraProjection}, mesh::Mesh, primitives::{Aabb, Frustum, Sphere}, - world_sync::RenderWorldSyncEntity, }; use super::NoCpuCulling; diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 94cbf69036f52..4d3e264739906 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -1,31 +1,30 @@ -use std::marker::PhantomData; - use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - bundle::Bundle, - change_detection::DetectChanges, - component::{Component, ComponentHooks, StorageType}, - entity::{Entity, EntityHashSet}, + component::Component, + entity::Entity, observer::Trigger, - query::Has, - system::{Commands, Query, ResMut, Resource}, - world::{self, Mut, OnAdd, OnRemove, World}, + system::{ResMut, Resource}, + world::{Mut, OnAdd, OnRemove, World}, }; use bevy_hierarchy::DespawnRecursiveExt; -#[derive(Component, Deref, Default, Clone, Debug)] -#[component(storage = "SparseSet")] -pub struct RenderWorldSyncEntity(Option); +// marker component to indicate that its entity needs to be synchronized between RenderWorld and MainWorld +#[derive(Component)] +pub struct ToRenderWorld; -impl RenderWorldSyncEntity { - pub fn entity(&self) -> Option { +#[derive(Component, Deref, Clone, Debug)] +#[component(storage = "SparseSet")] +pub struct RenderEntity(Entity); +impl RenderEntity { + pub fn entity(&self) -> Entity { self.0 } } + enum EntityRecord { Added(Entity), - Removed(Option), + Removed(Entity), } #[derive(Resource, Default, Deref, DerefMut)] @@ -39,17 +38,15 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl match record { EntityRecord::Added(e) => { let id = render_world.spawn_empty().id(); - println!("sync added :main [{:?}],render:[{:?}]", e, id); - world.get_mut::(e).map(|mut e| { - e.0 = Some(id); - }); + // println!("sync added :main [{:?}],render:[{:?}]", e, id); + if let Some(mut entity) = world.get_entity_mut(e) { + entity.insert(RenderEntity(id)); + } } EntityRecord::Removed(e) => { - if let Some(e) = e { - render_world - .get_entity_mut(e) - .map(|ec| ec.despawn_recursive()); - } + render_world + .get_entity_mut(e) + .map(|ec| ec.despawn_recursive()); } } } @@ -62,17 +59,13 @@ impl Plugin for WorldSyncPlugin { fn build(&self, app: &mut bevy_app::App) { app.init_resource::(); app.observe( - |trigger: Trigger, - mut pending: ResMut| { + |trigger: Trigger, mut pending: ResMut| { pending.push(EntityRecord::Added(trigger.entity())); }, ); app.observe( - |trigger: Trigger, - mut pending: ResMut, - query: Query<&RenderWorldSyncEntity>| { - let render_entity = query.get(trigger.entity()).unwrap().0; - pending.push(EntityRecord::Removed(render_entity)); + |trigger: Trigger, mut pending: ResMut| { + pending.push(EntityRecord::Removed(trigger.entity())); }, ); } diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index c988460c573dc..2cf2bd7723224 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -9,7 +9,7 @@ use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::texture::TRANSPARENT_IMAGE_HANDLE; -use bevy_render::world_sync::RenderWorldSyncEntity; +use bevy_render::world_sync::RenderEntity; use bevy_render::{ render_phase::{PhaseItem, PhaseItemExtraIndex}, texture::GpuImage, @@ -727,10 +727,7 @@ pub fn extract_default_ui_camera_view( mut transparent_render_phases: ResMut>, ui_scale: Extract>, query: Extract< - Query< - (&RenderWorldSyncEntity, &Camera), - (Or<(With, With)>, Changed), - >, + Query<(&RenderEntity, &Camera), (Or<(With, With)>, Changed)>, >, render_camera_view_query: Query<&DefaultCameraView>, mut view_query: Query<&mut ExtractedView>, @@ -744,59 +741,57 @@ pub fn extract_default_ui_camera_view( if !camera.is_active { continue; } - if let Some(entity) = entity.entity().clone() { - if let ( - Some(logical_size), - Some(URect { - min: physical_origin, - .. - }), - Some(physical_size), - ) = ( - camera.logical_viewport_size(), - camera.physical_viewport_rect(), - camera.physical_viewport_size(), - ) { - // use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection - let projection_matrix = Mat4::orthographic_rh( - 0.0, - logical_size.x * scale, - logical_size.y * scale, + let entity = entity.entity(); + if let ( + Some(logical_size), + Some(URect { + min: physical_origin, + .. + }), + Some(physical_size), + ) = ( + camera.logical_viewport_size(), + camera.physical_viewport_rect(), + camera.physical_viewport_size(), + ) { + // use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection + let projection_matrix = Mat4::orthographic_rh( + 0.0, + logical_size.x * scale, + logical_size.y * scale, + 0.0, + 0.0, + UI_CAMERA_FAR, + ); + let extract_view = ExtractedView { + clip_from_view: projection_matrix, + world_from_view: GlobalTransform::from_xyz( 0.0, 0.0, - UI_CAMERA_FAR, - ); - let extract_view = ExtractedView { - clip_from_view: projection_matrix, - world_from_view: GlobalTransform::from_xyz( - 0.0, - 0.0, - UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, - ), - clip_from_world: None, - hdr: camera.hdr, - viewport: UVec4::new( - physical_origin.x, - physical_origin.y, - physical_size.x, - physical_size.y, - ), - color_grading: Default::default(), - }; - if let Ok(default_ui_camera_view) = render_camera_view_query.get(entity) { - let mut extract_view_item = - view_query.get_mut(default_ui_camera_view.0).unwrap(); - *extract_view_item = extract_view - } else { - let default_camera_view = commands.spawn(extract_view).id(); - commands - .get_or_spawn(entity) - .insert(DefaultCameraView(default_camera_view)); - }; - transparent_render_phases.insert_or_clear(entity); - - live_entities.insert(entity); - } + UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, + ), + clip_from_world: None, + hdr: camera.hdr, + viewport: UVec4::new( + physical_origin.x, + physical_origin.y, + physical_size.x, + physical_size.y, + ), + color_grading: Default::default(), + }; + if let Ok(default_ui_camera_view) = render_camera_view_query.get(entity) { + let mut extract_view_item = view_query.get_mut(default_ui_camera_view.0).unwrap(); + *extract_view_item = extract_view + } else { + let default_camera_view = commands.spawn(extract_view).id(); + commands + .get_or_spawn(entity) + .insert(DefaultCameraView(default_camera_view)); + }; + transparent_render_phases.insert_or_clear(entity); + + live_entities.insert(entity); } } From f9bae87599b1f539109ee1e40844a5fcba19b24c Mon Sep 17 00:00:00 2001 From: re0312 Date: Mon, 22 Jul 2024 20:37:50 +0800 Subject: [PATCH 04/55] clean --- .../src/auto_exposure/buffers.rs | 2 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 7 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 20 ++- crates/bevy_core_pipeline/src/dof/mod.rs | 1 - crates/bevy_pbr/src/material.rs | 4 - crates/bevy_pbr/src/render/light.rs | 114 ++++++++---------- crates/bevy_render/src/camera/camera.rs | 4 +- crates/bevy_render/src/view/visibility/mod.rs | 2 +- crates/bevy_render/src/world_sync.rs | 3 +- 9 files changed, 67 insertions(+), 90 deletions(-) diff --git a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs index 3d273f275dce5..c9571daae7329 100644 --- a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs +++ b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs @@ -37,7 +37,7 @@ pub(super) fn extract_buffers( changed: changed .iter() .map(|(entity, settings)| { - (entity.entity(), settings.clone()); + (entity.entity(), settings.clone()) }) .collect(), removed: removed.read().collect(), diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index 4f9b8a8d88710..669bc1ada1fb4 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -27,16 +27,13 @@ pub mod graph { } } -use std::ops::{Deref, Range}; +use std::ops::Range; pub use camera_2d::*; pub use main_transparent_pass_2d_node::*; use bevy_app::{App, Plugin}; -use bevy_ecs::{ - entity::{self, EntityHashSet}, - prelude::*, -}; +use bevy_ecs::{entity::EntityHashSet, prelude::*}; use bevy_math::FloatOrd; use bevy_render::{ camera::Camera, diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index bc40a7e410f15..5ea91cd436ac6 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -62,7 +62,7 @@ pub const DEPTH_TEXTURE_SAMPLING_SUPPORTED: bool = false; #[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))] pub const DEPTH_TEXTURE_SAMPLING_SUPPORTED: bool = true; -use std::ops::{Deref, Range}; +use std::ops::Range; use bevy_asset::{AssetId, UntypedAssetId}; use bevy_color::LinearRgba; @@ -71,10 +71,7 @@ pub use main_opaque_pass_3d_node::*; pub use main_transparent_pass_3d_node::*; use bevy_app::{App, Plugin, PostUpdate}; -use bevy_ecs::{ - entity::{self, EntityHashSet}, - prelude::*, -}; +use bevy_ecs::{entity::EntityHashSet, prelude::*}; use bevy_math::FloatOrd; use bevy_render::{ camera::{Camera, ExtractedCamera}, @@ -521,14 +518,13 @@ pub fn extract_core_3d_camera_phases( continue; } - if let Some(entity) = render_entity.entity() { - opaque_3d_phases.insert_or_clear(entity); - alpha_mask_3d_phases.insert_or_clear(entity); - transmissive_3d_phases.insert_or_clear(entity); - transparent_3d_phases.insert_or_clear(entity); + let entity = render_entity.entity(); + opaque_3d_phases.insert_or_clear(entity); + alpha_mask_3d_phases.insert_or_clear(entity); + transmissive_3d_phases.insert_or_clear(entity); + transparent_3d_phases.insert_or_clear(entity); - live_entities.insert(entity); - }; + live_entities.insert(entity); } opaque_3d_phases.retain(|entity, _| live_entities.contains(entity)); diff --git a/crates/bevy_core_pipeline/src/dof/mod.rs b/crates/bevy_core_pipeline/src/dof/mod.rs index ad08dd4306fb8..c71518aa0cbe1 100644 --- a/crates/bevy_core_pipeline/src/dof/mod.rs +++ b/crates/bevy_core_pipeline/src/dof/mod.rs @@ -14,7 +14,6 @@ //! //! [Depth of field]: https://en.wikipedia.org/wiki/Depth_of_field -use std::ops::Deref; use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, Handle}; diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index 1c288c96e3156..a1c07e7413501 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -676,10 +676,6 @@ pub fn queue_material_meshes( } let rangefinder = view.rangefinder3d(); - println!( - "visible_entities:{}", - visible_entities.iter::().count() - ); for visible_entity in visible_entities.iter::() { let Some(material_asset_id) = render_material_instances.get(visible_entity) else { continue; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index d5fa893b66554..356c0f4b8b4a9 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -268,16 +268,14 @@ pub fn extract_lights( * std::f32::consts::SQRT_2, spot_light_angles: None, }; - if let Some(entity) = render_entity.entity() { - point_lights_values.push(( - entity, - ( - extracted_point_light, - render_cubemap_visible_entities, - (*frusta).clone(), - ), - )); - } + point_lights_values.push(( + render_entity.entity(), + ( + extracted_point_light, + render_cubemap_visible_entities, + (*frusta).clone(), + ), + )); } *previous_point_lights_len = point_lights_values.len(); commands.insert_or_spawn_batch(point_lights_values); @@ -302,38 +300,33 @@ pub fn extract_lights( let texel_size = 2.0 * spot_light.outer_angle.tan() / directional_light_shadow_map.size as f32; - if let Some(entity) = render_entity.entity() { - spot_lights_values.push(( - entity, - ( - ExtractedPointLight { - color: spot_light.color.into(), - // NOTE: Map from luminous power in lumens to luminous intensity in lumens per steradian - // for a point light. See https://google.github.io/filament/Filament.html#mjx-eqn-pointLightLuminousPower - // for details. - // Note: Filament uses a divisor of PI for spot lights. We choose to use the same 4*PI divisor - // in both cases so that toggling between point light and spot light keeps lit areas lit equally, - // which seems least surprising for users - intensity: spot_light.intensity / (4.0 * std::f32::consts::PI), - range: spot_light.range, - radius: spot_light.radius, - transform: *transform, - shadows_enabled: spot_light.shadows_enabled, - shadow_depth_bias: spot_light.shadow_depth_bias, - // The factor of SQRT_2 is for the worst-case diagonal offset - shadow_normal_bias: spot_light.shadow_normal_bias - * texel_size - * std::f32::consts::SQRT_2, - spot_light_angles: Some(( - spot_light.inner_angle, - spot_light.outer_angle, - )), - }, - render_visible_entities, - *frustum, - ), - )); - } + spot_lights_values.push(( + render_entity.entity(), + ( + ExtractedPointLight { + color: spot_light.color.into(), + // NOTE: Map from luminous power in lumens to luminous intensity in lumens per steradian + // for a point light. See https://google.github.io/filament/Filament.html#mjx-eqn-pointLightLuminousPower + // for details. + // Note: Filament uses a divisor of PI for spot lights. We choose to use the same 4*PI divisor + // in both cases so that toggling between point light and spot light keeps lit areas lit equally, + // which seems least surprising for users + intensity: spot_light.intensity / (4.0 * std::f32::consts::PI), + range: spot_light.range, + radius: spot_light.radius, + transform: *transform, + shadows_enabled: spot_light.shadows_enabled, + shadow_depth_bias: spot_light.shadow_depth_bias, + // The factor of SQRT_2 is for the worst-case diagonal offset + shadow_normal_bias: spot_light.shadow_normal_bias + * texel_size + * std::f32::consts::SQRT_2, + spot_light_angles: Some((spot_light.inner_angle, spot_light.outer_angle)), + }, + render_visible_entities, + *frustum, + ), + )); } } *previous_spot_lights_len = spot_lights_values.len(); @@ -358,26 +351,23 @@ pub fn extract_lights( // TODO: As above let render_visible_entities = visible_entities.clone(); - if let Some(entity) = render_entity.entity() { - commands.get_or_spawn(entity).insert(( - ExtractedDirectionalLight { - color: directional_light.color.into(), - illuminance: directional_light.illuminance, - transform: *transform, - volumetric: volumetric_light.is_some(), - shadows_enabled: directional_light.shadows_enabled, - shadow_depth_bias: directional_light.shadow_depth_bias, - // The factor of SQRT_2 is for the worst-case diagonal offset - shadow_normal_bias: directional_light.shadow_normal_bias - * std::f32::consts::SQRT_2, - cascade_shadow_config: cascade_config.clone(), - cascades: cascades.cascades.clone(), - frusta: frusta.frusta.clone(), - render_layers: maybe_layers.unwrap_or_default().clone(), - }, - render_visible_entities, - )); - } + commands.get_or_spawn(render_entity.entity()).insert(( + ExtractedDirectionalLight { + color: directional_light.color.into(), + illuminance: directional_light.illuminance, + transform: *transform, + volumetric: volumetric_light.is_some(), + shadows_enabled: directional_light.shadows_enabled, + shadow_depth_bias: directional_light.shadow_depth_bias, + // The factor of SQRT_2 is for the worst-case diagonal offset + shadow_normal_bias: directional_light.shadow_normal_bias * std::f32::consts::SQRT_2, + cascade_shadow_config: cascade_config.clone(), + cascades: cascades.cascades.clone(), + frusta: frusta.frusta.clone(), + render_layers: maybe_layers.unwrap_or_default().clone(), + }, + render_visible_entities, + )); } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index bd035443a773e..a920e29ad0d2c 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -832,12 +832,12 @@ pub fn extract_cameras( mut commands: Commands, query: Extract< Query<( + &RenderEntity, &Camera, &CameraRenderGraph, &GlobalTransform, &VisibleEntities, &Frustum, - &RenderEntity, Option<&ColorGrading>, Option<&Exposure>, Option<&TemporalJitter>, @@ -851,12 +851,12 @@ pub fn extract_cameras( ) { let primary_window = primary_window.iter().next(); for ( + render_entity, camera, camera_render_graph, transform, visible_entities, frustum, - render_entity, color_grading, exposure, temporal_jitter, diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index e077ee39cdfa7..341404d189fdb 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -1,7 +1,7 @@ mod range; mod render_layers; -use std::{any::TypeId, ops::Deref}; +use std::any::TypeId; pub use range::*; pub use render_layers::*; diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 4d3e264739906..17a2e917904c0 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -10,11 +10,10 @@ use bevy_ecs::{ use bevy_hierarchy::DespawnRecursiveExt; // marker component to indicate that its entity needs to be synchronized between RenderWorld and MainWorld -#[derive(Component)] +#[derive(Component,Clone)] pub struct ToRenderWorld; #[derive(Component, Deref, Clone, Debug)] -#[component(storage = "SparseSet")] pub struct RenderEntity(Entity); impl RenderEntity { pub fn entity(&self) -> Entity { From 34853b2244c0930f1604498107d77e7b803cc180 Mon Sep 17 00:00:00 2001 From: re0312 Date: Mon, 22 Jul 2024 20:46:26 +0800 Subject: [PATCH 05/55] fix --- .../src/auto_exposure/buffers.rs | 6 +- .../src/core_3d/camera_3d.rs | 4 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 57 +++++++++---------- crates/bevy_pbr/src/bundle.rs | 4 +- crates/bevy_pbr/src/cluster/mod.rs | 2 +- crates/bevy_pbr/src/light_probe/mod.rs | 31 ++++------ crates/bevy_pbr/src/prepass/mod.rs | 1 - crates/bevy_pbr/src/ssao/mod.rs | 1 - crates/bevy_pbr/src/volumetric_fog/mod.rs | 13 ++--- crates/bevy_render/src/camera/camera.rs | 1 - crates/bevy_render/src/world_sync.rs | 2 +- 11 files changed, 52 insertions(+), 70 deletions(-) diff --git a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs index c9571daae7329..5e228acc032a5 100644 --- a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs +++ b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs @@ -1,5 +1,3 @@ -use std::ops::Deref; - use bevy_ecs::prelude::*; use bevy_render::{ render_resource::{StorageBuffer, UniformBuffer}, @@ -36,9 +34,7 @@ pub(super) fn extract_buffers( commands.insert_resource(ExtractedStateBuffers { changed: changed .iter() - .map(|(entity, settings)| { - (entity.entity(), settings.clone()) - }) + .map(|(entity, settings)| (entity.entity(), settings.clone())) .collect(), removed: removed.read().collect(), }); diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index 82fe502a7259f..ad4b26e2b61ea 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -10,7 +10,7 @@ use bevy_render::{ primitives::Frustum, render_resource::{LoadOp, TextureUsages}, view::{ColorGrading, VisibleEntities}, - world_sync::{RenderEntity, ToRenderWorld}, + world_sync::ToRenderWorld, }; use bevy_transform::prelude::{GlobalTransform, Transform}; use serde::{Deserialize, Serialize}; @@ -153,7 +153,7 @@ pub struct Camera3dBundle { pub color_grading: ColorGrading, pub exposure: Exposure, pub main_texture_usages: CameraMainTextureUsages, - _marker: ToRenderWorld, + pub _marker: ToRenderWorld, } // NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 5ea91cd436ac6..ea5b9d5ecd222 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -570,38 +570,37 @@ pub fn extract_camera_prepass_phase( continue; } - if let Some(entity) = render_entity.entity() { - if depth_prepass || normal_prepass || motion_vector_prepass { - opaque_3d_prepass_phases.insert_or_clear(entity); - alpha_mask_3d_prepass_phases.insert_or_clear(entity); - } else { - opaque_3d_prepass_phases.remove(&entity); - alpha_mask_3d_prepass_phases.remove(&entity); - } + let entity = render_entity.entity(); + if depth_prepass || normal_prepass || motion_vector_prepass { + opaque_3d_prepass_phases.insert_or_clear(entity); + alpha_mask_3d_prepass_phases.insert_or_clear(entity); + } else { + opaque_3d_prepass_phases.remove(&entity); + alpha_mask_3d_prepass_phases.remove(&entity); + } - if deferred_prepass { - opaque_3d_deferred_phases.insert_or_clear(entity); - alpha_mask_3d_deferred_phases.insert_or_clear(entity); - } else { - opaque_3d_deferred_phases.remove(&entity); - alpha_mask_3d_deferred_phases.remove(&entity); - } - live_entities.insert(entity); + if deferred_prepass { + opaque_3d_deferred_phases.insert_or_clear(entity); + alpha_mask_3d_deferred_phases.insert_or_clear(entity); + } else { + opaque_3d_deferred_phases.remove(&entity); + alpha_mask_3d_deferred_phases.remove(&entity); + } + live_entities.insert(entity); - let mut entity = commands.get_or_spawn(entity); + let mut entity = commands.get_or_spawn(entity); - if depth_prepass { - entity.insert(DepthPrepass); - } - if normal_prepass { - entity.insert(NormalPrepass); - } - if motion_vector_prepass { - entity.insert(MotionVectorPrepass); - } - if deferred_prepass { - entity.insert(DeferredPrepass); - } + if depth_prepass { + entity.insert(DepthPrepass); + } + if normal_prepass { + entity.insert(NormalPrepass); + } + if motion_vector_prepass { + entity.insert(MotionVectorPrepass); + } + if deferred_prepass { + entity.insert(DeferredPrepass); } } diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index 4a4b375e34488..b41c6817a4592 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -6,7 +6,7 @@ use bevy_asset::Handle; use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent}; use bevy_reflect::Reflect; -use bevy_render::world_sync::{RenderEntity, ToRenderWorld}; +use bevy_render::world_sync::ToRenderWorld; use bevy_render::{ mesh::Mesh, primitives::{CascadesFrusta, CubemapFrusta, Frustum}, @@ -93,7 +93,7 @@ pub struct PointLightBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, - _marker: ToRenderWorld, + pub _marker: ToRenderWorld, } /// A component bundle for spot light entities diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index dc21d941eb1b0..10fa67682bd89 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -4,7 +4,7 @@ use std::num::NonZeroU64; use bevy_ecs::{ component::Component, - entity::{self, Entity, EntityHashMap}, + entity::{Entity, EntityHashMap}, query::Without, reflect::ReflectComponent, system::{Commands, Query, Res, Resource}, diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index aa2fbe887e47b..d2400e96d478c 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -346,15 +346,7 @@ fn gather_light_probes( image_assets: Res>, light_probe_query: Extract>>, view_query: Extract< - Query< - ( - &RenderEntity, - &GlobalTransform, - &Frustum, - Option<&C>, - ), - With, - >, + Query<(&RenderEntity, &GlobalTransform, &Frustum, Option<&C>), With>, >, mut reflection_probes: Local>>, mut view_reflection_probes: Local>>, @@ -393,17 +385,16 @@ fn gather_light_probes( // Gather up the light probes in the list. render_view_light_probes.maybe_gather_light_probes(&view_reflection_probes); - if let Some(entity) = view_entity.entity() { - // Record the per-view light probes. - if render_view_light_probes.is_empty() { - commands - .get_or_spawn(entity) - .remove::>(); - } else { - commands - .get_or_spawn(entity) - .insert(render_view_light_probes); - } + let entity = view_entity.entity(); + // Record the per-view light probes. + if render_view_light_probes.is_empty() { + commands + .get_or_spawn(entity) + .remove::>(); + } else { + commands + .get_or_spawn(entity) + .insert(render_view_light_probes); } } } diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 37cba4d5401bc..92ce47dcd5882 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -1,6 +1,5 @@ mod prepass_bindings; -use bevy_ecs::entity; use bevy_render::mesh::{GpuMesh, MeshVertexBufferLayoutRef}; use bevy_render::render_resource::binding_types::uniform_buffer; use bevy_render::view::WithMesh; diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 9f3b436c7d147..1857dc6bb8b43 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -7,7 +7,6 @@ use bevy_core_pipeline::{ prepass::{DepthPrepass, NormalPrepass, ViewPrepassTextures}, }; use bevy_ecs::{ - entity, prelude::{Bundle, Component, Entity}, query::{Has, QueryItem, With}, reflect::ReflectComponent, diff --git a/crates/bevy_pbr/src/volumetric_fog/mod.rs b/crates/bevy_pbr/src/volumetric_fog/mod.rs index f8e0cb90c6ea8..24d9d3b94a7da 100644 --- a/crates/bevy_pbr/src/volumetric_fog/mod.rs +++ b/crates/bevy_pbr/src/volumetric_fog/mod.rs @@ -380,22 +380,21 @@ pub fn extract_volumetric_fog( view_targets: Extract< Query<(&RenderEntity, &VolumetricFogSettings), Changed>, >, - volumetric_lights: Extract>, + volumetric_lights: Extract>, ) { if volumetric_lights.is_empty() { return; } for (view_target, volumetric_fog_settings) in view_targets.iter() { - if let Some(entity) = view_target.entity() { - commands - .get_or_spawn(entity) - .insert(*volumetric_fog_settings); - } + let entity = view_target.entity(); + commands + .get_or_spawn(entity) + .insert(*volumetric_fog_settings); } for (entity, volumetric_light) in volumetric_lights.iter() { - commands.get_or_spawn(entity).insert(*volumetric_light); + commands.get_or_spawn(entity.entity()).insert(*volumetric_light); } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index a920e29ad0d2c..14de8f5cfb5a9 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -9,7 +9,6 @@ use crate::{ texture::GpuImage, view::{ ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, RenderLayers, VisibleEntities, - WithMesh, }, world_sync::RenderEntity, Extract, diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 17a2e917904c0..000440a6e5ce5 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ use bevy_hierarchy::DespawnRecursiveExt; // marker component to indicate that its entity needs to be synchronized between RenderWorld and MainWorld -#[derive(Component,Clone)] +#[derive(Component,Clone,Debug,Default)] pub struct ToRenderWorld; #[derive(Component, Deref, Clone, Debug)] From 000cef46887f56a2adf80de863cecf7ef85b67b9 Mon Sep 17 00:00:00 2001 From: re0312 Date: Mon, 22 Jul 2024 21:03:03 +0800 Subject: [PATCH 06/55] Fly --- crates/bevy_pbr/src/render/light.rs | 5 ++++- crates/bevy_render/src/lib.rs | 4 ++-- crates/bevy_render/src/world_sync.rs | 19 +++++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 356c0f4b8b4a9..c6a5e29a0461b 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -5,7 +5,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_render::world_sync::RenderEntity; +use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::GpuMesh, @@ -937,6 +937,7 @@ pub fn prepare_lights( light_entity, face_index, }, + RenderFlyEntity, )) .id(); view_lights.push(view_light_entity); @@ -995,6 +996,7 @@ pub fn prepare_lights( }, *spot_light_frustum.unwrap(), LightEntity::Spot { light_entity }, + RenderFlyEntity, )) .id(); @@ -1094,6 +1096,7 @@ pub fn prepare_lights( light_entity, cascade_index, }, + RenderFlyEntity )) .id(); view_lights.push(view_light_entity); diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 92b52f8568ba4..43a384407d17b 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -65,7 +65,7 @@ use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; -use world_sync::{entity_sync_system, WorldSyncPlugin}; +use world_sync::{despawn_fly_entity, entity_sync_system, WorldSyncPlugin}; use crate::mesh::GpuMesh; use crate::renderer::WgpuWrapper; @@ -467,7 +467,7 @@ unsafe fn initialize_render_app(app: &mut App) { render_system, ) .in_set(RenderSet::Render), - // World::clear_entities.in_set(RenderSet::Cleanup), + despawn_fly_entity.in_set(RenderSet::Cleanup), ), ); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 000440a6e5ce5..bca9ed1316c7c 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -4,17 +4,23 @@ use bevy_ecs::{ component::Component, entity::Entity, observer::Trigger, - system::{ResMut, Resource}, + query::With, + system::{Commands, Query, ResMut, Resource}, world::{Mut, OnAdd, OnRemove, World}, }; use bevy_hierarchy::DespawnRecursiveExt; // marker component to indicate that its entity needs to be synchronized between RenderWorld and MainWorld -#[derive(Component,Clone,Debug,Default)] +#[derive(Component, Clone, Debug, Default)] pub struct ToRenderWorld; #[derive(Component, Deref, Clone, Debug)] pub struct RenderEntity(Entity); + +// marker component that its entity needs to be despawned per frame. +#[derive(Component, Clone, Debug, Default)] +pub struct RenderFlyEntity; + impl RenderEntity { pub fn entity(&self) -> Entity { self.0 @@ -52,6 +58,15 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl }); } +pub(crate) fn despawn_fly_entity( + mut command: Commands, + query: Query>, +) { + query.iter().for_each(|e| { + // TODO : performant delete + command.entity(e).despawn_recursive(); + }) +} pub(crate) struct WorldSyncPlugin; impl Plugin for WorldSyncPlugin { From f90c360646f6757736d5bcced09e0fd8584b5244 Mon Sep 17 00:00:00 2001 From: re0312 Date: Mon, 22 Jul 2024 21:23:58 +0800 Subject: [PATCH 07/55] fly entity --- crates/bevy_pbr/src/light_probe/mod.rs | 4 +- crates/bevy_ui/src/render/mod.rs | 73 ++++++++++++-------------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index 82edfb7bfbad9..7ac65b86b0919 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -372,7 +372,7 @@ impl Plugin for LightProbePlugin { /// Compared to the `ExtractComponentPlugin`, this implementation will create a default instance /// if one does not already exist. fn gather_environment_map_uniform( - view_query: Extract), With>>, + view_query: Extract), With>>, mut commands: Commands, ) { for (view_entity, environment_map_light) in view_query.iter() { @@ -386,7 +386,7 @@ fn gather_environment_map_uniform( EnvironmentMapUniform::default() }; commands - .get_or_spawn(view_entity) + .get_or_spawn(view_entity.entity()) .insert(environment_map_uniform); } } diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 2cf2bd7723224..7374b0f8b8321 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -9,7 +9,7 @@ use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::texture::TRANSPARENT_IMAGE_HANDLE; -use bevy_render::world_sync::RenderEntity; +use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; use bevy_render::{ render_phase::{PhaseItem, PhaseItemExtraIndex}, texture::GpuImage, @@ -347,7 +347,7 @@ pub fn extract_uinode_images( extracted_uinodes.uinodes.extend( slices .extract_ui_nodes(transform, uinode, image, clip, camera_entity) - .map(|e| (commands.spawn_empty().id(), e)), + .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), ); continue; } @@ -413,7 +413,7 @@ pub fn extract_uinode_images( }; extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -588,7 +588,7 @@ pub fn extract_uinode_borders( let transform = global_transform.compute_matrix(); extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -680,7 +680,7 @@ pub fn extract_uinode_outlines( for edge in outline_edges { if edge.min.x < edge.max.x && edge.min.y < edge.max.y { extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -726,11 +726,7 @@ pub fn extract_default_ui_camera_view( mut commands: Commands, mut transparent_render_phases: ResMut>, ui_scale: Extract>, - query: Extract< - Query<(&RenderEntity, &Camera), (Or<(With, With)>, Changed)>, - >, - render_camera_view_query: Query<&DefaultCameraView>, - mut view_query: Query<&mut ExtractedView>, + query: Extract, With)>>>, mut live_entities: Local, ) { live_entities.clear(); @@ -741,7 +737,7 @@ pub fn extract_default_ui_camera_view( if !camera.is_active { continue; } - let entity = entity.entity(); + if let ( Some(logical_size), Some(URect { @@ -754,6 +750,7 @@ pub fn extract_default_ui_camera_view( camera.physical_viewport_rect(), camera.physical_viewport_size(), ) { + let entity = entity.entity(); // use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection let projection_matrix = Mat4::orthographic_rh( 0.0, @@ -763,32 +760,31 @@ pub fn extract_default_ui_camera_view( 0.0, UI_CAMERA_FAR, ); - let extract_view = ExtractedView { - clip_from_view: projection_matrix, - world_from_view: GlobalTransform::from_xyz( - 0.0, - 0.0, - UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, - ), - clip_from_world: None, - hdr: camera.hdr, - viewport: UVec4::new( - physical_origin.x, - physical_origin.y, - physical_size.x, - physical_size.y, - ), - color_grading: Default::default(), - }; - if let Ok(default_ui_camera_view) = render_camera_view_query.get(entity) { - let mut extract_view_item = view_query.get_mut(default_ui_camera_view.0).unwrap(); - *extract_view_item = extract_view - } else { - let default_camera_view = commands.spawn(extract_view).id(); - commands - .get_or_spawn(entity) - .insert(DefaultCameraView(default_camera_view)); - }; + let default_camera_view = commands + .spawn(( + ExtractedView { + clip_from_view: projection_matrix, + world_from_view: GlobalTransform::from_xyz( + 0.0, + 0.0, + UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, + ), + clip_from_world: None, + hdr: camera.hdr, + viewport: UVec4::new( + physical_origin.x, + physical_origin.y, + physical_size.x, + physical_size.y, + ), + color_grading: Default::default(), + }, + RenderFlyEntity, + )) + .id(); + commands + .get_or_spawn(entity) + .insert(DefaultCameraView(default_camera_view)); transparent_render_phases.insert_or_clear(entity); live_entities.insert(entity); @@ -873,8 +869,9 @@ pub fn extract_uinode_text( let mut rect = atlas.textures[atlas_info.location.glyph_index].as_rect(); rect.min *= inverse_scale_factor; rect.max *= inverse_scale_factor; + let id = commands.spawn(RenderFlyEntity).id(); extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + id, ExtractedUiNode { stack_index: uinode.stack_index, transform: transform From 756b082fb16d09a46dee426efdeb08646b1c600f Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 01:58:14 +0800 Subject: [PATCH 08/55] sync world --- .../src/core_3d/camera_3d.rs | 3 - crates/bevy_pbr/src/bundle.rs | 2 - crates/bevy_pbr/src/lib.rs | 16 +++- crates/bevy_pbr/src/light/mod.rs | 5 +- crates/bevy_pbr/src/render/light.rs | 6 +- crates/bevy_pbr/src/volumetric_fog/render.rs | 13 +-- crates/bevy_render/src/camera/camera.rs | 2 +- crates/bevy_render/src/lib.rs | 8 +- crates/bevy_render/src/world_sync.rs | 95 ++++++++++++------- 9 files changed, 94 insertions(+), 56 deletions(-) diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index ad4b26e2b61ea..cf062d340ff79 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -10,7 +10,6 @@ use bevy_render::{ primitives::Frustum, render_resource::{LoadOp, TextureUsages}, view::{ColorGrading, VisibleEntities}, - world_sync::ToRenderWorld, }; use bevy_transform::prelude::{GlobalTransform, Transform}; use serde::{Deserialize, Serialize}; @@ -153,7 +152,6 @@ pub struct Camera3dBundle { pub color_grading: ColorGrading, pub exposure: Exposure, pub main_texture_usages: CameraMainTextureUsages, - pub _marker: ToRenderWorld, } // NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference @@ -173,7 +171,6 @@ impl Default for Camera3dBundle { exposure: Default::default(), main_texture_usages: Default::default(), deband_dither: DebandDither::Enabled, - _marker: ToRenderWorld, } } } diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index f7763e6ae0b73..e1147a46e4297 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -7,7 +7,6 @@ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::entity::{Entity, EntityHashMap}; use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent}; use bevy_reflect::Reflect; -use bevy_render::world_sync::ToRenderWorld; use bevy_render::{ mesh::Mesh, primitives::{CascadesFrusta, CubemapFrusta, Frustum}, @@ -104,7 +103,6 @@ pub struct PointLightBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, - pub _marker: ToRenderWorld, } /// A component bundle for spot light entities diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 8e288a8228152..b5d0cd77cb9f7 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -118,6 +118,7 @@ use bevy_render::{ render_resource::Shader, texture::{GpuImage, Image}, view::{check_visibility, VisibilitySystems}, + world_sync::WorldSyncPlugin, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::TransformSystem; @@ -319,18 +320,23 @@ impl Plugin for PbrPlugin { ScreenSpaceAmbientOcclusionPlugin, ExtractResourcePlugin::::default(), FogPlugin, - ExtractResourcePlugin::::default(), - ExtractComponentPlugin::::default(), + ( + ExtractResourcePlugin::::default(), + ExtractComponentPlugin::::default(), + ), LightmapPlugin, LightProbePlugin, - PbrProjectionPlugin::::default(), - PbrProjectionPlugin::::default(), - PbrProjectionPlugin::::default(), + ( + PbrProjectionPlugin::::default(), + PbrProjectionPlugin::::default(), + PbrProjectionPlugin::::default(), + ), GpuMeshPreprocessPlugin { use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder, }, VolumetricFogPlugin, ScreenSpaceReflectionsPlugin, + WorldSyncPlugin::<(PointLight, SpotLight, DirectionalLight)>::default(), )) .configure_sets( PostUpdate, diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index d895ac767289c..817913d61256b 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -13,6 +13,7 @@ use bevy_render::{ view::{ InheritedVisibility, RenderLayers, ViewVisibility, VisibilityRange, VisibleEntityRanges, }, + world_sync::RenderEntity, }; use bevy_transform::components::{GlobalTransform, Transform}; use bevy_utils::Parallel; @@ -301,7 +302,7 @@ pub fn clear_directional_light_cascades(mut lights: Query<(&DirectionalLight, &m pub fn build_directional_light_cascades( directional_light_shadow_map: Res, - views: Query<(Entity, &GlobalTransform, &P, &Camera)>, + views: Query<(&RenderEntity, &GlobalTransform, &P, &Camera)>, mut lights: Query<( &GlobalTransform, &DirectionalLight, @@ -313,7 +314,7 @@ pub fn build_directional_light_cascades( .iter() .filter_map(|(entity, transform, projection, camera)| { if camera.is_active { - Some((entity, projection, transform.compute_matrix())) + Some((entity.entity(), projection, transform.compute_matrix())) } else { None } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index fbdb30443b763..3cf581ca460e5 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1027,16 +1027,18 @@ pub fn prepare_lights( continue; } + let empty_cascades = vec![]; + let empty_frusta = vec![]; let cascades = light .cascades .get(&entity) - .unwrap() + .unwrap_or(&empty_cascades) .iter() .take(MAX_CASCADES_PER_LIGHT); let frusta = light .frusta .get(&entity) - .unwrap() + .unwrap_or(&empty_frusta) .iter() .take(MAX_CASCADES_PER_LIGHT); for (cascade_index, ((cascade, frustum), bound)) in cascades diff --git a/crates/bevy_pbr/src/volumetric_fog/render.rs b/crates/bevy_pbr/src/volumetric_fog/render.rs index 735a9653ddb16..301fad1d7f621 100644 --- a/crates/bevy_pbr/src/volumetric_fog/render.rs +++ b/crates/bevy_pbr/src/volumetric_fog/render.rs @@ -38,6 +38,7 @@ use bevy_render::{ renderer::{RenderContext, RenderDevice, RenderQueue}, texture::{BevyDefault as _, GpuImage, Image}, view::{ExtractedView, Msaa, ViewDepthTexture, ViewTarget, ViewUniformOffset}, + world_sync::RenderEntity, Extract, }; use bevy_transform::components::GlobalTransform; @@ -269,9 +270,9 @@ impl FromWorld for VolumetricFogPipeline { /// from the main world to the render world. pub fn extract_volumetric_fog( mut commands: Commands, - view_targets: Extract>, - fog_volumes: Extract>, - volumetric_lights: Extract>, + view_targets: Extract>, + fog_volumes: Extract>, + volumetric_lights: Extract>, ) { if volumetric_lights.is_empty() { return; @@ -279,19 +280,19 @@ pub fn extract_volumetric_fog( for (entity, volumetric_fog_settings) in view_targets.iter() { commands - .get_or_spawn(entity) + .get_or_spawn(entity.entity()) .insert(*volumetric_fog_settings); } for (entity, fog_volume, fog_transform) in fog_volumes.iter() { commands - .get_or_spawn(entity) + .get_or_spawn(entity.entity()) .insert((*fog_volume).clone()) .insert(*fog_transform); } for (entity, volumetric_light) in volumetric_lights.iter() { - commands.get_or_spawn(entity).insert(*volumetric_light); + commands.get_or_spawn(entity.entity()).insert(*volumetric_light); } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 0aedb3fde21ac..6e32339191531 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -10,7 +10,7 @@ use crate::{ view::{ ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, RenderLayers, VisibleEntities, }, - world_sync::RenderEntity, + world_sync::{MainToRenderEntityMap, RenderEntity}, Extract, }; use bevy_asset::{AssetEvent, AssetId, Assets, Handle}; diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index d527b4be0fffe..68a97bf0a0725 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -57,15 +57,16 @@ use batching::gpu_preprocessing::BatchingPlugin; use bevy_ecs::component::ComponentInfo; use bevy_ecs::schedule::ScheduleBuildSettings; use bevy_utils::prelude::default; +use camera::Camera; pub use extract_param::Extract; use bevy_hierarchy::ValidParentCheckPlugin; -use bevy_window::{PrimaryWindow, RawHandleWrapperHolder}; +use bevy_window::{PrimaryWindow, RawHandleWrapperHolder, Window}; use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; -use world_sync::{despawn_fly_entity, entity_sync_system, WorldSyncPlugin}; +use world_sync::{despawn_fly_entity, entity_sync_system, MainToRenderEntityMap, WorldSyncPlugin}; use crate::mesh::RenderMesh; use crate::renderer::WgpuWrapper; @@ -353,7 +354,7 @@ impl Plugin for RenderPlugin { GlobalsPlugin, MorphPlugin, BatchingPlugin, - WorldSyncPlugin, + WorldSyncPlugin::::default(), )); app.init_resource::() @@ -397,6 +398,7 @@ impl Plugin for RenderPlugin { let render_app = app.sub_app_mut(RenderApp); render_app + .init_resource::() .insert_resource(instance) .insert_resource(PipelineCache::new( device.clone(), diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index bca9ed1316c7c..a3c45da9aceb0 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -1,60 +1,84 @@ +use std::{marker::PhantomData, ops::DerefMut}; + use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ + bundle::Bundle, component::Component, - entity::Entity, + entity::{Entity, EntityHashMap}, observer::Trigger, query::With, system::{Commands, Query, ResMut, Resource}, world::{Mut, OnAdd, OnRemove, World}, }; use bevy_hierarchy::DespawnRecursiveExt; - -// marker component to indicate that its entity needs to be synchronized between RenderWorld and MainWorld -#[derive(Component, Clone, Debug, Default)] -pub struct ToRenderWorld; +use bevy_reflect::Reflect; #[derive(Component, Deref, Clone, Debug)] pub struct RenderEntity(Entity); - -// marker component that its entity needs to be despawned per frame. -#[derive(Component, Clone, Debug, Default)] -pub struct RenderFlyEntity; - impl RenderEntity { pub fn entity(&self) -> Entity { self.0 } } -enum EntityRecord { +#[derive(Component, Deref, Clone, Debug)] +pub struct MainEntity(Entity); +impl MainEntity { + pub fn entity(&self) -> Entity { + self.0 + } +} +// marker component that its entity needs to be despawned per frame. +#[derive(Component, Clone, Debug, Default, Reflect)] +pub struct RenderFlyEntity; + +pub(crate) enum EntityRecord { Added(Entity), - Removed(Entity), + // (main , render) + Removed(Entity, Entity), } +// Entity Record in MainWorld pending to Sync #[derive(Resource, Default, Deref, DerefMut)] -struct PendingSyncEntity { +pub(crate) struct PendingSyncEntity { records: Vec, } +// resource to hold main world to entity world mapping +#[derive(Resource, Default, Deref, DerefMut)] +pub struct MainToRenderEntityMap { + map: EntityHashMap, +} + pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut World) { - main_world.resource_scope(|world, mut pending: Mut| { - for record in pending.drain(..) { - match record { - EntityRecord::Added(e) => { - let id = render_world.spawn_empty().id(); - // println!("sync added :main [{:?}],render:[{:?}]", e, id); - if let Some(mut entity) = world.get_entity_mut(e) { - entity.insert(RenderEntity(id)); + render_world.resource_scope(|render_world, mut mapper: Mut| { + let mapper = mapper.deref_mut(); + main_world.resource_scope(|world, mut pending: Mut| { + for record in pending.drain(..) { + match record { + EntityRecord::Added(e) => { + if let Some(mut entity) = world.get_entity_mut(e) { + match entity.entry::() { + bevy_ecs::world::Entry::Occupied(_) => {} + bevy_ecs::world::Entry::Vacant(entry) => { + let id = render_world.spawn(MainEntity(e)).id(); + + mapper.insert(e, id); + entry.insert(RenderEntity(id)); + } + }; + } + } + EntityRecord::Removed(e1, e2) => { + mapper.remove(&e1); + render_world + .get_entity_mut(e2) + .map(|ec| ec.despawn_recursive()); } - } - EntityRecord::Removed(e) => { - render_world - .get_entity_mut(e) - .map(|ec| ec.despawn_recursive()); } } - } + }); }); } @@ -67,19 +91,26 @@ pub(crate) fn despawn_fly_entity( command.entity(e).despawn_recursive(); }) } -pub(crate) struct WorldSyncPlugin; +#[derive(Default)] +pub struct WorldSyncPlugin { + _marker: PhantomData, +} -impl Plugin for WorldSyncPlugin { +impl Plugin for WorldSyncPlugin { fn build(&self, app: &mut bevy_app::App) { app.init_resource::(); app.observe( - |trigger: Trigger, mut pending: ResMut| { + |trigger: Trigger, mut pending: ResMut| { pending.push(EntityRecord::Added(trigger.entity())); }, ); app.observe( - |trigger: Trigger, mut pending: ResMut| { - pending.push(EntityRecord::Removed(trigger.entity())); + |trigger: Trigger, + mut pending: ResMut, + query: Query<&RenderEntity>| { + if let Ok(e) = query.get(trigger.entity()) { + pending.push(EntityRecord::Removed(trigger.entity(), e.entity())); + }; }, ); } From 5b5ef76ffb65121855c70a39f6d581e2b035130d Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 03:00:23 +0800 Subject: [PATCH 09/55] ui --- crates/bevy_ui/src/render/mod.rs | 60 ++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 7374b0f8b8321..0dbb1aa2617f5 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -206,6 +206,7 @@ pub fn extract_uinode_background_colors( )>, >, node_query: Extract>, + mapping: Res, ) { for ( entity, @@ -220,7 +221,16 @@ pub fn extract_uinode_background_colors( parent, ) in &uinode_query { - let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get()) + let Some(camera_entity) = camera + .map(TargetCamera::entity) + .or(default_ui_camera.get()) + .map(|e| { + if let Some(entity) = mapping.get(&e) { + *entity + } else { + e + } + }) else { continue; }; @@ -315,6 +325,7 @@ pub fn extract_uinode_images( )>, >, node_query: Extract>, + mapping: Res, ) { for ( uinode, @@ -330,7 +341,16 @@ pub fn extract_uinode_images( style, ) in &uinode_query { - let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get()) + let Some(camera_entity) = camera + .map(TargetCamera::entity) + .or(default_ui_camera.get()) + .map(|e| { + if let Some(entity) = mapping.get(&e) { + *entity + } else { + e + } + }) else { continue; }; @@ -517,6 +537,7 @@ pub fn extract_uinode_borders( >, >, node_query: Extract>, + mapping: Res, ) { let image = AssetId::::default(); @@ -532,7 +553,16 @@ pub fn extract_uinode_borders( border_radius, ) in &uinode_query { - let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get()) + let Some(camera_entity) = camera + .map(TargetCamera::entity) + .or(default_ui_camera.get()) + .map(|e| { + if let Some(entity) = mapping.get(&e) { + *entity + } else { + e + } + }) else { continue; }; @@ -626,11 +656,19 @@ pub fn extract_uinode_outlines( &Outline, )>, >, + entity_mapper: Res, ) { + let mapping = |e| { + if let Some(entity) = entity_mapper.get(&e) { + *entity + } else { + e + } + }; + let default_ui_camera = default_ui_camera.get().map(mapping); let image = AssetId::::default(); for (node, global_transform, view_visibility, maybe_clip, camera, outline) in &uinode_query { - let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get()) - else { + let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera) else { continue; }; @@ -813,11 +851,21 @@ pub fn extract_uinode_text( &TextLayoutInfo, )>, >, + mapping: Res, ) { for (uinode, global_transform, view_visibility, clip, camera, text, text_layout_info) in &uinode_query { - let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get()) + let Some(camera_entity) = camera + .map(TargetCamera::entity) + .or(default_ui_camera.get()) + .map(|e| { + if let Some(entity) = mapping.get(&e) { + *entity + } else { + e + } + }) else { continue; }; From e15e3a3bdad88d3d088a3f4bfea87677c6bb37ee Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 03:36:58 +0800 Subject: [PATCH 10/55] lighting --- crates/bevy_ecs/src/world/mod.rs | 1 + crates/bevy_pbr/src/cluster/mod.rs | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index f1165daade536..95fc8f3923505 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -517,6 +517,7 @@ impl World { Some(unsafe { EntityWorldMut::new(self, entity, location) }) } AllocAtWithoutReplacement::DidNotExist => { + println!("not exisit :{}", entity); // SAFETY: entity was just allocated Some(unsafe { self.spawn_at_empty_internal(entity) }) } diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index 10fa67682bd89..346402b3bdce0 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -19,7 +19,7 @@ use bevy_render::{ UniformBuffer, }, renderer::{RenderDevice, RenderQueue}, - world_sync::RenderEntity, + world_sync::{MainToRenderEntityMap, RenderEntity}, Extract, }; use bevy_utils::{hashbrown::HashSet, tracing::warn}; @@ -513,6 +513,7 @@ pub(crate) fn clusterable_object_order( pub fn extract_clusters( mut commands: Commands, views: Extract>, + mapper: Res, ) { for (entity, clusters, camera) in &views { if !camera.is_active { @@ -531,9 +532,11 @@ pub fn extract_clusters( cluster_objects.spot_light_count as u32, )); for clusterable_entity in &cluster_objects.entities { - data.push(ExtractedClusterableObjectElement::ClusterableObjectEntity( - *clusterable_entity, - )); + if let Some(entity) = mapper.get(clusterable_entity) { + data.push(ExtractedClusterableObjectElement::ClusterableObjectEntity( + *entity, + )); + } } } From e4e0bc0a06032fc45133ded6653fb58aca83084a Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 03:56:33 +0800 Subject: [PATCH 11/55] fix example --- crates/bevy_render/src/lib.rs | 9 ++++++--- crates/bevy_render/src/spatial_bundle.rs | 8 +++++++- crates/bevy_render/src/world_sync.rs | 13 ++++++------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 68a97bf0a0725..b62939e01d052 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -66,7 +66,9 @@ use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; -use world_sync::{despawn_fly_entity, entity_sync_system, MainToRenderEntityMap, WorldSyncPlugin}; +use world_sync::{ + despawn_fly_entity, entity_sync_system, MainToRenderEntityMap, ToRenderWorld, WorldSyncPlugin, +}; use crate::mesh::RenderMesh; use crate::renderer::WgpuWrapper; @@ -354,7 +356,7 @@ impl Plugin for RenderPlugin { GlobalsPlugin, MorphPlugin, BatchingPlugin, - WorldSyncPlugin::::default(), + WorldSyncPlugin::<(Camera, ToRenderWorld)>::default(), )); app.init_resource::() @@ -366,7 +368,8 @@ impl Plugin for RenderPlugin { .register_type::() .register_type::() .register_type::() - .register_type::(); + .register_type::() + .register_type::(); } fn ready(&self, app: &App) -> bool { diff --git a/crates/bevy_render/src/spatial_bundle.rs b/crates/bevy_render/src/spatial_bundle.rs index e84f765a27fe8..0faa67380afb6 100644 --- a/crates/bevy_render/src/spatial_bundle.rs +++ b/crates/bevy_render/src/spatial_bundle.rs @@ -1,7 +1,10 @@ use bevy_ecs::prelude::Bundle; use bevy_transform::prelude::{GlobalTransform, Transform}; -use crate::view::{InheritedVisibility, ViewVisibility, Visibility}; +use crate::{ + view::{InheritedVisibility, ViewVisibility, Visibility}, + world_sync::ToRenderWorld, +}; /// A [`Bundle`] that allows the correct positional rendering of an entity. /// @@ -27,6 +30,8 @@ pub struct SpatialBundle { pub transform: Transform, /// The global transform of the entity. pub global_transform: GlobalTransform, + + pub _marker: ToRenderWorld, } impl SpatialBundle { @@ -48,6 +53,7 @@ impl SpatialBundle { view_visibility: ViewVisibility::HIDDEN, transform: Transform::IDENTITY, global_transform: GlobalTransform::IDENTITY, + _marker: ToRenderWorld, }; /// An invisible [`SpatialBundle`] with identity transform. diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index a3c45da9aceb0..72483cbd56930 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -3,17 +3,16 @@ use std::{marker::PhantomData, ops::DerefMut}; use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - bundle::Bundle, - component::Component, - entity::{Entity, EntityHashMap}, - observer::Trigger, - query::With, - system::{Commands, Query, ResMut, Resource}, - world::{Mut, OnAdd, OnRemove, World}, + bundle::Bundle, component::Component, entity::{Entity, EntityHashMap}, observer::Trigger, query::With, reflect::ReflectComponent, system::{Commands, Query, ResMut, Resource}, world::{Mut, OnAdd, OnRemove, World} }; use bevy_hierarchy::DespawnRecursiveExt; use bevy_reflect::Reflect; +/// Marker component that indicate its entity needs to be Synchronized to render world +#[derive(Component, Clone, Debug, Default, Reflect)] +#[reflect[Component]] +pub struct ToRenderWorld; + #[derive(Component, Deref, Clone, Debug)] pub struct RenderEntity(Entity); impl RenderEntity { From 33cae8d8966c4a156d2e60dce1c2285f306ceed2 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 04:58:08 +0800 Subject: [PATCH 12/55] ui --- crates/bevy_render/src/camera/camera.rs | 2 +- crates/bevy_render/src/lib.rs | 2 +- crates/bevy_ui/src/render/mod.rs | 117 +++++++++--------------- 3 files changed, 47 insertions(+), 74 deletions(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 6e32339191531..0aedb3fde21ac 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -10,7 +10,7 @@ use crate::{ view::{ ColorGrading, ExtractedView, ExtractedWindows, GpuCulling, RenderLayers, VisibleEntities, }, - world_sync::{MainToRenderEntityMap, RenderEntity}, + world_sync::RenderEntity, Extract, }; use bevy_asset::{AssetEvent, AssetId, Assets, Handle}; diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index b62939e01d052..3d8b8714c815e 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -61,7 +61,7 @@ use camera::Camera; pub use extract_param::Extract; use bevy_hierarchy::ValidParentCheckPlugin; -use bevy_window::{PrimaryWindow, RawHandleWrapperHolder, Window}; +use bevy_window::{PrimaryWindow, RawHandleWrapperHolder}; use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 0dbb1aa2617f5..67048b8e325a4 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -2,6 +2,7 @@ mod pipeline; mod render_pass; mod ui_material_pipeline; +use crate::DefaultUiCamera; use bevy_color::{Alpha, ColorToComponents, LinearRgba}; use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d}; use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; @@ -24,8 +25,7 @@ pub use ui_material_pipeline::*; use crate::graph::{NodeUi, SubGraphUi}; use crate::{ texture_slice::ComputedTextureSlices, BackgroundColor, BorderColor, BorderRadius, - CalculatedClip, ContentSize, DefaultUiCamera, Node, Outline, Style, TargetCamera, UiImage, - UiScale, Val, + CalculatedClip, ContentSize, Node, Outline, Style, TargetCamera, UiImage, UiScale, Val, }; use bevy_app::prelude::*; @@ -188,7 +188,7 @@ pub struct ExtractedUiNodes { pub fn extract_uinode_background_colors( mut extracted_uinodes: ResMut, - camera_query: Extract>, + camera_query: Extract>, default_ui_camera: Extract, ui_scale: Extract>, uinode_query: Extract< @@ -208,6 +208,7 @@ pub fn extract_uinode_background_colors( node_query: Extract>, mapping: Res, ) { + let default_ui_camera = default_ui_camera.get(); for ( entity, uinode, @@ -221,17 +222,7 @@ pub fn extract_uinode_background_colors( parent, ) in &uinode_query { - let Some(camera_entity) = camera - .map(TargetCamera::entity) - .or(default_ui_camera.get()) - .map(|e| { - if let Some(entity) = mapping.get(&e) { - *entity - } else { - e - } - }) - else { + let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera) else { continue; }; @@ -243,12 +234,15 @@ pub fn extract_uinode_background_colors( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(|(_, c)| c.logical_viewport_size()) + .and_then(| c| c.logical_viewport_size()) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. / ui_scale.0; + let Some(&camera_entity) = mapping.get(&camera_entity) else { + continue; + }; // Both vertical and horizontal percentage border values are calculated based on the width of the parent node // let parent_width = parent @@ -305,7 +299,7 @@ pub fn extract_uinode_background_colors( pub fn extract_uinode_images( mut commands: Commands, mut extracted_uinodes: ResMut, - camera_query: Extract>, + camera_query: Extract>, texture_atlases: Extract>>, ui_scale: Extract>, default_ui_camera: Extract, @@ -327,6 +321,7 @@ pub fn extract_uinode_images( node_query: Extract>, mapping: Res, ) { + let default_ui_camera = default_ui_camera.get(); for ( uinode, transform, @@ -341,17 +336,7 @@ pub fn extract_uinode_images( style, ) in &uinode_query { - let Some(camera_entity) = camera - .map(TargetCamera::entity) - .or(default_ui_camera.get()) - .map(|e| { - if let Some(entity) = mapping.get(&e) { - *entity - } else { - e - } - }) - else { + let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera) else { continue; }; @@ -363,6 +348,19 @@ pub fn extract_uinode_images( continue; } + let ui_logical_viewport_size = camera_query + .get(camera_entity) + .ok() + .and_then(| c| c.logical_viewport_size()) + .unwrap_or(Vec2::ZERO) + // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, + // so we have to divide by `UiScale` to get the size of the UI viewport. + / ui_scale.0; + + let Some(&camera_entity) = mapping.get(&camera_entity) else { + continue; + }; + if let Some(slices) = slices { extracted_uinodes.uinodes.extend( slices @@ -395,15 +393,6 @@ pub fn extract_uinode_images( ), }; - let ui_logical_viewport_size = camera_query - .get(camera_entity) - .ok() - .and_then(|(_, c)| c.logical_viewport_size()) - .unwrap_or(Vec2::ZERO) - // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, - // so we have to divide by `UiScale` to get the size of the UI viewport. - / ui_scale.0; - // Both vertical and horizontal percentage border values are calculated based on the width of the parent node // let parent_width = parent @@ -517,7 +506,7 @@ fn clamp_radius( pub fn extract_uinode_borders( mut commands: Commands, mut extracted_uinodes: ResMut, - camera_query: Extract>, + camera_query: Extract>, default_ui_camera: Extract, ui_scale: Extract>, uinode_query: Extract< @@ -540,6 +529,7 @@ pub fn extract_uinode_borders( mapping: Res, ) { let image = AssetId::::default(); + let default_ui_camera = default_ui_camera.get(); for ( node, @@ -553,20 +543,9 @@ pub fn extract_uinode_borders( border_radius, ) in &uinode_query { - let Some(camera_entity) = camera - .map(TargetCamera::entity) - .or(default_ui_camera.get()) - .map(|e| { - if let Some(entity) = mapping.get(&e) { - *entity - } else { - e - } - }) - else { + let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera) else { continue; }; - // Skip invisible borders if !view_visibility.get() || border_color.0.is_fully_transparent() @@ -579,12 +558,16 @@ pub fn extract_uinode_borders( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(|(_, c)| c.logical_viewport_size()) + .and_then(|c| c.logical_viewport_size()) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. / ui_scale.0; + let Some(&camera_entity) = mapping.get(&camera_entity) else { + continue; + }; + // Both vertical and horizontal percentage border values are calculated based on the width of the parent node // let parent_width = parent @@ -656,21 +639,17 @@ pub fn extract_uinode_outlines( &Outline, )>, >, - entity_mapper: Res, + mapping: Res, ) { - let mapping = |e| { - if let Some(entity) = entity_mapper.get(&e) { - *entity - } else { - e - } - }; - let default_ui_camera = default_ui_camera.get().map(mapping); + let default_ui_camera = default_ui_camera.get(); let image = AssetId::::default(); for (node, global_transform, view_visibility, maybe_clip, camera, outline) in &uinode_query { let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera) else { continue; }; + let Some(&camera_entity) = mapping.get(&camera_entity) else { + continue; + }; // Skip invisible outlines if !view_visibility.get() @@ -836,7 +815,7 @@ pub fn extract_default_ui_camera_view( pub fn extract_uinode_text( mut commands: Commands, mut extracted_uinodes: ResMut, - camera_query: Extract>, + camera_query: Extract>, default_ui_camera: Extract, texture_atlases: Extract>>, ui_scale: Extract>, @@ -853,20 +832,11 @@ pub fn extract_uinode_text( >, mapping: Res, ) { + let default_ui_camera = default_ui_camera.get(); for (uinode, global_transform, view_visibility, clip, camera, text, text_layout_info) in &uinode_query { - let Some(camera_entity) = camera - .map(TargetCamera::entity) - .or(default_ui_camera.get()) - .map(|e| { - if let Some(entity) = mapping.get(&e) { - *entity - } else { - e - } - }) - else { + let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera) else { continue; }; @@ -878,11 +848,14 @@ pub fn extract_uinode_text( let scale_factor = camera_query .get(camera_entity) .ok() - .and_then(|(_, c)| c.target_scaling_factor()) + .and_then(|c| c.target_scaling_factor()) .unwrap_or(1.0) * ui_scale.0; let inverse_scale_factor = scale_factor.recip(); + let Some(&camera_entity) = mapping.get(&camera_entity) else { + continue; + }; // Align the text to the nearest physical pixel: // * Translate by minus the text node's half-size // (The transform translates to the center of the node but the text coordinates are relative to the node's top left corner) From 4a58b0ea2823d58664c8ddb91db4f6f68380ba83 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 05:26:34 +0800 Subject: [PATCH 13/55] fix ui --- crates/bevy_ui/src/render/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 67048b8e325a4..11e03fb6e8cda 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -187,6 +187,7 @@ pub struct ExtractedUiNodes { } pub fn extract_uinode_background_colors( + mut commands: Commands, mut extracted_uinodes: ResMut, camera_query: Extract>, default_ui_camera: Extract, @@ -210,7 +211,7 @@ pub fn extract_uinode_background_colors( ) { let default_ui_camera = default_ui_camera.get(); for ( - entity, + _e, uinode, transform, view_visibility, @@ -272,7 +273,7 @@ pub fn extract_uinode_background_colors( }; extracted_uinodes.uinodes.insert( - entity, + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -960,6 +961,7 @@ pub(crate) const QUAD_VERTEX_POSITIONS: [Vec3; 4] = [ pub(crate) const QUAD_INDICES: [usize; 6] = [0, 2, 3, 0, 1, 2]; #[derive(Component)] +#[component(storage = "SparseSet")] pub struct UiBatch { pub range: Range, pub image: AssetId, From 3fc2207132cdadeffdbfd6fecd20c1c3f8ac3c88 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 05:31:49 +0800 Subject: [PATCH 14/55] fix gizmos --- crates/bevy_gizmos/src/lib.rs | 2 ++ crates/bevy_render/src/lib.rs | 42 ----------------------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 8bab13a62b849..df99bef80e0de 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -93,6 +93,7 @@ use bevy_render::{ ShaderType, VertexAttribute, VertexBufferLayout, VertexFormat, VertexStepMode, }, renderer::RenderDevice, + world_sync::RenderFlyEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_time::Fixed; @@ -432,6 +433,7 @@ fn extract_gizmo_data( }, (*handle).clone_weak(), GizmoMeshConfig::from(config), + RenderFlyEntity, )); } } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 3d8b8714c815e..d204673d18544 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -54,7 +54,6 @@ pub mod prelude { } use batching::gpu_preprocessing::BatchingPlugin; -use bevy_ecs::component::ComponentInfo; use bevy_ecs::schedule::ScheduleBuildSettings; use bevy_utils::prelude::default; use camera::Camera; @@ -481,47 +480,6 @@ unsafe fn initialize_render_app(app: &mut App) { ); render_app.set_extract(|main_world, render_world| { - // #[cfg(feature = "trace")] - // let _render_span = bevy_utils::tracing::info_span!("extract main app to render subapp").entered(); - // { - // #[cfg(feature = "trace")] - // let _stage_span = - // bevy_utils::tracing::info_span!("reserve_and_flush") - // .entered(); - - // // reserve all existing main world entities for use in render_app - // // they can only be spawned using `get_or_spawn()` - // let total_count = main_world.entities().total_count(); - - // assert_eq!( - // render_world.entities().len(), - // 0, - // "An entity was spawned after the entity list was cleared last frame and before the extract schedule began. This is not supported", - // ); - - // // SAFETY: This is safe given the clear_entities call in the past frame and the assert above - // unsafe { - // render_world - // .entities_mut() - // .flush_and_reserve_invalid_assuming_no_entities(total_count); - // } - // } - println!("render World Entity:{}", render_world.entities().len()); - let mut vec = vec![]; - for e in render_world.iter_entities() { - vec.push(e.id()); - } - for e in vec { - fn log_components(entity: Entity, world: &mut World) { - let debug_infos: Vec<_> = world - .inspect_entity(entity) - .map(ComponentInfo::name) - .collect(); - println!("Entity {:?}: {:?}", entity, debug_infos); - } - log_components(e, render_world); - } - { #[cfg(feature = "trace")] let _stage_span = bevy_utils::tracing::info_span!("entity_sync").entered(); From f9c8d5af95291c1ac41ff94dbb3ed840f5716d6d Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 05:58:39 +0800 Subject: [PATCH 15/55] fix light --- crates/bevy_pbr/src/light/mod.rs | 5 +- crates/bevy_pbr/src/render/light.rs | 104 ++++++++++++++++++---------- 2 files changed, 69 insertions(+), 40 deletions(-) diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index 817913d61256b..d895ac767289c 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -13,7 +13,6 @@ use bevy_render::{ view::{ InheritedVisibility, RenderLayers, ViewVisibility, VisibilityRange, VisibleEntityRanges, }, - world_sync::RenderEntity, }; use bevy_transform::components::{GlobalTransform, Transform}; use bevy_utils::Parallel; @@ -302,7 +301,7 @@ pub fn clear_directional_light_cascades(mut lights: Query<(&DirectionalLight, &m pub fn build_directional_light_cascades( directional_light_shadow_map: Res, - views: Query<(&RenderEntity, &GlobalTransform, &P, &Camera)>, + views: Query<(Entity, &GlobalTransform, &P, &Camera)>, mut lights: Query<( &GlobalTransform, &DirectionalLight, @@ -314,7 +313,7 @@ pub fn build_directional_light_cascades( .iter() .filter_map(|(entity, transform, projection, camera)| { if camera.is_active { - Some((entity.entity(), projection, transform.compute_matrix())) + Some((entity, projection, transform.compute_matrix())) } else { None } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 3cf581ca460e5..235a3eeefb25c 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -5,7 +5,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; +use bevy_render::world_sync::{MainToRenderEntityMap, RenderEntity, RenderFlyEntity}; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::RenderMesh, @@ -212,6 +212,7 @@ pub fn extract_lights( Without, >, >, + mapper: Res, mut previous_point_lights_len: Local, mut previous_spot_lights_len: Local, ) { @@ -332,43 +333,71 @@ pub fn extract_lights( *previous_spot_lights_len = spot_lights_values.len(); commands.insert_or_spawn_batch(spot_lights_values); - for ( - render_entity, - directional_light, - visible_entities, - cascades, - cascade_config, - frusta, - transform, - view_visibility, - maybe_layers, - volumetric_light, - ) in &directional_lights - { - if !view_visibility.get() { - continue; - } + directional_lights.iter().for_each( + |( + entity, + directional_light, + visible_entities, + cascades, + cascade_config, + frusta, + transform, + view_visibility, + maybe_layers, + volumetric_light, + )| { + if !view_visibility.get() { + return; + } - // TODO: As above - let render_visible_entities = visible_entities.clone(); - commands.get_or_spawn(render_entity.entity()).insert(( - ExtractedDirectionalLight { - color: directional_light.color.into(), - illuminance: directional_light.illuminance, - transform: *transform, - volumetric: volumetric_light.is_some(), - shadows_enabled: directional_light.shadows_enabled, - shadow_depth_bias: directional_light.shadow_depth_bias, - // The factor of SQRT_2 is for the worst-case diagonal offset - shadow_normal_bias: directional_light.shadow_normal_bias * std::f32::consts::SQRT_2, - cascade_shadow_config: cascade_config.clone(), - cascades: cascades.cascades.clone(), - frusta: frusta.frusta.clone(), - render_layers: maybe_layers.unwrap_or_default().clone(), - }, - render_visible_entities, - )); - } + // TODO: As above + let mut extracted_cascades = EntityHashMap::default(); + let mut extracted_frusta = EntityHashMap::default(); + let mut cascade_visible_entities = EntityHashMap::default(); + for (e, v) in cascades.cascades.iter() { + if let Some(entity) = mapper.get(e) { + extracted_cascades.insert(*entity, v.clone()); + } else { + return; + } + } + for (e, v) in frusta.frusta.iter() { + if let Some(entity) = mapper.get(e) { + extracted_frusta.insert(*entity, v.clone()); + } else { + return; + } + } + for (e, v) in visible_entities.entities.iter() { + if let Some(entity) = mapper.get(e) { + cascade_visible_entities.insert(*entity, v.clone()); + } else { + return; + } + } + + commands.get_or_spawn(entity.entity()).insert(( + ExtractedDirectionalLight { + color: directional_light.color.into(), + illuminance: directional_light.illuminance, + transform: *transform, + volumetric: volumetric_light.is_some(), + shadows_enabled: directional_light.shadows_enabled, + shadow_depth_bias: directional_light.shadow_depth_bias, + // The factor of SQRT_2 is for the worst-case diagonal offset + shadow_normal_bias: directional_light.shadow_normal_bias + * std::f32::consts::SQRT_2, + cascade_shadow_config: cascade_config.clone(), + cascades: extracted_cascades, + frusta: extracted_frusta, + render_layers: maybe_layers.unwrap_or_default().clone(), + }, + CascadesVisibleEntities { + entities: cascade_visible_entities, + }, + )); + }, + ); } pub(crate) const POINT_LIGHT_NEAR_Z: f32 = 0.1f32; @@ -1209,6 +1238,7 @@ pub fn queue_shadows( }; let is_directional_light = matches!(light_entity, LightEntity::Directional { .. }); + println!("queue_shadow get:{}", entity); let visible_entities = match light_entity { LightEntity::Directional { light_entity, From 44d36a4b9032d2f5ebb211d092f9ab9181e5b359 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 06:01:10 +0800 Subject: [PATCH 16/55] cleanup --- crates/bevy_pbr/src/render/light.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 235a3eeefb25c..9153c5c6bbf8d 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1238,7 +1238,6 @@ pub fn queue_shadows( }; let is_directional_light = matches!(light_entity, LightEntity::Directional { .. }); - println!("queue_shadow get:{}", entity); let visible_entities = match light_entity { LightEntity::Directional { light_entity, From 7989d21e12247311f06f0c05e9173d3a3ac24243 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 06:06:08 +0800 Subject: [PATCH 17/55] fix cli --- crates/bevy_pbr/src/ssao/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 8768b00ce03b7..2134fbdf2a90f 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -485,7 +485,7 @@ fn extract_ssao_settings( mut commands: Commands, cameras: Extract< Query< - (Entity, &Camera, &ScreenSpaceAmbientOcclusionSettings, &Msaa), + (&RenderEntity, &Camera, &ScreenSpaceAmbientOcclusionSettings, &Msaa), (With, With, With), >, >, From 94854553f408c5a1ed040052ab210da4ce13be02 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 16:03:04 +0800 Subject: [PATCH 18/55] fix ui --- crates/bevy_render/src/world_sync.rs | 26 +++++++++++------ crates/bevy_ui/src/render/render_pass.rs | 7 ++--- .../src/render/ui_material_pipeline.rs | 28 ++++++++----------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 72483cbd56930..460338e5282b7 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -3,7 +3,14 @@ use std::{marker::PhantomData, ops::DerefMut}; use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - bundle::Bundle, component::Component, entity::{Entity, EntityHashMap}, observer::Trigger, query::With, reflect::ReflectComponent, system::{Commands, Query, ResMut, Resource}, world::{Mut, OnAdd, OnRemove, World} + bundle::Bundle, + component::Component, + entity::{Entity, EntityHashMap}, + observer::Trigger, + query::With, + reflect::ReflectComponent, + system::{Query, ResMut, Resource}, + world::{Mut, OnAdd, OnRemove, World}, }; use bevy_hierarchy::DespawnRecursiveExt; use bevy_reflect::Reflect; @@ -81,14 +88,15 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl }); } -pub(crate) fn despawn_fly_entity( - mut command: Commands, - query: Query>, -) { - query.iter().for_each(|e| { - // TODO : performant delete - command.entity(e).despawn_recursive(); - }) +pub(crate) fn despawn_fly_entity(world: &mut World) { + let mut query = world.query_filtered::>(); + + // ensure next frame allocation keeps order + let mut entities: Vec<_> = query.iter(&world).collect(); + entities.sort_unstable_by_key(|e| e.index()); + for e in entities.into_iter().rev() { + world.despawn(e); + } } #[derive(Default)] pub struct WorldSyncPlugin { diff --git a/crates/bevy_ui/src/render/render_pass.rs b/crates/bevy_ui/src/render/render_pass.rs index 7c9931b82f183..bc8504554ae73 100644 --- a/crates/bevy_ui/src/render/render_pass.rs +++ b/crates/bevy_ui/src/render/render_pass.rs @@ -6,7 +6,6 @@ use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemParamItem}, }; -use bevy_math::FloatOrd; use bevy_render::{ camera::ExtractedCamera, render_graph::*, @@ -90,7 +89,7 @@ impl Node for UiPassNode { } pub struct TransparentUi { - pub sort_key: (FloatOrd, u32), + pub sort_key: (u32, u32), pub entity: Entity, pub pipeline: CachedRenderPipelineId, pub draw_function: DrawFunctionId, @@ -131,7 +130,7 @@ impl PhaseItem for TransparentUi { } impl SortedPhaseItem for TransparentUi { - type SortKey = (FloatOrd, u32); + type SortKey = (u32, u32); #[inline] fn sort_key(&self) -> Self::SortKey { @@ -140,7 +139,7 @@ impl SortedPhaseItem for TransparentUi { #[inline] fn sort(items: &mut [Self]) { - items.sort_by_key(SortedPhaseItem::sort_key); + items.sort_unstable_by_key(SortedPhaseItem::sort_key); } } diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index e15dc4223e456..9085c0985d222 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ system::lifetimeless::{Read, SRes}, system::*, }; -use bevy_math::{FloatOrd, Mat4, Rect, Vec2, Vec4Swizzles}; +use bevy_math::{Mat4, Rect, Vec2, Vec4Swizzles}; use bevy_render::{ extract_component::ExtractComponentPlugin, globals::{GlobalsBuffer, GlobalsUniform}, @@ -327,7 +327,7 @@ impl RenderCommand

for DrawUiMaterialNode { } pub struct ExtractedUiMaterialNode { - pub stack_index: usize, + pub stack_index: u32, pub transform: Mat4, pub rect: Rect, pub border: [f32; 4], @@ -355,7 +355,6 @@ impl Default for ExtractedUiMaterialNodes { pub fn extract_ui_material_nodes( mut extracted_uinodes: ResMut>, materials: Extract>>, - ui_stack: Extract>, default_ui_camera: Extract, uinode_query: Extract< Query< @@ -386,23 +385,21 @@ pub fn extract_ui_material_nodes( // If there is only one camera, we use it as default let default_single_camera = default_ui_camera.get(); - for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() { - if let Ok((entity, uinode, style, transform, handle, view_visibility, clip, camera)) = - uinode_query.get(*entity) - { + uinode_query.iter().for_each( + |(entity, uinode, style, transform, handle, view_visibility, clip, camera)| { let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_single_camera) else { - continue; + return; }; // skip invisible nodes if !view_visibility.get() { - continue; + return; } // Skip loading materials if !materials.contains(handle) { - continue; + return; } // Both vertical and horizontal percentage border values are calculated based on the width of the parent node @@ -428,7 +425,7 @@ pub fn extract_ui_material_nodes( extracted_uinodes.uinodes.insert( entity, ExtractedUiMaterialNode { - stack_index, + stack_index: uinode.stack_index, transform: transform.compute_matrix(), material: handle.id(), rect: Rect { @@ -440,8 +437,8 @@ pub fn extract_ui_material_nodes( camera_entity, }, ); - }; - } + }, + ); } #[allow(clippy::too_many_arguments)] @@ -671,10 +668,7 @@ pub fn queue_ui_material_nodes( draw_function, pipeline, entity: *entity, - sort_key: ( - FloatOrd(extracted_uinode.stack_index as f32), - entity.index(), - ), + sort_key: (extracted_uinode.stack_index, entity.index()), batch_range: 0..0, extra_index: PhaseItemExtraIndex::NONE, }); From bb3289bc488cfc73ec24de312a174774e88d5e1e Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 16:03:40 +0800 Subject: [PATCH 19/55] clean --- crates/bevy_ui/src/render/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 11e03fb6e8cda..75bf4460b93ff 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -32,7 +32,7 @@ use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, AssetId, Assets, Handle}; use bevy_ecs::entity::{EntityHashMap, EntityHashSet}; use bevy_ecs::prelude::*; -use bevy_math::{FloatOrd, Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_math::{Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_render::{ camera::Camera, render_asset::RenderAssets, @@ -1006,10 +1006,7 @@ pub fn queue_uinodes( draw_function, pipeline, entity: *entity, - sort_key: ( - FloatOrd(extracted_uinode.stack_index as f32), - entity.index(), - ), + sort_key: (extracted_uinode.stack_index, entity.index()), // batch_range will be calculated in prepare_uinodes batch_range: 0..0, extra_index: PhaseItemExtraIndex::NONE, From 39e4f2ef5c6c31a9e4887819eddafbb52f202f66 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 17:40:48 +0800 Subject: [PATCH 20/55] fix cli --- crates/bevy_core_pipeline/src/dof/mod.rs | 1 - crates/bevy_ecs/src/world/mod.rs | 1 - crates/bevy_pbr/src/ssao/mod.rs | 7 ++++++- crates/bevy_pbr/src/volumetric_fog/render.rs | 4 +++- crates/bevy_render/src/lib.rs | 14 ++++++++++++++ crates/bevy_render/src/world_sync.rs | 8 ++++---- crates/bevy_ui/src/render/mod.rs | 11 +++++++---- 7 files changed, 34 insertions(+), 12 deletions(-) diff --git a/crates/bevy_core_pipeline/src/dof/mod.rs b/crates/bevy_core_pipeline/src/dof/mod.rs index 378b923433160..b3717b4328774 100644 --- a/crates/bevy_core_pipeline/src/dof/mod.rs +++ b/crates/bevy_core_pipeline/src/dof/mod.rs @@ -14,7 +14,6 @@ //! //! [Depth of field]: https://en.wikipedia.org/wiki/Depth_of_field - use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, Handle}; use bevy_derive::{Deref, DerefMut}; diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 95fc8f3923505..f1165daade536 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -517,7 +517,6 @@ impl World { Some(unsafe { EntityWorldMut::new(self, entity, location) }) } AllocAtWithoutReplacement::DidNotExist => { - println!("not exisit :{}", entity); // SAFETY: entity was just allocated Some(unsafe { self.spawn_at_empty_internal(entity) }) } diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index 2134fbdf2a90f..b1cc528f3dbdb 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -485,7 +485,12 @@ fn extract_ssao_settings( mut commands: Commands, cameras: Extract< Query< - (&RenderEntity, &Camera, &ScreenSpaceAmbientOcclusionSettings, &Msaa), + ( + &RenderEntity, + &Camera, + &ScreenSpaceAmbientOcclusionSettings, + &Msaa, + ), (With, With, With), >, >, diff --git a/crates/bevy_pbr/src/volumetric_fog/render.rs b/crates/bevy_pbr/src/volumetric_fog/render.rs index eb284fe857665..8a7d685fdd93d 100644 --- a/crates/bevy_pbr/src/volumetric_fog/render.rs +++ b/crates/bevy_pbr/src/volumetric_fog/render.rs @@ -292,7 +292,9 @@ pub fn extract_volumetric_fog( } for (entity, volumetric_light) in volumetric_lights.iter() { - commands.get_or_spawn(entity.entity()).insert(*volumetric_light); + commands + .get_or_spawn(entity.entity()) + .insert(*volumetric_light); } } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index d204673d18544..b5a23031cd5a5 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -480,6 +480,20 @@ unsafe fn initialize_render_app(app: &mut App) { ); render_app.set_extract(|main_world, render_world| { + // let mut vec = vec![]; + // for e in render_world.iter_entities() { + // vec.push(e.id()); + // } + // for e in vec { + // fn log_components(entity: Entity, world: &mut World) { + // let debug_infos: Vec<_> = world + // .inspect_entity(entity) + // .map(bevy_ecs::component::ComponentInfo::name) + // .collect(); + // println!("Entity {:?}: {:?}", entity, debug_infos); + // } + // log_components(e, render_world); + // } { #[cfg(feature = "trace")] let _stage_span = bevy_utils::tracing::info_span!("entity_sync").entered(); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 460338e5282b7..2d335010e491c 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -78,9 +78,9 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl } EntityRecord::Removed(e1, e2) => { mapper.remove(&e1); - render_world - .get_entity_mut(e2) - .map(|ec| ec.despawn_recursive()); + if let Some(ec) = render_world.get_entity_mut(e2) { + ec.despawn_recursive(); + }; } } } @@ -92,7 +92,7 @@ pub(crate) fn despawn_fly_entity(world: &mut World) { let mut query = world.query_filtered::>(); // ensure next frame allocation keeps order - let mut entities: Vec<_> = query.iter(&world).collect(); + let mut entities: Vec<_> = query.iter(world).collect(); entities.sort_unstable_by_key(|e| e.index()); for e in entities.into_iter().rev() { world.despawn(e); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 75bf4460b93ff..495b7a38338bc 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -186,6 +186,7 @@ pub struct ExtractedUiNodes { pub uinodes: EntityHashMap, } +#[allow(clippy::too_many_arguments)] pub fn extract_uinode_background_colors( mut commands: Commands, mut extracted_uinodes: ResMut, @@ -235,7 +236,7 @@ pub fn extract_uinode_background_colors( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(| c| c.logical_viewport_size()) + .and_then(bevy_render::camera::Camera::logical_viewport_size) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. @@ -352,7 +353,7 @@ pub fn extract_uinode_images( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(| c| c.logical_viewport_size()) + .and_then(bevy_render::camera::Camera::logical_viewport_size) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. @@ -504,6 +505,7 @@ fn clamp_radius( ] } +#[allow(clippy::too_many_arguments)] pub fn extract_uinode_borders( mut commands: Commands, mut extracted_uinodes: ResMut, @@ -559,7 +561,7 @@ pub fn extract_uinode_borders( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(|c| c.logical_viewport_size()) + .and_then(bevy_render::camera::Camera::logical_viewport_size) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. @@ -813,6 +815,7 @@ pub fn extract_default_ui_camera_view( } #[cfg(feature = "bevy_text")] +#[allow(clippy::too_many_arguments)] pub fn extract_uinode_text( mut commands: Commands, mut extracted_uinodes: ResMut, @@ -849,7 +852,7 @@ pub fn extract_uinode_text( let scale_factor = camera_query .get(camera_entity) .ok() - .and_then(|c| c.target_scaling_factor()) + .and_then(bevy_render::camera::Camera::target_scaling_factor) .unwrap_or(1.0) * ui_scale.0; let inverse_scale_factor = scale_factor.recip(); From 4b6506e7aff32b966e05f7e60592267129f52d51 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 19:29:51 +0800 Subject: [PATCH 21/55] fix ui_material --- crates/bevy_render/src/lib.rs | 28 +++++++++---------- crates/bevy_render/src/world_sync.rs | 4 ++- .../src/render/ui_material_pipeline.rs | 15 ++++++---- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index b5a23031cd5a5..abcf955c945cb 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -480,20 +480,20 @@ unsafe fn initialize_render_app(app: &mut App) { ); render_app.set_extract(|main_world, render_world| { - // let mut vec = vec![]; - // for e in render_world.iter_entities() { - // vec.push(e.id()); - // } - // for e in vec { - // fn log_components(entity: Entity, world: &mut World) { - // let debug_infos: Vec<_> = world - // .inspect_entity(entity) - // .map(bevy_ecs::component::ComponentInfo::name) - // .collect(); - // println!("Entity {:?}: {:?}", entity, debug_infos); - // } - // log_components(e, render_world); - // } + let mut vec = vec![]; + for e in render_world.iter_entities() { + vec.push(e.id()); + } + for e in vec { + fn log_components(entity: Entity, world: &mut World) { + let debug_infos: Vec<_> = world + .inspect_entity(entity) + .map(bevy_ecs::component::ComponentInfo::name) + .collect(); + println!("Entity {:?}: {:?}", entity, debug_infos); + } + log_components(e, render_world); + } { #[cfg(feature = "trace")] let _stage_span = bevy_utils::tracing::info_span!("entity_sync").entered(); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 2d335010e491c..cd1ec76a5f922 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -21,6 +21,7 @@ use bevy_reflect::Reflect; pub struct ToRenderWorld; #[derive(Component, Deref, Clone, Debug)] +#[component(storage = "SparseSet")] pub struct RenderEntity(Entity); impl RenderEntity { pub fn entity(&self) -> Entity { @@ -29,6 +30,7 @@ impl RenderEntity { } #[derive(Component, Deref, Clone, Debug)] +#[component(storage = "SparseSet")] pub struct MainEntity(Entity); impl MainEntity { pub fn entity(&self) -> Entity { @@ -51,7 +53,7 @@ pub(crate) struct PendingSyncEntity { records: Vec, } -// resource to hold main world to entity world mapping +// resource to maintain entity mapping from the main world to the render world #[derive(Resource, Default, Deref, DerefMut)] pub struct MainToRenderEntityMap { map: EntityHashMap, diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 9085c0985d222..03c1f6131803a 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -18,6 +18,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, FallbackImage, GpuImage}, view::*, + world_sync::RenderFlyEntity, Extract, ExtractSchedule, Render, RenderSet, }; use bevy_transform::prelude::GlobalTransform; @@ -373,6 +374,7 @@ pub fn extract_ui_material_nodes( >, windows: Extract>>, ui_scale: Extract>, + mapping: Res, ) { let ui_logical_viewport_size = windows .get_single() @@ -391,6 +393,9 @@ pub fn extract_ui_material_nodes( else { return; }; + let Some(&camera_entity) = mapping.get(&camera_entity) else { + return; + }; // skip invisible nodes if !view_visibility.get() { @@ -458,7 +463,8 @@ pub fn prepare_uimaterial_nodes( view_uniforms.uniforms.binding(), globals_buffer.buffer.binding(), ) { - let mut batches: Vec<(Entity, UiMaterialBatch)> = Vec::with_capacity(*previous_len); + let mut batches: Vec<(Entity, (UiMaterialBatch, RenderFlyEntity))> = + Vec::with_capacity(*previous_len); ui_meta.vertices.clear(); ui_meta.view_bind_group = Some(render_device.create_bind_group( @@ -488,7 +494,7 @@ pub fn prepare_uimaterial_nodes( material: extracted_uinode.material, }; - batches.push((item.entity, new_batch)); + batches.push((item.entity, (new_batch, RenderFlyEntity))); existing_batch = batches.last_mut(); } @@ -578,7 +584,7 @@ pub fn prepare_uimaterial_nodes( } index += QUAD_INDICES.len() as u32; - existing_batch.unwrap().1.range.end = index; + existing_batch.unwrap().1.0.range.end = index; ui_phase.items[batch_item_index].batch_range_mut().end += 1; } else { batch_shader_handle = AssetId::invalid(); @@ -661,9 +667,6 @@ pub fn queue_ui_material_nodes( bind_group_data: material.key.clone(), }, ); - transparent_phase - .items - .reserve(extracted_uinodes.uinodes.len()); transparent_phase.add(TransparentUi { draw_function, pipeline, From 03a6e0992781a3a1debc30fefa2f9f20b292ccba Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 23 Jul 2024 20:01:40 +0800 Subject: [PATCH 22/55] fix sprite --- crates/bevy_render/src/lib.rs | 14 -------------- crates/bevy_sprite/src/render/mod.rs | 7 ++++--- crates/bevy_ui/src/render/ui_material_pipeline.rs | 14 +++++++------- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index abcf955c945cb..d204673d18544 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -480,20 +480,6 @@ unsafe fn initialize_render_app(app: &mut App) { ); render_app.set_extract(|main_world, render_world| { - let mut vec = vec![]; - for e in render_world.iter_entities() { - vec.push(e.id()); - } - for e in vec { - fn log_components(entity: Entity, world: &mut World) { - let debug_infos: Vec<_> = world - .inspect_entity(entity) - .map(bevy_ecs::component::ComponentInfo::name) - .collect(); - println!("Entity {:?}: {:?}", entity, debug_infos); - } - log_components(e, render_world); - } { #[cfg(feature = "trace")] let _stage_span = bevy_utils::tracing::info_span!("entity_sync").entered(); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 8b767cde419ec..410208ff2681a 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -38,6 +38,7 @@ use bevy_render::{ ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, ViewVisibility, VisibleEntities, }, + world_sync::RenderFlyEntity, Extract, }; use bevy_transform::components::GlobalTransform; @@ -372,7 +373,7 @@ pub fn extract_sprites( extracted_sprites.sprites.extend( slices .extract_sprites(transform, entity, sprite, handle) - .map(|e| (commands.spawn_empty().id(), e)), + .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), ); } else { let atlas_rect = @@ -391,7 +392,7 @@ pub fn extract_sprites( // PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive extracted_sprites.sprites.insert( - entity, + commands.spawn(RenderFlyEntity).id(), ExtractedSprite { color: sprite.color.into(), transform: *transform, @@ -402,7 +403,7 @@ pub fn extract_sprites( flip_y: sprite.flip_y, image_handle_id: handle.id(), anchor: sprite.anchor.as_vec(), - original_entity: None, + original_entity: Some(entity), }, ); } diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 03c1f6131803a..9810e1323642d 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -353,14 +353,15 @@ impl Default for ExtractedUiMaterialNodes { } } +#[allow(clippy::too_many_arguments)] pub fn extract_ui_material_nodes( + mut commands: Commands, mut extracted_uinodes: ResMut>, materials: Extract>>, default_ui_camera: Extract, uinode_query: Extract< Query< ( - Entity, &Node, &Style, &GlobalTransform, @@ -388,7 +389,7 @@ pub fn extract_ui_material_nodes( let default_single_camera = default_ui_camera.get(); uinode_query.iter().for_each( - |(entity, uinode, style, transform, handle, view_visibility, clip, camera)| { + |(uinode, style, transform, handle, view_visibility, clip, camera)| { let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_single_camera) else { return; @@ -428,7 +429,7 @@ pub fn extract_ui_material_nodes( ) / uinode.size().y; extracted_uinodes.uinodes.insert( - entity, + commands.spawn(RenderFlyEntity).id(), ExtractedUiMaterialNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -463,8 +464,7 @@ pub fn prepare_uimaterial_nodes( view_uniforms.uniforms.binding(), globals_buffer.buffer.binding(), ) { - let mut batches: Vec<(Entity, (UiMaterialBatch, RenderFlyEntity))> = - Vec::with_capacity(*previous_len); + let mut batches: Vec<(Entity, UiMaterialBatch)> = Vec::with_capacity(*previous_len); ui_meta.vertices.clear(); ui_meta.view_bind_group = Some(render_device.create_bind_group( @@ -494,7 +494,7 @@ pub fn prepare_uimaterial_nodes( material: extracted_uinode.material, }; - batches.push((item.entity, (new_batch, RenderFlyEntity))); + batches.push((item.entity, new_batch)); existing_batch = batches.last_mut(); } @@ -584,7 +584,7 @@ pub fn prepare_uimaterial_nodes( } index += QUAD_INDICES.len() as u32; - existing_batch.unwrap().1.0.range.end = index; + existing_batch.unwrap().1.range.end = index; ui_phase.items[batch_item_index].batch_range_mut().end += 1; } else { batch_shader_handle = AssetId::invalid(); From b8b82250a353c475b924b570cc609124aba788c3 Mon Sep 17 00:00:00 2001 From: re0312 Date: Wed, 24 Jul 2024 06:19:05 +0800 Subject: [PATCH 23/55] whilelist --- crates/bevy_gizmos/src/lib.rs | 2 - crates/bevy_pbr/src/render/light.rs | 5 +- crates/bevy_render/src/world_sync.rs | 7 +-- crates/bevy_sprite/src/render/mod.rs | 5 +- crates/bevy_ui/src/render/mod.rs | 51 +++++++++---------- .../src/render/ui_material_pipeline.rs | 3 +- 6 files changed, 30 insertions(+), 43 deletions(-) diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index f4e42d36f92bb..3bda59054d25e 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -93,7 +93,6 @@ use bevy_render::{ ShaderType, VertexAttribute, VertexBufferLayout, VertexFormat, VertexStepMode, }, renderer::RenderDevice, - world_sync::RenderFlyEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_time::Fixed; @@ -433,7 +432,6 @@ fn extract_gizmo_data( }, (*handle).clone_weak(), GizmoMeshConfig::from(config), - RenderFlyEntity, )); } } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index e10dd0623fc25..013c7d70b8a7b 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -5,7 +5,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_render::world_sync::{MainToRenderEntityMap, RenderEntity, RenderFlyEntity}; +use bevy_render::world_sync::{MainToRenderEntityMap, RenderEntity}; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::RenderMesh, @@ -966,7 +966,6 @@ pub fn prepare_lights( light_entity, face_index, }, - RenderFlyEntity, )) .id(); view_lights.push(view_light_entity); @@ -1025,7 +1024,6 @@ pub fn prepare_lights( }, *spot_light_frustum.unwrap(), LightEntity::Spot { light_entity }, - RenderFlyEntity, )) .id(); @@ -1127,7 +1125,6 @@ pub fn prepare_lights( light_entity, cascade_index, }, - RenderFlyEntity )) .id(); view_lights.push(view_light_entity); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index cd1ec76a5f922..1960fae62b53a 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -7,7 +7,7 @@ use bevy_ecs::{ component::Component, entity::{Entity, EntityHashMap}, observer::Trigger, - query::With, + query::Without, reflect::ReflectComponent, system::{Query, ResMut, Resource}, world::{Mut, OnAdd, OnRemove, World}, @@ -37,9 +37,6 @@ impl MainEntity { self.0 } } -// marker component that its entity needs to be despawned per frame. -#[derive(Component, Clone, Debug, Default, Reflect)] -pub struct RenderFlyEntity; pub(crate) enum EntityRecord { Added(Entity), @@ -91,7 +88,7 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl } pub(crate) fn despawn_fly_entity(world: &mut World) { - let mut query = world.query_filtered::>(); + let mut query = world.query_filtered::>(); // ensure next frame allocation keeps order let mut entities: Vec<_> = query.iter(world).collect(); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 410208ff2681a..29045b044d2cf 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -38,7 +38,6 @@ use bevy_render::{ ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, ViewVisibility, VisibleEntities, }, - world_sync::RenderFlyEntity, Extract, }; use bevy_transform::components::GlobalTransform; @@ -373,7 +372,7 @@ pub fn extract_sprites( extracted_sprites.sprites.extend( slices .extract_sprites(transform, entity, sprite, handle) - .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), + .map(|e| (commands.spawn_empty().id(), e)), ); } else { let atlas_rect = @@ -392,7 +391,7 @@ pub fn extract_sprites( // PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive extracted_sprites.sprites.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn_empty().id(), ExtractedSprite { color: sprite.color.into(), transform: *transform, diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 495b7a38338bc..c1f2706189d46 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -10,7 +10,7 @@ use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::texture::TRANSPARENT_IMAGE_HANDLE; -use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; +use bevy_render::world_sync::RenderEntity; use bevy_render::{ render_phase::{PhaseItem, PhaseItemExtraIndex}, texture::GpuImage, @@ -274,7 +274,7 @@ pub fn extract_uinode_background_colors( }; extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn_empty().id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -367,7 +367,7 @@ pub fn extract_uinode_images( extracted_uinodes.uinodes.extend( slices .extract_ui_nodes(transform, uinode, image, clip, camera_entity) - .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), + .map(|e| (commands.spawn_empty().id(), e)), ); continue; } @@ -424,7 +424,7 @@ pub fn extract_uinode_images( }; extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn_empty().id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -604,7 +604,7 @@ pub fn extract_uinode_borders( let transform = global_transform.compute_matrix(); extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn_empty().id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -700,7 +700,7 @@ pub fn extract_uinode_outlines( for edge in outline_edges { if edge.min.x < edge.max.x && edge.min.y < edge.max.y { extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn_empty().id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -781,26 +781,23 @@ pub fn extract_default_ui_camera_view( UI_CAMERA_FAR, ); let default_camera_view = commands - .spawn(( - ExtractedView { - clip_from_view: projection_matrix, - world_from_view: GlobalTransform::from_xyz( - 0.0, - 0.0, - UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, - ), - clip_from_world: None, - hdr: camera.hdr, - viewport: UVec4::new( - physical_origin.x, - physical_origin.y, - physical_size.x, - physical_size.y, - ), - color_grading: Default::default(), - }, - RenderFlyEntity, - )) + .spawn((ExtractedView { + clip_from_view: projection_matrix, + world_from_view: GlobalTransform::from_xyz( + 0.0, + 0.0, + UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, + ), + clip_from_world: None, + hdr: camera.hdr, + viewport: UVec4::new( + physical_origin.x, + physical_origin.y, + physical_size.x, + physical_size.y, + ), + color_grading: Default::default(), + },)) .id(); commands .get_or_spawn(entity) @@ -894,7 +891,7 @@ pub fn extract_uinode_text( let mut rect = atlas.textures[atlas_info.location.glyph_index].as_rect(); rect.min *= inverse_scale_factor; rect.max *= inverse_scale_factor; - let id = commands.spawn(RenderFlyEntity).id(); + let id = commands.spawn_empty().id(); extracted_uinodes.uinodes.insert( id, ExtractedUiNode { diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 9810e1323642d..5bfad8856401e 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -18,7 +18,6 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, FallbackImage, GpuImage}, view::*, - world_sync::RenderFlyEntity, Extract, ExtractSchedule, Render, RenderSet, }; use bevy_transform::prelude::GlobalTransform; @@ -429,7 +428,7 @@ pub fn extract_ui_material_nodes( ) / uinode.size().y; extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn_empty().id(), ExtractedUiMaterialNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), From 24212f59d112934f25e1c93436886524904aea97 Mon Sep 17 00:00:00 2001 From: re0312 Date: Wed, 24 Jul 2024 07:43:56 +0800 Subject: [PATCH 24/55] Revert "whilelist" This reverts commit b8b82250a353c475b924b570cc609124aba788c3. --- crates/bevy_gizmos/src/lib.rs | 2 + crates/bevy_pbr/src/render/light.rs | 5 +- crates/bevy_render/src/world_sync.rs | 7 ++- crates/bevy_sprite/src/render/mod.rs | 5 +- crates/bevy_ui/src/render/mod.rs | 51 ++++++++++--------- .../src/render/ui_material_pipeline.rs | 3 +- 6 files changed, 43 insertions(+), 30 deletions(-) diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 3bda59054d25e..f4e42d36f92bb 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -93,6 +93,7 @@ use bevy_render::{ ShaderType, VertexAttribute, VertexBufferLayout, VertexFormat, VertexStepMode, }, renderer::RenderDevice, + world_sync::RenderFlyEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_time::Fixed; @@ -432,6 +433,7 @@ fn extract_gizmo_data( }, (*handle).clone_weak(), GizmoMeshConfig::from(config), + RenderFlyEntity, )); } } diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 013c7d70b8a7b..e10dd0623fc25 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -5,7 +5,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_render::world_sync::{MainToRenderEntityMap, RenderEntity}; +use bevy_render::world_sync::{MainToRenderEntityMap, RenderEntity, RenderFlyEntity}; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::RenderMesh, @@ -966,6 +966,7 @@ pub fn prepare_lights( light_entity, face_index, }, + RenderFlyEntity, )) .id(); view_lights.push(view_light_entity); @@ -1024,6 +1025,7 @@ pub fn prepare_lights( }, *spot_light_frustum.unwrap(), LightEntity::Spot { light_entity }, + RenderFlyEntity, )) .id(); @@ -1125,6 +1127,7 @@ pub fn prepare_lights( light_entity, cascade_index, }, + RenderFlyEntity )) .id(); view_lights.push(view_light_entity); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 1960fae62b53a..cd1ec76a5f922 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -7,7 +7,7 @@ use bevy_ecs::{ component::Component, entity::{Entity, EntityHashMap}, observer::Trigger, - query::Without, + query::With, reflect::ReflectComponent, system::{Query, ResMut, Resource}, world::{Mut, OnAdd, OnRemove, World}, @@ -37,6 +37,9 @@ impl MainEntity { self.0 } } +// marker component that its entity needs to be despawned per frame. +#[derive(Component, Clone, Debug, Default, Reflect)] +pub struct RenderFlyEntity; pub(crate) enum EntityRecord { Added(Entity), @@ -88,7 +91,7 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl } pub(crate) fn despawn_fly_entity(world: &mut World) { - let mut query = world.query_filtered::>(); + let mut query = world.query_filtered::>(); // ensure next frame allocation keeps order let mut entities: Vec<_> = query.iter(world).collect(); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 29045b044d2cf..410208ff2681a 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -38,6 +38,7 @@ use bevy_render::{ ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, ViewVisibility, VisibleEntities, }, + world_sync::RenderFlyEntity, Extract, }; use bevy_transform::components::GlobalTransform; @@ -372,7 +373,7 @@ pub fn extract_sprites( extracted_sprites.sprites.extend( slices .extract_sprites(transform, entity, sprite, handle) - .map(|e| (commands.spawn_empty().id(), e)), + .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), ); } else { let atlas_rect = @@ -391,7 +392,7 @@ pub fn extract_sprites( // PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive extracted_sprites.sprites.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedSprite { color: sprite.color.into(), transform: *transform, diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index c1f2706189d46..495b7a38338bc 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -10,7 +10,7 @@ use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::texture::TRANSPARENT_IMAGE_HANDLE; -use bevy_render::world_sync::RenderEntity; +use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; use bevy_render::{ render_phase::{PhaseItem, PhaseItemExtraIndex}, texture::GpuImage, @@ -274,7 +274,7 @@ pub fn extract_uinode_background_colors( }; extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -367,7 +367,7 @@ pub fn extract_uinode_images( extracted_uinodes.uinodes.extend( slices .extract_ui_nodes(transform, uinode, image, clip, camera_entity) - .map(|e| (commands.spawn_empty().id(), e)), + .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), ); continue; } @@ -424,7 +424,7 @@ pub fn extract_uinode_images( }; extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -604,7 +604,7 @@ pub fn extract_uinode_borders( let transform = global_transform.compute_matrix(); extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -700,7 +700,7 @@ pub fn extract_uinode_outlines( for edge in outline_edges { if edge.min.x < edge.max.x && edge.min.y < edge.max.y { extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -781,23 +781,26 @@ pub fn extract_default_ui_camera_view( UI_CAMERA_FAR, ); let default_camera_view = commands - .spawn((ExtractedView { - clip_from_view: projection_matrix, - world_from_view: GlobalTransform::from_xyz( - 0.0, - 0.0, - UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, - ), - clip_from_world: None, - hdr: camera.hdr, - viewport: UVec4::new( - physical_origin.x, - physical_origin.y, - physical_size.x, - physical_size.y, - ), - color_grading: Default::default(), - },)) + .spawn(( + ExtractedView { + clip_from_view: projection_matrix, + world_from_view: GlobalTransform::from_xyz( + 0.0, + 0.0, + UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, + ), + clip_from_world: None, + hdr: camera.hdr, + viewport: UVec4::new( + physical_origin.x, + physical_origin.y, + physical_size.x, + physical_size.y, + ), + color_grading: Default::default(), + }, + RenderFlyEntity, + )) .id(); commands .get_or_spawn(entity) @@ -891,7 +894,7 @@ pub fn extract_uinode_text( let mut rect = atlas.textures[atlas_info.location.glyph_index].as_rect(); rect.min *= inverse_scale_factor; rect.max *= inverse_scale_factor; - let id = commands.spawn_empty().id(); + let id = commands.spawn(RenderFlyEntity).id(); extracted_uinodes.uinodes.insert( id, ExtractedUiNode { diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 5bfad8856401e..9810e1323642d 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -18,6 +18,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, FallbackImage, GpuImage}, view::*, + world_sync::RenderFlyEntity, Extract, ExtractSchedule, Render, RenderSet, }; use bevy_transform::prelude::GlobalTransform; @@ -428,7 +429,7 @@ pub fn extract_ui_material_nodes( ) / uinode.size().y; extracted_uinodes.uinodes.insert( - commands.spawn_empty().id(), + commands.spawn(RenderFlyEntity).id(), ExtractedUiMaterialNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), From 2de636a77a6d56436f5fee1c45edda79fe02e382 Mon Sep 17 00:00:00 2001 From: re0312 Date: Wed, 24 Jul 2024 08:19:47 +0800 Subject: [PATCH 25/55] address review --- crates/bevy_pbr/src/render/light.rs | 8 +++----- crates/bevy_sprite/src/mesh2d/mesh.rs | 2 -- crates/bevy_ui/src/render/mod.rs | 7 +++++-- crates/bevy_ui/src/render/render_pass.rs | 7 ++++--- crates/bevy_ui/src/render/ui_material_pipeline.rs | 7 +++++-- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index e10dd0623fc25..04eaa7cd1c987 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -350,7 +350,7 @@ pub fn extract_lights( return; } - // TODO: As above + // TODO: re-use the memory let mut extracted_cascades = EntityHashMap::default(); let mut extracted_frusta = EntityHashMap::default(); let mut cascade_visible_entities = EntityHashMap::default(); @@ -1056,18 +1056,16 @@ pub fn prepare_lights( continue; } - let empty_cascades = vec![]; - let empty_frusta = vec![]; let cascades = light .cascades .get(&entity) - .unwrap_or(&empty_cascades) + .unwrap() .iter() .take(MAX_CASCADES_PER_LIGHT); let frusta = light .frusta .get(&entity) - .unwrap_or(&empty_frusta) + .unwrap() .iter() .take(MAX_CASCADES_PER_LIGHT); for (cascade_index, ((cascade, frustum), bound)) in cascades diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 67237f836d3d6..78b15de6ca5c0 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -227,8 +227,6 @@ pub fn extract_mesh2d( if !view_visibility.get() { continue; } - // FIXME: Remove this - it is just a workaround to enable rendering to work as - // render commands require an entity to exist at the moment. render_mesh_instances.insert( entity, RenderMesh2dInstance { diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 495b7a38338bc..0b30c22a9fe6e 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -32,7 +32,7 @@ use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, AssetId, Assets, Handle}; use bevy_ecs::entity::{EntityHashMap, EntityHashSet}; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; +use bevy_math::{FloatOrd, Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_render::{ camera::Camera, render_asset::RenderAssets, @@ -1009,7 +1009,10 @@ pub fn queue_uinodes( draw_function, pipeline, entity: *entity, - sort_key: (extracted_uinode.stack_index, entity.index()), + sort_key: ( + FloatOrd(extracted_uinode.stack_index as f32), + entity.index(), + ), // batch_range will be calculated in prepare_uinodes batch_range: 0..0, extra_index: PhaseItemExtraIndex::NONE, diff --git a/crates/bevy_ui/src/render/render_pass.rs b/crates/bevy_ui/src/render/render_pass.rs index bc8504554ae73..7c9931b82f183 100644 --- a/crates/bevy_ui/src/render/render_pass.rs +++ b/crates/bevy_ui/src/render/render_pass.rs @@ -6,6 +6,7 @@ use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemParamItem}, }; +use bevy_math::FloatOrd; use bevy_render::{ camera::ExtractedCamera, render_graph::*, @@ -89,7 +90,7 @@ impl Node for UiPassNode { } pub struct TransparentUi { - pub sort_key: (u32, u32), + pub sort_key: (FloatOrd, u32), pub entity: Entity, pub pipeline: CachedRenderPipelineId, pub draw_function: DrawFunctionId, @@ -130,7 +131,7 @@ impl PhaseItem for TransparentUi { } impl SortedPhaseItem for TransparentUi { - type SortKey = (u32, u32); + type SortKey = (FloatOrd, u32); #[inline] fn sort_key(&self) -> Self::SortKey { @@ -139,7 +140,7 @@ impl SortedPhaseItem for TransparentUi { #[inline] fn sort(items: &mut [Self]) { - items.sort_unstable_by_key(SortedPhaseItem::sort_key); + items.sort_by_key(SortedPhaseItem::sort_key); } } diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 9810e1323642d..da5158f6487f8 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ system::lifetimeless::{Read, SRes}, system::*, }; -use bevy_math::{Mat4, Rect, Vec2, Vec4Swizzles}; +use bevy_math::{FloatOrd, Mat4, Rect, Vec2, Vec4Swizzles}; use bevy_render::{ extract_component::ExtractComponentPlugin, globals::{GlobalsBuffer, GlobalsUniform}, @@ -671,7 +671,10 @@ pub fn queue_ui_material_nodes( draw_function, pipeline, entity: *entity, - sort_key: (extracted_uinode.stack_index, entity.index()), + sort_key: ( + FloatOrd(extracted_uinode.stack_index as f32), + entity.index(), + ), batch_range: 0..0, extra_index: PhaseItemExtraIndex::NONE, }); From 1fbb76c1a9b8f232a147fc3433c31d4cf383e598 Mon Sep 17 00:00:00 2001 From: re0312 <45868716+re0312@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:58:34 +0800 Subject: [PATCH 26/55] Update crates/bevy_render/src/world_sync.rs Co-authored-by: Trashtalk217 --- crates/bevy_render/src/world_sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index cd1ec76a5f922..912b90ab3eb3a 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -15,7 +15,7 @@ use bevy_ecs::{ use bevy_hierarchy::DespawnRecursiveExt; use bevy_reflect::Reflect; -/// Marker component that indicate its entity needs to be Synchronized to render world +/// Marker component that indicates that its entity needs to be Synchronized to the render world #[derive(Component, Clone, Debug, Default, Reflect)] #[reflect[Component]] pub struct ToRenderWorld; From c25d560de6f56c612ffb1fc0d9976f975a1bc8fb Mon Sep 17 00:00:00 2001 From: re0312 <45868716+re0312@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:58:45 +0800 Subject: [PATCH 27/55] Update crates/bevy_render/src/world_sync.rs Co-authored-by: Trashtalk217 --- crates/bevy_render/src/world_sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 912b90ab3eb3a..d5f634a8e9ed6 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -37,7 +37,7 @@ impl MainEntity { self.0 } } -// marker component that its entity needs to be despawned per frame. +// marker component that indicates that its entity needs to be despawned at the end of every frame. #[derive(Component, Clone, Debug, Default, Reflect)] pub struct RenderFlyEntity; From 457e83fb53a58adf85acc0d8d5055820a65cbb8d Mon Sep 17 00:00:00 2001 From: re0312 <45868716+re0312@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:59:15 +0800 Subject: [PATCH 28/55] Update crates/bevy_render/src/world_sync.rs Co-authored-by: Trashtalk217 --- crates/bevy_render/src/world_sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index d5f634a8e9ed6..3fa9b9b55b8ed 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -42,6 +42,7 @@ impl MainEntity { pub struct RenderFlyEntity; pub(crate) enum EntityRecord { + // main Added(Entity), // (main , render) Removed(Entity, Entity), From cba1183b0db70ab0a92a8ac1b38a2068a5d221ce Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 25 Jul 2024 10:12:06 +0800 Subject: [PATCH 29/55] address review --- crates/bevy_render/src/world_sync.rs | 2 ++ crates/bevy_ui/src/render/mod.rs | 2 -- crates/bevy_ui/src/render/ui_material_pipeline.rs | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 3fa9b9b55b8ed..0b4d6e72f674a 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -101,6 +101,8 @@ pub(crate) fn despawn_fly_entity(world: &mut World) { world.despawn(e); } } + +/// A Plugin that synchronizes entities with specific Components between the main world and render world. #[derive(Default)] pub struct WorldSyncPlugin { _marker: PhantomData, diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 0b30c22a9fe6e..771270d367e59 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -195,7 +195,6 @@ pub fn extract_uinode_background_colors( ui_scale: Extract>, uinode_query: Extract< Query<( - Entity, &Node, &GlobalTransform, &ViewVisibility, @@ -212,7 +211,6 @@ pub fn extract_uinode_background_colors( ) { let default_ui_camera = default_ui_camera.get(); for ( - _e, uinode, transform, view_visibility, diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index da5158f6487f8..1c01e6d841428 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -328,7 +328,7 @@ impl RenderCommand

for DrawUiMaterialNode { } pub struct ExtractedUiMaterialNode { - pub stack_index: u32, + pub stack_index: usize, pub transform: Mat4, pub rect: Rect, pub border: [f32; 4], @@ -431,7 +431,7 @@ pub fn extract_ui_material_nodes( extracted_uinodes.uinodes.insert( commands.spawn(RenderFlyEntity).id(), ExtractedUiMaterialNode { - stack_index: uinode.stack_index, + stack_index: uinode.stack_index as usize, transform: transform.compute_matrix(), material: handle.id(), rect: Rect { @@ -667,6 +667,9 @@ pub fn queue_ui_material_nodes( bind_group_data: material.key.clone(), }, ); + transparent_phase + .items + .reserve(extracted_uinodes.uinodes.len()); transparent_phase.add(TransparentUi { draw_function, pipeline, From 2821849c169796c8e96c35c60ac2a7e927209bd0 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 25 Jul 2024 10:14:03 +0800 Subject: [PATCH 30/55] fmt --- crates/bevy_ui/src/render/ui_material_pipeline.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 1c01e6d841428..53882ac645bce 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -668,8 +668,8 @@ pub fn queue_ui_material_nodes( }, ); transparent_phase - .items - .reserve(extracted_uinodes.uinodes.len()); + .items + .reserve(extracted_uinodes.uinodes.len()); transparent_phase.add(TransparentUi { draw_function, pipeline, From a86dd3963014db4c2c70c27dec607bd68d91406e Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 25 Jul 2024 17:00:48 +0800 Subject: [PATCH 31/55] address review --- .../src/auto_exposure/buffers.rs | 2 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 2 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 4 +- crates/bevy_core_pipeline/src/dof/mod.rs | 2 +- crates/bevy_core_pipeline/src/taa/mod.rs | 2 +- crates/bevy_pbr/src/cluster/mod.rs | 3 +- crates/bevy_pbr/src/light_probe/mod.rs | 4 +- crates/bevy_pbr/src/prepass/mod.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 122 +++++++++--------- crates/bevy_pbr/src/ssao/mod.rs | 5 +- crates/bevy_pbr/src/volumetric_fog/render.rs | 8 +- crates/bevy_render/src/camera/camera.rs | 3 +- crates/bevy_render/src/extract_component.rs | 4 +- crates/bevy_render/src/world_sync.rs | 7 +- crates/bevy_ui/src/render/mod.rs | 3 +- .../src/render/ui_material_pipeline.rs | 21 +-- 16 files changed, 96 insertions(+), 98 deletions(-) diff --git a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs index 5e228acc032a5..8cfc43f07f772 100644 --- a/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs +++ b/crates/bevy_core_pipeline/src/auto_exposure/buffers.rs @@ -34,7 +34,7 @@ pub(super) fn extract_buffers( commands.insert_resource(ExtractedStateBuffers { changed: changed .iter() - .map(|(entity, settings)| (entity.entity(), settings.clone())) + .map(|(entity, settings)| (entity.id(), settings.clone())) .collect(), removed: removed.read().collect(), }); diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index d3fb874376df0..e3f4fb67f3625 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -171,7 +171,7 @@ pub fn extract_core_2d_camera_phases( if !camera.is_active { continue; } - let entity = entity.entity(); + let entity = entity.id(); transparent_2d_phases.insert_or_clear(entity); live_entities.insert(entity); } diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 7e5315ca9ebb1..644dc2bbf57ca 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -519,7 +519,7 @@ pub fn extract_core_3d_camera_phases( continue; } - let entity = render_entity.entity(); + let entity = render_entity.id(); opaque_3d_phases.insert_or_clear(entity); alpha_mask_3d_phases.insert_or_clear(entity); transmissive_3d_phases.insert_or_clear(entity); @@ -571,7 +571,7 @@ pub fn extract_camera_prepass_phase( continue; } - let entity = render_entity.entity(); + let entity = render_entity.id(); if depth_prepass || normal_prepass || motion_vector_prepass { opaque_3d_prepass_phases.insert_or_clear(entity); alpha_mask_3d_prepass_phases.insert_or_clear(entity); diff --git a/crates/bevy_core_pipeline/src/dof/mod.rs b/crates/bevy_core_pipeline/src/dof/mod.rs index b3717b4328774..dc529a3ea2da1 100644 --- a/crates/bevy_core_pipeline/src/dof/mod.rs +++ b/crates/bevy_core_pipeline/src/dof/mod.rs @@ -803,7 +803,7 @@ fn extract_depth_of_field_settings( } for (entity, dof_settings, projection) in query.iter_mut() { - let entity = entity.entity(); + let entity = entity.id(); // Depth of field is nonsensical without a perspective projection. let Projection::Perspective(ref perspective_projection) = *projection else { continue; diff --git a/crates/bevy_core_pipeline/src/taa/mod.rs b/crates/bevy_core_pipeline/src/taa/mod.rs index 0184b52fbc584..c3a1f990a1d5d 100644 --- a/crates/bevy_core_pipeline/src/taa/mod.rs +++ b/crates/bevy_core_pipeline/src/taa/mod.rs @@ -362,7 +362,7 @@ fn extract_taa_settings(mut commands: Commands, mut main_world: ResMut( // Gather up the light probes in the list. render_view_light_probes.maybe_gather_light_probes(&view_reflection_probes); - let entity = view_entity.entity(); + let entity = view_entity.id(); // Record the per-view light probes. if render_view_light_probes.is_empty() { commands diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 9c54bd747cadb..c1bab32aeb4af 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -582,7 +582,7 @@ pub fn extract_camera_previous_view_data( ) { for (entity, camera, maybe_previous_view_data) in cameras_3d.iter() { if camera.is_active { - let entity = entity.entity(); + let entity = entity.id(); let mut entity = commands.get_or_spawn(entity); if let Some(previous_view_data) = maybe_previous_view_data { diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 04eaa7cd1c987..c270bc3c075a6 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -270,7 +270,7 @@ pub fn extract_lights( spot_light_angles: None, }; point_lights_values.push(( - render_entity.entity(), + render_entity.id(), ( extracted_point_light, render_cubemap_visible_entities, @@ -302,7 +302,7 @@ pub fn extract_lights( 2.0 * spot_light.outer_angle.tan() / directional_light_shadow_map.size as f32; spot_lights_values.push(( - render_entity.entity(), + render_entity.id(), ( ExtractedPointLight { color: spot_light.color.into(), @@ -333,71 +333,69 @@ pub fn extract_lights( *previous_spot_lights_len = spot_lights_values.len(); commands.insert_or_spawn_batch(spot_lights_values); - directional_lights.iter().for_each( - |( - entity, - directional_light, - visible_entities, - cascades, - cascade_config, - frusta, - transform, - view_visibility, - maybe_layers, - volumetric_light, - )| { - if !view_visibility.get() { - return; - } + for ( + entity, + directional_light, + visible_entities, + cascades, + cascade_config, + frusta, + transform, + view_visibility, + maybe_layers, + volumetric_light, + ) in &directional_lights + { + if !view_visibility.get() { + continue; + } - // TODO: re-use the memory - let mut extracted_cascades = EntityHashMap::default(); - let mut extracted_frusta = EntityHashMap::default(); - let mut cascade_visible_entities = EntityHashMap::default(); - for (e, v) in cascades.cascades.iter() { - if let Some(entity) = mapper.get(e) { - extracted_cascades.insert(*entity, v.clone()); - } else { - return; - } + // TODO: re-use the memory + let mut extracted_cascades = EntityHashMap::default(); + let mut extracted_frusta = EntityHashMap::default(); + let mut cascade_visible_entities = EntityHashMap::default(); + for (e, v) in cascades.cascades.iter() { + if let Some(entity) = mapper.get(e) { + extracted_cascades.insert(*entity, v.clone()); + } else { + break; } - for (e, v) in frusta.frusta.iter() { - if let Some(entity) = mapper.get(e) { - extracted_frusta.insert(*entity, v.clone()); - } else { - return; - } + } + for (e, v) in frusta.frusta.iter() { + if let Some(entity) = mapper.get(e) { + extracted_frusta.insert(*entity, v.clone()); + } else { + break; } - for (e, v) in visible_entities.entities.iter() { - if let Some(entity) = mapper.get(e) { - cascade_visible_entities.insert(*entity, v.clone()); - } else { - return; - } + } + for (e, v) in visible_entities.entities.iter() { + if let Some(entity) = mapper.get(e) { + cascade_visible_entities.insert(*entity, v.clone()); + } else { + break; } + } - commands.get_or_spawn(entity.entity()).insert(( - ExtractedDirectionalLight { - color: directional_light.color.into(), - illuminance: directional_light.illuminance, - transform: *transform, - volumetric: volumetric_light.is_some(), - shadows_enabled: directional_light.shadows_enabled, - shadow_depth_bias: directional_light.shadow_depth_bias, - // The factor of SQRT_2 is for the worst-case diagonal offset - shadow_normal_bias: directional_light.shadow_normal_bias - * std::f32::consts::SQRT_2, - cascade_shadow_config: cascade_config.clone(), - cascades: extracted_cascades, - frusta: extracted_frusta, - render_layers: maybe_layers.unwrap_or_default().clone(), - }, - CascadesVisibleEntities { - entities: cascade_visible_entities, - }, - )); - }, - ); + commands.get_or_spawn(entity.id()).insert(( + ExtractedDirectionalLight { + color: directional_light.color.into(), + illuminance: directional_light.illuminance, + transform: *transform, + volumetric: volumetric_light.is_some(), + shadows_enabled: directional_light.shadows_enabled, + shadow_depth_bias: directional_light.shadow_depth_bias, + // The factor of SQRT_2 is for the worst-case diagonal offset + shadow_normal_bias: directional_light.shadow_normal_bias * std::f32::consts::SQRT_2, + cascade_shadow_config: cascade_config.clone(), + cascades: extracted_cascades, + frusta: extracted_frusta, + render_layers: maybe_layers.unwrap_or_default().clone(), + }, + CascadesVisibleEntities { + entities: cascade_visible_entities, + }, + )); + } } pub(crate) const POINT_LIGHT_NEAR_Z: f32 = 0.1f32; diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_pbr/src/ssao/mod.rs index b1cc528f3dbdb..63d7f31287ea4 100644 --- a/crates/bevy_pbr/src/ssao/mod.rs +++ b/crates/bevy_pbr/src/ssao/mod.rs @@ -504,8 +504,9 @@ fn extract_ssao_settings( return; } if camera.is_active { - let entity = entity.entity(); - commands.get_or_spawn(entity).insert(ssao_settings.clone()); + commands + .get_or_spawn(entity.id()) + .insert(ssao_settings.clone()); } } } diff --git a/crates/bevy_pbr/src/volumetric_fog/render.rs b/crates/bevy_pbr/src/volumetric_fog/render.rs index 8a7d685fdd93d..783c131617d97 100644 --- a/crates/bevy_pbr/src/volumetric_fog/render.rs +++ b/crates/bevy_pbr/src/volumetric_fog/render.rs @@ -280,21 +280,19 @@ pub fn extract_volumetric_fog( for (entity, volumetric_fog_settings) in view_targets.iter() { commands - .get_or_spawn(entity.entity()) + .get_or_spawn(entity.id()) .insert(*volumetric_fog_settings); } for (entity, fog_volume, fog_transform) in fog_volumes.iter() { commands - .get_or_spawn(entity.entity()) + .get_or_spawn(entity.id()) .insert((*fog_volume).clone()) .insert(*fog_transform); } for (entity, volumetric_light) in volumetric_lights.iter() { - commands - .get_or_spawn(entity.entity()) - .insert(*volumetric_light); + commands.get_or_spawn(entity.id()).insert(*volumetric_light); } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 18eee60572886..9e7c5ac61fc41 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -884,8 +884,7 @@ pub fn extract_cameras( continue; } - let entity = render_entity.entity(); - let mut commands = commands.entity(entity); + let mut commands = commands.entity(render_entity.id()); commands.insert(( ExtractedCamera { target: camera.target.normalize(primary_window), diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index 9289aecf9b266..ede665c7d1b86 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -215,7 +215,7 @@ fn extract_components( let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in &query { if let Some(component) = C::extract_component(query_item) { - values.push((entity.entity(), component)); + values.push((entity.id(), component)); } } *previous_len = values.len(); @@ -232,7 +232,7 @@ fn extract_visible_components( for (entity, view_visibility, query_item) in &query { if view_visibility.get() { if let Some(component) = C::extract_component(query_item) { - values.push((entity.entity(), component)); + values.push((entity.id(), component)); } } } diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 0b4d6e72f674a..ba457dc76a457 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -24,7 +24,7 @@ pub struct ToRenderWorld; #[component(storage = "SparseSet")] pub struct RenderEntity(Entity); impl RenderEntity { - pub fn entity(&self) -> Entity { + pub fn id(&self) -> Entity { self.0 } } @@ -33,12 +33,13 @@ impl RenderEntity { #[component(storage = "SparseSet")] pub struct MainEntity(Entity); impl MainEntity { - pub fn entity(&self) -> Entity { + pub fn id(&self) -> Entity { self.0 } } // marker component that indicates that its entity needs to be despawned at the end of every frame. #[derive(Component, Clone, Debug, Default, Reflect)] +#[component(storage = "SparseSet")] pub struct RenderFlyEntity; pub(crate) enum EntityRecord { @@ -121,7 +122,7 @@ impl Plugin for WorldSyncPlugin { mut pending: ResMut, query: Query<&RenderEntity>| { if let Ok(e) = query.get(trigger.entity()) { - pending.push(EntityRecord::Removed(trigger.entity(), e.entity())); + pending.push(EntityRecord::Removed(trigger.entity(), e.id())); }; }, ); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 771270d367e59..5a3976dec9c85 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -768,7 +768,7 @@ pub fn extract_default_ui_camera_view( camera.physical_viewport_rect(), camera.physical_viewport_size(), ) { - let entity = entity.entity(); + let entity = entity.id(); // use a projection matrix with the origin in the top left instead of the bottom left that comes with OrthographicProjection let projection_matrix = Mat4::orthographic_rh( 0.0, @@ -962,7 +962,6 @@ pub(crate) const QUAD_VERTEX_POSITIONS: [Vec3; 4] = [ pub(crate) const QUAD_INDICES: [usize; 6] = [0, 2, 3, 0, 1, 2]; #[derive(Component)] -#[component(storage = "SparseSet")] pub struct UiBatch { pub range: Range, pub image: AssetId, diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 53882ac645bce..de9d4d7054ea3 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -358,6 +358,7 @@ pub fn extract_ui_material_nodes( mut commands: Commands, mut extracted_uinodes: ResMut>, materials: Extract>>, + ui_stack: Extract>, default_ui_camera: Extract, uinode_query: Extract< Query< @@ -388,24 +389,26 @@ pub fn extract_ui_material_nodes( // If there is only one camera, we use it as default let default_single_camera = default_ui_camera.get(); - uinode_query.iter().for_each( - |(uinode, style, transform, handle, view_visibility, clip, camera)| { + for (stack_index, entity) in ui_stack.uinodes.iter().enumerate() { + if let Ok((uinode, style, transform, handle, view_visibility, clip, camera)) = + uinode_query.get(*entity) + { let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_single_camera) else { - return; + continue; }; let Some(&camera_entity) = mapping.get(&camera_entity) else { - return; + continue; }; // skip invisible nodes if !view_visibility.get() { - return; + continue; } // Skip loading materials if !materials.contains(handle) { - return; + continue; } // Both vertical and horizontal percentage border values are calculated based on the width of the parent node @@ -431,7 +434,7 @@ pub fn extract_ui_material_nodes( extracted_uinodes.uinodes.insert( commands.spawn(RenderFlyEntity).id(), ExtractedUiMaterialNode { - stack_index: uinode.stack_index as usize, + stack_index, transform: transform.compute_matrix(), material: handle.id(), rect: Rect { @@ -443,8 +446,8 @@ pub fn extract_ui_material_nodes( camera_entity, }, ); - }, - ); + }; + } } #[allow(clippy::too_many_arguments)] From 8422a48bf8b49ca23e5495dfb1e1bd07fb6f0b89 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 25 Jul 2024 17:12:35 +0800 Subject: [PATCH 32/55] comment --- crates/bevy_pbr/src/render/light.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index c270bc3c075a6..ae2632802d1dd 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -350,7 +350,7 @@ pub fn extract_lights( continue; } - // TODO: re-use the memory + // TODO: update in place instead of reinserting. let mut extracted_cascades = EntityHashMap::default(); let mut extracted_frusta = EntityHashMap::default(); let mut cascade_visible_entities = EntityHashMap::default(); From dc5f10fb73a8a378e2092113b5f04c871168bfad Mon Sep 17 00:00:00 2001 From: re0312 Date: Sat, 27 Jul 2024 04:25:09 +0800 Subject: [PATCH 33/55] remove mapping --- crates/bevy_pbr/src/cluster/mod.rs | 8 +-- crates/bevy_pbr/src/lib.rs | 16 ++---- crates/bevy_pbr/src/render/light.rs | 16 +++--- crates/bevy_render/src/lib.rs | 5 +- crates/bevy_render/src/world_sync.rs | 57 ++++++++----------- crates/bevy_ui/src/render/mod.rs | 32 +++++------ .../src/render/ui_material_pipeline.rs | 8 +-- 7 files changed, 62 insertions(+), 80 deletions(-) diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index dc6c4bf854dcc..669483c39dca8 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -19,7 +19,7 @@ use bevy_render::{ UniformBuffer, }, renderer::{RenderDevice, RenderQueue}, - world_sync::{MainToRenderEntityMap, RenderEntity}, + world_sync::RenderEntity, Extract, }; use bevy_utils::{hashbrown::HashSet, tracing::warn}; @@ -513,7 +513,7 @@ pub(crate) fn clusterable_object_order( pub fn extract_clusters( mut commands: Commands, views: Extract>, - mapper: Res, + mapper: Extract>, ) { for (entity, clusters, camera) in &views { if !camera.is_active { @@ -532,9 +532,9 @@ pub fn extract_clusters( cluster_objects.spot_light_count as u32, )); for clusterable_entity in &cluster_objects.entities { - if let Some(entity) = mapper.get(clusterable_entity) { + if let Ok(entity) = mapper.get(*clusterable_entity) { data.push(ExtractedClusterableObjectElement::ClusterableObjectEntity( - *entity, + entity.id(), )); } } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index b5d0cd77cb9f7..6a960837d1476 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -320,24 +320,20 @@ impl Plugin for PbrPlugin { ScreenSpaceAmbientOcclusionPlugin, ExtractResourcePlugin::::default(), FogPlugin, - ( - ExtractResourcePlugin::::default(), - ExtractComponentPlugin::::default(), - ), + ExtractResourcePlugin::::default(), + ExtractComponentPlugin::::default(), LightmapPlugin, LightProbePlugin, - ( - PbrProjectionPlugin::::default(), - PbrProjectionPlugin::::default(), - PbrProjectionPlugin::::default(), - ), + PbrProjectionPlugin::::default(), + PbrProjectionPlugin::::default(), + PbrProjectionPlugin::::default(), GpuMeshPreprocessPlugin { use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder, }, VolumetricFogPlugin, ScreenSpaceReflectionsPlugin, - WorldSyncPlugin::<(PointLight, SpotLight, DirectionalLight)>::default(), )) + .add_plugins(WorldSyncPlugin::<(PointLight, SpotLight, DirectionalLight)>::default()) .configure_sets( PostUpdate, ( diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index ae2632802d1dd..71292146ae5d4 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -5,7 +5,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_render::world_sync::{MainToRenderEntityMap, RenderEntity, RenderFlyEntity}; +use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::RenderMesh, @@ -212,7 +212,7 @@ pub fn extract_lights( Without, >, >, - mapper: Res, + mapper: Extract>, mut previous_point_lights_len: Local, mut previous_spot_lights_len: Local, ) { @@ -355,22 +355,22 @@ pub fn extract_lights( let mut extracted_frusta = EntityHashMap::default(); let mut cascade_visible_entities = EntityHashMap::default(); for (e, v) in cascades.cascades.iter() { - if let Some(entity) = mapper.get(e) { - extracted_cascades.insert(*entity, v.clone()); + if let Ok(entity) = mapper.get(*e) { + extracted_cascades.insert(entity.id(), v.clone()); } else { break; } } for (e, v) in frusta.frusta.iter() { - if let Some(entity) = mapper.get(e) { - extracted_frusta.insert(*entity, v.clone()); + if let Ok(entity) = mapper.get(*e) { + extracted_frusta.insert(entity.id(), v.clone()); } else { break; } } for (e, v) in visible_entities.entities.iter() { - if let Some(entity) = mapper.get(e) { - cascade_visible_entities.insert(*entity, v.clone()); + if let Ok(entity) = mapper.get(*e) { + cascade_visible_entities.insert(entity.id(), v.clone()); } else { break; } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index d204673d18544..abed1b5cdb036 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -65,9 +65,7 @@ use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; -use world_sync::{ - despawn_fly_entity, entity_sync_system, MainToRenderEntityMap, ToRenderWorld, WorldSyncPlugin, -}; +use world_sync::{despawn_fly_entity, entity_sync_system, ToRenderWorld, WorldSyncPlugin}; use crate::mesh::RenderMesh; use crate::renderer::WgpuWrapper; @@ -400,7 +398,6 @@ impl Plugin for RenderPlugin { let render_app = app.sub_app_mut(RenderApp); render_app - .init_resource::() .insert_resource(instance) .insert_resource(PipelineCache::new( device.clone(), diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index ba457dc76a457..92bd9f7892def 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -1,11 +1,11 @@ -use std::{marker::PhantomData, ops::DerefMut}; +use std::marker::PhantomData; use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ bundle::Bundle, component::Component, - entity::{Entity, EntityHashMap}, + entity::Entity, observer::Trigger, query::With, reflect::ReflectComponent, @@ -20,7 +20,7 @@ use bevy_reflect::Reflect; #[reflect[Component]] pub struct ToRenderWorld; -#[derive(Component, Deref, Clone, Debug)] +#[derive(Component, Deref, Clone, Debug, Copy)] #[component(storage = "SparseSet")] pub struct RenderEntity(Entity); impl RenderEntity { @@ -45,8 +45,8 @@ pub struct RenderFlyEntity; pub(crate) enum EntityRecord { // main Added(Entity), - // (main , render) - Removed(Entity, Entity), + // render + Removed(Entity), } // Entity Record in MainWorld pending to Sync @@ -55,40 +55,29 @@ pub(crate) struct PendingSyncEntity { records: Vec, } -// resource to maintain entity mapping from the main world to the render world -#[derive(Resource, Default, Deref, DerefMut)] -pub struct MainToRenderEntityMap { - map: EntityHashMap, -} - pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut World) { - render_world.resource_scope(|render_world, mut mapper: Mut| { - let mapper = mapper.deref_mut(); - main_world.resource_scope(|world, mut pending: Mut| { - for record in pending.drain(..) { - match record { - EntityRecord::Added(e) => { - if let Some(mut entity) = world.get_entity_mut(e) { - match entity.entry::() { - bevy_ecs::world::Entry::Occupied(_) => {} - bevy_ecs::world::Entry::Vacant(entry) => { - let id = render_world.spawn(MainEntity(e)).id(); + main_world.resource_scope(|world, mut pending: Mut| { + for record in pending.drain(..) { + match record { + EntityRecord::Added(e) => { + if let Some(mut entity) = world.get_entity_mut(e) { + match entity.entry::() { + bevy_ecs::world::Entry::Occupied(_) => {} + bevy_ecs::world::Entry::Vacant(entry) => { + let id = render_world.spawn(MainEntity(e)).id(); - mapper.insert(e, id); - entry.insert(RenderEntity(id)); - } - }; - } - } - EntityRecord::Removed(e1, e2) => { - mapper.remove(&e1); - if let Some(ec) = render_world.get_entity_mut(e2) { - ec.despawn_recursive(); + entry.insert(RenderEntity(id)); + } }; } } + EntityRecord::Removed(e) => { + if let Some(ec) = render_world.get_entity_mut(e) { + ec.despawn_recursive(); + }; + } } - }); + } }); } @@ -122,7 +111,7 @@ impl Plugin for WorldSyncPlugin { mut pending: ResMut, query: Query<&RenderEntity>| { if let Ok(e) = query.get(trigger.entity()) { - pending.push(EntityRecord::Removed(trigger.entity(), e.id())); + pending.push(EntityRecord::Removed(e.id())); }; }, ); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 5a3976dec9c85..6128d6efb1e63 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -207,7 +207,7 @@ pub fn extract_uinode_background_colors( )>, >, node_query: Extract>, - mapping: Res, + mapping: Extract>, ) { let default_ui_camera = default_ui_camera.get(); for ( @@ -240,7 +240,7 @@ pub fn extract_uinode_background_colors( // so we have to divide by `UiScale` to get the size of the UI viewport. / ui_scale.0; - let Some(&camera_entity) = mapping.get(&camera_entity) else { + let Ok(&camera_entity) = mapping.get(camera_entity) else { continue; }; // Both vertical and horizontal percentage border values are calculated based on the width of the parent node @@ -286,7 +286,7 @@ pub fn extract_uinode_background_colors( atlas_size: None, flip_x: false, flip_y: false, - camera_entity, + camera_entity: camera_entity.id(), border, border_radius, node_type: NodeType::Rect, @@ -319,7 +319,7 @@ pub fn extract_uinode_images( )>, >, node_query: Extract>, - mapping: Res, + mapping: Extract>, ) { let default_ui_camera = default_ui_camera.get(); for ( @@ -357,14 +357,14 @@ pub fn extract_uinode_images( // so we have to divide by `UiScale` to get the size of the UI viewport. / ui_scale.0; - let Some(&camera_entity) = mapping.get(&camera_entity) else { + let Ok(&camera_entity) = mapping.get(camera_entity) else { continue; }; if let Some(slices) = slices { extracted_uinodes.uinodes.extend( slices - .extract_ui_nodes(transform, uinode, image, clip, camera_entity) + .extract_ui_nodes(transform, uinode, image, clip, camera_entity.id()) .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), ); continue; @@ -433,7 +433,7 @@ pub fn extract_uinode_images( atlas_size, flip_x: image.flip_x, flip_y: image.flip_y, - camera_entity, + camera_entity: camera_entity.id(), border, border_radius, node_type: NodeType::Rect, @@ -527,7 +527,7 @@ pub fn extract_uinode_borders( >, >, node_query: Extract>, - mapping: Res, + mapping: Extract>, ) { let image = AssetId::::default(); let default_ui_camera = default_ui_camera.get(); @@ -565,7 +565,7 @@ pub fn extract_uinode_borders( // so we have to divide by `UiScale` to get the size of the UI viewport. / ui_scale.0; - let Some(&camera_entity) = mapping.get(&camera_entity) else { + let Ok(&camera_entity) = mapping.get(camera_entity) else { continue; }; @@ -617,7 +617,7 @@ pub fn extract_uinode_borders( clip: clip.map(|clip| clip.clip), flip_x: false, flip_y: false, - camera_entity, + camera_entity: camera_entity.id(), border_radius, border, node_type: NodeType::Border, @@ -640,7 +640,7 @@ pub fn extract_uinode_outlines( &Outline, )>, >, - mapping: Res, + mapping: Extract>, ) { let default_ui_camera = default_ui_camera.get(); let image = AssetId::::default(); @@ -648,7 +648,7 @@ pub fn extract_uinode_outlines( let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera) else { continue; }; - let Some(&camera_entity) = mapping.get(&camera_entity) else { + let Ok(&camera_entity) = mapping.get(camera_entity) else { continue; }; @@ -714,7 +714,7 @@ pub fn extract_uinode_outlines( clip: maybe_clip.map(|clip| clip.clip), flip_x: false, flip_y: false, - camera_entity, + camera_entity: camera_entity.id(), border: [0.; 4], border_radius: [0.; 4], node_type: NodeType::Rect, @@ -832,7 +832,7 @@ pub fn extract_uinode_text( &TextLayoutInfo, )>, >, - mapping: Res, + mapping: Extract>, ) { let default_ui_camera = default_ui_camera.get(); for (uinode, global_transform, view_visibility, clip, camera, text, text_layout_info) in @@ -855,7 +855,7 @@ pub fn extract_uinode_text( * ui_scale.0; let inverse_scale_factor = scale_factor.recip(); - let Some(&camera_entity) = mapping.get(&camera_entity) else { + let Ok(&camera_entity) = mapping.get(camera_entity) else { continue; }; // Align the text to the nearest physical pixel: @@ -906,7 +906,7 @@ pub fn extract_uinode_text( clip: clip.map(|clip| clip.clip), flip_x: false, flip_y: false, - camera_entity, + camera_entity: camera_entity.id(), border: [0.; 4], border_radius: [0.; 4], node_type: NodeType::Rect, diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index de9d4d7054ea3..9df7015da155a 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -18,7 +18,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::{BevyDefault, FallbackImage, GpuImage}, view::*, - world_sync::RenderFlyEntity, + world_sync::{RenderEntity, RenderFlyEntity}, Extract, ExtractSchedule, Render, RenderSet, }; use bevy_transform::prelude::GlobalTransform; @@ -376,7 +376,7 @@ pub fn extract_ui_material_nodes( >, windows: Extract>>, ui_scale: Extract>, - mapping: Res, + mapping: Extract>, ) { let ui_logical_viewport_size = windows .get_single() @@ -397,7 +397,7 @@ pub fn extract_ui_material_nodes( else { continue; }; - let Some(&camera_entity) = mapping.get(&camera_entity) else { + let Ok(&camera_entity) = mapping.get(camera_entity) else { continue; }; @@ -443,7 +443,7 @@ pub fn extract_ui_material_nodes( }, border: [left, right, top, bottom], clip: clip.map(|clip| clip.clip), - camera_entity, + camera_entity: camera_entity.id(), }, ); }; From 2a6df8dc22f241a6667ce9a7fd6f221d82a7da40 Mon Sep 17 00:00:00 2001 From: re0312 Date: Sat, 27 Jul 2024 09:09:16 +0800 Subject: [PATCH 34/55] retain sprite --- crates/bevy_render/src/world_sync.rs | 4 +--- crates/bevy_sprite/src/lib.rs | 2 ++ crates/bevy_sprite/src/render/mod.rs | 13 ++++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 92bd9f7892def..3a9775442700e 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -21,7 +21,6 @@ use bevy_reflect::Reflect; pub struct ToRenderWorld; #[derive(Component, Deref, Clone, Debug, Copy)] -#[component(storage = "SparseSet")] pub struct RenderEntity(Entity); impl RenderEntity { pub fn id(&self) -> Entity { @@ -30,16 +29,15 @@ impl RenderEntity { } #[derive(Component, Deref, Clone, Debug)] -#[component(storage = "SparseSet")] pub struct MainEntity(Entity); impl MainEntity { pub fn id(&self) -> Entity { self.0 } } + // marker component that indicates that its entity needs to be despawned at the end of every frame. #[derive(Component, Clone, Debug, Default, Reflect)] -#[component(storage = "SparseSet")] pub struct RenderFlyEntity; pub(crate) enum EntityRecord { diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index 77a31f505e0b8..400c416c9a156 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -54,6 +54,7 @@ use bevy_render::{ render_resource::{Shader, SpecializedRenderPipelines}, texture::Image, view::{check_visibility, NoFrustumCulling, VisibilitySystems}, + world_sync::WorldSyncPlugin, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -115,6 +116,7 @@ impl Plugin for SpritePlugin { Mesh2dRenderPlugin, ColorMaterialPlugin, ExtractComponentPlugin::::default(), + WorldSyncPlugin::::default(), )) .add_systems( PostUpdate, diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 410208ff2681a..bc84487bc8839 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -38,7 +38,7 @@ use bevy_render::{ ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, ViewVisibility, VisibleEntities, }, - world_sync::RenderFlyEntity, + world_sync::{RenderEntity, RenderFlyEntity}, Extract, }; use bevy_transform::components::GlobalTransform; @@ -354,6 +354,7 @@ pub fn extract_sprites( sprite_query: Extract< Query<( Entity, + &RenderEntity, &ViewVisibility, &Sprite, &GlobalTransform, @@ -364,7 +365,9 @@ pub fn extract_sprites( >, ) { extracted_sprites.sprites.clear(); - for (entity, view_visibility, sprite, transform, handle, sheet, slices) in sprite_query.iter() { + for (original_entity, entity, view_visibility, sprite, transform, handle, sheet, slices) in + sprite_query.iter() + { if !view_visibility.get() { continue; } @@ -372,7 +375,7 @@ pub fn extract_sprites( if let Some(slices) = slices { extracted_sprites.sprites.extend( slices - .extract_sprites(transform, entity, sprite, handle) + .extract_sprites(transform, original_entity, sprite, handle) .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), ); } else { @@ -392,7 +395,7 @@ pub fn extract_sprites( // PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive extracted_sprites.sprites.insert( - commands.spawn(RenderFlyEntity).id(), + entity.id(), ExtractedSprite { color: sprite.color.into(), transform: *transform, @@ -403,7 +406,7 @@ pub fn extract_sprites( flip_y: sprite.flip_y, image_handle_id: handle.id(), anchor: sprite.anchor.as_vec(), - original_entity: Some(entity), + original_entity: Some(original_entity), }, ); } From ce2ea3660a00a6e3f7e555d19fb9e164f0888876 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 1 Aug 2024 10:58:53 +0800 Subject: [PATCH 35/55] cache state --- crates/bevy_render/src/world_sync.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 3a9775442700e..26e929b3cb039 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -9,7 +9,7 @@ use bevy_ecs::{ observer::Trigger, query::With, reflect::ReflectComponent, - system::{Query, ResMut, Resource}, + system::{Local, Query, ResMut, Resource, SystemState}, world::{Mut, OnAdd, OnRemove, World}, }; use bevy_hierarchy::DespawnRecursiveExt; @@ -23,6 +23,7 @@ pub struct ToRenderWorld; #[derive(Component, Deref, Clone, Debug, Copy)] pub struct RenderEntity(Entity); impl RenderEntity { + #[inline] pub fn id(&self) -> Entity { self.0 } @@ -31,6 +32,7 @@ impl RenderEntity { #[derive(Component, Deref, Clone, Debug)] pub struct MainEntity(Entity); impl MainEntity { + #[inline] pub fn id(&self) -> Entity { self.0 } @@ -79,13 +81,18 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl }); } -pub(crate) fn despawn_fly_entity(world: &mut World) { - let mut query = world.query_filtered::>(); +pub(crate) fn despawn_fly_entity( + world: &mut World, + mut state: SystemState>>, + mut local: Local>, +) { + let query = state.get(world); + local.extend(query.iter()); // ensure next frame allocation keeps order - let mut entities: Vec<_> = query.iter(world).collect(); - entities.sort_unstable_by_key(|e| e.index()); - for e in entities.into_iter().rev() { + // let mut entities: Vec<_> = query.iter().collect(); + local.sort_unstable_by_key(|e| e.index()); + for e in local.drain(..).rev() { world.despawn(e); } } From c1a4fb9cfc8bd4e41466bc71505479e7d583b654 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 1 Aug 2024 11:11:28 +0800 Subject: [PATCH 36/55] fix cli --- crates/bevy_render/src/world_sync.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 26e929b3cb039..52a44c3d7ed6b 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -83,14 +83,13 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl pub(crate) fn despawn_fly_entity( world: &mut World, - mut state: SystemState>>, + state: &mut SystemState>>, mut local: Local>, ) { let query = state.get(world); local.extend(query.iter()); // ensure next frame allocation keeps order - // let mut entities: Vec<_> = query.iter().collect(); local.sort_unstable_by_key(|e| e.index()); for e in local.drain(..).rev() { world.despawn(e); From 672778d4ad2d4b8e7784e712a412e81eb7a81848 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 1 Aug 2024 13:29:03 +0800 Subject: [PATCH 37/55] fix --- crates/bevy_pbr/src/lib.rs | 6 ++ crates/bevy_pbr/src/render/light.rs | 88 ++++++++++++++++++----------- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 6a960837d1476..3fec5b8cff059 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -411,6 +411,12 @@ impl Plugin for PbrPlugin { // Extract the required data from the main world render_app .add_systems(ExtractSchedule, (extract_clusters, extract_lights)) + .add_systems( + Render, + spawn_dir_view_light_entitiy + .in_set(RenderSet::ManageViews) + .before(prepare_lights), + ) .add_systems( Render, ( diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 71292146ae5d4..f46d21cf8e636 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1,6 +1,7 @@ use bevy_asset::UntypedAssetId; use bevy_color::ColorToComponents; use bevy_core_pipeline::core_3d::CORE_3D_DEPTH_FORMAT; +use bevy_derive::{Deref, DerefMut}; use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; @@ -398,6 +399,17 @@ pub fn extract_lights( } } +#[derive(Component, Default, Deref, DerefMut)] +pub struct ViewLightEntity(Vec); +pub fn spawn_dir_view_light_entitiy( + mut commands: Commands, + query: Query, Without)>, +) { + query.iter().for_each(|e| { + commands.entity(e).insert(ViewLightEntity::default()); + }) +} + pub(crate) const POINT_LIGHT_NEAR_Z: f32 = 0.1f32; pub(crate) struct CubeMapFace { @@ -567,14 +579,17 @@ pub fn prepare_lights( point_light_shadow_map: Res, directional_light_shadow_map: Res, mut shadow_render_phases: ResMut>, - mut max_directional_lights_warning_emitted: Local, - mut max_cascades_per_light_warning_emitted: Local, + (mut max_directional_lights_warning_emitted, mut max_cascades_per_light_warning_emitted): ( + Local, + Local, + ), point_lights: Query<( Entity, &ExtractedPointLight, AnyOf<(&CubemapFrusta, &Frustum)>, )>, directional_lights: Query<(Entity, &ExtractedDirectionalLight)>, + mut view_light_entites: Query<&mut ViewLightEntity>, mut live_shadow_mapping_lights: Local, ) { let views_iter = views.iter(); @@ -1043,6 +1058,9 @@ pub fn prepare_lights( { let gpu_light = &mut gpu_lights.directional_lights[light_index]; + let Ok(mut view_light_entites) = view_light_entites.get_mut(light_entity) else { + continue; + }; // Check if the light intersects with the view. if !view_layers.intersects(&light.render_layers) { gpu_light.skip = 1u32; @@ -1066,10 +1084,16 @@ pub fn prepare_lights( .unwrap() .iter() .take(MAX_CASCADES_PER_LIGHT); - for (cascade_index, ((cascade, frustum), bound)) in cascades + + let iter = cascades .zip(frusta) - .zip(&light.cascade_shadow_config.bounds) - .enumerate() + .zip(&light.cascade_shadow_config.bounds); + while view_light_entites.len() < iter.len() { + view_light_entites.push(commands.spawn_empty().id()); + } + + for (cascade_index, (((cascade, frustum), bound), view_light_entity)) in + iter.zip(view_light_entites.iter().copied()).enumerate() { gpu_lights.directional_lights[light_index].cascades[cascade_index] = GpuDirectionalCascade { @@ -1098,34 +1122,32 @@ pub fn prepare_lights( frustum.half_spaces[4] = HalfSpace::new(frustum.half_spaces[4].normal().extend(f32::INFINITY)); - let view_light_entity = commands - .spawn(( - ShadowView { - depth_attachment: DepthAttachment::new(depth_texture_view, Some(0.0)), - pass_name: format!( - "shadow pass directional light {light_index} cascade {cascade_index}"), - }, - ExtractedView { - viewport: UVec4::new( - 0, - 0, - directional_light_shadow_map.size as u32, - directional_light_shadow_map.size as u32, - ), - world_from_view: GlobalTransform::from(cascade.world_from_cascade), - clip_from_view: cascade.clip_from_cascade, - clip_from_world: Some(cascade.clip_from_world), - hdr: false, - color_grading: Default::default(), - }, - frustum, - LightEntity::Directional { - light_entity, - cascade_index, - }, - RenderFlyEntity - )) - .id(); + commands.entity(view_light_entity).insert(( + ShadowView { + depth_attachment: DepthAttachment::new(depth_texture_view, Some(0.0)), + pass_name: format!( + "shadow pass directional light {light_index} cascade {cascade_index}" + ), + }, + ExtractedView { + viewport: UVec4::new( + 0, + 0, + directional_light_shadow_map.size as u32, + directional_light_shadow_map.size as u32, + ), + world_from_view: GlobalTransform::from(cascade.world_from_cascade), + clip_from_view: cascade.clip_from_cascade, + clip_from_world: Some(cascade.clip_from_world), + hdr: false, + color_grading: Default::default(), + }, + frustum, + LightEntity::Directional { + light_entity, + cascade_index, + }, + )); view_lights.push(view_light_entity); shadow_render_phases.insert_or_clear(view_light_entity); From 0eed037e7d8cb07adc0d6b1226b07aa7909dc984 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 1 Aug 2024 14:15:13 +0800 Subject: [PATCH 38/55] fix point light --- crates/bevy_pbr/src/render/light.rs | 130 +++++++++++++++------------- 1 file changed, 72 insertions(+), 58 deletions(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index f46d21cf8e636..18afec59ca47a 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -6,7 +6,7 @@ use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; use bevy_math::{Mat4, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; +use bevy_render::world_sync::RenderEntity; use bevy_render::{ diagnostic::RecordDiagnostics, mesh::RenderMesh, @@ -403,7 +403,13 @@ pub fn extract_lights( pub struct ViewLightEntity(Vec); pub fn spawn_dir_view_light_entitiy( mut commands: Commands, - query: Query, Without)>, + query: Query< + Entity, + ( + Or<(With, With)>, + Without, + ), + >, ) { query.iter().for_each(|e| { commands.entity(e).insert(ViewLightEntity::default()); @@ -932,9 +938,14 @@ pub fn prepare_lights( // and ignore rotation because we want the shadow map projections to align with the axes let view_translation = GlobalTransform::from_translation(light.transform.translation()); - for (face_index, (view_rotation, frustum)) in cube_face_rotations + let Ok(mut view_light_entities) = view_light_entites.get_mut(light_entity) else { + continue; + }; + view_light_entities.resize_with(6, || commands.spawn_empty().id()); + for (face_index, ((view_rotation, frustum), view_light_entity)) in cube_face_rotations .iter() .zip(&point_light_frusta.unwrap().frusta) + .zip(view_light_entities.iter().copied()) .enumerate() { let depth_texture_view = @@ -951,37 +962,35 @@ pub fn prepare_lights( array_layer_count: Some(1u32), }); - let view_light_entity = commands - .spawn(( - ShadowView { - depth_attachment: DepthAttachment::new(depth_texture_view, Some(0.0)), - pass_name: format!( - "shadow pass point light {} {}", - light_index, - face_index_to_name(face_index) - ), - }, - ExtractedView { - viewport: UVec4::new( - 0, - 0, - point_light_shadow_map.size as u32, - point_light_shadow_map.size as u32, - ), - world_from_view: view_translation * *view_rotation, - clip_from_world: None, - clip_from_view: cube_face_projection, - hdr: false, - color_grading: Default::default(), - }, - *frustum, - LightEntity::Point { - light_entity, - face_index, - }, - RenderFlyEntity, - )) - .id(); + commands.entity(view_light_entity).insert(( + ShadowView { + depth_attachment: DepthAttachment::new(depth_texture_view, Some(0.0)), + pass_name: format!( + "shadow pass point light {} {}", + light_index, + face_index_to_name(face_index) + ), + }, + ExtractedView { + viewport: UVec4::new( + 0, + 0, + point_light_shadow_map.size as u32, + point_light_shadow_map.size as u32, + ), + world_from_view: view_translation * *view_rotation, + clip_from_world: None, + clip_from_view: cube_face_projection, + hdr: false, + color_grading: Default::default(), + }, + *frustum, + LightEntity::Point { + light_entity, + face_index, + }, + )); + view_lights.push(view_light_entity); shadow_render_phases.insert_or_clear(view_light_entity); @@ -999,6 +1008,10 @@ pub fn prepare_lights( let spot_world_from_view = spot_light_world_from_view(&light.transform); let spot_world_from_view = spot_world_from_view.into(); + let Ok(mut view_light_entities) = view_light_entites.get_mut(light_entity) else { + continue; + }; + let angle = light.spot_light_angles.expect("lights should be sorted so that \ [point_light_count..point_light_count + spot_light_shadow_maps_count] are spot lights").1; let spot_projection = spot_light_clip_from_view(angle); @@ -1017,30 +1030,31 @@ pub fn prepare_lights( array_layer_count: Some(1u32), }); - let view_light_entity = commands - .spawn(( - ShadowView { - depth_attachment: DepthAttachment::new(depth_texture_view, Some(0.0)), - pass_name: format!("shadow pass spot light {light_index}"), - }, - ExtractedView { - viewport: UVec4::new( - 0, - 0, - directional_light_shadow_map.size as u32, - directional_light_shadow_map.size as u32, - ), - world_from_view: spot_world_from_view, - clip_from_view: spot_projection, - clip_from_world: None, - hdr: false, - color_grading: Default::default(), - }, - *spot_light_frustum.unwrap(), - LightEntity::Spot { light_entity }, - RenderFlyEntity, - )) - .id(); + view_light_entities.resize_with(1, || commands.spawn_empty().id()); + + let view_light_entity = view_light_entities[0]; + + commands.entity(view_light_entity).insert(( + ShadowView { + depth_attachment: DepthAttachment::new(depth_texture_view, Some(0.0)), + pass_name: format!("shadow pass spot light {light_index}"), + }, + ExtractedView { + viewport: UVec4::new( + 0, + 0, + directional_light_shadow_map.size as u32, + directional_light_shadow_map.size as u32, + ), + world_from_view: spot_world_from_view, + clip_from_view: spot_projection, + clip_from_world: None, + hdr: false, + color_grading: Default::default(), + }, + *spot_light_frustum.unwrap(), + LightEntity::Spot { light_entity }, + )); view_lights.push(view_light_entity); From 5a83da46e634f57b732d1a40f6f6cd58e1dcfabd Mon Sep 17 00:00:00 2001 From: re0312 Date: Fri, 9 Aug 2024 08:00:25 +0800 Subject: [PATCH 39/55] fix regression --- crates/bevy_pbr/src/lib.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 50 ++++++++++++++++++---------- crates/bevy_render/src/world_sync.rs | 3 +- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 3fec5b8cff059..c334f456e0e20 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -413,7 +413,7 @@ impl Plugin for PbrPlugin { .add_systems(ExtractSchedule, (extract_clusters, extract_lights)) .add_systems( Render, - spawn_dir_view_light_entitiy + insert_light_view_entities .in_set(RenderSet::ManageViews) .before(prepare_lights), ) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 18afec59ca47a..215416340526c 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -400,19 +400,20 @@ pub fn extract_lights( } #[derive(Component, Default, Deref, DerefMut)] -pub struct ViewLightEntity(Vec); -pub fn spawn_dir_view_light_entitiy( +pub struct LightViewEntities(Vec); + +pub fn insert_light_view_entities( mut commands: Commands, query: Query< Entity, ( Or<(With, With)>, - Without, + Without, ), >, ) { query.iter().for_each(|e| { - commands.entity(e).insert(ViewLightEntity::default()); + commands.entity(e).insert(LightViewEntities::default()); }) } @@ -595,7 +596,7 @@ pub fn prepare_lights( AnyOf<(&CubemapFrusta, &Frustum)>, )>, directional_lights: Query<(Entity, &ExtractedDirectionalLight)>, - mut view_light_entites: Query<&mut ViewLightEntity>, + mut light_view_entities: Query<&mut LightViewEntities>, mut live_shadow_mapping_lights: Local, ) { let views_iter = views.iter(); @@ -851,8 +852,9 @@ pub fn prepare_lights( live_shadow_mapping_lights.clear(); + let mut dir_light_view_offset = 0; // set up light data for each view - for (entity, extracted_view, clusters, maybe_layers) in &views { + for (offset, (entity, extracted_view, clusters, maybe_layers)) in views.iter().enumerate() { let point_light_depth_texture = texture_cache.get( &render_device, TextureDescriptor { @@ -938,14 +940,18 @@ pub fn prepare_lights( // and ignore rotation because we want the shadow map projections to align with the axes let view_translation = GlobalTransform::from_translation(light.transform.translation()); - let Ok(mut view_light_entities) = view_light_entites.get_mut(light_entity) else { + let Ok(mut light_entities) = light_view_entities.get_mut(light_entity) else { continue; }; - view_light_entities.resize_with(6, || commands.spawn_empty().id()); + + while light_entities.len() < 6 * (offset + 1) { + light_entities.push(commands.spawn_empty().id()); + } + for (face_index, ((view_rotation, frustum), view_light_entity)) in cube_face_rotations .iter() .zip(&point_light_frusta.unwrap().frusta) - .zip(view_light_entities.iter().copied()) + .zip(light_entities.iter().skip(6 * offset).copied()) .enumerate() { let depth_texture_view = @@ -1008,7 +1014,7 @@ pub fn prepare_lights( let spot_world_from_view = spot_light_world_from_view(&light.transform); let spot_world_from_view = spot_world_from_view.into(); - let Ok(mut view_light_entities) = view_light_entites.get_mut(light_entity) else { + let Ok(mut light_view_entities) = light_view_entities.get_mut(light_entity) else { continue; }; @@ -1030,9 +1036,11 @@ pub fn prepare_lights( array_layer_count: Some(1u32), }); - view_light_entities.resize_with(1, || commands.spawn_empty().id()); + while light_view_entities.len() < offset + 1 { + light_view_entities.push(commands.spawn_empty().id()) + } - let view_light_entity = view_light_entities[0]; + let view_light_entity = light_view_entities[offset]; commands.entity(view_light_entity).insert(( ShadowView { @@ -1072,7 +1080,7 @@ pub fn prepare_lights( { let gpu_light = &mut gpu_lights.directional_lights[light_index]; - let Ok(mut view_light_entites) = view_light_entites.get_mut(light_entity) else { + let Ok(mut light_view_entities) = light_view_entities.get_mut(light_entity) else { continue; }; // Check if the light intersects with the view. @@ -1102,12 +1110,19 @@ pub fn prepare_lights( let iter = cascades .zip(frusta) .zip(&light.cascade_shadow_config.bounds); - while view_light_entites.len() < iter.len() { - view_light_entites.push(commands.spawn_empty().id()); + + while light_view_entities.len() < dir_light_view_offset + iter.len() { + light_view_entities.push(commands.spawn_empty().id()); } - for (cascade_index, (((cascade, frustum), bound), view_light_entity)) in - iter.zip(view_light_entites.iter().copied()).enumerate() + for (cascade_index, (((cascade, frustum), bound), view_light_entity)) in iter + .zip( + light_view_entities + .iter() + .skip(dir_light_view_offset) + .copied(), + ) + .enumerate() { gpu_lights.directional_lights[light_index].cascades[cascade_index] = GpuDirectionalCascade { @@ -1166,6 +1181,7 @@ pub fn prepare_lights( shadow_render_phases.insert_or_clear(view_light_entity); live_shadow_mapping_lights.insert(view_light_entity); + dir_light_view_offset += 1; } } diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 52a44c3d7ed6b..f742791dafee3 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -88,7 +88,8 @@ pub(crate) fn despawn_fly_entity( ) { let query = state.get(world); - local.extend(query.iter()); + query.iter().for_each(|e| local.push(e)); + // ensure next frame allocation keeps order local.sort_unstable_by_key(|e| e.index()); for e in local.drain(..).rev() { From ed296f1098e822d599e1388f2a305a40a0100414 Mon Sep 17 00:00:00 2001 From: re0312 Date: Fri, 9 Aug 2024 08:09:13 +0800 Subject: [PATCH 40/55] fix cli --- crates/bevy_pbr/src/render/light.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 215416340526c..01c6b79b55598 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -414,7 +414,7 @@ pub fn insert_light_view_entities( ) { query.iter().for_each(|e| { commands.entity(e).insert(LightViewEntities::default()); - }) + }); } pub(crate) const POINT_LIGHT_NEAR_Z: f32 = 0.1f32; @@ -1037,7 +1037,7 @@ pub fn prepare_lights( }); while light_view_entities.len() < offset + 1 { - light_view_entities.push(commands.spawn_empty().id()) + light_view_entities.push(commands.spawn_empty().id()); } let view_light_entity = light_view_entities[offset]; From 94be0cd377101b8b9bd338b8a8dd3cae86d5d4f2 Mon Sep 17 00:00:00 2001 From: re0312 Date: Fri, 9 Aug 2024 08:29:19 +0800 Subject: [PATCH 41/55] fix conflict --- crates/bevy_core_pipeline/src/core_2d/mod.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index ba35c7b8902ea..e269375315ff5 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -55,6 +55,7 @@ use bevy_render::{ renderer::RenderDevice, texture::TextureCache, view::{Msaa, ViewDepthTexture}, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -247,7 +248,6 @@ pub fn extract_core_2d_camera_phases( mut transparent_2d_phases: ResMut>, cameras_2d: Extract>>, mut opaque_2d_phases: ResMut>, - cameras_2d: Extract>>, mut live_entities: Local, ) { live_entities.clear(); diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 4d9b0c9562017..ba918068a821b 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1,6 +1,7 @@ use bevy_asset::UntypedAssetId; use bevy_color::ColorToComponents; use bevy_core_pipeline::core_3d::{Camera3d, CORE_3D_DEPTH_FORMAT}; +use bevy_derive::{Deref, DerefMut}; use bevy_ecs::entity::EntityHashSet; use bevy_ecs::prelude::*; use bevy_ecs::{entity::EntityHashMap, system::lifetimeless::Read}; From fd36379261140c2aaa4bb6dbadc6f79c63efac46 Mon Sep 17 00:00:00 2001 From: re0312 <45868716+re0312@users.noreply.github.com> Date: Tue, 13 Aug 2024 04:35:15 +0800 Subject: [PATCH 42/55] Apply suggestions from code review Co-authored-by: Periwink --- crates/bevy_render/src/world_sync.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index f742791dafee3..b866764ea6c3f 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -21,6 +21,7 @@ use bevy_reflect::Reflect; pub struct ToRenderWorld; #[derive(Component, Deref, Clone, Debug, Copy)] +/// Marker component added on the main world entities that are synced to the Render World in order to keep track of the corresponding render world entity pub struct RenderEntity(Entity); impl RenderEntity { #[inline] @@ -30,6 +31,7 @@ impl RenderEntity { } #[derive(Component, Deref, Clone, Debug)] +/// Marker component added on the render world entities to keep track of the corresponding main world entity pub struct MainEntity(Entity); impl MainEntity { #[inline] @@ -43,9 +45,9 @@ impl MainEntity { pub struct RenderFlyEntity; pub(crate) enum EntityRecord { - // main + // When an entity is spawned on the main world, notify the render world so that it can spawn a corresponding entity. This contains the main world entity Added(Entity), - // render + // When an entity is despawned on the main world, notify the render world so that the corresponding entity can be despawned. This contains the render world entity. Removed(Entity), } From 67e7a07dc54ad9a3d3ba747d9dcb9f641a1e0e62 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 13 Aug 2024 05:07:46 +0800 Subject: [PATCH 43/55] fix cli --- crates/bevy_core_pipeline/src/core_2d/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index ecce1e325dc2e..1e750cfb6f172 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -274,7 +274,7 @@ impl CachedRenderPipelinePhaseItem for Transparent2d { pub fn extract_core_2d_camera_phases( mut transparent_2d_phases: ResMut>, mut opaque_2d_phases: ResMut>, - cameras_2d: Extract>>, + cameras_2d: Extract>>, mut live_entities: Local, ) { live_entities.clear(); From e5254be58f53229e1e1ad1be61d4b72416f60ba9 Mon Sep 17 00:00:00 2001 From: re0312 Date: Mon, 26 Aug 2024 06:14:45 +0800 Subject: [PATCH 44/55] fix --- crates/bevy_core_pipeline/src/core_2d/mod.rs | 2 +- crates/bevy_render/src/lib.rs | 2 +- crates/bevy_render/src/world_sync.rs | 2 +- crates/bevy_ui/src/render/mod.rs | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index c87752c841065..54fc5364c4a74 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -361,7 +361,7 @@ pub fn extract_core_2d_camera_phases( mut transparent_2d_phases: ResMut>, mut opaque_2d_phases: ResMut>, mut alpha_mask_2d_phases: ResMut>, - cameras_2d: Extract>>, + cameras_2d: Extract>>, mut live_entities: Local, ) { live_entities.clear(); diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index e9d6ed48fb93a..c8c498b3235ab 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -478,7 +478,7 @@ unsafe fn initialize_render_app(app: &mut App) { render_system, ) .in_set(RenderSet::Render), - World::clear_entities.in_set(RenderSet::PostCleanup), + despawn_fly_entity.in_set(RenderSet::PostCleanup), ), ); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index b866764ea6c3f..0c2ed0f372982 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -90,7 +90,7 @@ pub(crate) fn despawn_fly_entity( ) { let query = state.get(world); - query.iter().for_each(|e| local.push(e)); + local.extend(query.iter()); // ensure next frame allocation keeps order local.sort_unstable_by_key(|e| e.index()); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 84f53d2daae50..61b4f49cb72ce 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -234,7 +234,7 @@ pub fn extract_uinode_background_colors( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(bevy_render::camera::Camera::logical_viewport_size) + .and_then(Camera::logical_viewport_size) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. @@ -351,7 +351,7 @@ pub fn extract_uinode_images( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(bevy_render::camera::Camera::logical_viewport_size) + .and_then(Camera::logical_viewport_size) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. @@ -557,7 +557,7 @@ pub fn extract_uinode_borders( let ui_logical_viewport_size = camera_query .get(camera_entity) .ok() - .and_then(bevy_render::camera::Camera::logical_viewport_size) + .and_then(Camera::logical_viewport_size) .unwrap_or(Vec2::ZERO) // The logical window resolution returned by `Window` only takes into account the window scale factor and not `UiScale`, // so we have to divide by `UiScale` to get the size of the UI viewport. @@ -848,7 +848,7 @@ pub fn extract_uinode_text( let scale_factor = camera_query .get(camera_entity) .ok() - .and_then(bevy_render::camera::Camera::target_scaling_factor) + .and_then(Camera::target_scaling_factor) .unwrap_or(1.0) * ui_scale.0; let inverse_scale_factor = scale_factor.recip(); From faf5ef24bc6be8a1a053fab6f74314df1c25641d Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 27 Aug 2024 23:29:41 +0800 Subject: [PATCH 45/55] fix --- crates/bevy_pbr/src/lib.rs | 9 ++---- .../bevy_pbr/src/meshlet/instance_manager.rs | 6 ++-- crates/bevy_pbr/src/prepass/mod.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 31 ++++++++++++------- crates/bevy_render/src/camera/camera.rs | 2 +- crates/bevy_render/src/world_sync.rs | 1 + 6 files changed, 29 insertions(+), 22 deletions(-) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 8a545bdd9bc4e..58ea11b802025 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -411,12 +411,6 @@ impl Plugin for PbrPlugin { // Extract the required data from the main world render_app .add_systems(ExtractSchedule, (extract_clusters, extract_lights)) - .add_systems( - Render, - insert_light_view_entities - .in_set(RenderSet::ManageViews) - .before(prepare_lights), - ) .add_systems( Render, ( @@ -428,6 +422,9 @@ impl Plugin for PbrPlugin { ) .init_resource::(); + render_app.world_mut().observe(add_light_view_entities); + render_app.world_mut().observe(remove_light_view_entities); + let shadow_pass_node = ShadowPassNode::new(render_app.world_mut()); let mut graph = render_app.world_mut().resource_mut::(); let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap(); diff --git a/crates/bevy_pbr/src/meshlet/instance_manager.rs b/crates/bevy_pbr/src/meshlet/instance_manager.rs index 0f370f2200459..e24896cf5f990 100644 --- a/crates/bevy_pbr/src/meshlet/instance_manager.rs +++ b/crates/bevy_pbr/src/meshlet/instance_manager.rs @@ -178,21 +178,21 @@ pub fn extract_meshlet_mesh_entities( Res, ResMut>, EventReader>, - &Entities, )>, >, >, + render_entities: &Entities, ) { // Get instances query if system_state.is_none() { *system_state = Some(SystemState::new(&mut main_world)); } let system_state = system_state.as_mut().unwrap(); - let (instances_query, asset_server, mut assets, mut asset_events, entities) = + let (instances_query, asset_server, mut assets, mut asset_events) = system_state.get_mut(&mut main_world); // Reset per-frame data - instance_manager.reset(entities); + instance_manager.reset(render_entities); // Free GPU buffer space for any modified or dropped MeshletMesh assets for asset_event in asset_events.read() { diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index f5932b86662b2..b6e58445f1419 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -583,7 +583,7 @@ pub fn extract_camera_previous_view_data( for (entity, camera, maybe_previous_view_data) in cameras_3d.iter() { if camera.is_active { let entity = entity.id(); - let mut entity = commands.get_or_spawn(entity); + let entity = commands.get_or_spawn(entity); if let Some(previous_view_data) = maybe_previous_view_data { entity.insert(previous_view_data.clone()); diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 975ca30b09d3a..40922753108ba 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -402,19 +402,28 @@ pub fn extract_lights( #[derive(Component, Default, Deref, DerefMut)] pub struct LightViewEntities(Vec); -pub fn insert_light_view_entities( +// TODO: using required component +pub(crate) fn add_light_view_entities( + trigger: Trigger, mut commands: Commands, - query: Query< - Entity, - ( - Or<(With, With)>, - Without, - ), - >, ) { - query.iter().for_each(|e| { - commands.entity(e).insert(LightViewEntities::default()); - }); + commands + .get_entity(trigger.entity()) + .map(|v| v.insert(LightViewEntities::default())); +} + +pub(crate) fn remove_light_view_entities( + trigger: Trigger, + query: Query<&LightViewEntities>, + mut commands: Commands, +) { + if let Ok(entities) = query.get(trigger.entity()) { + for e in entities.0.iter().copied() { + commands.get_entity(e).map(|v| { + v.despawn(); + }); + } + } } pub(crate) const POINT_LIGHT_NEAR_Z: f32 = 0.1f32; diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 7d4428f34d770..c960d60a65219 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -936,7 +936,7 @@ pub fn extract_cameras( } let mut commands = commands.entity(render_entity.id()); - commands.insert(( + commands = commands.insert(( ExtractedCamera { target: camera.target.normalize(primary_window), viewport: camera.viewport.clone(), diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 0c2ed0f372982..49c7e02c80dc1 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -59,6 +59,7 @@ pub(crate) struct PendingSyncEntity { pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut World) { main_world.resource_scope(|world, mut pending: Mut| { + // TODO : batching record for record in pending.drain(..) { match record { EntityRecord::Added(e) => { From f127719a6f6657497e0c86b3161bb7dc53e73ad9 Mon Sep 17 00:00:00 2001 From: re0312 Date: Tue, 27 Aug 2024 23:36:49 +0800 Subject: [PATCH 46/55] to render world --- crates/bevy_render/src/spatial_bundle.rs | 8 +------- examples/3d/fog_volumes.rs | 5 ++++- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/bevy_render/src/spatial_bundle.rs b/crates/bevy_render/src/spatial_bundle.rs index 0faa67380afb6..e84f765a27fe8 100644 --- a/crates/bevy_render/src/spatial_bundle.rs +++ b/crates/bevy_render/src/spatial_bundle.rs @@ -1,10 +1,7 @@ use bevy_ecs::prelude::Bundle; use bevy_transform::prelude::{GlobalTransform, Transform}; -use crate::{ - view::{InheritedVisibility, ViewVisibility, Visibility}, - world_sync::ToRenderWorld, -}; +use crate::view::{InheritedVisibility, ViewVisibility, Visibility}; /// A [`Bundle`] that allows the correct positional rendering of an entity. /// @@ -30,8 +27,6 @@ pub struct SpatialBundle { pub transform: Transform, /// The global transform of the entity. pub global_transform: GlobalTransform, - - pub _marker: ToRenderWorld, } impl SpatialBundle { @@ -53,7 +48,6 @@ impl SpatialBundle { view_visibility: ViewVisibility::HIDDEN, transform: Transform::IDENTITY, global_transform: GlobalTransform::IDENTITY, - _marker: ToRenderWorld, }; /// An invisible [`SpatialBundle`] with identity transform. diff --git a/examples/3d/fog_volumes.rs b/examples/3d/fog_volumes.rs index 40818a2f93cc1..2c0cb87882be9 100644 --- a/examples/3d/fog_volumes.rs +++ b/examples/3d/fog_volumes.rs @@ -10,6 +10,7 @@ use bevy::{ pbr::{FogVolume, VolumetricFogSettings, VolumetricLight}, prelude::*, }; +use bevy_render::world_sync::ToRenderWorld; /// Entry point. fn main() { @@ -43,7 +44,9 @@ fn setup(mut commands: Commands, asset_server: Res) { // up. scattering: 1.0, ..default() - }); + }) + // indicates that this spatial needs to be Synchronized to the render world + .insert(ToRenderWorld); // Spawn a bright directional light that illuminates the fog well. commands From c7ba4667227614589b5df3a188812bcf2dcd422d Mon Sep 17 00:00:00 2001 From: re0312 Date: Wed, 28 Aug 2024 00:13:25 +0800 Subject: [PATCH 47/55] SyncRenderWorld --- .../src/core_2d/camera_2d.rs | 5 +++++ .../src/core_3d/camera_3d.rs | 5 ++++- crates/bevy_pbr/src/bundle.rs | 7 +++++++ crates/bevy_pbr/src/lib.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 4 ++-- crates/bevy_render/src/lib.rs | 6 ++---- crates/bevy_render/src/world_sync.rs | 19 +++++++++---------- crates/bevy_sprite/src/bundle.rs | 5 +++++ crates/bevy_sprite/src/lib.rs | 2 -- examples/3d/fog_volumes.rs | 4 ++-- 10 files changed, 37 insertions(+), 22 deletions(-) diff --git a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs index 857c2202164ab..5c248ead23e5f 100644 --- a/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs +++ b/crates/bevy_core_pipeline/src/core_2d/camera_2d.rs @@ -3,6 +3,7 @@ use crate::tonemapping::{DebandDither, Tonemapping}; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; use bevy_render::prelude::Msaa; +use bevy_render::world_sync::SyncRenderWorld; use bevy_render::{ camera::{ Camera, CameraMainTextureUsages, CameraProjection, CameraRenderGraph, @@ -37,6 +38,8 @@ pub struct Camera2dBundle { pub deband_dither: DebandDither, pub main_texture_usages: CameraMainTextureUsages, pub msaa: Msaa, + /// Marker component that indicates that its entity needs to be Synchronized to the render world + pub sync: SyncRenderWorld, } impl Default for Camera2dBundle { @@ -61,6 +64,7 @@ impl Default for Camera2dBundle { deband_dither: DebandDither::Disabled, main_texture_usages: Default::default(), msaa: Default::default(), + sync: Default::default(), } } } @@ -94,6 +98,7 @@ impl Camera2dBundle { deband_dither: DebandDither::Disabled, main_texture_usages: Default::default(), msaa: Default::default(), + sync: Default::default(), } } } diff --git a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs index 697d9df64b339..a63d8cb5344bf 100644 --- a/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs +++ b/crates/bevy_core_pipeline/src/core_3d/camera_3d.rs @@ -4,7 +4,6 @@ use crate::{ }; use bevy_ecs::prelude::*; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; -use bevy_render::view::Msaa; use bevy_render::{ camera::{Camera, CameraMainTextureUsages, CameraRenderGraph, Exposure, Projection}, extract_component::ExtractComponent, @@ -12,6 +11,7 @@ use bevy_render::{ render_resource::{LoadOp, TextureUsages}, view::{ColorGrading, VisibleEntities}, }; +use bevy_render::{view::Msaa, world_sync::SyncRenderWorld}; use bevy_transform::prelude::{GlobalTransform, Transform}; use serde::{Deserialize, Serialize}; @@ -154,6 +154,8 @@ pub struct Camera3dBundle { pub exposure: Exposure, pub main_texture_usages: CameraMainTextureUsages, pub msaa: Msaa, + /// Marker component that indicates that its entity needs to be Synchronized to the render world + pub sync: SyncRenderWorld, } // NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference @@ -174,6 +176,7 @@ impl Default for Camera3dBundle { main_texture_usages: Default::default(), deband_dither: DebandDither::Enabled, msaa: Default::default(), + sync: Default::default(), } } } diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index e1147a46e4297..4210cca405513 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -7,6 +7,7 @@ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::entity::{Entity, EntityHashMap}; use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent}; use bevy_reflect::Reflect; +use bevy_render::world_sync::SyncRenderWorld; use bevy_render::{ mesh::Mesh, primitives::{CascadesFrusta, CubemapFrusta, Frustum}, @@ -103,6 +104,8 @@ pub struct PointLightBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, + /// Marker component that indicates that its entity needs to be Synchronized to the render world + pub sync: SyncRenderWorld, } /// A component bundle for spot light entities @@ -119,6 +122,8 @@ pub struct SpotLightBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, + /// Marker component that indicates that its entity needs to be Synchronized to the render world + pub sync: SyncRenderWorld, } /// A component bundle for [`DirectionalLight`] entities. @@ -137,4 +142,6 @@ pub struct DirectionalLightBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, + /// Marker component that indicates that its entity needs to be Synchronized to the render world + pub sync: SyncRenderWorld, } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 58ea11b802025..a9ad395b31e4d 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -333,7 +333,7 @@ impl Plugin for PbrPlugin { VolumetricFogPlugin, ScreenSpaceReflectionsPlugin, )) - .add_plugins(WorldSyncPlugin::<(PointLight, SpotLight, DirectionalLight)>::default()) + .add_plugins(WorldSyncPlugin) .configure_sets( PostUpdate, ( diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 40922753108ba..8133ac3be4028 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -419,9 +419,9 @@ pub(crate) fn remove_light_view_entities( ) { if let Ok(entities) = query.get(trigger.entity()) { for e in entities.0.iter().copied() { - commands.get_entity(e).map(|v| { + if let Some(v) = commands.get_entity(e) { v.despawn(); - }); + } } } } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index c8c498b3235ab..a8f05495daad3 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -58,7 +58,6 @@ pub mod prelude { use batching::gpu_preprocessing::BatchingPlugin; use bevy_ecs::schedule::ScheduleBuildSettings; use bevy_utils::prelude::default; -use camera::Camera; pub use extract_param::Extract; use bevy_hierarchy::ValidParentCheckPlugin; @@ -67,7 +66,7 @@ use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; -use world_sync::{despawn_fly_entity, entity_sync_system, ToRenderWorld, WorldSyncPlugin}; +use world_sync::{despawn_fly_entity, entity_sync_system, SyncRenderWorld}; use crate::mesh::RenderMesh; use crate::renderer::WgpuWrapper; @@ -359,7 +358,6 @@ impl Plugin for RenderPlugin { GlobalsPlugin, MorphPlugin, BatchingPlugin, - WorldSyncPlugin::<(Camera, ToRenderWorld)>::default(), )); app.init_resource::() @@ -372,7 +370,7 @@ impl Plugin for RenderPlugin { .register_type::() .register_type::() .register_type::() - .register_type::(); + .register_type::(); } fn ready(&self, app: &App) -> bool { diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 49c7e02c80dc1..9766d8cd6724b 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -1,9 +1,6 @@ -use std::marker::PhantomData; - use bevy_app::Plugin; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - bundle::Bundle, component::Component, entity::Entity, observer::Trigger, @@ -16,9 +13,12 @@ use bevy_hierarchy::DespawnRecursiveExt; use bevy_reflect::Reflect; /// Marker component that indicates that its entity needs to be Synchronized to the render world +/// +/// NOTE: This component should persist throughout the entity's entire lifecycle. +/// If this component is removed from its entity, the entity will be despawned. #[derive(Component, Clone, Debug, Default, Reflect)] #[reflect[Component]] -pub struct ToRenderWorld; +pub struct SyncRenderWorld; #[derive(Component, Deref, Clone, Debug, Copy)] /// Marker component added on the main world entities that are synced to the Render World in order to keep track of the corresponding render world entity @@ -84,6 +84,7 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl }); } +// TODO: performance remove matched archetype pub(crate) fn despawn_fly_entity( world: &mut World, state: &mut SystemState>>, @@ -102,20 +103,18 @@ pub(crate) fn despawn_fly_entity( /// A Plugin that synchronizes entities with specific Components between the main world and render world. #[derive(Default)] -pub struct WorldSyncPlugin { - _marker: PhantomData, -} +pub struct WorldSyncPlugin; -impl Plugin for WorldSyncPlugin { +impl Plugin for WorldSyncPlugin { fn build(&self, app: &mut bevy_app::App) { app.init_resource::(); app.observe( - |trigger: Trigger, mut pending: ResMut| { + |trigger: Trigger, mut pending: ResMut| { pending.push(EntityRecord::Added(trigger.entity())); }, ); app.observe( - |trigger: Trigger, + |trigger: Trigger, mut pending: ResMut, query: Query<&RenderEntity>| { if let Ok(e) = query.get(trigger.entity()) { diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index a9a1736fa0132..e2e616f17cc41 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -6,6 +6,7 @@ use bevy_ecs::bundle::Bundle; use bevy_render::{ texture::Image, view::{InheritedVisibility, ViewVisibility, Visibility}, + world_sync::SyncRenderWorld, }; use bevy_transform::components::{GlobalTransform, Transform}; @@ -32,6 +33,8 @@ pub struct SpriteBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, + /// Marker component that indicates that its entity needs to be Synchronized to the render world + pub sync: SyncRenderWorld, } /// A [`Bundle`] of components for drawing a single sprite from a sprite sheet (also referred @@ -66,4 +69,6 @@ pub struct SpriteSheetBundle { pub inherited_visibility: InheritedVisibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub view_visibility: ViewVisibility, + /// Marker component that indicates that its entity needs to be Synchronized to the render world + pub sync: SyncRenderWorld, } diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index 51704493e1953..1278b73fdbde7 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -56,7 +56,6 @@ use bevy_render::{ render_resource::{Shader, SpecializedRenderPipelines}, texture::Image, view::{check_visibility, NoFrustumCulling, VisibilitySystems}, - world_sync::WorldSyncPlugin, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -118,7 +117,6 @@ impl Plugin for SpritePlugin { Mesh2dRenderPlugin, ColorMaterialPlugin, ExtractComponentPlugin::::default(), - WorldSyncPlugin::::default(), )) .add_systems( PostUpdate, diff --git a/examples/3d/fog_volumes.rs b/examples/3d/fog_volumes.rs index 2c0cb87882be9..68deb1246faf0 100644 --- a/examples/3d/fog_volumes.rs +++ b/examples/3d/fog_volumes.rs @@ -10,7 +10,7 @@ use bevy::{ pbr::{FogVolume, VolumetricFogSettings, VolumetricLight}, prelude::*, }; -use bevy_render::world_sync::ToRenderWorld; +use bevy_render::world_sync::SyncRenderWorld; /// Entry point. fn main() { @@ -46,7 +46,7 @@ fn setup(mut commands: Commands, asset_server: Res) { ..default() }) // indicates that this spatial needs to be Synchronized to the render world - .insert(ToRenderWorld); + .insert(SyncRenderWorld); // Spawn a bright directional light that illuminates the fog well. commands From 23a8bba3ff8b2cdfd99ca42bff39435cbd6372a1 Mon Sep 17 00:00:00 2001 From: re0312 Date: Wed, 28 Aug 2024 02:00:21 +0800 Subject: [PATCH 48/55] extract_component --- crates/bevy_render/src/extract_component.rs | 15 ++++++++++----- crates/bevy_render/src/world_sync.rs | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index ede665c7d1b86..b11c69b01590c 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -2,7 +2,7 @@ use crate::{ render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ViewVisibility, - world_sync::RenderEntity, + world_sync::{RenderEntity, SyncRenderWorld}, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_app::{App, Plugin}; @@ -206,11 +206,11 @@ impl ExtractComponent for Handle { } } -/// This system extracts all components of the corresponding [`ExtractComponent`] type. +/// This system extracts all synced entities components of the corresponding [`ExtractComponent`] type. fn extract_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract)>>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in &query { @@ -222,11 +222,16 @@ fn extract_components( commands.insert_or_spawn_batch(values); } -/// This system extracts all visible components of the corresponding [`ExtractComponent`] type. +/// This system extracts all synced visible entities components of the corresponding [`ExtractComponent`] type. fn extract_visible_components( mut commands: Commands, mut previous_len: Local, - query: Extract>, + query: Extract< + Query< + (&RenderEntity, &ViewVisibility, C::QueryData), + (C::QueryFilter, With), + >, + >, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, view_visibility, query_item) in &query { diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index 9766d8cd6724b..ed3d0d1ae6bf5 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -84,7 +84,7 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl }); } -// TODO: performance remove matched archetype +// TODO: directly remove matched archetype for performance pub(crate) fn despawn_fly_entity( world: &mut World, state: &mut SystemState>>, From 37944a84c3658bdedb31526db2936c11643e1fbd Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 29 Aug 2024 02:26:31 +0800 Subject: [PATCH 49/55] document and test --- crates/bevy_pbr/src/lib.rs | 1 - crates/bevy_render/src/lib.rs | 3 +- crates/bevy_render/src/world_sync.rs | 144 +++++++++++++++++++++++++-- 3 files changed, 137 insertions(+), 11 deletions(-) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index a9ad395b31e4d..8ee3a7024a9e1 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -333,7 +333,6 @@ impl Plugin for PbrPlugin { VolumetricFogPlugin, ScreenSpaceReflectionsPlugin, )) - .add_plugins(WorldSyncPlugin) .configure_sets( PostUpdate, ( diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index a8f05495daad3..4174d617e02c2 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -66,7 +66,7 @@ use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; -use world_sync::{despawn_fly_entity, entity_sync_system, SyncRenderWorld}; +use world_sync::{despawn_fly_entity, entity_sync_system, SyncRenderWorld, WorldSyncPlugin}; use crate::mesh::RenderMesh; use crate::renderer::WgpuWrapper; @@ -358,6 +358,7 @@ impl Plugin for RenderPlugin { GlobalsPlugin, MorphPlugin, BatchingPlugin, + WorldSyncPlugin, )); app.init_resource::() diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index ed3d0d1ae6bf5..e135194b61c55 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -11,13 +11,81 @@ use bevy_ecs::{ }; use bevy_hierarchy::DespawnRecursiveExt; use bevy_reflect::Reflect; +use bevy_utils::tracing::warn; +/// A Plugin that synchronizes entities with specific Components between the main world and render world. +/// +/// Bevy's renderer is architected independently from main app, It operates in its own separate ECS World. Therefore, the renderer could run in parrallel with main app logic, This is called "Pipelined Rendering". See [`PipelinedRenderingPlugin`] for more information. +/// +/// Previously, `extract` will copy the related main world entity and its data into the render world , and then render world will clear all render entities at the end of frame to reserve enough entity space to ensure that no main world entity ID has been occupied during next `extract`. +/// +/// With `* as entities`, we should not clear all entities in render world because some core metadata(e.g. [`Component`], [`Query`]`) are also stored in the form of entity. +/// +/// So we turn to an entity-to-entity mapping strategy to sync between main world entity and render world entity,where each `synchronized` main entity has a component [`RenderEntity`] that holds an Entity ID pointer to its unique counterpart entity in the render world. +/// +/// A example for `synchronized` main entity 1v1 and 18v1 +/// +/// ```text +/// |---------------------------Main World----------------------------| +/// | Entity | Component | +/// |-----------------------------------------------------------------| +/// | ID: 1v1 | PointLight | RenderEntity(ID: 3V1) | SyncRenderWorld | +/// | ID: 18v1 | PointLight | RenderEntity(ID: 5V1) | SyncRenderWorld | +/// |-----------------------------------------------------------------| +/// +/// |----------Render World-----------| +/// | Entity | Component | +/// |---------------------------------| +/// | ID: 3v1 | MainEntity(ID: 1V1) | +/// | ID: 5v1 | MainEntity(ID: 18V1) | +/// |---------------------------------| +/// +/// ``` +/// +/// To establish a "Synchronous Relationship", you can add a [`SyncRenderWorld`] component to an entity, indicating that it needs to be synchronized with the render world. +/// +/// Now a single frame of execution looks something like below +/// +/// ```text +/// |--------------------------------------------------------------------| +/// | | | Main world lopp | +/// | Sync | extract |---------------------------------------------------| +/// | | | Render wrold loop | +/// |--------------------------------------------------------------------| +/// ``` +/// +/// `Sync` is the step that syncs main entity behavior(add, remove) to its counterpart render entity. [`entity_sync_system`] +/// +/// [`PipelinedRenderingPlugin`]: crate::pipelined_rendering::PipelinedRenderingPlugin +#[derive(Default)] +pub struct WorldSyncPlugin; + +impl Plugin for WorldSyncPlugin { + fn build(&self, app: &mut bevy_app::App) { + app.init_resource::(); + app.observe( + |trigger: Trigger, mut pending: ResMut| { + pending.push(EntityRecord::Added(trigger.entity())); + }, + ); + app.observe( + |trigger: Trigger, + mut pending: ResMut, + query: Query<&RenderEntity>| { + if let Ok(e) = query.get(trigger.entity()) { + pending.push(EntityRecord::Removed(e.id())); + }; + }, + ); + } +} /// Marker component that indicates that its entity needs to be Synchronized to the render world /// /// NOTE: This component should persist throughout the entity's entire lifecycle. /// If this component is removed from its entity, the entity will be despawned. #[derive(Component, Clone, Debug, Default, Reflect)] #[reflect[Component]] +#[component(storage = "SparseSet")] pub struct SyncRenderWorld; #[derive(Component, Deref, Clone, Debug, Copy)] @@ -65,7 +133,9 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl EntityRecord::Added(e) => { if let Some(mut entity) = world.get_entity_mut(e) { match entity.entry::() { - bevy_ecs::world::Entry::Occupied(_) => {} + bevy_ecs::world::Entry::Occupied(_) => { + warn!("Attempting to synchronize an entity that has already been synchronized!"); + } bevy_ecs::world::Entry::Vacant(entry) => { let id = render_world.spawn(MainEntity(e)).id(); @@ -101,19 +171,37 @@ pub(crate) fn despawn_fly_entity( } } -/// A Plugin that synchronizes entities with specific Components between the main world and render world. -#[derive(Default)] -pub struct WorldSyncPlugin; +#[cfg(test)] +mod tests { + use bevy_ecs::{ + component::Component, + entity::Entity, + observer::Trigger, + query::With, + system::{Query, ResMut}, + world::{OnAdd, OnRemove, World}, + }; -impl Plugin for WorldSyncPlugin { - fn build(&self, app: &mut bevy_app::App) { - app.init_resource::(); - app.observe( + use super::{ + entity_sync_system, EntityRecord, MainEntity, PendingSyncEntity, RenderEntity, + SyncRenderWorld, + }; + + #[derive(Component)] + struct RenderDataComponent; + + #[test] + fn world_sync() { + let mut main_world = World::new(); + let mut render_world = World::new(); + main_world.init_resource::(); + + main_world.observe( |trigger: Trigger, mut pending: ResMut| { pending.push(EntityRecord::Added(trigger.entity())); }, ); - app.observe( + main_world.observe( |trigger: Trigger, mut pending: ResMut, query: Query<&RenderEntity>| { @@ -122,5 +210,43 @@ impl Plugin for WorldSyncPlugin { }; }, ); + + // spawn some empty entities for test + for _ in 0..99 { + main_world.spawn_empty(); + } + + // spawn + let main_entity = main_world + .spawn(RenderDataComponent) + // indicates that its entity needs to be Synchronized to the render world + .insert(SyncRenderWorld) + .id(); + + entity_sync_system(&mut main_world, &mut render_world); + + let mut q = render_world.query_filtered::>(); + + // Only one synchronized entity + assert!(q.iter(&render_world).count() == 1); + + let render_entity = q.get_single(&render_world).unwrap(); + let render_entity_component = main_world.get::(main_entity).unwrap(); + + assert!(render_entity_component.id() == render_entity); + + let main_entity_component = render_world + .get::(render_entity_component.id()) + .unwrap(); + + assert!(main_entity_component.id() == main_entity); + + // despawn + main_world.despawn(main_entity); + + entity_sync_system(&mut main_world, &mut render_world); + + // Only one synchronized entity + assert!(q.iter(&render_world).count() == 0); } } From 1e8601f4d8a33132bc64fd9345e5699703d45096 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 29 Aug 2024 03:09:55 +0800 Subject: [PATCH 50/55] fix --- crates/bevy_pbr/src/lib.rs | 1 - crates/bevy_render/src/world_sync.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 8ee3a7024a9e1..2dda2aedb18e1 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -118,7 +118,6 @@ use bevy_render::{ render_resource::Shader, texture::{GpuImage, Image}, view::{check_visibility, VisibilitySystems}, - world_sync::WorldSyncPlugin, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::TransformSystem; diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index e135194b61c55..c031b14e2ad67 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -19,7 +19,7 @@ use bevy_utils::tracing::warn; /// /// Previously, `extract` will copy the related main world entity and its data into the render world , and then render world will clear all render entities at the end of frame to reserve enough entity space to ensure that no main world entity ID has been occupied during next `extract`. /// -/// With `* as entities`, we should not clear all entities in render world because some core metadata(e.g. [`Component`], [`Query`]`) are also stored in the form of entity. +/// With `* as entities`, we should not clear all entities in render world because some core metadata (e.g. [`Component`], [`Query`]) are also stored in the form of entity. /// /// So we turn to an entity-to-entity mapping strategy to sync between main world entity and render world entity,where each `synchronized` main entity has a component [`RenderEntity`] that holds an Entity ID pointer to its unique counterpart entity in the render world. /// @@ -54,7 +54,7 @@ use bevy_utils::tracing::warn; /// |--------------------------------------------------------------------| /// ``` /// -/// `Sync` is the step that syncs main entity behavior(add, remove) to its counterpart render entity. [`entity_sync_system`] +/// `Sync` is the step that syncs main entity behavior(add, remove) to its counterpart render entity. /// /// [`PipelinedRenderingPlugin`]: crate::pipelined_rendering::PipelinedRenderingPlugin #[derive(Default)] From 7167cc07a6f0ff28f9698bcf7dbbb2c83af1e962 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 29 Aug 2024 03:20:54 +0800 Subject: [PATCH 51/55] typo --- crates/bevy_render/src/world_sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index c031b14e2ad67..d166251cfc68b 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -15,7 +15,7 @@ use bevy_utils::tracing::warn; /// A Plugin that synchronizes entities with specific Components between the main world and render world. /// -/// Bevy's renderer is architected independently from main app, It operates in its own separate ECS World. Therefore, the renderer could run in parrallel with main app logic, This is called "Pipelined Rendering". See [`PipelinedRenderingPlugin`] for more information. +/// Bevy's renderer is architected independently from main app, It operates in its own separate ECS World. Therefore, the renderer could run in parallel with main app logic, This is called "Pipelined Rendering". See [`PipelinedRenderingPlugin`] for more information. /// /// Previously, `extract` will copy the related main world entity and its data into the render world , and then render world will clear all render entities at the end of frame to reserve enough entity space to ensure that no main world entity ID has been occupied during next `extract`. /// From bfad1de73d4b6fc4ea140ce46d16deecf8e78ae3 Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 29 Aug 2024 03:30:10 +0800 Subject: [PATCH 52/55] cleanup --- crates/bevy_render/src/extract_component.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/bevy_render/src/extract_component.rs b/crates/bevy_render/src/extract_component.rs index b11c69b01590c..e8c11bf75a20f 100644 --- a/crates/bevy_render/src/extract_component.rs +++ b/crates/bevy_render/src/extract_component.rs @@ -2,7 +2,7 @@ use crate::{ render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType}, renderer::{RenderDevice, RenderQueue}, view::ViewVisibility, - world_sync::{RenderEntity, SyncRenderWorld}, + world_sync::RenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_app::{App, Plugin}; @@ -210,7 +210,7 @@ impl ExtractComponent for Handle { fn extract_components( mut commands: Commands, mut previous_len: Local, - query: Extract)>>, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, query_item) in &query { @@ -226,12 +226,7 @@ fn extract_components( fn extract_visible_components( mut commands: Commands, mut previous_len: Local, - query: Extract< - Query< - (&RenderEntity, &ViewVisibility, C::QueryData), - (C::QueryFilter, With), - >, - >, + query: Extract>, ) { let mut values = Vec::with_capacity(*previous_len); for (entity, view_visibility, query_item) in &query { From 8d2c81a1a887f6786fec944f7b9099e2259351fa Mon Sep 17 00:00:00 2001 From: re0312 Date: Thu, 29 Aug 2024 03:58:05 +0800 Subject: [PATCH 53/55] rename --- crates/bevy_gizmos/src/lib.rs | 4 ++-- crates/bevy_render/src/lib.rs | 6 ++++-- crates/bevy_render/src/world_sync.rs | 14 +++++++------- crates/bevy_sprite/src/render/mod.rs | 4 ++-- crates/bevy_ui/src/render/mod.rs | 16 ++++++++-------- .../bevy_ui/src/render/ui_material_pipeline.rs | 4 ++-- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 29ebeb3d8375d..0d80e74b25816 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -105,7 +105,7 @@ use bevy_render::{ ShaderType, VertexFormat, }, renderer::RenderDevice, - world_sync::RenderFlyEntity, + world_sync::TemporaryRenderEntity, Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; @@ -453,7 +453,7 @@ fn extract_gizmo_data( (*handle).clone_weak(), #[cfg(any(feature = "bevy_pbr", feature = "bevy_sprite"))] config::GizmoMeshConfig::from(config), - RenderFlyEntity, + TemporaryRenderEntity, )); } } diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 4174d617e02c2..c26610aae5613 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -66,7 +66,9 @@ use extract_resource::ExtractResourcePlugin; use globals::GlobalsPlugin; use render_asset::RenderAssetBytesPerFrame; use renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue}; -use world_sync::{despawn_fly_entity, entity_sync_system, SyncRenderWorld, WorldSyncPlugin}; +use world_sync::{ + despawn_temporary_render_entity, entity_sync_system, SyncRenderWorld, WorldSyncPlugin, +}; use crate::mesh::RenderMesh; use crate::renderer::WgpuWrapper; @@ -477,7 +479,7 @@ unsafe fn initialize_render_app(app: &mut App) { render_system, ) .in_set(RenderSet::Render), - despawn_fly_entity.in_set(RenderSet::PostCleanup), + despawn_temporary_render_entity.in_set(RenderSet::PostCleanup), ), ); diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index d166251cfc68b..f2bc142cd6369 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -21,7 +21,7 @@ use bevy_utils::tracing::warn; /// /// With `* as entities`, we should not clear all entities in render world because some core metadata (e.g. [`Component`], [`Query`]) are also stored in the form of entity. /// -/// So we turn to an entity-to-entity mapping strategy to sync between main world entity and render world entity,where each `synchronized` main entity has a component [`RenderEntity`] that holds an Entity ID pointer to its unique counterpart entity in the render world. +/// So we turn to an entity-to-entity mapping strategy to sync between main world entity and render world entity, where each `synchronized` main entity has a [`RenderEntity`] component holds an Entity ID pointer to its unique counterpart entity in the render world. /// /// A example for `synchronized` main entity 1v1 and 18v1 /// @@ -42,19 +42,18 @@ use bevy_utils::tracing::warn; /// /// ``` /// -/// To establish a "Synchronous Relationship", you can add a [`SyncRenderWorld`] component to an entity, indicating that it needs to be synchronized with the render world. +/// To establish a "Synchronous Relationship", you can add a [`SyncRenderWorld`] component to an entity. Once a `synchronized` main entity is despawned ,its corresponding render entity will be automatically purged in the next `Sync` /// /// Now a single frame of execution looks something like below /// /// ```text /// |--------------------------------------------------------------------| -/// | | | Main world lopp | +/// | | | Main world loop | /// | Sync | extract |---------------------------------------------------| /// | | | Render wrold loop | /// |--------------------------------------------------------------------| /// ``` /// -/// `Sync` is the step that syncs main entity behavior(add, remove) to its counterpart render entity. /// /// [`PipelinedRenderingPlugin`]: crate::pipelined_rendering::PipelinedRenderingPlugin #[derive(Default)] @@ -110,7 +109,8 @@ impl MainEntity { // marker component that indicates that its entity needs to be despawned at the end of every frame. #[derive(Component, Clone, Debug, Default, Reflect)] -pub struct RenderFlyEntity; +#[component(storage = "SparseSet")] +pub struct TemporaryRenderEntity; pub(crate) enum EntityRecord { // When an entity is spawned on the main world, notify the render world so that it can spawn a corresponding entity. This contains the main world entity @@ -155,9 +155,9 @@ pub(crate) fn entity_sync_system(main_world: &mut World, render_world: &mut Worl } // TODO: directly remove matched archetype for performance -pub(crate) fn despawn_fly_entity( +pub(crate) fn despawn_temporary_render_entity( world: &mut World, - state: &mut SystemState>>, + state: &mut SystemState>>, mut local: Local>, ) { let query = state.get(world); diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index a4943eddfa843..3fdde8a291ab2 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -38,7 +38,7 @@ use bevy_render::{ ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms, ViewVisibility, VisibleEntities, }, - world_sync::{RenderEntity, RenderFlyEntity}, + world_sync::{RenderEntity, TemporaryRenderEntity}, Extract, }; use bevy_transform::components::GlobalTransform; @@ -394,7 +394,7 @@ pub fn extract_sprites( extracted_sprites.sprites.extend( slices .extract_sprites(transform, original_entity, sprite, handle) - .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), + .map(|e| (commands.spawn(TemporaryRenderEntity).id(), e)), ); } else { let atlas_rect = diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 61b4f49cb72ce..5d33e614603dc 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -10,7 +10,7 @@ use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; use bevy_hierarchy::Parent; use bevy_render::render_phase::ViewSortedRenderPhases; use bevy_render::texture::TRANSPARENT_IMAGE_HANDLE; -use bevy_render::world_sync::{RenderEntity, RenderFlyEntity}; +use bevy_render::world_sync::{RenderEntity, TemporaryRenderEntity}; use bevy_render::{ render_phase::{PhaseItem, PhaseItemExtraIndex}, texture::GpuImage, @@ -272,7 +272,7 @@ pub fn extract_uinode_background_colors( }; extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn(TemporaryRenderEntity).id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -365,7 +365,7 @@ pub fn extract_uinode_images( extracted_uinodes.uinodes.extend( slices .extract_ui_nodes(transform, uinode, image, clip, camera_entity.id()) - .map(|e| (commands.spawn(RenderFlyEntity).id(), e)), + .map(|e| (commands.spawn(TemporaryRenderEntity).id(), e)), ); continue; } @@ -420,7 +420,7 @@ pub fn extract_uinode_images( }; extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn(TemporaryRenderEntity).id(), ExtractedUiNode { stack_index: uinode.stack_index, transform: transform.compute_matrix(), @@ -600,7 +600,7 @@ pub fn extract_uinode_borders( let transform = global_transform.compute_matrix(); extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn(TemporaryRenderEntity).id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -696,7 +696,7 @@ pub fn extract_uinode_outlines( for edge in outline_edges { if edge.min.x < edge.max.x && edge.min.y < edge.max.y { extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn(TemporaryRenderEntity).id(), ExtractedUiNode { stack_index: node.stack_index, // This translates the uinode's transform to the center of the current border rectangle @@ -795,7 +795,7 @@ pub fn extract_default_ui_camera_view( ), color_grading: Default::default(), }, - RenderFlyEntity, + TemporaryRenderEntity, )) .id(); commands @@ -890,7 +890,7 @@ pub fn extract_uinode_text( let mut rect = atlas.textures[atlas_info.location.glyph_index].as_rect(); rect.min *= inverse_scale_factor; rect.max *= inverse_scale_factor; - let id = commands.spawn(RenderFlyEntity).id(); + let id = commands.spawn(TemporaryRenderEntity).id(); extracted_uinodes.uinodes.insert( id, ExtractedUiNode { diff --git a/crates/bevy_ui/src/render/ui_material_pipeline.rs b/crates/bevy_ui/src/render/ui_material_pipeline.rs index 1bcec1290d268..6e16e59fc7002 100644 --- a/crates/bevy_ui/src/render/ui_material_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_material_pipeline.rs @@ -18,7 +18,7 @@ use bevy_render::{ renderer::{RenderDevice, RenderQueue}, texture::BevyDefault, view::*, - world_sync::{RenderEntity, RenderFlyEntity}, + world_sync::{RenderEntity, TemporaryRenderEntity}, Extract, ExtractSchedule, Render, RenderSet, }; use bevy_transform::prelude::GlobalTransform; @@ -432,7 +432,7 @@ pub fn extract_ui_material_nodes( ) / uinode.size().y; extracted_uinodes.uinodes.insert( - commands.spawn(RenderFlyEntity).id(), + commands.spawn(TemporaryRenderEntity).id(), ExtractedUiMaterialNode { stack_index, transform: transform.compute_matrix(), From d857e6ef983452c9669eb368e80a6486b434ddfa Mon Sep 17 00:00:00 2001 From: re0312 <45868716+re0312@users.noreply.github.com> Date: Sun, 1 Sep 2024 03:40:47 +0800 Subject: [PATCH 54/55] Apply suggestions from code review Co-authored-by: Trashtalk217 Co-authored-by: Anselmo Sampietro --- crates/bevy_render/src/world_sync.rs | 8 ++++---- examples/3d/fog_volumes.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index f2bc142cd6369..e2861ba6c1c8e 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -15,15 +15,15 @@ use bevy_utils::tracing::warn; /// A Plugin that synchronizes entities with specific Components between the main world and render world. /// -/// Bevy's renderer is architected independently from main app, It operates in its own separate ECS World. Therefore, the renderer could run in parallel with main app logic, This is called "Pipelined Rendering". See [`PipelinedRenderingPlugin`] for more information. +/// Bevy's renderer is architected independently from the main app. It operates in its own separate ECS World, so the renderer could run in parallel with the main app logic. This is called "Pipelined Rendering", see [`PipelinedRenderingPlugin`] for more information. /// /// Previously, `extract` will copy the related main world entity and its data into the render world , and then render world will clear all render entities at the end of frame to reserve enough entity space to ensure that no main world entity ID has been occupied during next `extract`. /// /// With `* as entities`, we should not clear all entities in render world because some core metadata (e.g. [`Component`], [`Query`]) are also stored in the form of entity. /// -/// So we turn to an entity-to-entity mapping strategy to sync between main world entity and render world entity, where each `synchronized` main entity has a [`RenderEntity`] component holds an Entity ID pointer to its unique counterpart entity in the render world. +/// [`WorldSyncPlugin`] maintains an entity-to-entity mapping to sync a main world entity and a render world entity. Each synchronized main entity has a [`RenderEntity`] component that holds an Entity pointer to its unique counterpart entity in the render world. /// -/// A example for `synchronized` main entity 1v1 and 18v1 +/// An example for synchronized main entities 1v1 and 18v1 /// /// ```text /// |---------------------------Main World----------------------------| @@ -42,7 +42,7 @@ use bevy_utils::tracing::warn; /// /// ``` /// -/// To establish a "Synchronous Relationship", you can add a [`SyncRenderWorld`] component to an entity. Once a `synchronized` main entity is despawned ,its corresponding render entity will be automatically purged in the next `Sync` +/// To establish a "Synchronous Relationship", you can add a [`SyncRenderWorld`] component to an entity. Once a synchronized main entity is despawned, its corresponding render entity will be automatically purged in the next `Sync` /// /// Now a single frame of execution looks something like below /// diff --git a/examples/3d/fog_volumes.rs b/examples/3d/fog_volumes.rs index 68deb1246faf0..cdc832521df84 100644 --- a/examples/3d/fog_volumes.rs +++ b/examples/3d/fog_volumes.rs @@ -45,7 +45,7 @@ fn setup(mut commands: Commands, asset_server: Res) { scattering: 1.0, ..default() }) - // indicates that this spatial needs to be Synchronized to the render world + // indicates that this fog volume needs to be Synchronized to the render world .insert(SyncRenderWorld); // Spawn a bright directional light that illuminates the fog well. From 9c1a523c036390d41655e04aeb6f9d412e86c4b5 Mon Sep 17 00:00:00 2001 From: Trashtalk Date: Tue, 3 Sep 2024 17:29:00 +0200 Subject: [PATCH 55/55] Cleared up some documentation --- crates/bevy_render/src/pipelined_rendering.rs | 14 ++++--- crates/bevy_render/src/world_sync.rs | 41 +++++++++++-------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/crates/bevy_render/src/pipelined_rendering.rs b/crates/bevy_render/src/pipelined_rendering.rs index b0db0398965f6..d9d130511f3fb 100644 --- a/crates/bevy_render/src/pipelined_rendering.rs +++ b/crates/bevy_render/src/pipelined_rendering.rs @@ -83,13 +83,15 @@ impl Drop for RenderAppChannels { /// A single frame of execution looks something like below /// /// ```text -/// |--------------------------------------------------------------------| -/// | | RenderExtractApp schedule | winit events | main schedule | -/// | extract |----------------------------------------------------------| -/// | | extract commands | rendering schedule | -/// |--------------------------------------------------------------------| +/// |---------------------------------------------------------------------------| +/// | | | RenderExtractApp schedule | winit events | main schedule | +/// | sync | extract |----------------------------------------------------------| +/// | | | extract commands | rendering schedule | +/// |---------------------------------------------------------------------------| /// ``` /// +/// - `sync` is the step where the entity-entity mapping between the main and render world is updated. +/// This is run on the main app's thread, for more information checkout [`WorldSyncPlugin`]. /// - `extract` is the step where data is copied from the main world to the render world. /// This is run on the main app's thread. /// - On the render thread, we first apply the `extract commands`. This is not run during extract, so the @@ -100,6 +102,8 @@ impl Drop for RenderAppChannels { /// - Next all the `winit events` are processed. /// - And finally the `main app schedule` is run. /// - Once both the `main app schedule` and the `render schedule` are finished running, `extract` is run again. +/// +/// [`WorldSyncPlugin`]: crate::world_sync::WorldSyncPlugin #[derive(Default)] pub struct PipelinedRenderingPlugin; diff --git a/crates/bevy_render/src/world_sync.rs b/crates/bevy_render/src/world_sync.rs index e2861ba6c1c8e..c4cd3a1895d37 100644 --- a/crates/bevy_render/src/world_sync.rs +++ b/crates/bevy_render/src/world_sync.rs @@ -13,15 +13,23 @@ use bevy_hierarchy::DespawnRecursiveExt; use bevy_reflect::Reflect; use bevy_utils::tracing::warn; -/// A Plugin that synchronizes entities with specific Components between the main world and render world. +/// A Plugin that synchronizes entities with specific Components between the main world and the render world. /// -/// Bevy's renderer is architected independently from the main app. It operates in its own separate ECS World, so the renderer could run in parallel with the main app logic. This is called "Pipelined Rendering", see [`PipelinedRenderingPlugin`] for more information. +/// Bevy's renderer is architected independently from the main app. +/// It operates in its own separate ECS World, so the renderer could run in parallel with the main world logic. +/// This is called "Pipelined Rendering", see [`PipelinedRenderingPlugin`] for more information. /// -/// Previously, `extract` will copy the related main world entity and its data into the render world , and then render world will clear all render entities at the end of frame to reserve enough entity space to ensure that no main world entity ID has been occupied during next `extract`. +/// [`WorldSyncPlugin`] is the first thing that runs every frame and it maintains an entity-to-entity mapping +/// between the main world and the render world. +/// This is necessary for extraction, which copies over component data from the main to the render world. /// -/// With `* as entities`, we should not clear all entities in render world because some core metadata (e.g. [`Component`], [`Query`]) are also stored in the form of entity. -/// -/// [`WorldSyncPlugin`] maintains an entity-to-entity mapping to sync a main world entity and a render world entity. Each synchronized main entity has a [`RenderEntity`] component that holds an Entity pointer to its unique counterpart entity in the render world. +/// ```text +/// |--------------------------------------------------------------------| +/// | | | Main world loop | +/// | sync | extract |---------------------------------------------------| +/// | | | Render world loop | +//are/ |--------------------------------------------------------------------| +/// ``` /// /// An example for synchronized main entities 1v1 and 18v1 /// @@ -42,18 +50,19 @@ use bevy_utils::tracing::warn; /// /// ``` /// -/// To establish a "Synchronous Relationship", you can add a [`SyncRenderWorld`] component to an entity. Once a synchronized main entity is despawned, its corresponding render entity will be automatically purged in the next `Sync` -/// -/// Now a single frame of execution looks something like below +/// Note that not this effectively establishes a link between the main world entity and the render world entity. +/// Not every entity needs to be synchronized, however, only entities with [`SyncRenderWorld`] are synced. +/// Adding [`SyncRenderWorld`] to a main world component will establish such a link. +/// Once a synchronized main entity is despawned, it's corresponding render entity will be automatically +/// despawned in the next `sync`. /// -/// ```text -/// |--------------------------------------------------------------------| -/// | | | Main world loop | -/// | Sync | extract |---------------------------------------------------| -/// | | | Render wrold loop | -/// |--------------------------------------------------------------------| -/// ``` +/// The sync step does not handle the transfer of component data between worlds, +/// since it's often not necessary to transfer over all the components of a main world entity. +/// The render world probably cares about a `Position` component, but not a `Velocity` component. +/// The extraction happens in it's own step, independently from synchronization. /// +/// Moreover, [`WorldSyncPlugin`] only synchronizes *entities*, stuff like mesh and texture data is handled +/// differently, as those assets are extracted to render world resources and not entities. /// /// [`PipelinedRenderingPlugin`]: crate::pipelined_rendering::PipelinedRenderingPlugin #[derive(Default)]