1pub struct DepthPeelPass {
10 peel_pipeline: wgpu::RenderPipeline,
12 composite_under_pipeline: wgpu::RenderPipeline,
14 composite_over_pipeline: wgpu::RenderPipeline,
16 depth_update_pipeline: wgpu::RenderPipeline,
18
19 min_depth_texture: wgpu::Texture,
23 min_depth_view: wgpu::TextureView,
24
25 peel_color_texture: wgpu::Texture,
27 peel_color_view: wgpu::TextureView,
28
29 peel_depth_color_texture: wgpu::Texture,
31 peel_depth_color_view: wgpu::TextureView,
32
33 peel_depth_texture: wgpu::Texture,
35 peel_depth_view: wgpu::TextureView,
36
37 pub(crate) final_texture: wgpu::Texture,
39 pub(crate) final_view: wgpu::TextureView,
40
41 pub(crate) peel_bind_group_layout: wgpu::BindGroupLayout,
43 peel_bind_group: wgpu::BindGroup,
45
46 composite_bind_group_layout: wgpu::BindGroupLayout,
48
49 depth_update_bind_group_layout: wgpu::BindGroupLayout,
51
52 sampler: wgpu::Sampler,
53
54 width: u32,
55 height: u32,
56}
57
58impl DepthPeelPass {
59 #[must_use]
61 pub fn new(
62 device: &wgpu::Device,
63 width: u32,
64 height: u32,
65 mesh_bind_group_layout: &wgpu::BindGroupLayout,
66 slice_plane_bind_group_layout: &wgpu::BindGroupLayout,
67 matcap_bind_group_layout: &wgpu::BindGroupLayout,
68 ) -> Self {
69 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
70 label: Some("depth peel sampler"),
71 mag_filter: wgpu::FilterMode::Nearest,
72 min_filter: wgpu::FilterMode::Nearest,
73 ..Default::default()
74 });
75
76 let (min_depth_texture, min_depth_view) =
80 Self::create_rgba16_texture(device, width, height, "peel min depth");
81 let (peel_color_texture, peel_color_view) =
82 Self::create_rgba16_texture(device, width, height, "peel layer color");
83 let (peel_depth_color_texture, peel_depth_color_view) =
84 Self::create_r32float_texture(device, width, height, "peel layer depth color");
85 let (peel_depth_texture, peel_depth_view) =
86 Self::create_depth_texture(device, width, height);
87 let (final_texture, final_view) =
88 Self::create_rgba16_texture(device, width, height, "peel final");
89
90 let peel_bind_group_layout =
94 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
95 label: Some("peel depth bind group layout"),
96 entries: &[
97 wgpu::BindGroupLayoutEntry {
98 binding: 0,
99 visibility: wgpu::ShaderStages::FRAGMENT,
100 ty: wgpu::BindingType::Texture {
101 sample_type: wgpu::TextureSampleType::Float { filterable: false },
102 view_dimension: wgpu::TextureViewDimension::D2,
103 multisampled: false,
104 },
105 count: None,
106 },
107 wgpu::BindGroupLayoutEntry {
108 binding: 1,
109 visibility: wgpu::ShaderStages::FRAGMENT,
110 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
111 count: None,
112 },
113 ],
114 });
115
116 let peel_bind_group = Self::create_peel_bind_group(
117 device,
118 &peel_bind_group_layout,
119 &min_depth_view,
120 &sampler,
121 );
122
123 let composite_bind_group_layout =
125 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
126 label: Some("peel composite bind group layout"),
127 entries: &[
128 wgpu::BindGroupLayoutEntry {
129 binding: 0,
130 visibility: wgpu::ShaderStages::FRAGMENT,
131 ty: wgpu::BindingType::Texture {
132 sample_type: wgpu::TextureSampleType::Float { filterable: true },
133 view_dimension: wgpu::TextureViewDimension::D2,
134 multisampled: false,
135 },
136 count: None,
137 },
138 wgpu::BindGroupLayoutEntry {
139 binding: 1,
140 visibility: wgpu::ShaderStages::FRAGMENT,
141 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
142 count: None,
143 },
144 ],
145 });
146
147 let depth_update_bind_group_layout =
149 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
150 label: Some("peel depth update bind group layout"),
151 entries: &[wgpu::BindGroupLayoutEntry {
152 binding: 0,
153 visibility: wgpu::ShaderStages::FRAGMENT,
154 ty: wgpu::BindingType::Texture {
155 sample_type: wgpu::TextureSampleType::Float { filterable: false },
156 view_dimension: wgpu::TextureViewDimension::D2,
157 multisampled: false,
158 },
159 count: None,
160 }],
161 });
162
163 let peel_pipeline = Self::create_peel_pipeline(
166 device,
167 mesh_bind_group_layout,
168 slice_plane_bind_group_layout,
169 matcap_bind_group_layout,
170 &peel_bind_group_layout,
171 );
172
173 let under_blend = wgpu::BlendState {
174 color: wgpu::BlendComponent {
175 src_factor: wgpu::BlendFactor::OneMinusDstAlpha,
176 dst_factor: wgpu::BlendFactor::One,
177 operation: wgpu::BlendOperation::Add,
178 },
179 alpha: wgpu::BlendComponent {
180 src_factor: wgpu::BlendFactor::OneMinusDstAlpha,
181 dst_factor: wgpu::BlendFactor::One,
182 operation: wgpu::BlendOperation::Add,
183 },
184 };
185
186 let over_blend = wgpu::BlendState {
187 color: wgpu::BlendComponent {
188 src_factor: wgpu::BlendFactor::One,
189 dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
190 operation: wgpu::BlendOperation::Add,
191 },
192 alpha: wgpu::BlendComponent {
193 src_factor: wgpu::BlendFactor::One,
194 dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
195 operation: wgpu::BlendOperation::Add,
196 },
197 };
198
199 let composite_under_pipeline = Self::create_composite_pipeline(
200 device,
201 &composite_bind_group_layout,
202 "composite peel (under)",
203 under_blend,
204 );
205
206 let composite_over_pipeline = Self::create_composite_pipeline(
207 device,
208 &composite_bind_group_layout,
209 "composite peel (over)",
210 over_blend,
211 );
212
213 let depth_update_pipeline =
214 Self::create_depth_update_pipeline(device, &depth_update_bind_group_layout);
215
216 Self {
217 peel_pipeline,
218 composite_under_pipeline,
219 composite_over_pipeline,
220 depth_update_pipeline,
221 min_depth_texture,
222 min_depth_view,
223 peel_color_texture,
224 peel_color_view,
225 peel_depth_color_texture,
226 peel_depth_color_view,
227 peel_depth_texture,
228 peel_depth_view,
229 final_texture,
230 final_view,
231 peel_bind_group_layout,
232 peel_bind_group,
233 composite_bind_group_layout,
234 depth_update_bind_group_layout,
235 sampler,
236 width,
237 height,
238 }
239 }
240
241 pub fn resize(&mut self, device: &wgpu::Device, width: u32, height: u32) {
243 if self.width == width && self.height == height {
244 return;
245 }
246 self.width = width;
247 self.height = height;
248
249 let (t, v) = Self::create_rgba16_texture(device, width, height, "peel min depth");
250 self.min_depth_texture = t;
251 self.min_depth_view = v;
252
253 let (t, v) = Self::create_rgba16_texture(device, width, height, "peel layer color");
254 self.peel_color_texture = t;
255 self.peel_color_view = v;
256
257 let (t, v) = Self::create_r32float_texture(device, width, height, "peel layer depth color");
258 self.peel_depth_color_texture = t;
259 self.peel_depth_color_view = v;
260
261 let (t, v) = Self::create_depth_texture(device, width, height);
262 self.peel_depth_texture = t;
263 self.peel_depth_view = v;
264
265 let (t, v) = Self::create_rgba16_texture(device, width, height, "peel final");
266 self.final_texture = t;
267 self.final_view = v;
268
269 self.peel_bind_group = Self::create_peel_bind_group(
271 device,
272 &self.peel_bind_group_layout,
273 &self.min_depth_view,
274 &self.sampler,
275 );
276 }
277
278 #[must_use]
280 pub fn peel_pipeline(&self) -> &wgpu::RenderPipeline {
281 &self.peel_pipeline
282 }
283
284 #[must_use]
286 pub fn peel_bind_group(&self) -> &wgpu::BindGroup {
287 &self.peel_bind_group
288 }
289
290 #[must_use]
292 pub fn peel_color_view(&self) -> &wgpu::TextureView {
293 &self.peel_color_view
294 }
295
296 #[must_use]
298 pub fn peel_depth_color_view(&self) -> &wgpu::TextureView {
299 &self.peel_depth_color_view
300 }
301
302 #[must_use]
304 pub fn peel_depth_view(&self) -> &wgpu::TextureView {
305 &self.peel_depth_view
306 }
307
308 #[must_use]
310 pub fn min_depth_view(&self) -> &wgpu::TextureView {
311 &self.min_depth_view
312 }
313
314 #[must_use]
316 pub fn final_view(&self) -> &wgpu::TextureView {
317 &self.final_view
318 }
319
320 pub fn composite_layer(&self, encoder: &mut wgpu::CommandEncoder, device: &wgpu::Device) {
322 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
323 label: Some("peel composite bind group"),
324 layout: &self.composite_bind_group_layout,
325 entries: &[
326 wgpu::BindGroupEntry {
327 binding: 0,
328 resource: wgpu::BindingResource::TextureView(&self.peel_color_view),
329 },
330 wgpu::BindGroupEntry {
331 binding: 1,
332 resource: wgpu::BindingResource::Sampler(&self.sampler),
333 },
334 ],
335 });
336
337 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
338 label: Some("peel composite pass"),
339 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
340 view: &self.final_view,
341 resolve_target: None,
342 ops: wgpu::Operations {
343 load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store,
345 },
346 depth_slice: None,
347 })],
348 depth_stencil_attachment: None,
349 ..Default::default()
350 });
351
352 pass.set_pipeline(&self.composite_under_pipeline);
353 pass.set_bind_group(0, &bind_group, &[]);
354 pass.draw(0..3, 0..1);
355 }
356
357 pub fn update_min_depth(&self, encoder: &mut wgpu::CommandEncoder, device: &wgpu::Device) {
360 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
361 label: Some("peel depth update bind group"),
362 layout: &self.depth_update_bind_group_layout,
363 entries: &[wgpu::BindGroupEntry {
364 binding: 0,
365 resource: wgpu::BindingResource::TextureView(&self.peel_depth_color_view),
366 }],
367 });
368
369 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
370 label: Some("peel min-depth update pass"),
371 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
372 view: &self.min_depth_view,
373 resolve_target: None,
374 ops: wgpu::Operations {
375 load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store,
377 },
378 depth_slice: None,
379 })],
380 depth_stencil_attachment: None,
381 ..Default::default()
382 });
383
384 pass.set_pipeline(&self.depth_update_pipeline);
385 pass.set_bind_group(0, &bind_group, &[]);
386 pass.draw(0..3, 0..1);
387 }
388
389 pub fn composite_final_to_scene(
391 &self,
392 encoder: &mut wgpu::CommandEncoder,
393 device: &wgpu::Device,
394 hdr_view: &wgpu::TextureView,
395 ) {
396 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
397 label: Some("peel final composite bind group"),
398 layout: &self.composite_bind_group_layout,
399 entries: &[
400 wgpu::BindGroupEntry {
401 binding: 0,
402 resource: wgpu::BindingResource::TextureView(&self.final_view),
403 },
404 wgpu::BindGroupEntry {
405 binding: 1,
406 resource: wgpu::BindingResource::Sampler(&self.sampler),
407 },
408 ],
409 });
410
411 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
412 label: Some("peel final-to-scene composite pass"),
413 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
414 view: hdr_view,
415 resolve_target: None,
416 ops: wgpu::Operations {
417 load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store,
419 },
420 depth_slice: None,
421 })],
422 depth_stencil_attachment: None,
423 ..Default::default()
424 });
425
426 pass.set_pipeline(&self.composite_over_pipeline);
427 pass.set_bind_group(0, &bind_group, &[]);
428 pass.draw(0..3, 0..1);
429 }
430
431 fn create_r32float_texture(
434 device: &wgpu::Device,
435 width: u32,
436 height: u32,
437 label: &str,
438 ) -> (wgpu::Texture, wgpu::TextureView) {
439 let texture = device.create_texture(&wgpu::TextureDescriptor {
440 label: Some(label),
441 size: wgpu::Extent3d {
442 width,
443 height,
444 depth_or_array_layers: 1,
445 },
446 mip_level_count: 1,
447 sample_count: 1,
448 dimension: wgpu::TextureDimension::D2,
449 format: wgpu::TextureFormat::R32Float,
450 usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
451 view_formats: &[],
452 });
453 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
454 (texture, view)
455 }
456
457 fn create_rgba16_texture(
458 device: &wgpu::Device,
459 width: u32,
460 height: u32,
461 label: &str,
462 ) -> (wgpu::Texture, wgpu::TextureView) {
463 let texture = device.create_texture(&wgpu::TextureDescriptor {
464 label: Some(label),
465 size: wgpu::Extent3d {
466 width,
467 height,
468 depth_or_array_layers: 1,
469 },
470 mip_level_count: 1,
471 sample_count: 1,
472 dimension: wgpu::TextureDimension::D2,
473 format: wgpu::TextureFormat::Rgba16Float,
474 usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
475 view_formats: &[],
476 });
477 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
478 (texture, view)
479 }
480
481 fn create_depth_texture(
482 device: &wgpu::Device,
483 width: u32,
484 height: u32,
485 ) -> (wgpu::Texture, wgpu::TextureView) {
486 let texture = device.create_texture(&wgpu::TextureDescriptor {
487 label: Some("peel depth buffer"),
488 size: wgpu::Extent3d {
489 width,
490 height,
491 depth_or_array_layers: 1,
492 },
493 mip_level_count: 1,
494 sample_count: 1,
495 dimension: wgpu::TextureDimension::D2,
496 format: wgpu::TextureFormat::Depth24PlusStencil8,
497 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
498 view_formats: &[],
499 });
500 let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
501 (texture, view)
502 }
503
504 fn create_peel_bind_group(
505 device: &wgpu::Device,
506 layout: &wgpu::BindGroupLayout,
507 min_depth_view: &wgpu::TextureView,
508 sampler: &wgpu::Sampler,
509 ) -> wgpu::BindGroup {
510 device.create_bind_group(&wgpu::BindGroupDescriptor {
511 label: Some("peel depth bind group"),
512 layout,
513 entries: &[
514 wgpu::BindGroupEntry {
515 binding: 0,
516 resource: wgpu::BindingResource::TextureView(min_depth_view),
517 },
518 wgpu::BindGroupEntry {
519 binding: 1,
520 resource: wgpu::BindingResource::Sampler(sampler),
521 },
522 ],
523 })
524 }
525
526 fn create_peel_pipeline(
527 device: &wgpu::Device,
528 mesh_bind_group_layout: &wgpu::BindGroupLayout,
529 slice_plane_bind_group_layout: &wgpu::BindGroupLayout,
530 matcap_bind_group_layout: &wgpu::BindGroupLayout,
531 peel_bind_group_layout: &wgpu::BindGroupLayout,
532 ) -> wgpu::RenderPipeline {
533 let shader_source = include_str!("shaders/surface_mesh_peel.wgsl");
534 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
535 label: Some("surface mesh peel shader"),
536 source: wgpu::ShaderSource::Wgsl(shader_source.into()),
537 });
538
539 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
540 label: Some("mesh peel pipeline layout"),
541 bind_group_layouts: &[
542 mesh_bind_group_layout, slice_plane_bind_group_layout, matcap_bind_group_layout, peel_bind_group_layout, ],
547 push_constant_ranges: &[],
548 });
549
550 device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
551 label: Some("surface mesh peel pipeline"),
552 layout: Some(&pipeline_layout),
553 vertex: wgpu::VertexState {
554 module: &shader,
555 entry_point: Some("vs_main"),
556 buffers: &[],
557 compilation_options: wgpu::PipelineCompilationOptions::default(),
558 },
559 fragment: Some(wgpu::FragmentState {
560 module: &shader,
561 entry_point: Some("fs_main"),
562 targets: &[
563 Some(wgpu::ColorTargetState {
565 format: wgpu::TextureFormat::Rgba16Float,
566 blend: None, write_mask: wgpu::ColorWrites::ALL,
568 }),
569 Some(wgpu::ColorTargetState {
571 format: wgpu::TextureFormat::R32Float,
572 blend: None,
573 write_mask: wgpu::ColorWrites::ALL,
574 }),
575 ],
576 compilation_options: wgpu::PipelineCompilationOptions::default(),
577 }),
578 primitive: wgpu::PrimitiveState {
579 topology: wgpu::PrimitiveTopology::TriangleList,
580 strip_index_format: None,
581 front_face: wgpu::FrontFace::Ccw,
582 cull_mode: None, polygon_mode: wgpu::PolygonMode::Fill,
584 unclipped_depth: false,
585 conservative: false,
586 },
587 depth_stencil: Some(wgpu::DepthStencilState {
588 format: wgpu::TextureFormat::Depth24PlusStencil8,
589 depth_write_enabled: true, depth_compare: wgpu::CompareFunction::Less,
591 stencil: wgpu::StencilState::default(),
592 bias: wgpu::DepthBiasState::default(),
593 }),
594 multisample: wgpu::MultisampleState::default(),
595 multiview: None,
596 cache: None,
597 })
598 }
599
600 fn create_composite_pipeline(
601 device: &wgpu::Device,
602 bind_group_layout: &wgpu::BindGroupLayout,
603 label: &str,
604 blend: wgpu::BlendState,
605 ) -> wgpu::RenderPipeline {
606 let shader_source = include_str!("shaders/composite_peel.wgsl");
607 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
608 label: Some("composite peel shader"),
609 source: wgpu::ShaderSource::Wgsl(shader_source.into()),
610 });
611
612 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
613 label: Some("composite peel pipeline layout"),
614 bind_group_layouts: &[bind_group_layout],
615 push_constant_ranges: &[],
616 });
617
618 device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
619 label: Some(label),
620 layout: Some(&pipeline_layout),
621 vertex: wgpu::VertexState {
622 module: &shader,
623 entry_point: Some("vs_main"),
624 buffers: &[],
625 compilation_options: wgpu::PipelineCompilationOptions::default(),
626 },
627 fragment: Some(wgpu::FragmentState {
628 module: &shader,
629 entry_point: Some("fs_main"),
630 targets: &[Some(wgpu::ColorTargetState {
631 format: wgpu::TextureFormat::Rgba16Float,
632 blend: Some(blend),
633 write_mask: wgpu::ColorWrites::ALL,
634 })],
635 compilation_options: wgpu::PipelineCompilationOptions::default(),
636 }),
637 primitive: wgpu::PrimitiveState {
638 topology: wgpu::PrimitiveTopology::TriangleList,
639 ..Default::default()
640 },
641 depth_stencil: None,
642 multisample: wgpu::MultisampleState::default(),
643 multiview: None,
644 cache: None,
645 })
646 }
647
648 fn create_depth_update_pipeline(
649 device: &wgpu::Device,
650 bind_group_layout: &wgpu::BindGroupLayout,
651 ) -> wgpu::RenderPipeline {
652 let shader_source = include_str!("shaders/depth_update_peel.wgsl");
655 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
656 label: Some("depth update shader"),
657 source: wgpu::ShaderSource::Wgsl(shader_source.into()),
658 });
659
660 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
661 label: Some("depth update pipeline layout"),
662 bind_group_layouts: &[bind_group_layout],
663 push_constant_ranges: &[],
664 });
665
666 device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
667 label: Some("depth update pipeline"),
668 layout: Some(&pipeline_layout),
669 vertex: wgpu::VertexState {
670 module: &shader,
671 entry_point: Some("vs_main"),
672 buffers: &[],
673 compilation_options: wgpu::PipelineCompilationOptions::default(),
674 },
675 fragment: Some(wgpu::FragmentState {
676 module: &shader,
677 entry_point: Some("fs_main"),
678 targets: &[Some(wgpu::ColorTargetState {
679 format: wgpu::TextureFormat::Rgba16Float,
680 blend: Some(wgpu::BlendState {
684 color: wgpu::BlendComponent {
685 src_factor: wgpu::BlendFactor::One,
686 dst_factor: wgpu::BlendFactor::One,
687 operation: wgpu::BlendOperation::Max,
688 },
689 alpha: wgpu::BlendComponent {
690 src_factor: wgpu::BlendFactor::One,
691 dst_factor: wgpu::BlendFactor::One,
692 operation: wgpu::BlendOperation::Max,
693 },
694 }),
695 write_mask: wgpu::ColorWrites::ALL,
696 })],
697 compilation_options: wgpu::PipelineCompilationOptions::default(),
698 }),
699 primitive: wgpu::PrimitiveState {
700 topology: wgpu::PrimitiveTopology::TriangleList,
701 ..Default::default()
702 },
703 depth_stencil: None,
704 multisample: wgpu::MultisampleState::default(),
705 multiview: None,
706 cache: None,
707 })
708 }
709}