Frustum Culling (for Sprites) (#1492)
This PR adds two systems to the sprite module that culls Sprites and AtlasSprites that are not within the camera's view. This is achieved by removing / adding a new `Viewable` Component dynamically. Some of the render queries now use a `With<Viewable>` filter to only process the sprites that are actually on screen, which improves performance drastically for scene swith a large amount of sprites off-screen. https://streamable.com/vvzh2u This scene shows a map with a 320x320 tiles, with a grid size of 64p. This is exactly 102400 Sprites in the entire scene. Without this PR, this scene runs with 1 to 4 FPS. With this PR.. .. at 720p, there are around 600 visible sprites and runs at ~215 FPS .. at 1440p there are around 2000 visible sprites and runs at ~135 FPS The Systems this PR adds take around 1.2ms (with 100K+ sprites in the scene) Note: This is only implemented for Sprites and AtlasTextureSprites. There is no culling for 3D in this PR. Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
		
							parent
							
								
									d3e020a1e7
								
							
						
					
					
						commit
						b65ec82d46
					
				@ -9,6 +9,7 @@ use bevy_utils::HashMap;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct ActiveCamera {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub entity: Option<Entity>,
 | 
			
		||||
    pub bindings: RenderResourceBindings,
 | 
			
		||||
}
 | 
			
		||||
@ -20,8 +21,13 @@ pub struct ActiveCameras {
 | 
			
		||||
 | 
			
		||||
impl ActiveCameras {
 | 
			
		||||
    pub fn add(&mut self, name: &str) {
 | 
			
		||||
        self.cameras
 | 
			
		||||
            .insert(name.to_string(), ActiveCamera::default());
 | 
			
		||||
        self.cameras.insert(
 | 
			
		||||
            name.to_string(),
 | 
			
		||||
            ActiveCamera {
 | 
			
		||||
                name: name.to_string(),
 | 
			
		||||
                ..Default::default()
 | 
			
		||||
            },
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get(&self, name: &str) -> Option<&ActiveCamera> {
 | 
			
		||||
@ -31,6 +37,14 @@ impl ActiveCameras {
 | 
			
		||||
    pub fn get_mut(&mut self, name: &str) -> Option<&mut ActiveCamera> {
 | 
			
		||||
        self.cameras.get_mut(name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn iter(&self) -> impl Iterator<Item = &ActiveCamera> {
 | 
			
		||||
        self.cameras.values()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ActiveCamera> {
 | 
			
		||||
        self.cameras.values_mut()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn active_cameras_system(
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
use super::{Camera, DepthCalculation};
 | 
			
		||||
use crate::prelude::Visible;
 | 
			
		||||
use crate::{draw::OutsideFrustum, prelude::Visible};
 | 
			
		||||
use bevy_core::FloatOrd;
 | 
			
		||||
use bevy_ecs::{entity::Entity, query::With, reflect::ReflectComponent, system::Query};
 | 
			
		||||
use bevy_ecs::{entity::Entity, query::Without, reflect::ReflectComponent, system::Query};
 | 
			
		||||
use bevy_reflect::Reflect;
 | 
			
		||||
use bevy_transform::prelude::GlobalTransform;
 | 
			
		||||
 | 
			
		||||
@ -204,8 +204,8 @@ pub fn visible_entities_system(
 | 
			
		||||
        &mut VisibleEntities,
 | 
			
		||||
        Option<&RenderLayers>,
 | 
			
		||||
    )>,
 | 
			
		||||
    visible_query: Query<(Entity, &Visible, Option<&RenderLayers>)>,
 | 
			
		||||
    visible_transform_query: Query<&GlobalTransform, With<Visible>>,
 | 
			
		||||
    visible_query: Query<(Entity, &Visible, Option<&RenderLayers>), Without<OutsideFrustum>>,
 | 
			
		||||
    visible_transform_query: Query<&GlobalTransform, Without<OutsideFrustum>>,
 | 
			
		||||
) {
 | 
			
		||||
    for (camera, camera_global_transform, mut visible_entities, maybe_camera_mask) in
 | 
			
		||||
        camera_query.iter_mut()
 | 
			
		||||
 | 
			
		||||
@ -66,6 +66,17 @@ impl Default for Visible {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A component that indicates that an entity is outside the view frustum.
 | 
			
		||||
/// Any entity with this component will be ignored during rendering.
 | 
			
		||||
///
 | 
			
		||||
/// # Note
 | 
			
		||||
/// This does not handle multiple "views" properly as it is a "global" filter.
 | 
			
		||||
/// This will be resolved in the future. For now, disable frustum culling if you
 | 
			
		||||
/// need to support multiple views (ex: set the `SpriteSettings::frustum_culling_enabled` resource).
 | 
			
		||||
#[derive(Debug, Default, Clone, Reflect)]
 | 
			
		||||
#[reflect(Component)]
 | 
			
		||||
pub struct OutsideFrustum;
 | 
			
		||||
 | 
			
		||||
/// A component that indicates how to draw an entity.
 | 
			
		||||
#[derive(Debug, Clone, Reflect)]
 | 
			
		||||
#[reflect(Component)]
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,8 @@ use bevy_ecs::{
 | 
			
		||||
    system::{IntoExclusiveSystem, IntoSystem},
 | 
			
		||||
};
 | 
			
		||||
use bevy_transform::TransformSystem;
 | 
			
		||||
use draw::Visible;
 | 
			
		||||
use draw::{OutsideFrustum, Visible};
 | 
			
		||||
 | 
			
		||||
pub use once_cell;
 | 
			
		||||
 | 
			
		||||
pub mod prelude {
 | 
			
		||||
@ -137,6 +138,7 @@ impl Plugin for RenderPlugin {
 | 
			
		||||
        .register_type::<DepthCalculation>()
 | 
			
		||||
        .register_type::<Draw>()
 | 
			
		||||
        .register_type::<Visible>()
 | 
			
		||||
        .register_type::<OutsideFrustum>()
 | 
			
		||||
        .register_type::<RenderPipelines>()
 | 
			
		||||
        .register_type::<OrthographicProjection>()
 | 
			
		||||
        .register_type::<PerspectiveProjection>()
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,13 @@
 | 
			
		||||
use super::{PipelineDescriptor, PipelineSpecialization};
 | 
			
		||||
use crate::{
 | 
			
		||||
    draw::{Draw, DrawContext},
 | 
			
		||||
    draw::{Draw, DrawContext, OutsideFrustum},
 | 
			
		||||
    mesh::{Indices, Mesh},
 | 
			
		||||
    prelude::{Msaa, Visible},
 | 
			
		||||
    renderer::RenderResourceBindings,
 | 
			
		||||
};
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use bevy_ecs::{
 | 
			
		||||
    query::Without,
 | 
			
		||||
    reflect::ReflectComponent,
 | 
			
		||||
    system::{Query, Res, ResMut},
 | 
			
		||||
};
 | 
			
		||||
@ -86,7 +87,10 @@ pub fn draw_render_pipelines_system(
 | 
			
		||||
    mut render_resource_bindings: ResMut<RenderResourceBindings>,
 | 
			
		||||
    msaa: Res<Msaa>,
 | 
			
		||||
    meshes: Res<Assets<Mesh>>,
 | 
			
		||||
    mut query: Query<(&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible)>,
 | 
			
		||||
    mut query: Query<
 | 
			
		||||
        (&mut Draw, &mut RenderPipelines, &Handle<Mesh>, &Visible),
 | 
			
		||||
        Without<OutsideFrustum>,
 | 
			
		||||
    >,
 | 
			
		||||
) {
 | 
			
		||||
    for (mut draw, mut render_pipelines, mesh_handle, visible) in query.iter_mut() {
 | 
			
		||||
        if !visible.is_visible {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,11 @@
 | 
			
		||||
use bevy_asset::{Asset, Assets, Handle};
 | 
			
		||||
 | 
			
		||||
use crate::{pipeline::RenderPipelines, Texture};
 | 
			
		||||
use crate::{draw::OutsideFrustum, pipeline::RenderPipelines, Texture};
 | 
			
		||||
pub use bevy_derive::ShaderDefs;
 | 
			
		||||
use bevy_ecs::system::{Query, Res};
 | 
			
		||||
use bevy_ecs::{
 | 
			
		||||
    query::Without,
 | 
			
		||||
    system::{Query, Res},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Something that can either be "defined" or "not defined". This is used to determine if a "shader
 | 
			
		||||
/// def" should be considered "defined"
 | 
			
		||||
@ -61,7 +64,7 @@ impl ShaderDef for Option<Handle<Texture>> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Updates [RenderPipelines] with the latest [ShaderDefs]
 | 
			
		||||
pub fn shader_defs_system<T>(mut query: Query<(&T, &mut RenderPipelines)>)
 | 
			
		||||
pub fn shader_defs_system<T>(mut query: Query<(&T, &mut RenderPipelines), Without<OutsideFrustum>>)
 | 
			
		||||
where
 | 
			
		||||
    T: ShaderDefs + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
@ -94,7 +97,7 @@ pub fn clear_shader_defs_system(mut query: Query<&mut RenderPipelines>) {
 | 
			
		||||
/// Updates [RenderPipelines] with the latest [ShaderDefs] from a given asset type
 | 
			
		||||
pub fn asset_shader_defs_system<T: Asset>(
 | 
			
		||||
    assets: Res<Assets<T>>,
 | 
			
		||||
    mut query: Query<(&Handle<T>, &mut RenderPipelines)>,
 | 
			
		||||
    mut query: Query<(&Handle<T>, &mut RenderPipelines), Without<OutsideFrustum>>,
 | 
			
		||||
) where
 | 
			
		||||
    T: ShaderDefs + Send + Sync + 'static,
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.4.0", features = ["bevy"
 | 
			
		||||
bevy_render = { path = "../bevy_render", version = "0.4.0" }
 | 
			
		||||
bevy_transform = { path = "../bevy_transform", version = "0.4.0" }
 | 
			
		||||
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
 | 
			
		||||
bevy_window = { path = "../bevy_window", version = "0.4.0" }
 | 
			
		||||
 | 
			
		||||
# other
 | 
			
		||||
rectangle-pack = "0.3"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										120
									
								
								crates/bevy_sprite/src/frustum_culling.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								crates/bevy_sprite/src/frustum_culling.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use bevy_ecs::prelude::{Commands, Entity, Query, Res, With};
 | 
			
		||||
use bevy_math::Vec2;
 | 
			
		||||
use bevy_render::{
 | 
			
		||||
    camera::{ActiveCameras, Camera},
 | 
			
		||||
    draw::OutsideFrustum,
 | 
			
		||||
};
 | 
			
		||||
use bevy_transform::components::Transform;
 | 
			
		||||
use bevy_window::Windows;
 | 
			
		||||
 | 
			
		||||
use crate::{Sprite, TextureAtlas, TextureAtlasSprite};
 | 
			
		||||
 | 
			
		||||
struct Rect {
 | 
			
		||||
    position: Vec2,
 | 
			
		||||
    size: Vec2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Rect {
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn is_intersecting(&self, other: Rect) -> bool {
 | 
			
		||||
        self.position.distance(other.position) < (self.get_radius() + other.get_radius())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn get_radius(&self) -> f32 {
 | 
			
		||||
        let half_size = self.size / Vec2::splat(2.0);
 | 
			
		||||
        (half_size.x.powf(2.0) + half_size.y.powf(2.0)).sqrt()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn sprite_frustum_culling_system(
 | 
			
		||||
    mut commands: Commands,
 | 
			
		||||
    windows: Res<Windows>,
 | 
			
		||||
    active_cameras: Res<ActiveCameras>,
 | 
			
		||||
    camera_transforms: Query<&Transform, With<Camera>>,
 | 
			
		||||
    culled_sprites: Query<&OutsideFrustum, With<Sprite>>,
 | 
			
		||||
    sprites: Query<(Entity, &Transform, &Sprite)>,
 | 
			
		||||
) {
 | 
			
		||||
    let window_size = if let Some(window) = windows.get_primary() {
 | 
			
		||||
        Vec2::new(window.width(), window.height())
 | 
			
		||||
    } else {
 | 
			
		||||
        return;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for active_camera_entity in active_cameras.iter().filter_map(|a| a.entity) {
 | 
			
		||||
        if let Ok(camera_transform) = camera_transforms.get(active_camera_entity) {
 | 
			
		||||
            let camera_size = window_size * camera_transform.scale.truncate();
 | 
			
		||||
 | 
			
		||||
            let rect = Rect {
 | 
			
		||||
                position: camera_transform.translation.truncate(),
 | 
			
		||||
                size: camera_size,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            for (entity, drawable_transform, sprite) in sprites.iter() {
 | 
			
		||||
                let sprite_rect = Rect {
 | 
			
		||||
                    position: drawable_transform.translation.truncate(),
 | 
			
		||||
                    size: sprite.size,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if rect.is_intersecting(sprite_rect) {
 | 
			
		||||
                    if culled_sprites.get(entity).is_ok() {
 | 
			
		||||
                        commands.entity(entity).remove::<OutsideFrustum>();
 | 
			
		||||
                    }
 | 
			
		||||
                } else if culled_sprites.get(entity).is_err() {
 | 
			
		||||
                    commands.entity(entity).insert(OutsideFrustum);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn atlas_frustum_culling_system(
 | 
			
		||||
    mut commands: Commands,
 | 
			
		||||
    windows: Res<Windows>,
 | 
			
		||||
    active_cameras: Res<ActiveCameras>,
 | 
			
		||||
    textures: Res<Assets<TextureAtlas>>,
 | 
			
		||||
    camera_transforms: Query<&Transform, With<Camera>>,
 | 
			
		||||
    culled_sprites: Query<&OutsideFrustum, With<TextureAtlasSprite>>,
 | 
			
		||||
    sprites: Query<(
 | 
			
		||||
        Entity,
 | 
			
		||||
        &Transform,
 | 
			
		||||
        &TextureAtlasSprite,
 | 
			
		||||
        &Handle<TextureAtlas>,
 | 
			
		||||
    )>,
 | 
			
		||||
) {
 | 
			
		||||
    let window = windows.get_primary().unwrap();
 | 
			
		||||
    let window_size = Vec2::new(window.width(), window.height());
 | 
			
		||||
 | 
			
		||||
    for active_camera_entity in active_cameras.iter().filter_map(|a| a.entity) {
 | 
			
		||||
        if let Ok(camera_transform) = camera_transforms.get(active_camera_entity) {
 | 
			
		||||
            let camera_size = window_size * camera_transform.scale.truncate();
 | 
			
		||||
 | 
			
		||||
            let rect = Rect {
 | 
			
		||||
                position: camera_transform.translation.truncate(),
 | 
			
		||||
                size: camera_size,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            for (entity, drawable_transform, sprite, atlas_handle) in sprites.iter() {
 | 
			
		||||
                if let Some(atlas) = textures.get(atlas_handle) {
 | 
			
		||||
                    if let Some(sprite) = atlas.textures.get(sprite.index as usize) {
 | 
			
		||||
                        let size = Vec2::new(sprite.width(), sprite.height());
 | 
			
		||||
 | 
			
		||||
                        let sprite_rect = Rect {
 | 
			
		||||
                            position: drawable_transform.translation.truncate(),
 | 
			
		||||
                            size,
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                        if rect.is_intersecting(sprite_rect) {
 | 
			
		||||
                            if culled_sprites.get(entity).is_ok() {
 | 
			
		||||
                                commands.entity(entity).remove::<OutsideFrustum>();
 | 
			
		||||
                            }
 | 
			
		||||
                        } else if culled_sprites.get(entity).is_err() {
 | 
			
		||||
                            commands.entity(entity).insert(OutsideFrustum);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,7 @@ pub mod entity;
 | 
			
		||||
 | 
			
		||||
mod color_material;
 | 
			
		||||
mod dynamic_texture_atlas_builder;
 | 
			
		||||
mod frustum_culling;
 | 
			
		||||
mod rect;
 | 
			
		||||
mod render;
 | 
			
		||||
mod sprite;
 | 
			
		||||
@ -26,10 +27,14 @@ pub use texture_atlas_builder::*;
 | 
			
		||||
 | 
			
		||||
use bevy_app::prelude::*;
 | 
			
		||||
use bevy_asset::{AddAsset, Assets, Handle, HandleUntyped};
 | 
			
		||||
use bevy_ecs::system::IntoSystem;
 | 
			
		||||
use bevy_ecs::{
 | 
			
		||||
    component::{ComponentDescriptor, StorageType},
 | 
			
		||||
    system::IntoSystem,
 | 
			
		||||
};
 | 
			
		||||
use bevy_math::Vec2;
 | 
			
		||||
use bevy_reflect::TypeUuid;
 | 
			
		||||
use bevy_render::{
 | 
			
		||||
    draw::OutsideFrustum,
 | 
			
		||||
    mesh::{shape, Mesh},
 | 
			
		||||
    pipeline::PipelineDescriptor,
 | 
			
		||||
    render_graph::RenderGraph,
 | 
			
		||||
@ -37,6 +42,19 @@ use bevy_render::{
 | 
			
		||||
};
 | 
			
		||||
use sprite::sprite_system;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct SpriteSettings {
 | 
			
		||||
    pub frustum_culling_enabled: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for SpriteSettings {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            frustum_culling_enabled: true,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Default)]
 | 
			
		||||
pub struct SpritePlugin;
 | 
			
		||||
 | 
			
		||||
@ -59,16 +77,39 @@ impl Plugin for SpritePlugin {
 | 
			
		||||
                asset_shader_defs_system::<ColorMaterial>.system(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        let world = app.world_mut().cell();
 | 
			
		||||
        let mut render_graph = world.get_resource_mut::<RenderGraph>().unwrap();
 | 
			
		||||
        let mut pipelines = world
 | 
			
		||||
        let sprite_settings = app
 | 
			
		||||
            .world_mut()
 | 
			
		||||
            .get_resource_or_insert_with(SpriteSettings::default)
 | 
			
		||||
            .clone();
 | 
			
		||||
        if sprite_settings.frustum_culling_enabled {
 | 
			
		||||
            app.add_system_to_stage(
 | 
			
		||||
                CoreStage::PostUpdate,
 | 
			
		||||
                frustum_culling::sprite_frustum_culling_system.system(),
 | 
			
		||||
            )
 | 
			
		||||
            .add_system_to_stage(
 | 
			
		||||
                CoreStage::PostUpdate,
 | 
			
		||||
                frustum_culling::atlas_frustum_culling_system.system(),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        let world = app.world_mut();
 | 
			
		||||
        world
 | 
			
		||||
            .register_component(ComponentDescriptor::new::<OutsideFrustum>(
 | 
			
		||||
                StorageType::SparseSet,
 | 
			
		||||
            ))
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        let world_cell = world.cell();
 | 
			
		||||
        let mut render_graph = world_cell.get_resource_mut::<RenderGraph>().unwrap();
 | 
			
		||||
        let mut pipelines = world_cell
 | 
			
		||||
            .get_resource_mut::<Assets<PipelineDescriptor>>()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        let mut shaders = world.get_resource_mut::<Assets<Shader>>().unwrap();
 | 
			
		||||
        let mut shaders = world_cell.get_resource_mut::<Assets<Shader>>().unwrap();
 | 
			
		||||
        crate::render::add_sprite_graph(&mut render_graph, &mut pipelines, &mut shaders);
 | 
			
		||||
 | 
			
		||||
        let mut meshes = world.get_resource_mut::<Assets<Mesh>>().unwrap();
 | 
			
		||||
        let mut color_materials = world.get_resource_mut::<Assets<ColorMaterial>>().unwrap();
 | 
			
		||||
        let mut meshes = world_cell.get_resource_mut::<Assets<Mesh>>().unwrap();
 | 
			
		||||
        let mut color_materials = world_cell
 | 
			
		||||
            .get_resource_mut::<Assets<ColorMaterial>>()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        color_materials.set_untracked(Handle::<ColorMaterial>::default(), ColorMaterial::default());
 | 
			
		||||
        meshes.set_untracked(
 | 
			
		||||
            QUAD_HANDLE,
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,14 @@
 | 
			
		||||
use crate::ColorMaterial;
 | 
			
		||||
use bevy_asset::{Assets, Handle};
 | 
			
		||||
use bevy_core::Bytes;
 | 
			
		||||
use bevy_ecs::system::{Query, Res};
 | 
			
		||||
use bevy_ecs::{
 | 
			
		||||
    query::Without,
 | 
			
		||||
    system::{Query, Res},
 | 
			
		||||
};
 | 
			
		||||
use bevy_math::Vec2;
 | 
			
		||||
use bevy_reflect::{Reflect, ReflectDeserialize, TypeUuid};
 | 
			
		||||
use bevy_render::{
 | 
			
		||||
    draw::OutsideFrustum,
 | 
			
		||||
    renderer::{RenderResource, RenderResourceType, RenderResources},
 | 
			
		||||
    texture::Texture,
 | 
			
		||||
};
 | 
			
		||||
@ -76,7 +80,7 @@ impl Sprite {
 | 
			
		||||
pub fn sprite_system(
 | 
			
		||||
    materials: Res<Assets<ColorMaterial>>,
 | 
			
		||||
    textures: Res<Assets<Texture>>,
 | 
			
		||||
    mut query: Query<(&mut Sprite, &Handle<ColorMaterial>)>,
 | 
			
		||||
    mut query: Query<(&mut Sprite, &Handle<ColorMaterial>), Without<OutsideFrustum>>,
 | 
			
		||||
) {
 | 
			
		||||
    for (mut sprite, handle) in query.iter_mut() {
 | 
			
		||||
        match sprite.resize_mode {
 | 
			
		||||
 | 
			
		||||
@ -2,12 +2,12 @@ use bevy_asset::Assets;
 | 
			
		||||
use bevy_ecs::{
 | 
			
		||||
    bundle::Bundle,
 | 
			
		||||
    entity::Entity,
 | 
			
		||||
    query::{Changed, With},
 | 
			
		||||
    query::{Changed, With, Without},
 | 
			
		||||
    system::{Local, Query, QuerySet, Res, ResMut},
 | 
			
		||||
};
 | 
			
		||||
use bevy_math::{Size, Vec3};
 | 
			
		||||
use bevy_render::{
 | 
			
		||||
    draw::{DrawContext, Drawable},
 | 
			
		||||
    draw::{DrawContext, Drawable, OutsideFrustum},
 | 
			
		||||
    mesh::Mesh,
 | 
			
		||||
    prelude::{Draw, Msaa, Texture, Visible},
 | 
			
		||||
    render_graph::base::MainPass,
 | 
			
		||||
@ -72,7 +72,7 @@ pub fn draw_text2d_system(
 | 
			
		||||
            &GlobalTransform,
 | 
			
		||||
            &Text2dSize,
 | 
			
		||||
        ),
 | 
			
		||||
        With<MainPass>,
 | 
			
		||||
        (With<MainPass>, Without<OutsideFrustum>),
 | 
			
		||||
    >,
 | 
			
		||||
) {
 | 
			
		||||
    let font_quad = meshes.get(&QUAD_HANDLE).unwrap();
 | 
			
		||||
 | 
			
		||||
@ -2,12 +2,12 @@ use crate::{CalculatedSize, Node, Style, Val};
 | 
			
		||||
use bevy_asset::Assets;
 | 
			
		||||
use bevy_ecs::{
 | 
			
		||||
    entity::Entity,
 | 
			
		||||
    query::{Changed, Or},
 | 
			
		||||
    query::{Changed, Or, Without},
 | 
			
		||||
    system::{Local, Query, QuerySet, Res, ResMut},
 | 
			
		||||
};
 | 
			
		||||
use bevy_math::Size;
 | 
			
		||||
use bevy_render::{
 | 
			
		||||
    draw::{Draw, DrawContext, Drawable},
 | 
			
		||||
    draw::{Draw, DrawContext, Drawable, OutsideFrustum},
 | 
			
		||||
    mesh::Mesh,
 | 
			
		||||
    prelude::{Msaa, Visible},
 | 
			
		||||
    renderer::RenderResourceBindings,
 | 
			
		||||
@ -136,7 +136,10 @@ pub fn draw_text_system(
 | 
			
		||||
    meshes: Res<Assets<Mesh>>,
 | 
			
		||||
    mut render_resource_bindings: ResMut<RenderResourceBindings>,
 | 
			
		||||
    text_pipeline: Res<DefaultTextPipeline>,
 | 
			
		||||
    mut query: Query<(Entity, &mut Draw, &Visible, &Text, &Node, &GlobalTransform)>,
 | 
			
		||||
    mut query: Query<
 | 
			
		||||
        (Entity, &mut Draw, &Visible, &Text, &Node, &GlobalTransform),
 | 
			
		||||
        Without<OutsideFrustum>,
 | 
			
		||||
    >,
 | 
			
		||||
) {
 | 
			
		||||
    let scale_factor = if let Some(window) = windows.get_primary() {
 | 
			
		||||
        window.scale_factor()
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user