diff --git a/all-is-cubes-gpu/src/in_wgpu/space.rs b/all-is-cubes-gpu/src/in_wgpu/space.rs index 095c3b184..5ac12b455 100644 --- a/all-is-cubes-gpu/src/in_wgpu/space.rs +++ b/all-is-cubes-gpu/src/in_wgpu/space.rs @@ -12,7 +12,7 @@ use all_is_cubes::content::palette; use all_is_cubes::listen::{self, Listen as _, Listener}; use all_is_cubes::math::{ rgba_const, Cube, Face6, FreeCoordinate, FreePoint, GridAab, GridCoordinate, GridPoint, - GridSize, GridVector, Rgb, Wireframe as _, ZeroOne, + GridSize, GridVector, Rgb, Rgba, Wireframe as _, ZeroOne, }; use all_is_cubes::raycast::Ray; #[cfg(feature = "rerun")] @@ -726,6 +726,18 @@ impl SpaceRenderer { return; }; + if camera.options().debug_reduce_view_frustum { + // Draw the modified view frustum, which becomes a viewport box in screen space. + // (Note the lines are at risk of being clipped, but in practice are sufficiently + // visible but flickery.) + camera + .view_frustum_geometry() + .wireframe_points(&mut crate::map_line_vertices::( + v, + Rgba::WHITE, + )); + } + if camera.options().debug_chunk_boxes { let view_chunk = csm.view_chunk(); diff --git a/all-is-cubes-mesh/src/dynamic/chunked_mesh.rs b/all-is-cubes-mesh/src/dynamic/chunked_mesh.rs index b45307f5b..6c3a34922 100644 --- a/all-is-cubes-mesh/src/dynamic/chunked_mesh.rs +++ b/all-is-cubes-mesh/src/dynamic/chunked_mesh.rs @@ -151,17 +151,14 @@ where .chunks(self.view_chunk(), camera.view_direction_mask()) .filter_map(|pos| { let chunk = self.chunk(pos)?; - let use_frustum_culling = camera.options().use_frustum_culling; let item = InViewChunkRef { chunk, - mesh_in_view: !use_frustum_culling - || chunk - .mesh_bounding_box() - .is_some_and(|bb| camera.aab_in_view(bb)), - instances_in_view: !use_frustum_culling - || chunk - .block_instances_bounding_box() - .is_some_and(|bb| camera.aab_in_view(bb)), + mesh_in_view: chunk + .mesh_bounding_box() + .is_some_and(|bb| camera.aab_in_view(bb)), + instances_in_view: chunk + .block_instances_bounding_box() + .is_some_and(|bb| camera.aab_in_view(bb)), }; (item.mesh_in_view || item.instances_in_view).then_some(item) }) diff --git a/all-is-cubes/src/camera.rs b/all-is-cubes/src/camera.rs index d6e948bfc..86af07bae 100644 --- a/all-is-cubes/src/camera.rs +++ b/all-is-cubes/src/camera.rs @@ -405,15 +405,20 @@ impl Camera { // Compute the view frustum's corner points, // by unprojecting the corners of clip space. + let xy_limit = if self.options.debug_reduce_view_frustum { + 0.5 + } else { + 1. + }; self.view_frustum = FrustumPoints { - lbn: self.project_ndc3_into_world(point3(-1., -1., 0.)), - rbn: self.project_ndc3_into_world(point3(1., -1., 0.)), - ltn: self.project_ndc3_into_world(point3(-1., 1., 0.)), - rtn: self.project_ndc3_into_world(point3(1., 1., 0.)), - lbf: self.project_ndc3_into_world(point3(-1., -1., 1.)), - rbf: self.project_ndc3_into_world(point3(1., -1., 1.)), - ltf: self.project_ndc3_into_world(point3(-1., 1., 1.)), - rtf: self.project_ndc3_into_world(point3(1., 1., 1.)), + lbn: self.project_ndc3_into_world(point3(-xy_limit, -xy_limit, 0.)), + rbn: self.project_ndc3_into_world(point3(xy_limit, -xy_limit, 0.)), + ltn: self.project_ndc3_into_world(point3(-xy_limit, xy_limit, 0.)), + rtn: self.project_ndc3_into_world(point3(xy_limit, xy_limit, 0.)), + lbf: self.project_ndc3_into_world(point3(-xy_limit, -xy_limit, 1.)), + rbf: self.project_ndc3_into_world(point3(xy_limit, -xy_limit, 1.)), + ltf: self.project_ndc3_into_world(point3(-xy_limit, xy_limit, 1.)), + rtf: self.project_ndc3_into_world(point3(xy_limit, xy_limit, 1.)), bounds: Aab::ZERO, }; self.view_frustum.compute_bounds(); diff --git a/all-is-cubes/src/camera/graphics_options.rs b/all-is-cubes/src/camera/graphics_options.rs index 812fc67e7..0e095039a 100644 --- a/all-is-cubes/src/camera/graphics_options.rs +++ b/all-is-cubes/src/camera/graphics_options.rs @@ -6,7 +6,7 @@ use crate::math::{ps64, zo32, FreeCoordinate, PositiveSign, Rgb, Rgba, ZeroOne}; use crate::util::ShowStatus; #[cfg(doc)] -use crate::{block::Block, space::Space}; +use crate::{block::Block, camera::Camera, space::Space}; /// Options for controlling rendering (not affecting gameplay except informationally). /// @@ -73,12 +73,6 @@ pub struct GraphicsOptions { /// Whether to apply antialiasing techniques. pub antialiasing: AntialiasingOption, - /// Whether to use frustum culling for drawing only in-view chunks and objects. - /// - /// This option is for debugging and performance testing and should not have any - /// visible effects. - pub use_frustum_culling: bool, - /// Draw text overlay showing debug information. pub debug_info_text: bool, @@ -103,6 +97,13 @@ pub struct GraphicsOptions { /// Draw the light rays that contribute to the selected block. pub debug_light_rays_at_cursor: bool, + + /// Causes [`Camera`] to compute a falsified view frustum which is 1/2 the width and height + /// it should be. + /// + /// This may be used to visualize the effect of frustum culling that is performed via + /// [`Camera::aab_in_view()`]. + pub debug_reduce_view_frustum: bool, } impl GraphicsOptions { @@ -132,13 +133,13 @@ impl GraphicsOptions { transparency: TransparencyOption::Volumetric, show_ui: true, antialiasing: AntialiasingOption::None, - use_frustum_culling: true, debug_info_text: true, debug_info_text_contents: ShowStatus::DEFAULT, debug_behaviors: false, debug_chunk_boxes: false, debug_collision_boxes: false, debug_light_rays_at_cursor: false, + debug_reduce_view_frustum: false, }; /// Constrain fields to valid/practical values. @@ -164,13 +165,13 @@ impl fmt::Debug for GraphicsOptions { transparency, show_ui, antialiasing, - use_frustum_culling, debug_info_text, debug_info_text_contents, debug_behaviors, debug_chunk_boxes, debug_collision_boxes, debug_light_rays_at_cursor, + debug_reduce_view_frustum, } = self; // This custom impl reduces unnecessary text by stripping off NotNan wrappers. f.debug_struct("GraphicsOptions") @@ -185,13 +186,13 @@ impl fmt::Debug for GraphicsOptions { .field("transparency", &transparency) .field("show_ui", &show_ui) .field("antialiasing", &antialiasing) - .field("use_frustum_culling", &use_frustum_culling) .field("debug_info_text", &debug_info_text) .field("debug_info_text_contents", &debug_info_text_contents) .field("debug_behaviors", &debug_behaviors) .field("debug_chunk_boxes", &debug_chunk_boxes) .field("debug_collision_boxes", &debug_collision_boxes) .field("debug_light_rays_at_cursor", &debug_light_rays_at_cursor) + .field("debug_reduce_view_frustum", &debug_reduce_view_frustum) .finish() } } @@ -215,13 +216,13 @@ impl Default for GraphicsOptions { transparency: TransparencyOption::Volumetric, show_ui: true, antialiasing: AntialiasingOption::default(), - use_frustum_culling: true, debug_info_text: true, debug_info_text_contents: ShowStatus::DEFAULT, debug_behaviors: false, debug_chunk_boxes: false, debug_collision_boxes: false, debug_light_rays_at_cursor: false, + debug_reduce_view_frustum: false, } } } @@ -486,7 +487,6 @@ mod tests { transparency: Volumetric, show_ui: true, antialiasing: None, - use_frustum_culling: true, debug_info_text: true, debug_info_text_contents: ShowStatus( WORLD | STEP | RENDER | CURSOR, @@ -495,6 +495,7 @@ mod tests { debug_chunk_boxes: false, debug_collision_boxes: false, debug_light_rays_at_cursor: false, + debug_reduce_view_frustum: false, }" } );