Repository: bevyengine/bevy
File: crates/bevy_camera/src/camera.rs (Rust)

Code before:
    /// # let mut app = App::new();
    /// // Run the system after transform propagation so the camera's global transform is up-to-date.
    /// app.add_systems(PostUpdate, system.after(TransformSystems::Propagate));
    /// ```
    ///
    /// # Panics
    ///
    /// Will panic if the camera's projection matrix is invalid (has a determinant of 0) and
    /// `glam_assert` is enabled (see [`ndc_to_world`](Self::ndc_to_world).
    pub fn viewport_to_world(
        &self,
        camera_transform: &GlobalTransform,
        viewport_position: Vec2,
    ) -> Result<Ray3d, ViewportConversionError> {
        let target_rect = self
            .logical_viewport_rect()
            .ok_or(ViewportConversionError::NoViewportSize)?;
        let mut rect_relative = (viewport_position - target_rect.min) / target_rect.size();
        // Flip the Y co-ordinate origin from the top to the bottom.
        rect_relative.y = 1.0 - rect_relative.y;

        let ndc_point_near = (rect_relative * 2. - Vec2::ONE).extend(1.0).into();
        let view_point_near = self
            .computed
            .clip_from_view
            .inverse()
            .project_point3a(ndc_point_near);
        let world_dir_near = camera_transform
            .affine()
            .transform_vector3a(view_point_near);
        let origin: Vec3 = (world_dir_near + camera_transform.affine().translation).into();
        if origin.is_nan() {
            return Err(ViewportConversionError::InvalidData);
        }

        Dir3::new(world_dir_near.into())
            .map_err(|_| ViewportConversionError::InvalidData)
            .map(|direction| Ray3d { origin, direction })
    }

    /// Returns a 2D world position computed from a position on this [`Camera`]'s viewport.
    ///
    /// Useful for 2D cameras and other cameras with an orthographic projection pointing along the Z axis.
    ///
    /// To get the world space coordinates with Normalized Device Coordinates, you should use
    /// [`ndc_to_world`](Self::ndc_to_world).
    ///
    /// # Example
    /// ```no_run
    /// # use bevy_window::Window;
    /// # use bevy_ecs::prelude::*;

Review comment (performance):
```suggestion
        // We multiply the point by `view_from_clip` and then `world_from_view` in sequence to avoid the precision loss
        // (and performance penalty) incurred by pre-composing an affine transform with a projective transform.
        // Additionally, we avoid adding and subtracting translation to the direction component to maintain precision.
        let view_point_near = self
```

Code after:
    /// # let mut app = App::new();
    /// // Run the system after transform propagation so the camera's global transform is up-to-date.
    /// app.add_systems(PostUpdate, system.after(TransformSystems::Propagate));
    /// ```
    ///
    /// # Panics
    ///
    /// Will panic if the camera's projection matrix is invalid (has a determinant of 0) and
    /// `glam_assert` is enabled (see [`ndc_to_world`](Self::ndc_to_world).
    pub fn viewport_to_world(
        &self,
        camera_transform: &GlobalTransform,
        viewport_position: Vec2,
    ) -> Result<Ray3d, ViewportConversionError> {
        let target_rect = self
            .logical_viewport_rect()
            .ok_or(ViewportConversionError::NoViewportSize)?;
        let mut rect_relative = (viewport_position - target_rect.min) / target_rect.size();
        // Flip the Y co-ordinate origin from the top to the bottom.
        rect_relative.y = 1.0 - rect_relative.y;

        let ndc_point_near = (rect_relative * 2. - Vec2::ONE).extend(1.0).into();
        // We multiply the point by `view_from_clip` and then `world_from_view` in sequence to avoid the precision loss
        // (and performance penalty) incurred by pre-composing an affine transform with a projective transform.
        // Additionally, we avoid adding and subtracting translation to the direction component to maintain precision.
        let view_point_near = self
            .computed
            .clip_from_view
            .inverse()
            .project_point3a(ndc_point_near);
        let world_dir_near = camera_transform
            .affine()
            .transform_vector3a(view_point_near);
        let origin: Vec3 = (world_dir_near + camera_transform.affine().translation).into();
        if origin.is_nan() {
            return Err(ViewportConversionError::InvalidData);
        }

        Dir3::new(world_dir_near.into())
            .map_err(|_| ViewportConversionError::InvalidData)
            .map(|direction| Ray3d { origin, direction })
    }

    /// Returns a 2D world position computed from a position on this [`Camera`]'s viewport.
    ///
    /// Useful for 2D cameras and other cameras with an orthographic projection pointing along the Z axis.
    ///
    /// To get the world space coordinates with Normalized Device Coordinates, you should use
    /// [`ndc_to_world`](Self::ndc_to_world).
    ///
    /// # Example