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)]
41#[extract_component_sync_target((Self, OrderIndependentTransparencySettingsOffset, OitResolvePipelineId))]
42#[reflect(Clone, Default)]
43#[extract_app(RenderApp)]
44pub struct OrderIndependentTransparencySettings {
45 pub sorted_fragment_max_count: u32,
49 pub fragments_per_pixel_average: f32,
52 pub alpha_threshold: f32,
56}
57
58impl Default for OrderIndependentTransparencySettings {
59 fn default() -> Self {
60 Self {
61 sorted_fragment_max_count: 8,
62 fragments_per_pixel_average: 4.0,
63 alpha_threshold: 0.0,
64 }
65 }
66}
67
68pub struct OrderIndependentTransparencyPlugin;
87impl Plugin for OrderIndependentTransparencyPlugin {
88 fn build(&self, app: &mut App) {
89 load_shader_library!(app, "draw.wesl");
90
91 app.add_plugins((
92 ExtractComponentPlugin::<OrderIndependentTransparencySettings>::default(),
93 OitResolvePlugin,
94 ))
95 .add_systems(Update, check_msaa);
96
97 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
98 return;
99 };
100
101 render_app
102 .add_systems(RenderStartup, init_oit_buffers)
103 .add_systems(
104 Render,
105 (
106 configure_camera_depth_usages
107 .in_set(RenderSystems::PrepareViews)
108 .ambiguous_with(RenderSystems::PrepareViews),
109 prepare_oit_buffers.in_set(RenderSystems::PrepareResources),
110 ),
111 );
112
113 render_app.add_systems(
114 Core3d,
115 oit_resolve
116 .after(main_transparent_pass_3d)
117 .in_set(Core3dSystems::MainPass),
118 );
119 }
120}
121
122fn configure_camera_depth_usages(
123 mut cameras: Query<
124 &mut Camera3d,
125 (
126 Changed<Camera3d>,
127 With<OrderIndependentTransparencySettings>,
128 ),
129 >,
130) {
131 for mut camera in &mut cameras {
132 camera.depth_texture_usages.0 |= TextureUsages::TEXTURE_BINDING.bits();
133 }
134}
135
136fn check_msaa(cameras: Query<&Msaa, With<OrderIndependentTransparencySettings>>) {
137 for msaa in &cameras {
138 if msaa.samples() > 1 {
139 panic!("MSAA is not supported when using OrderIndependentTransparency");
140 }
141 }
142}
143
144#[derive(Clone, Copy, ShaderType)]
145pub struct OitFragmentNode {
146 pub color: u32,
147 pub depth_alpha: u32,
148 pub next: u32,
149}
150
151#[derive(Resource)]
155pub struct OitBuffers {
156 pub settings: DynamicUniformBuffer<OrderIndependentTransparencySettings>,
157 pub nodes_capacity: UniformBuffer<u32>,
158 pub nodes: UninitBufferVec<OitFragmentNode>,
160 pub heads: UninitBufferVec<u32>,
163 pub atomic_counter: UninitBufferVec<u32>,
164}
165
166impl OitBuffers {
167 fn create_nodes_buffer(
168 size: usize,
169 render_device: &RenderDevice,
170 ) -> UninitBufferVec<OitFragmentNode> {
171 let mut nodes = UninitBufferVec::new(BufferUsages::COPY_DST | BufferUsages::STORAGE);
172 nodes.set_label(Some("oit_nodes"));
173 nodes.reserve(size, render_device);
174 nodes
175 }
176
177 fn create_heads_buffer(size: usize, render_device: &RenderDevice) -> UninitBufferVec<u32> {
178 let mut nodes = UninitBufferVec::new(BufferUsages::COPY_DST | BufferUsages::STORAGE);
179 nodes.set_label(Some("oit_heads"));
180 nodes.reserve(size, render_device);
181 nodes
182 }
183}
184
185pub fn init_oit_buffers(
186 mut commands: Commands,
187 render_device: Res<RenderDevice>,
188 render_queue: Res<RenderQueue>,
189) {
190 let mut nodes_capacity = UniformBuffer::default();
193 nodes_capacity.set_label(Some("oit_nodes_capacity"));
194 nodes_capacity.set(1);
195 nodes_capacity.write_buffer(&render_device, &render_queue);
196
197 let nodes = OitBuffers::create_nodes_buffer(1, &render_device);
198
199 let heads = OitBuffers::create_heads_buffer(1, &render_device);
200
201 let mut atomic_counter = UninitBufferVec::new(BufferUsages::COPY_DST | BufferUsages::STORAGE);
202 atomic_counter.set_label(Some("oit_atomic_counter"));
203 atomic_counter.reserve(1, &render_device);
204
205 let mut settings = DynamicUniformBuffer::default();
206 settings.set_label(Some("oit_settings"));
207
208 commands.insert_resource(OitBuffers {
209 nodes_capacity,
210 nodes,
211 heads,
212 atomic_counter,
213 settings,
214 });
215}
216
217#[derive(Component)]
218pub struct OrderIndependentTransparencySettingsOffset {
219 pub offset: u32,
220}
221
222pub fn prepare_oit_buffers(
226 mut commands: Commands,
227 render_device: Res<RenderDevice>,
228 render_queue: Res<RenderQueue>,
229 cameras: Query<
230 (&ExtractedCamera, &OrderIndependentTransparencySettings),
231 (
232 Changed<ExtractedCamera>,
233 Changed<OrderIndependentTransparencySettings>,
234 ),
235 >,
236 camera_oit_uniforms: Query<
237 (Entity, &OrderIndependentTransparencySettings),
238 With<ExtractedCamera>,
239 >,
240 mut buffers: ResMut<OitBuffers>,
241) {
242 let camera_count = camera_oit_uniforms.count();
243 if camera_count == 0 {
244 if buffers.nodes_capacity.get() > &1 {
245 buffers.nodes = OitBuffers::create_nodes_buffer(1, &render_device);
247 buffers.heads = OitBuffers::create_heads_buffer(1, &render_device);
248 buffers.nodes_capacity.set(1);
249 buffers
250 .nodes_capacity
251 .write_buffer(&render_device, &render_queue);
252 }
253 return;
254 }
255
256 let mut max_size = UVec2::new(0, 0);
258 let mut fragments_per_pixel_average = 0f32;
259 for (camera, settings) in &cameras {
260 let Some(size) = camera.physical_target_size else {
261 continue;
262 };
263 max_size = max_size.max(size);
264 fragments_per_pixel_average =
265 fragments_per_pixel_average.max(settings.fragments_per_pixel_average);
266 }
267
268 let heads_size = (max_size.x * max_size.y) as usize;
270 if buffers.heads.capacity() != heads_size {
271 let start = Instant::now();
272 buffers.heads = OitBuffers::create_heads_buffer(heads_size, &render_device);
273 trace!(
274 "OIT heads buffer updated in {:.01}ms with total size {} MiB",
275 start.elapsed().as_millis(),
276 (buffers.heads.capacity() * size_of::<u32>()) as f32 / 1024.0 / 1024.0,
277 );
278 }
279
280 let nodes_size = ((max_size.x * max_size.y) as f32 * fragments_per_pixel_average) as usize;
282 if buffers.nodes.capacity() != nodes_size {
283 let start = Instant::now();
284 buffers.nodes = OitBuffers::create_nodes_buffer(nodes_size, &render_device);
285 trace!(
286 "OIT nodes buffer updated in {:.01}ms with total size {} MiB",
287 start.elapsed().as_millis(),
288 (buffers.nodes.capacity() * size_of::<OitFragmentNode>()) as f32 / 1024.0 / 1024.0,
289 );
290 }
291
292 buffers.nodes_capacity.set(nodes_size as u32);
293 buffers
294 .nodes_capacity
295 .write_buffer(&render_device, &render_queue);
296
297 if let Some(mut writer) =
298 buffers
299 .settings
300 .get_writer(camera_count, &render_device, &render_queue)
301 {
302 for (entity, settings) in &camera_oit_uniforms {
303 let offset = writer.write(settings);
304 commands
305 .entity(entity)
306 .insert(OrderIndependentTransparencySettingsOffset { offset });
307 }
308 }
309}