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

Code before:
    pub fn depth_ndc_to_view_z(&self, ndc_depth: f32) -> f32 {
        let near = self.clip_from_view().w_axis.z; // [3][2]
        -near / ndc_depth
    }

    /// Converts the depth in Normalized Device Coordinates
    /// to linear view z for orthographic projections.
    ///
    /// Note: Depth values in front of the camera will be negative as -z is forward
    pub fn depth_ndc_to_view_z_2d(&self, ndc_depth: f32) -> f32 {
        -(self.clip_from_view().w_axis.z - ndc_depth) / self.clip_from_view().z_axis.z
        //                       [3][2]                                         [2][2]
    }

    /// Converts a position in viewport coordinates to NDC.
    pub fn viewport_to_ndc(
        &self,
        viewport_position: Vec2,
    ) -> Result<Vec2, 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;
        Ok(rect_relative * 2. - Vec2::ONE)
    }
}

/// Control how this [`Camera`] outputs once rendering is completed.
#[derive(Debug, Clone, Copy, Reflect)]
pub enum CameraOutputMode {
    /// Writes the camera output to configured render target.
    Write {
        /// The blend state that will be used by the pipeline that writes the intermediate render textures to the final render target texture.
        /// If not set, the output will be written as-is, ignoring `clear_color` and the existing data in the final render target texture.
        blend_state: Option<BlendState>,
        /// The clear color operation to perform on the final render target texture.
        clear_color: ClearColorConfig,
    },
    /// Skips writing the camera output to the configured render target. The output will remain in the
    /// Render Target's "intermediate" textures, which a camera with a higher order should write to the render target
    /// using [`CameraOutputMode::Write`]. The "skip" mode can easily prevent render results from being displayed, or cause
    /// them to be lost. Only use this if you know what you are doing!
    /// In camera setups with multiple active cameras rendering to the same [`RenderTarget`], the Skip mode can be used to remove
    /// unnecessary / redundant writes to the final output texture, removing unnecessary render passes.
    Skip,
}

impl Default for CameraOutputMode {
    fn default() -> Self {

Review comment (suggestion):
can you keep the subtraction-less flip version because it avoids a bit of precision loss
```suggestion
        let mut ndc_xy = rect_relative * 2. - Vec2::ONE;
        // Flip the Y co-ordinate from the top to the bottom to enter NDC.
        ndc_xy.y = -ndc_xy.y;
        Ok(ndc_xy)
```

Code after:
    pub fn depth_ndc_to_view_z(&self, ndc_depth: f32) -> f32 {
        let near = self.clip_from_view().w_axis.z; // [3][2]
        -near / ndc_depth
    }

    /// Converts the depth in Normalized Device Coordinates
    /// to linear view z for orthographic projections.
    ///
    /// Note: Depth values in front of the camera will be negative as -z is forward
    pub fn depth_ndc_to_view_z_2d(&self, ndc_depth: f32) -> f32 {
        -(self.clip_from_view().w_axis.z - ndc_depth) / self.clip_from_view().z_axis.z
        //                       [3][2]                                         [2][2]
    }

    /// Converts a position in viewport coordinates to NDC.
    pub fn viewport_to_ndc(
        &self,
        viewport_position: Vec2,
    ) -> Result<Vec2, ViewportConversionError> {
        let target_rect = self
            .logical_viewport_rect()
            .ok_or(ViewportConversionError::NoViewportSize)?;
        let rect_relative = (viewport_position - target_rect.min) / target_rect.size();
        let mut ndc = rect_relative * 2. - Vec2::ONE;
        // Flip the Y co-ordinate from the top to the bottom to enter NDC.
        ndc.y = -ndc.y;
        Ok(ndc)
    }
}

/// Control how this [`Camera`] outputs once rendering is completed.
#[derive(Debug, Clone, Copy, Reflect)]
pub enum CameraOutputMode {
    /// Writes the camera output to configured render target.
    Write {
        /// The blend state that will be used by the pipeline that writes the intermediate render textures to the final render target texture.
        /// If not set, the output will be written as-is, ignoring `clear_color` and the existing data in the final render target texture.
        blend_state: Option<BlendState>,
        /// The clear color operation to perform on the final render target texture.
        clear_color: ClearColorConfig,
    },
    /// Skips writing the camera output to the configured render target. The output will remain in the
    /// Render Target's "intermediate" textures, which a camera with a higher order should write to the render target
    /// using [`CameraOutputMode::Write`]. The "skip" mode can easily prevent render results from being displayed, or cause
    /// them to be lost. Only use this if you know what you are doing!
    /// In camera setups with multiple active cameras rendering to the same [`RenderTarget`], the Skip mode can be used to remove
    /// unnecessary / redundant writes to the final output texture, removing unnecessary render passes.
    Skip,
}

impl Default for CameraOutputMode {