From 55da315432074e32a28b1ef0ad39b8eadf92467a Mon Sep 17 00:00:00 2001 From: Robert Swain Date: Mon, 17 Jan 2022 22:55:44 +0000 Subject: [PATCH] bevy_render: Provide a way to opt-out of the built-in frustum culling (#3711) # Objective - Allow opting-out of the built-in frustum culling for cases where its behaviour would be incorrect - Make use of the this in the shader_instancing example that uses a custom instancing method. The built-in frustum culling breaks the custom instancing in the shader_instancing example if the camera is moved to: ```rust commands.spawn_bundle(PerspectiveCameraBundle { transform: Transform::from_xyz(12.0, 0.0, 15.0) .looking_at(Vec3::new(12.0, 0.0, 0.0), Vec3::Y), ..Default::default() }); ``` ...such that the Aabb of the cube Mesh that is at the origin goes completely out of view. This incorrectly (for the purpose of the custom instancing) culls the `Mesh` and so culls all instances even though some may be visible. ## Solution - Add a `NoFrustumCulling` marker component - Do not compute and add an `Aabb` to `Mesh` entities without an `Aabb` if they have a `NoFrustumCulling` marker component - Do not apply frustum culling to entities with the `NoFrustumCulling` marker component --- crates/bevy_render/src/view/visibility/mod.rs | 12 ++++++++++-- examples/shader/shader_instancing.rs | 10 +++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 61da101d02d3e..cec6525d1acf2 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -40,6 +40,10 @@ impl Default for ComputedVisibility { } } +/// Use this component to opt-out of built-in frustum culling for Mesh entities +#[derive(Component)] +pub struct NoFrustumCulling; + #[derive(Clone, Component, Default, Debug, Reflect)] #[reflect(Component)] pub struct VisibleEntities { @@ -106,7 +110,7 @@ impl Plugin for VisibilityPlugin { pub fn calculate_bounds( mut commands: Commands, meshes: Res>, - without_aabb: Query<(Entity, &Handle), Without>, + without_aabb: Query<(Entity, &Handle), (Without, Without)>, ) { for (entity, mesh_handle) in without_aabb.iter() { if let Some(mesh) = meshes.get(mesh_handle) { @@ -142,6 +146,7 @@ pub fn check_visibility( &mut ComputedVisibility, Option<&RenderLayers>, Option<&Aabb>, + Option<&NoFrustumCulling>, Option<&GlobalTransform>, )>, )>, @@ -161,6 +166,7 @@ pub fn check_visibility( mut computed_visibility, maybe_entity_mask, maybe_aabb, + maybe_no_frustum_culling, maybe_transform, ) in visible_entity_query.q1().iter_mut() { @@ -174,7 +180,9 @@ pub fn check_visibility( } // If we have an aabb and transform, do frustum culling - if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { + if let (Some(aabb), None, Some(transform)) = + (maybe_aabb, maybe_no_frustum_culling, maybe_transform) + { if !frustum.intersects_obb(aabb, &transform.compute_matrix()) { continue; } diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index fee46581d4e63..9c5a048ea6107 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -14,7 +14,7 @@ use bevy::{ }, render_resource::*, renderer::RenderDevice, - view::{ComputedVisibility, ExtractedView, Msaa, Visibility}, + view::{ComputedVisibility, ExtractedView, Msaa, NoFrustumCulling, Visibility}, RenderApp, RenderStage, }, }; @@ -45,6 +45,14 @@ fn setup(mut commands: Commands, mut meshes: ResMut>) { ), Visibility::default(), ComputedVisibility::default(), + // NOTE: Frustum culling is done based on the Aabb of the Mesh and the GlobalTransform. + // As the cube is at the origin, if its Aabb moves outside the view frustum, all the + // instanced cubes will be culled. + // The InstanceMaterialData contains the 'GlobalTransform' information for this custom + // instancing, and that is not taken into account with the built-in frustum culling. + // We must disable the built-in frustum culling by adding the `NoFrustumCulling` marker + // component to avoid incorrect culling. + NoFrustumCulling, )); // camera