honour NoFrustumCulling for shadows (#15117)

# Objective

`NoFrustumCulling` prevents meshes from being considered out of view
based on AABBs (sometimes useful for skinned meshes which don't
recalculate AABBs currently). it currently only applies for primary view
rendering, not for shadow rendering which can result in missing shadows.

## Solution

Add checks for `NoFrustumCulling` to `check_dir_light_mesh_visibility`
and `check_point_light_mesh_visibility` so that `NoFrustumCulling`
entities are rendered to all shadow views as well as all primary views.
This commit is contained in:
robtfm 2024-09-09 18:51:38 +01:00 committed by GitHub
parent ccb8854ec1
commit 4e6471ed23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -11,7 +11,8 @@ use bevy_render::{
mesh::Mesh, mesh::Mesh,
primitives::{Aabb, CascadesFrusta, CubemapFrusta, Frustum, Sphere}, primitives::{Aabb, CascadesFrusta, CubemapFrusta, Frustum, Sphere},
view::{ view::{
InheritedVisibility, RenderLayers, ViewVisibility, VisibilityRange, VisibleEntityRanges, InheritedVisibility, NoFrustumCulling, RenderLayers, ViewVisibility, VisibilityRange,
VisibleEntityRanges,
}, },
}; };
use bevy_transform::components::{GlobalTransform, Transform}; use bevy_transform::components::{GlobalTransform, Transform};
@ -683,6 +684,7 @@ pub fn check_dir_light_mesh_visibility(
Option<&Aabb>, Option<&Aabb>,
Option<&GlobalTransform>, Option<&GlobalTransform>,
Has<VisibilityRange>, Has<VisibilityRange>,
Has<NoFrustumCulling>,
), ),
( (
Without<NotShadowCaster>, Without<NotShadowCaster>,
@ -742,6 +744,7 @@ pub fn check_dir_light_mesh_visibility(
maybe_aabb, maybe_aabb,
maybe_transform, maybe_transform,
has_visibility_range, has_visibility_range,
has_no_frustum_culling,
)| { )| {
if !inherited_visibility.get() { if !inherited_visibility.get() {
return; return;
@ -768,7 +771,9 @@ pub fn check_dir_light_mesh_visibility(
.zip(view_visible_entities_local_queue.iter_mut()) .zip(view_visible_entities_local_queue.iter_mut())
{ {
// Disable near-plane culling, as a shadow caster could lie before the near plane. // Disable near-plane culling, as a shadow caster could lie before the near plane.
if !frustum.intersects_obb(aabb, &transform.affine(), false, true) { if !has_no_frustum_culling
&& !frustum.intersects_obb(aabb, &transform.affine(), false, true)
{
continue; continue;
} }
visible = true; visible = true;
@ -848,6 +853,7 @@ pub fn check_point_light_mesh_visibility(
Option<&Aabb>, Option<&Aabb>,
Option<&GlobalTransform>, Option<&GlobalTransform>,
Has<VisibilityRange>, Has<VisibilityRange>,
Has<NoFrustumCulling>,
), ),
( (
Without<NotShadowCaster>, Without<NotShadowCaster>,
@ -897,6 +903,7 @@ pub fn check_point_light_mesh_visibility(
maybe_aabb, maybe_aabb,
maybe_transform, maybe_transform,
has_visibility_range, has_visibility_range,
has_no_frustum_culling,
)| { )| {
if !inherited_visibility.get() { if !inherited_visibility.get() {
return; return;
@ -917,7 +924,9 @@ pub fn check_point_light_mesh_visibility(
if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) {
let model_to_world = transform.affine(); let model_to_world = transform.affine();
// Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light // Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light
if !light_sphere.intersects_obb(aabb, &model_to_world) { if !has_no_frustum_culling
&& !light_sphere.intersects_obb(aabb, &model_to_world)
{
return; return;
} }
@ -925,7 +934,9 @@ pub fn check_point_light_mesh_visibility(
.iter() .iter()
.zip(cubemap_visible_entities_local_queue.iter_mut()) .zip(cubemap_visible_entities_local_queue.iter_mut())
{ {
if frustum.intersects_obb(aabb, &model_to_world, true, true) { if has_no_frustum_culling
|| frustum.intersects_obb(aabb, &model_to_world, true, true)
{
view_visibility.set(); view_visibility.set();
visible_entities.push(entity); visible_entities.push(entity);
} }
@ -980,6 +991,7 @@ pub fn check_point_light_mesh_visibility(
maybe_aabb, maybe_aabb,
maybe_transform, maybe_transform,
has_visibility_range, has_visibility_range,
has_no_frustum_culling,
)| { )| {
if !inherited_visibility.get() { if !inherited_visibility.get() {
return; return;
@ -1001,11 +1013,15 @@ pub fn check_point_light_mesh_visibility(
if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) { if let (Some(aabb), Some(transform)) = (maybe_aabb, maybe_transform) {
let model_to_world = transform.affine(); let model_to_world = transform.affine();
// Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light // Do a cheap sphere vs obb test to prune out most meshes outside the sphere of the light
if !light_sphere.intersects_obb(aabb, &model_to_world) { if !has_no_frustum_culling
&& !light_sphere.intersects_obb(aabb, &model_to_world)
{
return; return;
} }
if frustum.intersects_obb(aabb, &model_to_world, true, true) { if has_no_frustum_culling
|| frustum.intersects_obb(aabb, &model_to_world, true, true)
{
view_visibility.set(); view_visibility.set();
spot_visible_entities_local_queue.push(entity); spot_visible_entities_local_queue.push(entity);
} }