-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce support for far culling when using PerspectiveProjection
#16789
base: main
Are you sure you want to change the base?
Changes from all commits
0e95061
f699b19
8859128
a555da5
a5b7e10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ use bevy_utils::{Parallel, TypeIdMap}; | |
use super::NoCpuCulling; | ||
use crate::sync_world::MainEntity; | ||
use crate::{ | ||
camera::{Camera, CameraProjection}, | ||
camera::{Camera, CameraProjection, Projection}, | ||
mesh::{Mesh, Mesh3d, MeshAabb}, | ||
primitives::{Aabb, Frustum, Sphere}, | ||
}; | ||
|
@@ -507,6 +507,7 @@ pub fn check_visibility<QF>( | |
&mut VisibleEntities, | ||
&Frustum, | ||
Option<&RenderLayers>, | ||
Option<&Projection>, | ||
&Camera, | ||
Has<NoCpuCulling>, | ||
)>, | ||
|
@@ -529,8 +530,15 @@ pub fn check_visibility<QF>( | |
{ | ||
let visible_entity_ranges = visible_entity_ranges.as_deref(); | ||
|
||
for (view, mut visible_entities, frustum, maybe_view_mask, camera, no_cpu_culling) in | ||
&mut view_query | ||
for ( | ||
view, | ||
mut visible_entities, | ||
frustum, | ||
maybe_view_mask, | ||
maybe_projection, | ||
camera, | ||
no_cpu_culling, | ||
) in &mut view_query | ||
{ | ||
if !camera.is_active { | ||
continue; | ||
|
@@ -575,17 +583,25 @@ pub fn check_visibility<QF>( | |
// If we have an aabb, do frustum culling | ||
if !no_frustum_culling && !no_cpu_culling { | ||
if let Some(model_aabb) = maybe_model_aabb { | ||
// Only use far culling if we have a projection with some `far` value. | ||
let use_far_culling = maybe_projection.is_some_and(|p| p.far().is_some()); | ||
|
||
let world_from_local = transform.affine(); | ||
let model_sphere = Sphere { | ||
center: world_from_local.transform_point3a(model_aabb.center), | ||
radius: transform.radius_vec3a(model_aabb.half_extents), | ||
}; | ||
// Do quick sphere-based frustum culling | ||
if !frustum.intersects_sphere(&model_sphere, false) { | ||
if !frustum.intersects_sphere(&model_sphere, use_far_culling) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought this would preserve existing behaviour when using the default projections, but maybe I'm misunderstanding as |
||
return; | ||
} | ||
// Do aabb-based frustum culling | ||
if !frustum.intersects_obb(model_aabb, &world_from_local, true, false) { | ||
if !frustum.intersects_obb( | ||
model_aabb, | ||
&world_from_local, | ||
true, | ||
use_far_culling, | ||
) { | ||
return; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,7 +114,10 @@ fn sprite_picking( | |
let Ok(cursor_ray_world) = camera.viewport_to_world(cam_transform, pos_in_viewport) else { | ||
continue; | ||
}; | ||
let cursor_ray_len = cam_ortho.far - cam_ortho.near; | ||
let cursor_ray_len = cam_ortho | ||
.far | ||
.unwrap_or(OrthographicProjection::DEFAULT_FAR_PLANE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is definitely wrong and I'm open to suggestions. Would also allow |
||
- cam_ortho.near; | ||
let cursor_ray_end = cursor_ray_world.origin + cursor_ray_world.direction * cursor_ray_len; | ||
|
||
let picks: Vec<(Entity, HitData)> = sorted_sprites | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,8 +111,12 @@ fn setup_scene_after_load( | |
let aabb = Aabb::from_min_max(Vec3::from(min), Vec3::from(max)); | ||
|
||
info!("Spawning a controllable 3D perspective camera"); | ||
let min_required_far = size * 10.0; | ||
let mut projection = PerspectiveProjection::default(); | ||
projection.far = projection.far.max(size * 10.0); | ||
projection.far = projection | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This preserves the existing intention (I think...) but feels odd as the default would be an essentialy infinite far plane anyway? |
||
.far | ||
.map(|far| far.max(min_required_far)) | ||
.or(Some(min_required_far)); | ||
|
||
let walk_speed = size * 3.0; | ||
let camera_controller = CameraController { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this should default to None since bevy currently doesn't do far plane culling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the orthographic case, where bevy does currently do far culling. See #16746 (Additional information)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does
None
even make sense for ortho? It doesn't have the ability to use infinite z, because depth is linear.