From 18e4fa8cdfaa34ee0f1f5987a899eed9da4a1d4c Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Thu, 21 Jan 2021 17:49:29 -0800 Subject: [PATCH] world coords to screen space (#1258) Add Camera::world_to_screen to convert world coordinates to screen space --- crates/bevy_render/src/camera/camera.rs | 27 ++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index ba1636228c..05b2dbc116 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -1,8 +1,9 @@ use super::CameraProjection; use bevy_app::prelude::EventReader; use bevy_ecs::{Added, Component, Entity, Query, QuerySet, Res}; -use bevy_math::Mat4; +use bevy_math::{Mat4, Vec2, Vec3}; use bevy_reflect::{Reflect, ReflectComponent}; +use bevy_transform::components::GlobalTransform; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; #[derive(Default, Debug, Reflect)] @@ -28,6 +29,30 @@ impl Default for DepthCalculation { } } +impl Camera { + /// Given a position in world space, use the camera to compute the screen space coordinates. + pub fn world_to_screen( + &self, + windows: &Windows, + camera_transform: &GlobalTransform, + world_position: Vec3, + ) -> Option { + let window = windows.get(self.window)?; + let window_size = Vec2::new(window.width(), window.height()); + // 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(); + let ndc_space_coords: Vec3 = world_to_ndc.transform_point3(world_position); + // NDC z-values outside of 0 < z < 1 are behind the camera 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) + } +} + pub fn camera_system( mut window_resized_events: EventReader, mut window_created_events: EventReader,