Skip to content

Commit

Permalink
Adding alpha_threshold to OrderIndependentTransparencySettings for us…
Browse files Browse the repository at this point in the history
…er-level optimization
  • Loading branch information
hexroll committed Oct 24, 2024
1 parent 9274bfe commit 5c8829b
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 29 deletions.
61 changes: 46 additions & 15 deletions crates/bevy_core_pipeline/src/oit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@

use bevy_app::prelude::*;
use bevy_asset::{load_internal_asset, Handle};
use bevy_ecs::prelude::*;
use bevy_ecs::{component::*, prelude::*};
use bevy_math::UVec2;
use bevy_reflect::Reflect;
use bevy_render::{
camera::{Camera, ExtractedCamera},
extract_component::{ExtractComponent, ExtractComponentPlugin},
render_graph::{RenderGraphApp, ViewNodeRunner},
render_resource::{BufferUsages, BufferVec, DynamicUniformBuffer, Shader, TextureUsages},
render_resource::{
BufferUsages, BufferVec, DynamicUniformBuffer, Shader, ShaderType, TextureUsages,
},
renderer::{RenderDevice, RenderQueue},
view::Msaa,
Render, RenderApp, RenderSet,
};
use bevy_utils::{tracing::trace, HashSet, Instant};
use bevy_utils::{
tracing::{trace, warn},
HashSet, Instant,
};
use bevy_window::PrimaryWindow;
use resolve::{
node::{OitResolveNode, OitResolvePass},
Expand All @@ -36,17 +42,41 @@ pub const OIT_DRAW_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(404252
// TODO consider supporting multiple OIT techniques like WBOIT, Moment Based OIT,
// depth peeling, stochastic transparency, ray tracing etc.
// This should probably be done by adding an enum to this component.
#[derive(Component, Clone, Copy, ExtractComponent)]
// We use the same struct to pass on the settings to the drawing shader.
#[derive(Clone, Copy, ExtractComponent, Reflect, ShaderType)]
pub struct OrderIndependentTransparencySettings {
/// Controls how many layers will be used to compute the blending.
/// The more layers you use the more memory it will use but it will also give better results.
/// 8 is generally recommended, going above 16 is probably not worth it in the vast majority of cases
pub layer_count: u8,
pub layer_count: i32,
/// Controls the threshold from which fragments will be added to the blending layers.
/// This can be tweaked to optimize quality / layers count. Higher values will
/// allow lower number of layers and a better performance, compromising quality.
pub alpha_threshold: f32,
}

impl Default for OrderIndependentTransparencySettings {
fn default() -> Self {
Self { layer_count: 8 }
Self {
layer_count: 8,
alpha_threshold: 0.0,
}
}
}

// OrderIndependentTransparencySettings is also a Component. We explicitly implement the trait so
// we can hook on_add to issue a warning in case `layer_count` is seemingly too high.
impl Component for OrderIndependentTransparencySettings {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;

fn register_component_hooks(hooks: &mut ComponentHooks) {
hooks.on_add(|world, entity, _| {
if let Some(value) = world.get::<OrderIndependentTransparencySettings>(entity) {
if value.layer_count > 32 {
warn!("OrderIndependentTransparencySettings layer_count set to {} might be too high.", value.layer_count);
}
}
});
}
}

Expand Down Expand Up @@ -82,7 +112,8 @@ impl Plugin for OrderIndependentTransparencyPlugin {
OitResolvePlugin,
))
.add_systems(Update, check_msaa)
.add_systems(Last, configure_depth_texture_usages);
.add_systems(Last, configure_depth_texture_usages)
.register_type::<OrderIndependentTransparencySettings>();

let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
Expand Down Expand Up @@ -164,7 +195,7 @@ pub struct OitBuffers {
pub layers: BufferVec<UVec2>,
/// Buffer containing the index of the last layer that was written for each fragment.
pub layer_ids: BufferVec<i32>,
pub layers_count_uniforms: DynamicUniformBuffer<i32>,
pub settings: DynamicUniformBuffer<OrderIndependentTransparencySettings>,
}

impl FromWorld for OitBuffers {
Expand All @@ -184,19 +215,19 @@ impl FromWorld for OitBuffers {
layer_ids.reserve(1, render_device);
layer_ids.write_buffer(render_device, render_queue);

let mut layers_count_uniforms = DynamicUniformBuffer::default();
layers_count_uniforms.set_label(Some("oit_layers_count"));
let mut settings = DynamicUniformBuffer::default();
settings.set_label(Some("oit_settings"));

Self {
layers,
layer_ids,
layers_count_uniforms,
settings,
}
}
}

#[derive(Component)]
pub struct OitLayersCountOffset {
pub struct OrderIndependentTransparencySettingsOffset {
pub offset: u32,
}

Expand Down Expand Up @@ -268,16 +299,16 @@ pub fn prepare_oit_buffers(
);
}

if let Some(mut writer) = buffers.layers_count_uniforms.get_writer(
if let Some(mut writer) = buffers.settings.get_writer(
camera_oit_uniforms.iter().len(),
&render_device,
&render_queue,
) {
for (entity, settings) in &camera_oit_uniforms {
let offset = writer.write(&(settings.layer_count as i32));
let offset = writer.write(settings);
commands
.entity(entity)
.insert(OitLayersCountOffset { offset });
.insert(OrderIndependentTransparencySettingsOffset { offset });
}
}
}
9 changes: 4 additions & 5 deletions crates/bevy_core_pipeline/src/oit/oit_draw.wgsl
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#define_import_path bevy_core_pipeline::oit

#import bevy_pbr::mesh_view_bindings::{view, oit_layers, oit_layer_ids, oit_layers_count}
#import bevy_pbr::mesh_view_bindings::{view, oit_layers, oit_layer_ids, oit_settings}

#ifdef OIT_ENABLED
// Add the fragment to the oit buffer
fn oit_draw(position: vec4f, color: vec4f) {
// Don't add fully transparent fragments to the list
// because we don't want to have to sort them in the resolve pass
// TODO should this be comparing with < espilon ?
if color.a == 0.0 {
if color.a < oit_settings.alpha_threshold {
return;
}
// get the index of the current fragment relative to the screen size
Expand All @@ -20,10 +19,10 @@ fn oit_draw(position: vec4f, color: vec4f) {
// gets the layer index of the current fragment
var layer_id = atomicAdd(&oit_layer_ids[screen_index], 1);
// exit early if we've reached the maximum amount of fragments per layer
if layer_id >= oit_layers_count {
if layer_id >= oit_settings.layers_count {
// force to store the oit_layers_count to make sure we don't
// accidentally increase the index above the maximum value
atomicStore(&oit_layer_ids[screen_index], oit_layers_count);
atomicStore(&oit_layer_ids[screen_index], oit_settings.layers_count);
// TODO for tail blending we should return the color here
return;
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_core_pipeline/src/oit/resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pub struct OitResolvePipelineId(pub CachedRenderPipelineId);
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct OitResolvePipelineKey {
hdr: bool,
layer_count: u8,
layer_count: i32,
}

#[allow(clippy::too_many_arguments)]
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use bevy_asset::{load_internal_asset, AssetId};
use bevy_core_pipeline::{
core_3d::{AlphaMask3d, Opaque3d, Transmissive3d, Transparent3d, CORE_3D_DEPTH_FORMAT},
deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
oit::{prepare_oit_buffers, OitLayersCountOffset},
oit::{prepare_oit_buffers, OrderIndependentTransparencySettingsOffset},
prepass::MotionVectorPrepass,
};
use bevy_derive::{Deref, DerefMut};
Expand Down Expand Up @@ -2195,7 +2195,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I>
Read<ViewScreenSpaceReflectionsUniformOffset>,
Read<ViewEnvironmentMapUniformOffset>,
Read<MeshViewBindGroup>,
Option<Read<OitLayersCountOffset>>,
Option<Read<OrderIndependentTransparencySettingsOffset>>,
);
type ItemQuery = ();

Expand Down
11 changes: 7 additions & 4 deletions crates/bevy_pbr/src/render/mesh_view_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,10 @@ fn layout_entries(
// oit_layer_ids,
(32, storage_buffer_sized(false, None)),
// oit_layer_count
(33, uniform_buffer::<i32>(true)),
(
33,
uniform_buffer::<OrderIndependentTransparencySettings>(true),
),
));
}
}
Expand Down Expand Up @@ -690,16 +693,16 @@ pub fn prepare_mesh_view_bind_groups(
if let (
Some(oit_layers_binding),
Some(oit_layer_ids_binding),
Some(oit_layers_count_uniforms_binding),
Some(oit_settings_binding),
) = (
oit_buffers.layers.binding(),
oit_buffers.layer_ids.binding(),
oit_buffers.layers_count_uniforms.binding(),
oit_buffers.settings.binding(),
) {
entries = entries.extend_with_indices((
(31, oit_layers_binding.clone()),
(32, oit_layer_ids_binding.clone()),
(33, oit_layers_count_uniforms_binding.clone()),
(33, oit_settings_binding.clone()),
));
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render/mesh_view_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,5 @@ const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u;
#ifdef OIT_ENABLED
@group(0) @binding(31) var<storage, read_write> oit_layers: array<vec2<u32>>;
@group(0) @binding(32) var<storage, read_write> oit_layer_ids: array<atomic<i32>>;
@group(0) @binding(33) var<uniform> oit_layers_count: i32;
@group(0) @binding(33) var<uniform> oit_settings: types::OrderIndependentTransparencySettings;
#endif OIT_ENABLED
8 changes: 7 additions & 1 deletion crates/bevy_pbr/src/render/mesh_view_types.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,10 @@ struct ScreenSpaceReflectionsSettings {
struct EnvironmentMapUniform {
// Transformation matrix for the environment cubemaps in world space.
transform: mat4x4<f32>,
};
};

// Shader version of the order independent transparency settings component.
struct OrderIndependentTransparencySettings {
layers_count: i32,
alpha_threshold: f32,
};

0 comments on commit 5c8829b

Please sign in to comment.