mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 15:14:50 +00:00
sort alpha masked pipelines by pipeline & mesh instead of by distance (#12117)
# Objective - followup to https://github.com/bevyengine/bevy/pull/11671 - I forgot to change the alpha masked phases. ## Solution - Change the sorting for alpha mask phases to sort by pipeline+mesh instead of distance, for much better batching for alpha masked materials. I also fixed some docs that I missed in the previous PR. --- ## Changelog - Alpha masked materials are now sorted by pipeline and mesh.
This commit is contained in:
parent
a463d0c637
commit
78b6fa1f1b
5 changed files with 31 additions and 39 deletions
|
@ -38,7 +38,7 @@ pub mod graph {
|
|||
// PERF: vulkan docs recommend using 24 bit depth for better performance
|
||||
pub const CORE_3D_DEPTH_FORMAT: TextureFormat = TextureFormat::Depth32Float;
|
||||
|
||||
use std::{cmp::Reverse, ops::Range};
|
||||
use std::ops::Range;
|
||||
|
||||
use bevy_asset::AssetId;
|
||||
pub use camera_3d::*;
|
||||
|
@ -242,7 +242,7 @@ impl CachedRenderPipelinePhaseItem for Opaque3d {
|
|||
}
|
||||
|
||||
pub struct AlphaMask3d {
|
||||
pub distance: f32,
|
||||
pub asset_id: AssetId<Mesh>,
|
||||
pub pipeline: CachedRenderPipelineId,
|
||||
pub entity: Entity,
|
||||
pub draw_function: DrawFunctionId,
|
||||
|
@ -251,8 +251,7 @@ pub struct AlphaMask3d {
|
|||
}
|
||||
|
||||
impl PhaseItem for AlphaMask3d {
|
||||
// NOTE: Values increase towards the camera. Front-to-back ordering for alpha mask means we need a descending sort.
|
||||
type SortKey = Reverse<FloatOrd>;
|
||||
type SortKey = (usize, AssetId<Mesh>);
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
|
@ -261,7 +260,8 @@ impl PhaseItem for AlphaMask3d {
|
|||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
Reverse(FloatOrd(self.distance))
|
||||
// Sort by pipeline, then by mesh to massively decrease drawcall counts in real scenes.
|
||||
(self.pipeline.id(), self.asset_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -271,8 +271,7 @@ impl PhaseItem for AlphaMask3d {
|
|||
|
||||
#[inline]
|
||||
fn sort(items: &mut [Self]) {
|
||||
// Key negated to match reversed SortKey ordering
|
||||
radsort::sort_by_key(items, |item| -item.distance);
|
||||
items.sort_unstable_by_key(Self::sort_key);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
pub mod copy_lighting_id;
|
||||
pub mod node;
|
||||
|
||||
use std::{cmp::Reverse, ops::Range};
|
||||
use std::ops::Range;
|
||||
|
||||
use bevy_asset::AssetId;
|
||||
use bevy_ecs::prelude::*;
|
||||
|
@ -10,7 +10,7 @@ use bevy_render::{
|
|||
render_phase::{CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItem},
|
||||
render_resource::{CachedRenderPipelineId, TextureFormat},
|
||||
};
|
||||
use bevy_utils::{nonmax::NonMaxU32, FloatOrd};
|
||||
use bevy_utils::nonmax::NonMaxU32;
|
||||
|
||||
pub const DEFERRED_PREPASS_FORMAT: TextureFormat = TextureFormat::Rgba32Uint;
|
||||
pub const DEFERRED_LIGHTING_PASS_ID_FORMAT: TextureFormat = TextureFormat::R8Uint;
|
||||
|
@ -18,7 +18,7 @@ pub const DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT: TextureFormat = TextureFormat:
|
|||
|
||||
/// Opaque phase of the 3D Deferred pass.
|
||||
///
|
||||
/// Sorted front-to-back by the z-distance in front of the camera.
|
||||
/// Sorted by pipeline, then by mesh to improve batching.
|
||||
///
|
||||
/// Used to render all 3D meshes with materials that have no transparency.
|
||||
pub struct Opaque3dDeferred {
|
||||
|
@ -84,11 +84,11 @@ impl CachedRenderPipelinePhaseItem for Opaque3dDeferred {
|
|||
|
||||
/// Alpha mask phase of the 3D Deferred pass.
|
||||
///
|
||||
/// Sorted front-to-back by the z-distance in front of the camera.
|
||||
/// Sorted by pipeline, then by mesh to improve batching.
|
||||
///
|
||||
/// Used to render all meshes with a material with an alpha mask.
|
||||
pub struct AlphaMask3dDeferred {
|
||||
pub distance: f32,
|
||||
pub asset_id: AssetId<Mesh>,
|
||||
pub entity: Entity,
|
||||
pub pipeline_id: CachedRenderPipelineId,
|
||||
pub draw_function: DrawFunctionId,
|
||||
|
@ -97,8 +97,7 @@ pub struct AlphaMask3dDeferred {
|
|||
}
|
||||
|
||||
impl PhaseItem for AlphaMask3dDeferred {
|
||||
// NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort.
|
||||
type SortKey = Reverse<FloatOrd>;
|
||||
type SortKey = (usize, AssetId<Mesh>);
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
|
@ -107,7 +106,8 @@ impl PhaseItem for AlphaMask3dDeferred {
|
|||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
Reverse(FloatOrd(self.distance))
|
||||
// Sort by pipeline, then by mesh to massively decrease drawcall counts in real scenes.
|
||||
(self.pipeline_id.id(), self.asset_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -117,8 +117,7 @@ impl PhaseItem for AlphaMask3dDeferred {
|
|||
|
||||
#[inline]
|
||||
fn sort(items: &mut [Self]) {
|
||||
// Key negated to match reversed SortKey ordering
|
||||
radsort::sort_by_key(items, |item| -item.distance);
|
||||
items.sort_unstable_by_key(Self::sort_key);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
pub mod node;
|
||||
|
||||
use std::{cmp::Reverse, ops::Range};
|
||||
use std::ops::Range;
|
||||
|
||||
use bevy_asset::AssetId;
|
||||
use bevy_ecs::prelude::*;
|
||||
|
@ -38,7 +38,7 @@ use bevy_render::{
|
|||
render_resource::{CachedRenderPipelineId, Extent3d, TextureFormat, TextureView},
|
||||
texture::ColorAttachment,
|
||||
};
|
||||
use bevy_utils::{nonmax::NonMaxU32, FloatOrd};
|
||||
use bevy_utils::nonmax::NonMaxU32;
|
||||
|
||||
pub const NORMAL_PREPASS_FORMAT: TextureFormat = TextureFormat::Rgb10a2Unorm;
|
||||
pub const MOTION_VECTOR_PREPASS_FORMAT: TextureFormat = TextureFormat::Rg16Float;
|
||||
|
@ -107,7 +107,7 @@ impl ViewPrepassTextures {
|
|||
|
||||
/// Opaque phase of the 3D prepass.
|
||||
///
|
||||
/// Sorted front-to-back by the z-distance in front of the camera.
|
||||
/// Sorted by pipeline, then by mesh to improve batching.
|
||||
///
|
||||
/// Used to render all 3D meshes with materials that have no transparency.
|
||||
pub struct Opaque3dPrepass {
|
||||
|
@ -173,11 +173,11 @@ impl CachedRenderPipelinePhaseItem for Opaque3dPrepass {
|
|||
|
||||
/// Alpha mask phase of the 3D prepass.
|
||||
///
|
||||
/// Sorted front-to-back by the z-distance in front of the camera.
|
||||
/// Sorted by pipeline, then by mesh to improve batching.
|
||||
///
|
||||
/// Used to render all meshes with a material with an alpha mask.
|
||||
pub struct AlphaMask3dPrepass {
|
||||
pub distance: f32,
|
||||
pub asset_id: AssetId<Mesh>,
|
||||
pub entity: Entity,
|
||||
pub pipeline_id: CachedRenderPipelineId,
|
||||
pub draw_function: DrawFunctionId,
|
||||
|
@ -186,8 +186,7 @@ pub struct AlphaMask3dPrepass {
|
|||
}
|
||||
|
||||
impl PhaseItem for AlphaMask3dPrepass {
|
||||
// NOTE: Values increase towards the camera. Front-to-back ordering for opaque means we need a descending sort.
|
||||
type SortKey = Reverse<FloatOrd>;
|
||||
type SortKey = (usize, AssetId<Mesh>);
|
||||
|
||||
#[inline]
|
||||
fn entity(&self) -> Entity {
|
||||
|
@ -196,7 +195,8 @@ impl PhaseItem for AlphaMask3dPrepass {
|
|||
|
||||
#[inline]
|
||||
fn sort_key(&self) -> Self::SortKey {
|
||||
Reverse(FloatOrd(self.distance))
|
||||
// Sort by pipeline, then by mesh to massively decrease drawcall counts in real scenes.
|
||||
(self.pipeline_id.id(), self.asset_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -206,8 +206,7 @@ impl PhaseItem for AlphaMask3dPrepass {
|
|||
|
||||
#[inline]
|
||||
fn sort(items: &mut [Self]) {
|
||||
// Key negated to match reversed SortKey ordering
|
||||
radsort::sort_by_key(items, |item| -item.distance);
|
||||
items.sort_unstable_by_key(Self::sort_key);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -672,10 +672,10 @@ pub fn queue_material_meshes<M: Material>(
|
|||
}
|
||||
}
|
||||
AlphaMode::Mask(_) => {
|
||||
if material.properties.reads_view_transmission_texture {
|
||||
let distance = rangefinder
|
||||
.distance_translation(&mesh_instance.transforms.transform.translation)
|
||||
+ material.properties.depth_bias;
|
||||
if material.properties.reads_view_transmission_texture {
|
||||
transmissive_phase.add(Transmissive3d {
|
||||
entity: *visible_entity,
|
||||
draw_function: draw_transmissive_pbr,
|
||||
|
@ -689,7 +689,7 @@ pub fn queue_material_meshes<M: Material>(
|
|||
entity: *visible_entity,
|
||||
draw_function: draw_alpha_mask_pbr,
|
||||
pipeline: pipeline_id,
|
||||
distance,
|
||||
asset_id: mesh_instance.mesh_asset_id,
|
||||
batch_range: 0..1,
|
||||
dynamic_offset: None,
|
||||
});
|
||||
|
|
|
@ -733,7 +733,7 @@ pub fn queue_prepass_material_meshes<M: Material>(
|
|||
.get_id::<DrawPrepass<M>>()
|
||||
.unwrap();
|
||||
for (
|
||||
view,
|
||||
_view,
|
||||
visible_entities,
|
||||
mut opaque_phase,
|
||||
mut alpha_mask_phase,
|
||||
|
@ -756,8 +756,6 @@ pub fn queue_prepass_material_meshes<M: Material>(
|
|||
view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
|
||||
}
|
||||
|
||||
let rangefinder = view.rangefinder3d();
|
||||
|
||||
for visible_entity in &visible_entities.entities {
|
||||
let Some(material_asset_id) = render_material_instances.get(visible_entity) else {
|
||||
continue;
|
||||
|
@ -860,9 +858,6 @@ pub fn queue_prepass_material_meshes<M: Material>(
|
|||
}
|
||||
}
|
||||
AlphaMode::Mask(_) => {
|
||||
let distance = rangefinder
|
||||
.distance_translation(&mesh_instance.transforms.transform.translation)
|
||||
+ material.properties.depth_bias;
|
||||
if deferred {
|
||||
alpha_mask_deferred_phase
|
||||
.as_mut()
|
||||
|
@ -871,7 +866,7 @@ pub fn queue_prepass_material_meshes<M: Material>(
|
|||
entity: *visible_entity,
|
||||
draw_function: alpha_mask_draw_deferred,
|
||||
pipeline_id,
|
||||
distance,
|
||||
asset_id: mesh_instance.mesh_asset_id,
|
||||
batch_range: 0..1,
|
||||
dynamic_offset: None,
|
||||
});
|
||||
|
@ -880,7 +875,7 @@ pub fn queue_prepass_material_meshes<M: Material>(
|
|||
entity: *visible_entity,
|
||||
draw_function: alpha_mask_draw_prepass,
|
||||
pipeline_id,
|
||||
distance,
|
||||
asset_id: mesh_instance.mesh_asset_id,
|
||||
batch_range: 0..1,
|
||||
dynamic_offset: None,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue