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
			
			
This commit is contained in:
		
							parent
							
								
									e88e394feb
								
							
						
					
					
						commit
						55da315432
					
				@ -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<Assets<Mesh>>,
 | 
			
		||||
    without_aabb: Query<(Entity, &Handle<Mesh>), Without<Aabb>>,
 | 
			
		||||
    without_aabb: Query<(Entity, &Handle<Mesh>), (Without<Aabb>, Without<NoFrustumCulling>)>,
 | 
			
		||||
) {
 | 
			
		||||
    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;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -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<Assets<Mesh>>) {
 | 
			
		||||
        ),
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user