diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index c49619c5179ee..42717b57c40fe 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -1217,7 +1217,7 @@ pub fn queue_material_meshes( match material.properties.render_phase_type { RenderPhaseType::Transmissive => { - let distance = rangefinder.distance_translation(&mesh_instance.translation) + let distance = rangefinder.distance(&mesh_instance.center) + material.properties.depth_bias; let Some(draw_function) = material .properties @@ -1304,7 +1304,7 @@ pub fn queue_material_meshes( ); } RenderPhaseType::Transparent => { - let distance = rangefinder.distance_translation(&mesh_instance.translation) + let distance = rangefinder.distance(&mesh_instance.center) + material.properties.depth_bias; let Some(draw_function) = material .properties diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 6e4b3b8aebd8d..538a41416acfa 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -715,11 +715,11 @@ pub struct RenderMeshInstanceGpu { /// uniform building paths. #[deref] pub shared: RenderMeshInstanceShared, - /// The translation of the mesh. + /// The representative position of the mesh instance in world-space. /// - /// This is the only part of the transform that we have to keep on CPU (for - /// distance sorting). - pub translation: Vec3, + /// This world-space center is used as a spatial proxy for view-dependent + /// operations such as distance computation and render-order sorting. + pub center: Vec3, /// The index of the [`MeshInputUniform`] in the buffer. pub current_uniform_index: NonMaxU32, } @@ -740,6 +740,12 @@ pub struct RenderMeshInstanceShared { pub tag: u32, /// Render layers that this mesh instance belongs to. pub render_layers: Option, + /// A representative position of the mesh instance in local space, + /// derived from its axis-aligned bounding box. + /// + /// This value is typically used as a spatial proxy for operations such as + /// view-dependent sorting (e.g., transparent object ordering). + pub center: Vec3, } /// Information that is gathered during the parallel portion of mesh extraction @@ -832,6 +838,7 @@ impl RenderMeshInstanceShared { not_shadow_caster: bool, no_automatic_batching: bool, render_layers: Option<&RenderLayers>, + aabb: Option<&Aabb>, ) -> Self { Self::for_cpu_building( previous_transform, @@ -841,6 +848,7 @@ impl RenderMeshInstanceShared { not_shadow_caster, no_automatic_batching, render_layers, + aabb, ) } @@ -853,6 +861,7 @@ impl RenderMeshInstanceShared { not_shadow_caster: bool, no_automatic_batching: bool, render_layers: Option<&RenderLayers>, + aabb: Option<&Aabb>, ) -> Self { let mut mesh_instance_flags = RenderMeshInstanceFlags::empty(); mesh_instance_flags.set(RenderMeshInstanceFlags::SHADOW_CASTER, !not_shadow_caster); @@ -872,6 +881,7 @@ impl RenderMeshInstanceShared { lightmap_slab_index: None, tag: tag.map_or(0, |i| **i), render_layers: render_layers.cloned(), + center: aabb.map_or(Vec3::ZERO, |aabb| aabb.center.into()), } } @@ -959,12 +969,19 @@ impl RenderMeshInstancesCpu { } fn render_mesh_queue_data(&self, entity: MainEntity) -> Option> { - self.get(&entity) - .map(|render_mesh_instance| RenderMeshQueueData { + self.get(&entity).map(|render_mesh_instance| { + let world_from_local = &render_mesh_instance.transforms.world_from_local; + let center = world_from_local + .matrix3 + .mul_vec3(render_mesh_instance.shared.center) + + world_from_local.translation; + + RenderMeshQueueData { shared: &render_mesh_instance.shared, - translation: render_mesh_instance.transforms.world_from_local.translation, + center, current_uniform_index: InputUniformIndex::default(), - }) + } + }) } /// Inserts the given flags into the render mesh instance data for the given @@ -986,7 +1003,7 @@ impl RenderMeshInstancesGpu { self.get(&entity) .map(|render_mesh_instance| RenderMeshQueueData { shared: &render_mesh_instance.shared, - translation: render_mesh_instance.translation, + center: render_mesh_instance.center, current_uniform_index: InputUniformIndex( render_mesh_instance.current_uniform_index.into(), ), @@ -1191,6 +1208,10 @@ impl RenderMeshInstanceGpuBuilder { // Did the last frame contain this entity as well? let current_uniform_index; + let world_from_local = &self.world_from_local; + let center = + world_from_local.matrix3.mul_vec3(self.shared.center) + world_from_local.translation; + match render_mesh_instances.entry(entity) { Entry::Occupied(mut occupied_entry) => { // Yes, it did. Replace its entry with the new one. @@ -1210,8 +1231,8 @@ impl RenderMeshInstanceGpuBuilder { occupied_entry.replace_entry_with(|_, _| { Some(RenderMeshInstanceGpu { - translation: self.world_from_local.translation, shared: self.shared, + center, current_uniform_index: NonMaxU32::new(current_uniform_index) .unwrap_or_default(), }) @@ -1223,8 +1244,8 @@ impl RenderMeshInstanceGpuBuilder { current_uniform_index = current_input_buffer.add(mesh_input_uniform); vacant_entry.insert(RenderMeshInstanceGpu { - translation: self.world_from_local.translation, shared: self.shared, + center, current_uniform_index: NonMaxU32::new(current_uniform_index) .unwrap_or_default(), }); @@ -1296,8 +1317,11 @@ pub struct RenderMeshQueueData<'a> { /// General information about the mesh instance. #[deref] pub shared: &'a RenderMeshInstanceShared, - /// The translation of the mesh instance. - pub translation: Vec3, + /// The representative position of the mesh instance in world-space. + /// + /// This world-space center is used as a spatial proxy for view-dependent + /// operations such as distance computation and render-order sorting. + pub center: Vec3, /// The index of the [`MeshInputUniform`] in the GPU buffer for this mesh /// instance. pub current_uniform_index: InputUniformIndex, @@ -1334,6 +1358,7 @@ pub fn extract_meshes_for_cpu_building( Has, Has, Option<&RenderLayers>, + Option<&Aabb>, )>, >, ) { @@ -1354,6 +1379,7 @@ pub fn extract_meshes_for_cpu_building( no_automatic_batching, visibility_range, render_layers, + aabb, )| { if !view_visibility.get() { return; @@ -1387,6 +1413,7 @@ pub fn extract_meshes_for_cpu_building( not_shadow_caster, no_automatic_batching, render_layers, + aabb, ); let world_from_local = transform.affine(); @@ -1593,6 +1620,7 @@ fn extract_mesh_for_gpu_building( not_shadow_caster, no_automatic_batching, render_layers, + aabb, ); let lightmap_uv_rect = pack_lightmap_uv_rect(lightmap.map(|lightmap| lightmap.uv_rect)); diff --git a/crates/bevy_render/src/render_phase/rangefinder.rs b/crates/bevy_render/src/render_phase/rangefinder.rs index 0a93651a41671..bc4fa303df865 100644 --- a/crates/bevy_render/src/render_phase/rangefinder.rs +++ b/crates/bevy_render/src/render_phase/rangefinder.rs @@ -15,36 +15,25 @@ impl ViewRangefinder3d { } } - /// Calculates the distance, or view-space `Z` value, for the given `translation`. + /// Calculates the distance, or view-space `Z` value, for the given world-space `position`. #[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.view_from_world_row_2.dot(translation.extend(1.0)) - } - - /// Calculates the distance, or view-space `Z` value, 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.view_from_world_row_2.dot(transform.col(3)) + pub fn distance(&self, position: &Vec3) -> f32 { + // NOTE: row 2 of the inverse view matrix dotted with the world-space position + // gives the z component of the point in view-space + self.view_from_world_row_2.dot(position.extend(1.0)) } } #[cfg(test)] mod tests { use super::ViewRangefinder3d; - use bevy_math::{Affine3A, Mat4, Vec3}; + use bevy_math::{Affine3A, Vec3}; #[test] fn distance() { let view_matrix = Affine3A::from_translation(Vec3::new(0.0, 0.0, -1.0)); let rangefinder = ViewRangefinder3d::from_world_from_view(&view_matrix); - 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 - ); + assert_eq!(rangefinder.distance(&Vec3::new(0., 0., 0.)), 1.0); + assert_eq!(rangefinder.distance(&Vec3::new(0., 0., 1.)), 2.0); } } diff --git a/examples/shader_advanced/custom_render_phase.rs b/examples/shader_advanced/custom_render_phase.rs index 866e96adca9da..8fd1cdc837539 100644 --- a/examples/shader_advanced/custom_render_phase.rs +++ b/examples/shader_advanced/custom_render_phase.rs @@ -549,7 +549,7 @@ fn queue_custom_meshes( continue; } }; - let distance = rangefinder.distance_translation(&mesh_instance.translation); + let distance = rangefinder.distance(&mesh_instance.center); // At this point we have all the data we need to create a phase item and add it to our // phase custom_phase.add(Stencil3d { diff --git a/examples/shader_advanced/custom_shader_instancing.rs b/examples/shader_advanced/custom_shader_instancing.rs index 4be7a37c2bda4..b9d01fdf481e7 100644 --- a/examples/shader_advanced/custom_shader_instancing.rs +++ b/examples/shader_advanced/custom_shader_instancing.rs @@ -161,7 +161,7 @@ fn queue_custom( entity: (entity, *main_entity), pipeline, draw_function: draw_custom, - distance: rangefinder.distance_translation(&mesh_instance.translation), + distance: rangefinder.distance(&mesh_instance.center), batch_range: 0..1, extra_index: PhaseItemExtraIndex::None, indexed: true,