From 72f242018aee9f7d65ce1936713b19dccc802df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 26 Feb 2022 03:01:57 +0100 Subject: [PATCH 1/5] simplified API to get NDC --- crates/bevy_render/src/camera/camera.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index a69892cd22a3a..a26fdc13d2858 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -130,6 +130,21 @@ impl Camera { world_position: Vec3, ) -> Option { let window_size = self.target.get_logical_size(windows, images)?; + + if let Some(ndc_space_coords) = self.world_to_ndc(camera_transform, world_position) { + // Once in NDC space, we can discard the z element and rescale x/y to fit the screen + let screen_space_coords = (ndc_space_coords.truncate() + Vec2::ONE) / 2.0 * window_size; + Some(screen_space_coords) + } else { + None + } + } + /// Given a position in world space, use the camera to compute the screen space coordinates. + pub fn world_to_ndc( + &self, + camera_transform: &GlobalTransform, + world_position: Vec3, + ) -> Option { // Build a transform to convert from world to NDC using camera data let world_to_ndc: Mat4 = self.projection_matrix * camera_transform.compute_matrix().inverse(); @@ -138,10 +153,9 @@ impl Camera { if ndc_space_coords.z < 0.0 || ndc_space_coords.z > 1.0 { return None; } - // Once in NDC space, we can discard the z element and rescale x/y to fit the screen - let screen_space_coords = (ndc_space_coords.truncate() + Vec2::ONE) / 2.0 * window_size; - if !screen_space_coords.is_nan() { - Some(screen_space_coords) + + if !ndc_space_coords.is_nan() { + Some(ndc_space_coords) } else { None } From 051e5027d620e8b7ef7b3c16a642c4a44852a06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 26 Feb 2022 03:06:21 +0100 Subject: [PATCH 2/5] doc --- crates/bevy_render/src/camera/camera.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index a26fdc13d2858..758db280247f0 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -139,7 +139,8 @@ impl Camera { None } } - /// Given a position in world space, use the camera to compute the screen space coordinates. + + /// Given a position in world space, use the camera to compute the normalized device coordinates. pub fn world_to_ndc( &self, camera_transform: &GlobalTransform, From bfb15b3e7b420b3e9feca79230803e70d32b9799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 5 Mar 2022 22:45:54 +0100 Subject: [PATCH 3/5] move z control to screen method --- crates/bevy_render/src/camera/camera.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 758db280247f0..a7089585fee76 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -132,6 +132,11 @@ impl Camera { let window_size = self.target.get_logical_size(windows, images)?; if let Some(ndc_space_coords) = self.world_to_ndc(camera_transform, world_position) { + // NDC z-values outside of 0 < z < 1 are outside the camera frustum and are thus not in screen space + if ndc_space_coords.z < 0.0 || ndc_space_coords.z > 1.0 { + return None; + } + // Once in NDC space, we can discard the z element and rescale x/y to fit the screen let screen_space_coords = (ndc_space_coords.truncate() + Vec2::ONE) / 2.0 * window_size; Some(screen_space_coords) @@ -150,10 +155,6 @@ impl Camera { let world_to_ndc: Mat4 = self.projection_matrix * camera_transform.compute_matrix().inverse(); let ndc_space_coords: Vec3 = world_to_ndc.project_point3(world_position); - // NDC z-values outside of 0 < z < 1 are outside the camera frustum and are thus not in screen space - if ndc_space_coords.z < 0.0 || ndc_space_coords.z > 1.0 { - return None; - } if !ndc_space_coords.is_nan() { Some(ndc_space_coords) From b42f1551f3356ba192f587fa6dc5b7abc2df16db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 5 Mar 2022 22:46:06 +0100 Subject: [PATCH 4/5] add doc --- crates/bevy_render/src/camera/camera.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index a7089585fee76..89a1fa44489df 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -122,6 +122,9 @@ impl Default for DepthCalculation { impl Camera { /// Given a position in world space, use the camera to compute the screen space coordinates. + /// + /// To get the coordinates in Normalized Device Coordinates, you should use + /// [`world_to_ndc`](Self::world_to_ndc). pub fn world_to_screen( &self, windows: &Windows, @@ -138,14 +141,17 @@ impl Camera { } // Once in NDC space, we can discard the z element and rescale x/y to fit the screen - let screen_space_coords = (ndc_space_coords.truncate() + Vec2::ONE) / 2.0 * window_size; - Some(screen_space_coords) + Some((ndc_space_coords.truncate() + Vec2::ONE) / 2.0 * window_size) } else { None } } - /// Given a position in world space, use the camera to compute the normalized device coordinates. + /// Given a position in world space, use the camera to compute the Normalized Device Coordinates. + /// + /// Values returned will be between -1.0 and 1.0 when the position is in screen space. + /// To get the coordinates in the render target dimensions, you should use + /// [`world_to_screen`](Self::world_to_screen). pub fn world_to_ndc( &self, camera_transform: &GlobalTransform, From 95f8b0b12fc9e505830751c5187e2cc413bd1354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Tue, 3 May 2022 21:50:30 +0200 Subject: [PATCH 5/5] ? on option --- crates/bevy_render/src/camera/camera.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 89a1fa44489df..bb3e1fdeb0c8d 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -133,18 +133,14 @@ impl Camera { world_position: Vec3, ) -> Option { let window_size = self.target.get_logical_size(windows, images)?; - - if let Some(ndc_space_coords) = self.world_to_ndc(camera_transform, world_position) { - // NDC z-values outside of 0 < z < 1 are outside the camera frustum and are thus not in screen space - if ndc_space_coords.z < 0.0 || ndc_space_coords.z > 1.0 { - return None; - } - - // Once in NDC space, we can discard the z element and rescale x/y to fit the screen - Some((ndc_space_coords.truncate() + Vec2::ONE) / 2.0 * window_size) - } else { - None + let ndc_space_coords = self.world_to_ndc(camera_transform, world_position)?; + // NDC z-values outside of 0 < z < 1 are outside the camera frustum and are thus not in screen space + if ndc_space_coords.z < 0.0 || ndc_space_coords.z > 1.0 { + return None; } + + // Once in NDC space, we can discard the z element and rescale x/y to fit the screen + Some((ndc_space_coords.truncate() + Vec2::ONE) / 2.0 * window_size) } /// Given a position in world space, use the camera to compute the Normalized Device Coordinates.