1use bevy_app::prelude::*;
4use bevy_camera::Camera3d;
5use bevy_ecs::{component::*, prelude::*};
6use bevy_log::trace;
7use bevy_math::UVec2;
8use bevy_platform::time::Instant;
9use bevy_reflect::{std_traits::ReflectDefault, Reflect};
10use bevy_render::{
11 camera::ExtractedCamera,
12 extract_component::{ExtractComponent, ExtractComponentPlugin},
13 render_resource::{
14 BufferUsages, DynamicUniformBuffer, ShaderType, TextureUsages, UniformBuffer,
15 UninitBufferVec,
16 },
17 renderer::{RenderDevice, RenderQueue},
18 view::Msaa,
19 Render, RenderApp, RenderStartup, RenderSystems,
20};
21use bevy_shader::load_shader_library;
22use resolve::OitResolvePlugin;
23
24use crate::{
25 core_3d::main_transparent_pass_3d,
26 oit::resolve::{node::oit_resolve, OitResolvePipelineId},
27 schedule::{Core3d, Core3dSystems},
28};
29
30pub mod resolve;
32
33#[derive(Clone, Copy, ExtractComponent, Reflect, ShaderType, Component)]
40#[extract_component_sync_target((Self, OrderIndependentTransparencySettingsOffset, OitResolvePipelineId))]
41#[reflect(Clone, Default)]
42pub struct OrderIndependentTransparencySettings {
43 pub sorted_fragment_max_count: u32,
47 pub fragments_per_pixel_average: f32,
50 pub alpha_threshold: f32,
54}
55
56impl Default for OrderIndependentTransparencySettings {
57 fn default() -> Self {
58 Self {
59 sorted_fragment_max_count: 8,
60 fragments_per_pixel_average: 4.0,
61 alpha_threshold: 0.0,
62 }
63 }
64}
65
66pub struct OrderIndependentTransparencyPlugin;
84impl Plugin for OrderIndependentTransparencyPlugin {
85 fn build(&self, app: &mut App) {
86 load_shader_library!(app, "oit_draw.wgsl");
87
88 app.add_plugins((
89 ExtractComponentPlugin::<OrderIndependentTransparencySettings>::default(),
90 OitResolvePlugin,
91 ))
92 .add_systems(Update, check_msaa);
93
94 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
95 return;
96 };
97
98 render_app
99 .add_systems(RenderStartup, init_oit_buffers)
100 .add_systems(
101 Render,
102 (
103 configure_camera_depth_usages
104 .in_set(RenderSystems::PrepareViews)
105 .ambiguous_with(RenderSystems::PrepareViews),
106 prepare_oit_buffers.in_set(RenderSystems::PrepareResources),
107 ),
108 );
109
110 render_app.add_systems(
111 Core3d,
112 oit_resolve
113 .after(main_transparent_pass_3d)
114 .in_set(Core3dSystems::MainPass),
115 );
116 }
117}
118
119fn configure_camera_depth_usages(
120 mut cameras: Query<
121 &mut Camera3d,
122 (
123 Changed<Camera3d>,
124 With<OrderIndependentTransparencySettings>,
125 ),
126 >,
127) {
128 for mut camera in &mut cameras {
129 camera.depth_texture_usages.0 |= TextureUsages::TEXTURE_BINDING.bits();
130 }
131}
132
133fn check_msaa(cameras: Query<&Msaa, With<OrderIndependentTransparencySettings>>) {
134 for msaa in &cameras {
135 if msaa.samples() > 1 {
136 panic!("MSAA is not supported when using OrderIndependentTransparency");
137 }
138 }
139}
140
141#[derive(Clone, Copy, ShaderType)]
142pub struct OitFragmentNode {
143 pub color: u32,
144 pub depth_alpha: u32,
145 pub next: u32,
146}
147
148#[derive(Resource)]
152pub struct OitBuffers {
153 pub settings: DynamicUniformBuffer<OrderIndependentTransparencySettings>,
154 pub nodes_capacity: UniformBuffer<u32>,
155 pub nodes: UninitBufferVec<OitFragmentNode>,
157 pub heads: UninitBufferVec<u32>,
160 pub atomic_counter: UninitBufferVec<u32>,
161}
162
163impl OitBuffers {
164 fn create_nodes_buffer(
165 size: usize,
166 render_device: &RenderDevice,
167 ) -> UninitBufferVec<OitFragmentNode> {
168 let mut nodes = UninitBufferVec::new(BufferUsages::COPY_DST | BufferUsages::STORAGE);
169 nodes.set_label(Some("oit_nodes"));
170 nodes.reserve(size, render_device);
171 nodes
172 }
173
174 fn create_heads_buffer(size: usize, render_device: &RenderDevice) -> UninitBufferVec<u32> {
175 let mut nodes = UninitBufferVec::new(BufferUsages::COPY_DST | BufferUsages::STORAGE);
176 nodes.set_label(Some("oit_heads"));
177 nodes.reserve(size, render_device);
178 nodes
179 }
180}
181
182pub fn init_oit_buffers(
183 mut commands: Commands,
184 render_device: Res<RenderDevice>,
185 render_queue: Res<RenderQueue>,
186) {
187 let mut nodes_capacity = UniformBuffer::default();
190 nodes_capacity.set_label(Some("oit_nodes_capacity"));
191 nodes_capacity.set(1);
192 nodes_capacity.write_buffer(&render_device, &render_queue);
193
194 let nodes = OitBuffers::create_nodes_buffer(1, &render_device);
195
196 let heads = OitBuffers::create_heads_buffer(1, &render_device);
197
198 let mut atomic_counter = UninitBufferVec::new(BufferUsages::COPY_DST | BufferUsages::STORAGE);
199 atomic_counter.set_label(Some("oit_atomic_counter"));
200 atomic_counter.reserve(1, &render_device);
201
202 let mut settings = DynamicUniformBuffer::default();
203 settings.set_label(Some("oit_settings"));
204
205 commands.insert_resource(OitBuffers {
206 nodes_capacity,
207 nodes,
208 heads,
209 atomic_counter,
210 settings,
211 });
212}
213
214#[derive(Component)]
215pub struct OrderIndependentTransparencySettingsOffset {
216 pub offset: u32,
217}
218
219pub fn prepare_oit_buffers(
223 mut commands: Commands,
224 render_device: Res<RenderDevice>,
225 render_queue: Res<RenderQueue>,
226 cameras: Query<
227 (&ExtractedCamera, &OrderIndependentTransparencySettings),
228 (
229 Changed<ExtractedCamera>,
230 Changed<OrderIndependentTransparencySettings>,
231 ),
232 >,
233 camera_oit_uniforms: Query<
234 (Entity, &OrderIndependentTransparencySettings),
235 With<ExtractedCamera>,
236 >,
237 mut buffers: ResMut<OitBuffers>,
238) {
239 let camera_count = camera_oit_uniforms.count();
240 if camera_count == 0 {
241 if buffers.nodes_capacity.get() > &1 {
242 buffers.nodes = OitBuffers::create_nodes_buffer(1, &render_device);
244 buffers.heads = OitBuffers::create_heads_buffer(1, &render_device);
245 buffers.nodes_capacity.set(1);
246 buffers
247 .nodes_capacity
248 .write_buffer(&render_device, &render_queue);
249 }
250 return;
251 }
252
253 let mut max_size = UVec2::new(0, 0);
255 let mut fragments_per_pixel_average = 0f32;
256 for (camera, settings) in &cameras {
257 let Some(size) = camera.physical_target_size else {
258 continue;
259 };
260 max_size = max_size.max(size);
261 fragments_per_pixel_average =
262 fragments_per_pixel_average.max(settings.fragments_per_pixel_average);
263 }
264
265 let heads_size = (max_size.x * max_size.y) as usize;
267 if buffers.heads.capacity() != heads_size {
268 let start = Instant::now();
269 buffers.heads = OitBuffers::create_heads_buffer(heads_size, &render_device);
270 trace!(
271 "OIT heads buffer updated in {:.01}ms with total size {} MiB",
272 start.elapsed().as_millis(),
273 (buffers.heads.capacity() * size_of::<u32>()) as f32 / 1024.0 / 1024.0,
274 );
275 }
276
277 let nodes_size = ((max_size.x * max_size.y) as f32 * fragments_per_pixel_average) as usize;
279 if buffers.nodes.capacity() != nodes_size {
280 let start = Instant::now();
281 buffers.nodes = OitBuffers::create_nodes_buffer(nodes_size, &render_device);
282 trace!(
283 "OIT nodes buffer updated in {:.01}ms with total size {} MiB",
284 start.elapsed().as_millis(),
285 (buffers.nodes.capacity() * size_of::<OitFragmentNode>()) as f32 / 1024.0 / 1024.0,
286 );
287 }
288
289 buffers.nodes_capacity.set(nodes_size as u32);
290 buffers
291 .nodes_capacity
292 .write_buffer(&render_device, &render_queue);
293
294 if let Some(mut writer) =
295 buffers
296 .settings
297 .get_writer(camera_count, &render_device, &render_queue)
298 {
299 for (entity, settings) in &camera_oit_uniforms {
300 let offset = writer.write(settings);
301 commands
302 .entity(entity)
303 .insert(OrderIndependentTransparencySettingsOffset { offset });
304 }
305 }
306}