Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect distance given by ViewRangefinder3d #11993

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions crates/bevy_render/src/render_phase/rangefinder.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
use bevy_math::{Mat4, Vec3, Vec4};

/// A distance calculator for the draw order of [`PhaseItem`](crate::render_phase::PhaseItem)s.
/// A depth calculator for the draw order of [`PhaseItem`](crate::render_phase::PhaseItem)s.
pub struct ViewRangefinder3d {
inverse_view_row_2: Vec4,
view_proj_row_2: Vec4,
view_proj_row_3: Vec4,
}

impl ViewRangefinder3d {
/// Creates a 3D rangefinder for a view matrix.
pub fn from_view_matrix(view_matrix: &Mat4) -> ViewRangefinder3d {
let inverse_view_matrix = view_matrix.inverse();

/// Creates a 3D rangefinder for a view-projection matrix.
pub fn from_view_proj_matrix(view_proj_matrix: &Mat4) -> ViewRangefinder3d {
ViewRangefinder3d {
inverse_view_row_2: inverse_view_matrix.row(2),
view_proj_row_2: view_proj_matrix.row(2),
view_proj_row_3: view_proj_matrix.row(3),
}
}

/// Calculates the distance, or view-space `Z` value, for the given `translation`.
/// Calculates the depth for the given `translation`.
#[inline]
pub fn distance_translation(&self, translation: &Vec3) -> f32 {
// NOTE: row 2 of the inverse view matrix dotted with the translation from the model matrix
// gives the z component of translation of the mesh in view-space
self.inverse_view_row_2.dot(translation.extend(1.0))
// NOTE: row 2 of the view-projection matrix dotted with the translation from the model matrix
// gives the z component of translation of the mesh in clip-space.
// However, as we are using an infinite projection matrix for perspective projection,
// this value is meaningless.
let position = translation.extend(1.0);
self.view_proj_row_2.dot(position) / self.view_proj_row_3.dot(position)
}

/// Calculates the distance, or view-space `Z` value, for the given `transform`.
/// Calculates the depth for the given `transform`.
#[inline]
pub fn distance(&self, transform: &Mat4) -> f32 {
// NOTE: row 2 of the inverse view matrix dotted with column 3 of the model matrix
// gives the z component of translation of the mesh in view-space
self.inverse_view_row_2.dot(transform.col(3))
let position = transform.col(3);
self.view_proj_row_2.dot(position) / self.view_proj_row_3.dot(position)
}
}

Expand All @@ -39,8 +41,8 @@ mod tests {

#[test]
fn distance() {
let view_matrix = Mat4::from_translation(Vec3::new(0.0, 0.0, -1.0));
let rangefinder = ViewRangefinder3d::from_view_matrix(&view_matrix);
let view_proj_matrix = Mat4::from_translation(Vec3::new(0.0, 0.0, -1.0));
let rangefinder = ViewRangefinder3d::from_view_proj_matrix(&view_proj_matrix);
assert_eq!(rangefinder.distance(&Mat4::IDENTITY), 1.0);
assert_eq!(
rangefinder.distance(&Mat4::from_translation(Vec3::new(0.0, 0.0, 1.0))),
Expand Down
7 changes: 6 additions & 1 deletion crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ pub struct ExtractedView {
impl ExtractedView {
/// Creates a 3D rangefinder for a view
pub fn rangefinder3d(&self) -> ViewRangefinder3d {
ViewRangefinder3d::from_view_matrix(&self.transform.compute_matrix())
if let Some(vp) = &self.view_projection {
ViewRangefinder3d::from_view_proj_matrix(vp)
} else {
let vp = self.projection * self.transform.compute_matrix().inverse();
ViewRangefinder3d::from_view_proj_matrix(&vp)
}
}
}

Expand Down
Loading