Skip to content

Commit

Permalink
added frustum culling implementation for sprites and sprite atlases
Browse files Browse the repository at this point in the history
  • Loading branch information
Byteron committed Feb 22, 2021
1 parent 89a41bc commit d4e6c7c
Show file tree
Hide file tree
Showing 17 changed files with 212 additions and 115 deletions.
4 changes: 3 additions & 1 deletion crates/bevy_pbr/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{light::Light, material::StandardMaterial, render_graph::FORWARD_PIPE
use bevy_asset::Handle;
use bevy_ecs::Bundle;
use bevy_render::{
draw::Draw,
draw::{Draw, Transparent},
mesh::Mesh,
pipeline::{RenderPipeline, RenderPipelines},
prelude::Visible,
Expand All @@ -18,6 +18,7 @@ pub struct PbrBundle {
pub main_pass: MainPass,
pub draw: Draw,
pub visible: Visible,
pub transparent: Transparent,
pub render_pipelines: RenderPipelines,
pub transform: Transform,
pub global_transform: GlobalTransform,
Expand All @@ -31,6 +32,7 @@ impl Default for PbrBundle {
)]),
mesh: Default::default(),
visible: Default::default(),
transparent: Default::default(),
material: Default::default(),
main_pass: Default::default(),
draw: Default::default(),
Expand Down
17 changes: 8 additions & 9 deletions crates/bevy_render/src/camera/visible_entities.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{Camera, DepthCalculation};
use crate::prelude::Visible;
use crate::{draw::Transparent, prelude::Visible};
use bevy_core::FloatOrd;
use bevy_ecs::{Entity, Query, With};
use bevy_reflect::{Reflect, ReflectComponent};
Expand Down Expand Up @@ -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, Option<&RenderLayers>, Option<&Transparent>), With<Visible>>,
visible_transform_query: Query<(&GlobalTransform, Option<&Transparent>), With<Visible>>,
) {
for (camera, camera_global_transform, mut visible_entities, maybe_camera_mask) in
camera_query.iter_mut()
Expand All @@ -216,17 +216,16 @@ pub fn visible_entities_system(

let mut no_transform_order = 0.0;
let mut transparent_entities = Vec::new();
for (entity, visible, maybe_entity_mask) in visible_query.iter() {
if !visible.is_visible {
continue;
}

for (entity, maybe_entity_mask, transparent) in visible_query.iter() {
let entity_mask = maybe_entity_mask.copied().unwrap_or_default();
if !camera_mask.intersects(&entity_mask) {
continue;
}

let order = if let Ok(global_transform) = visible_transform_query.get(entity) {
let order = if let Ok(global_transform) =
visible_transform_query.get_component::<GlobalTransform>(entity)
{
let position = global_transform.translation;
// smaller distances are sorted to lower indices by using the distance from the camera
FloatOrd(match camera.depth_calculation {
Expand All @@ -239,7 +238,7 @@ pub fn visible_entities_system(
order
};

if visible.is_transparent {
if transparent.is_some() {
transparent_entities.push(VisibleEntity { entity, order })
} else {
visible_entities.value.push(VisibleEntity { entity, order })
Expand Down
21 changes: 12 additions & 9 deletions crates/bevy_render/src/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,21 @@ pub enum RenderCommand {

#[derive(Debug, Clone, Reflect)]
#[reflect(Component)]
pub struct Visible {
pub is_visible: bool,
// TODO: consider moving this to materials
pub is_transparent: bool,
}
pub struct Visible;

impl Default for Visible {
fn default() -> Self {
Visible {
is_visible: true,
is_transparent: false,
}
Visible
}
}

#[derive(Debug, Clone, Reflect)]
#[reflect(Component)]
pub struct Transparent;

impl Default for Transparent {
fn default() -> Self {
Transparent
}
}

Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub mod texture;

use bevy_ecs::{IntoExclusiveSystem, IntoSystem, SystemStage};
use bevy_reflect::RegisterTypeBuilder;
use draw::Visible;
use draw::{Transparent, Visible};
pub use once_cell;

pub mod prelude {
Expand Down Expand Up @@ -129,6 +129,7 @@ impl Plugin for RenderPlugin {
.register_type::<Camera>()
.register_type::<Draw>()
.register_type::<Visible>()
.register_type::<Transparent>()
.register_type::<RenderPipelines>()
.register_type::<OrthographicProjection>()
.register_type::<PerspectiveProjection>()
Expand Down
10 changes: 3 additions & 7 deletions crates/bevy_render/src/pipeline/render_pipelines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
renderer::RenderResourceBindings,
};
use bevy_asset::{Assets, Handle};
use bevy_ecs::{Query, Res, ResMut};
use bevy_ecs::{Query, Res, ResMut, With};
use bevy_reflect::{Reflect, ReflectComponent};
use bevy_utils::HashSet;

Expand Down Expand Up @@ -82,13 +82,9 @@ 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>), With<Visible>>,
) {
for (mut draw, mut render_pipelines, mesh_handle, visible) in query.iter_mut() {
if !visible.is_visible {
continue;
}

for (mut draw, mut render_pipelines, mesh_handle) in query.iter_mut() {
// don't render if the mesh isn't loaded yet
let mesh = if let Some(mesh) = meshes.get(mesh_handle) {
mesh
Expand Down
6 changes: 2 additions & 4 deletions crates/bevy_render/src/render_graph/nodes/pass_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,8 @@ where
continue;
};

if let Ok(visible) = world.get::<Visible>(visible_entity.entity) {
if !visible.is_visible {
continue;
}
if world.get::<Visible>(visible_entity.entity).is_err() {
continue;
}

// each Draw component contains an ordered list of render commands. we turn those into actual render commands here
Expand Down
23 changes: 9 additions & 14 deletions crates/bevy_render/src/render_graph/nodes/render_resources_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,11 @@ fn render_resources_node_system<T: RenderResources>(
mut entities_waiting_for_textures: Local<Vec<Entity>>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
mut queries: QuerySet<(
Query<(Entity, &T, &Visible, &mut RenderPipelines), Or<(Changed<T>, Changed<Visible>)>>,
Query<(Entity, &T, &Visible, &mut RenderPipelines)>,
Query<
(Entity, &T, Option<&Visible>, &mut RenderPipelines),
Or<(Changed<T>, Changed<Visible>)>,
>,
Query<(Entity, &T, &mut RenderPipelines), With<Visible>>,
)>,
) {
let state = state.deref_mut();
Expand All @@ -456,9 +459,7 @@ fn render_resources_node_system<T: RenderResources>(

// handle entities that were waiting for texture loads on the last update
for entity in std::mem::take(&mut *entities_waiting_for_textures) {
if let Ok((entity, uniforms, _visible, mut render_pipelines)) =
queries.q1_mut().get_mut(entity)
{
if let Ok((entity, uniforms, mut render_pipelines)) = queries.q1_mut().get_mut(entity) {
if !setup_uniform_texture_resources::<T>(
&uniforms,
render_resource_context,
Expand All @@ -470,7 +471,7 @@ fn render_resources_node_system<T: RenderResources>(
}

for (entity, uniforms, visible, mut render_pipelines) in queries.q0_mut().iter_mut() {
if !visible.is_visible {
if visible.is_none() {
continue;
}
uniform_buffer_arrays.prepare_uniform_buffers(entity, uniforms);
Expand All @@ -497,13 +498,7 @@ fn render_resources_node_system<T: RenderResources>(
&mut |mut staging_buffer, _render_resource_context| {
// if the buffer array was resized, write all entities to the new buffer, otherwise only write changes
if resized {
for (entity, uniforms, visible, mut render_pipelines) in
queries.q1_mut().iter_mut()
{
if !visible.is_visible {
continue;
}

for (entity, uniforms, mut render_pipelines) in queries.q1_mut().iter_mut() {
state.uniform_buffer_arrays.write_uniform_buffers(
entity,
&uniforms,
Expand All @@ -517,7 +512,7 @@ fn render_resources_node_system<T: RenderResources>(
for (entity, uniforms, visible, mut render_pipelines) in
queries.q0_mut().iter_mut()
{
if !visible.is_visible {
if visible.is_none() {
continue;
}

Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_render/src/shader/shader_defs.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use bevy_asset::{Asset, Assets, Handle};

use crate::{pipeline::RenderPipelines, Texture};
use crate::{pipeline::RenderPipelines, prelude::Visible, Texture};
pub use bevy_derive::ShaderDefs;
use bevy_ecs::{Query, Res};
use bevy_ecs::{Query, Res, With};

/// Something that can either be "defined" or "not defined". This is used to determine if a "shader def" should be considered "defined"
pub trait ShaderDef {
Expand Down Expand Up @@ -60,7 +60,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), With<Visible>>)
where
T: ShaderDefs + Send + Sync + 'static,
{
Expand Down Expand Up @@ -93,7 +93,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), With<Visible>>,
) where
T: ShaderDefs + Send + Sync + 'static,
{
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_sprite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.2"
Expand Down
15 changes: 7 additions & 8 deletions crates/bevy_sprite/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
use bevy_asset::Handle;
use bevy_ecs::Bundle;
use bevy_render::{
draw::Transparent,
mesh::Mesh,
pipeline::{RenderPipeline, RenderPipelines},
prelude::{Draw, Visible},
Expand All @@ -20,6 +21,7 @@ pub struct SpriteBundle {
pub main_pass: MainPass,
pub draw: Draw,
pub visible: Visible,
pub transparent: Transparent,
pub render_pipelines: RenderPipelines,
pub transform: Transform,
pub global_transform: GlobalTransform,
Expand All @@ -32,10 +34,8 @@ impl Default for SpriteBundle {
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::new(
SPRITE_PIPELINE_HANDLE.typed(),
)]),
visible: Visible {
is_transparent: true,
..Default::default()
},
visible: Visible,
transparent: Transparent,
main_pass: MainPass,
draw: Default::default(),
sprite: Default::default(),
Expand All @@ -57,6 +57,7 @@ pub struct SpriteSheetBundle {
/// Data pertaining to how the sprite is drawn on the screen
pub draw: Draw,
pub visible: Visible,
pub transparent: Transparent,
pub render_pipelines: RenderPipelines,
pub main_pass: MainPass,
pub mesh: Handle<Mesh>, // TODO: maybe abstract this out
Expand All @@ -70,10 +71,8 @@ impl Default for SpriteSheetBundle {
render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::new(
SPRITE_SHEET_PIPELINE_HANDLE.typed(),
)]),
visible: Visible {
is_transparent: true,
..Default::default()
},
visible: Visible,
transparent: Transparent,
main_pass: MainPass,
mesh: QUAD_HANDLE.typed(),
draw: Default::default(),
Expand Down
Loading

0 comments on commit d4e6c7c

Please sign in to comment.