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

[Merged by Bors] - Add ViewRangefinder3d to reduce boilerplate when enqueuing standard 3D PhaseItems. #5014

Closed
wants to merge 10 commits into from
19 changes: 13 additions & 6 deletions crates/bevy_core_pipeline/src/core_3d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub mod graph {
}
}

use std::cmp::Reverse;

pub use camera_3d::*;
pub use main_pass_3d_node::*;

Expand Down Expand Up @@ -87,11 +89,12 @@ pub struct Opaque3d {
}

impl PhaseItem for Opaque3d {
type SortKey = FloatOrd;
// NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort.
type SortKey = Reverse<FloatOrd>;

#[inline]
fn sort_key(&self) -> Self::SortKey {
FloatOrd(self.distance)
Reverse(FloatOrd(self.distance))
}

#[inline]
Expand All @@ -101,7 +104,8 @@ impl PhaseItem for Opaque3d {

#[inline]
fn sort(items: &mut [Self]) {
radsort::sort_by_key(items, |item| item.distance);
// Key negated to match reversed SortKey ordering
radsort::sort_by_key(items, |item| -item.distance);
}
}

Expand All @@ -127,11 +131,12 @@ pub struct AlphaMask3d {
}

impl PhaseItem for AlphaMask3d {
type SortKey = FloatOrd;
// NOTE: Values increase towards the camera. Front-to-back ordering for alpha mask means we need a descending sort.
type SortKey = Reverse<FloatOrd>;

#[inline]
fn sort_key(&self) -> Self::SortKey {
FloatOrd(self.distance)
Reverse(FloatOrd(self.distance))
}

#[inline]
Expand All @@ -141,7 +146,8 @@ impl PhaseItem for AlphaMask3d {

#[inline]
fn sort(items: &mut [Self]) {
radsort::sort_by_key(items, |item| item.distance);
// Key negated to match reversed SortKey ordering
radsort::sort_by_key(items, |item| -item.distance);
}
}

Expand All @@ -167,6 +173,7 @@ pub struct Transparent3d {
}

impl PhaseItem for Transparent3d {
// NOTE: Values increase towards the camera. Back-to-front ordering for transparent means we need an ascending sort.
type SortKey = FloatOrd;

#[inline]
Expand Down
26 changes: 6 additions & 20 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use bevy_render::{
extract_component::ExtractComponentPlugin,
mesh::{Mesh, MeshVertexBufferLayout},
prelude::Image,
rangefinder::ViewRangefinder3d,
render_asset::{PrepareAssetLabel, RenderAssets},
render_phase::{
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
Expand Down Expand Up @@ -348,8 +349,7 @@ pub fn queue_material_meshes<M: Material>(
.get_id::<DrawMaterial<M>>()
.unwrap();

let inverse_view_matrix = view.transform.compute_matrix().inverse();
let inverse_view_row_2 = inverse_view_matrix.row(2);
let rangefinder = ViewRangefinder3d::from_view(view);
let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples);

for visible_entity in &visible_entities.entities {
Expand Down Expand Up @@ -383,45 +383,31 @@ pub fn queue_material_meshes<M: Material>(
}
};

// 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
let mesh_z = inverse_view_row_2.dot(mesh_uniform.transform.col(3))
let distance = rangefinder.distance(&mesh_uniform.transform)
+ material.properties.depth_bias;
match alpha_mode {
AlphaMode::Opaque => {
opaque_phase.add(Opaque3d {
entity: *visible_entity,
draw_function: draw_opaque_pbr,
pipeline: pipeline_id,
// NOTE: Front-to-back ordering for opaque with ascending sort means near should have the
// lowest sort key and getting further away should increase. As we have
// -z in front of the camera, values in view space decrease away from the
// camera. Flipping the sign of mesh_z results in the correct front-to-back ordering
distance: -mesh_z,
distance,
});
}
AlphaMode::Mask(_) => {
alpha_mask_phase.add(AlphaMask3d {
entity: *visible_entity,
draw_function: draw_alpha_mask_pbr,
pipeline: pipeline_id,
// NOTE: Front-to-back ordering for alpha mask with ascending sort means near should have the
// lowest sort key and getting further away should increase. As we have
// -z in front of the camera, values in view space decrease away from the
// camera. Flipping the sign of mesh_z results in the correct front-to-back ordering
distance: -mesh_z,
distance,
});
}
AlphaMode::Blend => {
transparent_phase.add(Transparent3d {
entity: *visible_entity,
draw_function: draw_transparent_pbr,
pipeline: pipeline_id,
// NOTE: Back-to-front ordering for transparent with ascending sort means far should have the
// lowest sort key and getting closer should increase. As we have
// -z in front of the camera, the largest distance is -far with values increasing toward the
// camera. As such we can just use mesh_z as the distance
distance: mesh_z,
distance,
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_pbr/src/wireframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bevy_core_pipeline::core_3d::Opaque3d;
use bevy_ecs::{prelude::*, reflect::ReflectComponent};
use bevy_reflect::std_traits::ReflectDefault;
use bevy_reflect::{Reflect, TypeUuid};
use bevy_render::rangefinder::ViewRangefinder3d;
use bevy_render::{
extract_resource::{ExtractResource, ExtractResourcePlugin},
mesh::{Mesh, MeshVertexBufferLayout},
Expand Down Expand Up @@ -117,8 +118,7 @@ fn queue_wireframes(
.unwrap();
let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples);
for (view, visible_entities, mut opaque_phase) in views.iter_mut() {
let view_matrix = view.transform.compute_matrix();
let view_row_2 = view_matrix.row(2);
let rangefinder = ViewRangefinder3d::from_view(view);
komadori marked this conversation as resolved.
Show resolved Hide resolved

let add_render_phase =
|(entity, mesh_handle, mesh_uniform): (Entity, &Handle<Mesh>, &MeshUniform)| {
Expand All @@ -142,7 +142,7 @@ fn queue_wireframes(
entity,
pipeline: pipeline_id,
draw_function: draw_custom,
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
distance: rangefinder.distance(&mesh_uniform.transform),
});
}
};
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod extract_component;
pub mod extract_resource;
pub mod mesh;
pub mod primitives;
pub mod rangefinder;
pub mod render_asset;
pub mod render_graph;
pub mod render_phase;
Expand Down
53 changes: 53 additions & 0 deletions crates/bevy_render/src/rangefinder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use bevy_math::{Mat4, Vec4};

use crate::view::ExtractedView;

/// A distance calculator for the draw order of [`PhaseItem`](crate::render_phase::PhaseItem)s.
pub struct ViewRangefinder3d {
komadori marked this conversation as resolved.
Show resolved Hide resolved
komadori marked this conversation as resolved.
Show resolved Hide resolved
inverse_view_row_2: Vec4,
}

impl ViewRangefinder3d {
/// Creates a rangefinder for a view
pub fn from_view(view: &ExtractedView) -> ViewRangefinder3d {
komadori marked this conversation as resolved.
Show resolved Hide resolved
let inverse_view_matrix = view.transform.compute_matrix().inverse();
ViewRangefinder3d {
inverse_view_row_2: inverse_view_matrix.row(2),
}
}

/// Calculates the distance, or view-space Z value, for a transform
pub fn distance(&self, transform: &Mat4) -> f32 {
komadori marked this conversation as resolved.
Show resolved Hide resolved
// 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))
}
}

#[cfg(test)]
mod tests {
use bevy_math::{Mat4, Vec3};
use bevy_transform::prelude::Transform;

use crate::view::ExtractedView;

use super::ViewRangefinder3d;

#[test]
fn distance() {
let view = ExtractedView {
projection: Mat4::IDENTITY,
transform: Transform::identity()
.with_translation(Vec3::new(0.0, 0.0, -1.0))
.into(),
width: 0,
height: 0,
};
let rangefinder = ViewRangefinder3d::from_view(&view);
assert_eq!(rangefinder.distance(&Mat4::IDENTITY), 1.0);
assert_eq!(
rangefinder.distance(&Mat4::from_translation(Vec3::new(0.0, 0.0, 1.0))),
2.0
);
}
}
6 changes: 3 additions & 3 deletions examples/shader/animate_shader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use bevy::{
prelude::*,
render::{
mesh::MeshVertexBufferLayout,
rangefinder::ViewRangefinder3d,
render_asset::RenderAssets,
render_phase::{
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
Expand Down Expand Up @@ -116,8 +117,7 @@ fn queue_custom(
| MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList);

for (view, mut transparent_phase) in views.iter_mut() {
let view_matrix = view.transform.compute_matrix();
let view_row_2 = view_matrix.row(2);
let rangefinder = ViewRangefinder3d::from_view(view);
for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() {
if let Some(mesh) = render_meshes.get(mesh_handle) {
let pipeline = pipelines
Expand All @@ -127,7 +127,7 @@ fn queue_custom(
entity,
pipeline,
draw_function: draw_custom,
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
distance: rangefinder.distance(&mesh_uniform.transform),
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions examples/shader/shader_instancing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bevy::{
render::{
extract_component::{ExtractComponent, ExtractComponentPlugin},
mesh::{GpuBufferInfo, MeshVertexBufferLayout},
rangefinder::ViewRangefinder3d,
render_asset::RenderAssets,
render_phase::{
AddRenderCommand, DrawFunctions, EntityRenderCommand, RenderCommandResult, RenderPhase,
Expand Down Expand Up @@ -117,8 +118,7 @@ fn queue_custom(
let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples);

for (view, mut transparent_phase) in views.iter_mut() {
let view_matrix = view.transform.compute_matrix();
let view_row_2 = view_matrix.row(2);
let rangefinder = ViewRangefinder3d::from_view(view);
for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() {
if let Some(mesh) = meshes.get(mesh_handle) {
let key =
Expand All @@ -130,7 +130,7 @@ fn queue_custom(
entity,
pipeline,
draw_function: draw_custom,
distance: view_row_2.dot(mesh_uniform.transform.col(3)),
distance: rangefinder.distance(&mesh_uniform.transform),
});
}
}
Expand Down