Skip to content

Commit 5c8829b

Browse files
committed
Adding alpha_threshold to OrderIndependentTransparencySettings for user-level optimization
1 parent 9274bfe commit 5c8829b

File tree

7 files changed

+68
-29
lines changed

7 files changed

+68
-29
lines changed

crates/bevy_core_pipeline/src/oit/mod.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,24 @@
22
33
use bevy_app::prelude::*;
44
use bevy_asset::{load_internal_asset, Handle};
5-
use bevy_ecs::prelude::*;
5+
use bevy_ecs::{component::*, prelude::*};
66
use bevy_math::UVec2;
7+
use bevy_reflect::Reflect;
78
use bevy_render::{
89
camera::{Camera, ExtractedCamera},
910
extract_component::{ExtractComponent, ExtractComponentPlugin},
1011
render_graph::{RenderGraphApp, ViewNodeRunner},
11-
render_resource::{BufferUsages, BufferVec, DynamicUniformBuffer, Shader, TextureUsages},
12+
render_resource::{
13+
BufferUsages, BufferVec, DynamicUniformBuffer, Shader, ShaderType, TextureUsages,
14+
},
1215
renderer::{RenderDevice, RenderQueue},
1316
view::Msaa,
1417
Render, RenderApp, RenderSet,
1518
};
16-
use bevy_utils::{tracing::trace, HashSet, Instant};
19+
use bevy_utils::{
20+
tracing::{trace, warn},
21+
HashSet, Instant,
22+
};
1723
use bevy_window::PrimaryWindow;
1824
use resolve::{
1925
node::{OitResolveNode, OitResolvePass},
@@ -36,17 +42,41 @@ pub const OIT_DRAW_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(404252
3642
// TODO consider supporting multiple OIT techniques like WBOIT, Moment Based OIT,
3743
// depth peeling, stochastic transparency, ray tracing etc.
3844
// This should probably be done by adding an enum to this component.
39-
#[derive(Component, Clone, Copy, ExtractComponent)]
45+
// We use the same struct to pass on the settings to the drawing shader.
46+
#[derive(Clone, Copy, ExtractComponent, Reflect, ShaderType)]
4047
pub struct OrderIndependentTransparencySettings {
4148
/// Controls how many layers will be used to compute the blending.
4249
/// The more layers you use the more memory it will use but it will also give better results.
4350
/// 8 is generally recommended, going above 16 is probably not worth it in the vast majority of cases
44-
pub layer_count: u8,
51+
pub layer_count: i32,
52+
/// Controls the threshold from which fragments will be added to the blending layers.
53+
/// This can be tweaked to optimize quality / layers count. Higher values will
54+
/// allow lower number of layers and a better performance, compromising quality.
55+
pub alpha_threshold: f32,
4556
}
4657

4758
impl Default for OrderIndependentTransparencySettings {
4859
fn default() -> Self {
49-
Self { layer_count: 8 }
60+
Self {
61+
layer_count: 8,
62+
alpha_threshold: 0.0,
63+
}
64+
}
65+
}
66+
67+
// OrderIndependentTransparencySettings is also a Component. We explicitly implement the trait so
68+
// we can hook on_add to issue a warning in case `layer_count` is seemingly too high.
69+
impl Component for OrderIndependentTransparencySettings {
70+
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
71+
72+
fn register_component_hooks(hooks: &mut ComponentHooks) {
73+
hooks.on_add(|world, entity, _| {
74+
if let Some(value) = world.get::<OrderIndependentTransparencySettings>(entity) {
75+
if value.layer_count > 32 {
76+
warn!("OrderIndependentTransparencySettings layer_count set to {} might be too high.", value.layer_count);
77+
}
78+
}
79+
});
5080
}
5181
}
5282

@@ -82,7 +112,8 @@ impl Plugin for OrderIndependentTransparencyPlugin {
82112
OitResolvePlugin,
83113
))
84114
.add_systems(Update, check_msaa)
85-
.add_systems(Last, configure_depth_texture_usages);
115+
.add_systems(Last, configure_depth_texture_usages)
116+
.register_type::<OrderIndependentTransparencySettings>();
86117

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

170201
impl FromWorld for OitBuffers {
@@ -184,19 +215,19 @@ impl FromWorld for OitBuffers {
184215
layer_ids.reserve(1, render_device);
185216
layer_ids.write_buffer(render_device, render_queue);
186217

187-
let mut layers_count_uniforms = DynamicUniformBuffer::default();
188-
layers_count_uniforms.set_label(Some("oit_layers_count"));
218+
let mut settings = DynamicUniformBuffer::default();
219+
settings.set_label(Some("oit_settings"));
189220

190221
Self {
191222
layers,
192223
layer_ids,
193-
layers_count_uniforms,
224+
settings,
194225
}
195226
}
196227
}
197228

198229
#[derive(Component)]
199-
pub struct OitLayersCountOffset {
230+
pub struct OrderIndependentTransparencySettingsOffset {
200231
pub offset: u32,
201232
}
202233

@@ -268,16 +299,16 @@ pub fn prepare_oit_buffers(
268299
);
269300
}
270301

271-
if let Some(mut writer) = buffers.layers_count_uniforms.get_writer(
302+
if let Some(mut writer) = buffers.settings.get_writer(
272303
camera_oit_uniforms.iter().len(),
273304
&render_device,
274305
&render_queue,
275306
) {
276307
for (entity, settings) in &camera_oit_uniforms {
277-
let offset = writer.write(&(settings.layer_count as i32));
308+
let offset = writer.write(settings);
278309
commands
279310
.entity(entity)
280-
.insert(OitLayersCountOffset { offset });
311+
.insert(OrderIndependentTransparencySettingsOffset { offset });
281312
}
282313
}
283314
}

crates/bevy_core_pipeline/src/oit/oit_draw.wgsl

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
#define_import_path bevy_core_pipeline::oit
22

3-
#import bevy_pbr::mesh_view_bindings::{view, oit_layers, oit_layer_ids, oit_layers_count}
3+
#import bevy_pbr::mesh_view_bindings::{view, oit_layers, oit_layer_ids, oit_settings}
44

55
#ifdef OIT_ENABLED
66
// Add the fragment to the oit buffer
77
fn oit_draw(position: vec4f, color: vec4f) {
88
// Don't add fully transparent fragments to the list
99
// because we don't want to have to sort them in the resolve pass
10-
// TODO should this be comparing with < espilon ?
11-
if color.a == 0.0 {
10+
if color.a < oit_settings.alpha_threshold {
1211
return;
1312
}
1413
// get the index of the current fragment relative to the screen size
@@ -20,10 +19,10 @@ fn oit_draw(position: vec4f, color: vec4f) {
2019
// gets the layer index of the current fragment
2120
var layer_id = atomicAdd(&oit_layer_ids[screen_index], 1);
2221
// exit early if we've reached the maximum amount of fragments per layer
23-
if layer_id >= oit_layers_count {
22+
if layer_id >= oit_settings.layers_count {
2423
// force to store the oit_layers_count to make sure we don't
2524
// accidentally increase the index above the maximum value
26-
atomicStore(&oit_layer_ids[screen_index], oit_layers_count);
25+
atomicStore(&oit_layer_ids[screen_index], oit_settings.layers_count);
2726
// TODO for tail blending we should return the color here
2827
return;
2928
}

crates/bevy_core_pipeline/src/oit/resolve/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub struct OitResolvePipelineId(pub CachedRenderPipelineId);
121121
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
122122
pub struct OitResolvePipelineKey {
123123
hdr: bool,
124-
layer_count: u8,
124+
layer_count: i32,
125125
}
126126

127127
#[allow(clippy::too_many_arguments)]

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use bevy_asset::{load_internal_asset, AssetId};
55
use bevy_core_pipeline::{
66
core_3d::{AlphaMask3d, Opaque3d, Transmissive3d, Transparent3d, CORE_3D_DEPTH_FORMAT},
77
deferred::{AlphaMask3dDeferred, Opaque3dDeferred},
8-
oit::{prepare_oit_buffers, OitLayersCountOffset},
8+
oit::{prepare_oit_buffers, OrderIndependentTransparencySettingsOffset},
99
prepass::MotionVectorPrepass,
1010
};
1111
use bevy_derive::{Deref, DerefMut};
@@ -2195,7 +2195,7 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I>
21952195
Read<ViewScreenSpaceReflectionsUniformOffset>,
21962196
Read<ViewEnvironmentMapUniformOffset>,
21972197
Read<MeshViewBindGroup>,
2198-
Option<Read<OitLayersCountOffset>>,
2198+
Option<Read<OrderIndependentTransparencySettingsOffset>>,
21992199
);
22002200
type ItemQuery = ();
22012201

crates/bevy_pbr/src/render/mesh_view_bindings.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,10 @@ fn layout_entries(
375375
// oit_layer_ids,
376376
(32, storage_buffer_sized(false, None)),
377377
// oit_layer_count
378-
(33, uniform_buffer::<i32>(true)),
378+
(
379+
33,
380+
uniform_buffer::<OrderIndependentTransparencySettings>(true),
381+
),
379382
));
380383
}
381384
}
@@ -690,16 +693,16 @@ pub fn prepare_mesh_view_bind_groups(
690693
if let (
691694
Some(oit_layers_binding),
692695
Some(oit_layer_ids_binding),
693-
Some(oit_layers_count_uniforms_binding),
696+
Some(oit_settings_binding),
694697
) = (
695698
oit_buffers.layers.binding(),
696699
oit_buffers.layer_ids.binding(),
697-
oit_buffers.layers_count_uniforms.binding(),
700+
oit_buffers.settings.binding(),
698701
) {
699702
entries = entries.extend_with_indices((
700703
(31, oit_layers_binding.clone()),
701704
(32, oit_layer_ids_binding.clone()),
702-
(33, oit_layers_count_uniforms_binding.clone()),
705+
(33, oit_settings_binding.clone()),
703706
));
704707
}
705708
}

crates/bevy_pbr/src/render/mesh_view_bindings.wgsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,5 @@ const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u;
105105
#ifdef OIT_ENABLED
106106
@group(0) @binding(31) var<storage, read_write> oit_layers: array<vec2<u32>>;
107107
@group(0) @binding(32) var<storage, read_write> oit_layer_ids: array<atomic<i32>>;
108-
@group(0) @binding(33) var<uniform> oit_layers_count: i32;
108+
@group(0) @binding(33) var<uniform> oit_settings: types::OrderIndependentTransparencySettings;
109109
#endif OIT_ENABLED

crates/bevy_pbr/src/render/mesh_view_types.wgsl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,10 @@ struct ScreenSpaceReflectionsSettings {
158158
struct EnvironmentMapUniform {
159159
// Transformation matrix for the environment cubemaps in world space.
160160
transform: mat4x4<f32>,
161-
};
161+
};
162+
163+
// Shader version of the order independent transparency settings component.
164+
struct OrderIndependentTransparencySettings {
165+
layers_count: i32,
166+
alpha_threshold: f32,
167+
};

0 commit comments

Comments
 (0)